diff --git a/.gn b/.gn index b7734ea..e41eb038 100644 --- a/.gn +++ b/.gn
@@ -74,7 +74,6 @@ "//chrome/notification_helper:*", # 4 errors "//chrome/test:*", # 2682 errors - "//clank/third_party/gvr_shim:*", # 1 error "//extensions/browser/api/declarative:*", # 20 errors "//extensions/browser/api/declarative_net_request:*", # 18 errors "//extensions/browser/api/declarative_webrequest:*", # 29 errors @@ -123,15 +122,7 @@ "//third_party/icu/*", "//third_party/libvpx:*", # 164 errors "//third_party/libwebp:*", # 80 errors, https://crbug.com/800762 - "//third_party/openscreen/src/cast/common:*", # 4 errors - "//third_party/openscreen/src/cast/receiver:*", # 1 error - "//third_party/openscreen/src/cast/streaming:*", # 66 errors "//third_party/openscreen/src/discovery:*", # 36 errors - "//third_party/openscreen/src/osp/impl/quic:*", # 16 errors - "//third_party/openscreen/src/osp/msgs:*", # 5 errors - "//third_party/openscreen/src/osp/public:*", # 1 error - "//third_party/openscreen/src/osp:*", # 13 errors - "//third_party/openscreen/src/util:*", # 29 errors # //v8/*, https://crbug.com/v8/7330 "//v8/src/inspector:*", # 20 errors
diff --git a/DEPS b/DEPS index ad955fb..53f477f2 100644 --- a/DEPS +++ b/DEPS
@@ -184,7 +184,7 @@ 'llvm_force_head_revision': False, # reclient CIPD package version - 'reclient_version': 're_client_version:0.19.3.3b3042c', + 'reclient_version': 're_client_version:0.20.1.c4bbd2f', 'android_git': 'https://android.googlesource.com', 'aomedia_git': 'https://aomedia.googlesource.com', @@ -199,11 +199,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': '140adc67621956d787c5580b2fc23a4fb8fba31a', + 'skia_revision': 'b849f7a791451bfaf7d8b9412ad241296101ceb8', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': 'ddadcacd13fae633df256fb967e61d4dbf1c8083', + 'v8_revision': '45ea66edc82419c79bba183762142785bb5a72e2', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other. @@ -211,7 +211,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': '0f74ae58ed185108ec38a4cb038ef3c31acd9ff4', + 'angle_revision': 'a8a2a71b3ab5e535def6239997f6f24da918556b', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -226,7 +226,7 @@ # # Note this revision should be updated with # third_party/boringssl/roll_boringssl.py, not roll-dep. - 'boringssl_revision': 'c47bfce062cc5a1b462176be626338224ae2a346', + 'boringssl_revision': 'ce9b002ebd0491a8dd802e208814360ce781f32b', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling google-toolbox-for-mac # and whatever else without interference from each other. @@ -246,7 +246,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling NaCl # and whatever else without interference from each other. - 'nacl_revision': '4de55da44c4b511989359381e8b7a88a01fe0634', + 'nacl_revision': '82ac8c0a6f0d3ffc843c693dd5149a356b866ae5', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling freetype # and whatever else without interference from each other. @@ -278,7 +278,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling devtools-frontend # and whatever else without interference from each other. - 'devtools_frontend_revision': 'ea45672fe179b3b841397ca11fb5a89b6e4828a9', + 'devtools_frontend_revision': 'fcfa1e2cc0237111eaaae616a696767e71164090', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libprotobuf-mutator # and whatever else without interference from each other. @@ -318,11 +318,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'dawn_revision': 'e0a588752c827daef74960bbc80d7f5c4f73c4dd', + 'dawn_revision': '7e80cce1a9065d60522d470d24526394d642e6d5', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'quiche_revision': '760dbed127dd9deb869f87e5924d851411cf15a2', + 'quiche_revision': '98ad9db36b75a65f26f239a9aae68ecd1a330125', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ios_webkit # and whatever else without interference from each other. @@ -357,7 +357,7 @@ 'ukey2_revision': '0275885d8e6038c39b8a8ca55e75d1d4d1727f47', # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'tint_revision': '7b7d69854d8d33c97b48795ec350d783dd09dd6a', + 'tint_revision': 'c2118b0dcb2a11d93267dc0877584f9d6855e796', # TODO(crbug.com/941824): The values below need to be kept in sync # between //DEPS and //buildtools/DEPS, so if you're updating one, @@ -554,7 +554,7 @@ }, 'src/ios/third_party/material_components_ios/src': { - 'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '22cb5afa87d9fedc134ae64002e48a3c227b2798', + 'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '25c9049d5a4ee13ed9085ca01a92ed3b25867989', 'condition': 'checkout_ios', }, @@ -678,7 +678,7 @@ 'packages': [ { 'package': 'chromium/third_party/androidx', - 'version': '1WBn0YPU9rlqli8Ctebdf9E3s-CIFp7jei5nojlCemAC', + 'version': 'CUNayWpb4JErvQkdCk8cchP0sY4xV9vBv35PWhtW4bcC', }, ], 'condition': 'checkout_android', @@ -882,6 +882,12 @@ 'dep_type': 'cipd', }, + # Dependency for ChromeVox. + 'src/third_party/chromevox/third_party/sre/src': { + 'url': Var('chromium_git') + '/external/github.com/zorkow/speech-rule-engine.git' + '@' + '5a56d4d33d67dc7c692da032d2ebbdefd7de780e', + 'condition': 'checkout_chromeos', + }, + # Tools used when building Chrome for Chrome OS. This affects both the Simple # Chrome workflow, as well as the chromeos-chrome ebuild. 'src/third_party/chromite': { @@ -905,7 +911,7 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '399c5918bf47ff1fe8477f27b57fa0e8c67e438d', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'b0763b2c57fed430291f0f2a76ec81976118d481', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), @@ -1253,7 +1259,7 @@ Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + '3dd5b80bc4f172dd82925bb259cb7c82348409c5', 'src/third_party/openscreen/src': - Var('chromium_git') + '/openscreen' + '@' + 'b98dcaa0db83132203774a577c0a64c39f7092e9', + Var('chromium_git') + '/openscreen' + '@' + '144746d4a6bd3df27095d321a97b01820c7c2e71', 'src/third_party/openxr/src': { 'url': Var('chromium_git') + '/external/github.com/KhronosGroup/OpenXR-SDK' + '@' + '97cfe495bb7a3853266b646d1c79e169387f9c7a', @@ -1270,7 +1276,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + '9b70f65e3d394d1294080c60bef32a484c1dfbd1', + Var('android_git') + '/platform/external/perfetto.git' + '@' + 'c0182a50034c0c17a444c40aec96ee54239bc269', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', @@ -1348,7 +1354,7 @@ 'packages': [ { 'package': 'fuchsia/third_party/aemu/linux-amd64', - 'version': '-TTr3It7eWfcBQBw8eIFSfLQo5tvHLBoyLYAb7f4LtcC' + 'version': 'ze82f_wfveFwoydF7LkeHv0d-sI8F7BLasfX6xmLVM0C' }, ], 'condition': 'host_os == "linux" and checkout_fuchsia', @@ -1479,7 +1485,7 @@ 'src/third_party/usrsctp/usrsctplib': Var('chromium_git') + '/external/github.com/sctplab/usrsctp' + '@' + 'a6647318b57c0a05d590c8c21fc22aba87f08749', - 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@4dc6ccfad74a3ebb2623bceefff002243d595048', + 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@4ee2104e26ffe3402587f4013eaf5019e56a47c2', 'src/third_party/vulkan_memory_allocator': Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + 'b1d65a2b3373fe12c622eaab65e5cf21b906d178', @@ -1506,7 +1512,7 @@ Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '66460536ee975a3e98931b7b40a661a63fd9cd57', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + 'fa5ad8c0b5efb1b3ad90d8a726feb5cb221a04fe', + Var('webrtc_git') + '/src.git' + '@' + '8bf61a3071b7306860261eadf43c157ce3ffe4fe', 'src/third_party/libgifcodec': Var('skia_git') + '/libgifcodec' + '@'+ Var('libgifcodec_revision'), @@ -1554,7 +1560,7 @@ 'packages': [ { 'package': 'skia/tools/goldctl/windows-amd64', - 'version': 'Evb_hYwKX21F3mSBdnoPa1gPiJlejpLrfECXIpdrrqgC', + 'version': 'xC87Xnbi3y7b2aSw2voaEk8MtTPrvU1peyj7NfC6ZtIC', }, ], 'dep_type': 'cipd', @@ -1578,7 +1584,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@3185e2343b7f9e915517d4125c95dbdb29e0d8f9', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@35f7c5f1cc0d0e3af064e520793179e35687438d', 'condition': 'checkout_src_internal', },
diff --git a/android_webview/browser/page_load_metrics/page_load_metrics_initialize.cc b/android_webview/browser/page_load_metrics/page_load_metrics_initialize.cc index f5a3086..e73229c 100644 --- a/android_webview/browser/page_load_metrics/page_load_metrics_initialize.cc +++ b/android_webview/browser/page_load_metrics/page_load_metrics_initialize.cc
@@ -8,6 +8,14 @@ #include "components/page_load_metrics/browser/metrics_web_contents_observer.h" #include "components/page_load_metrics/browser/page_load_metrics_embedder_base.h" +namespace content { +class BrowserContext; +} // namespace content + +namespace page_load_metrics { +class PageLoadMetricsMemoryTracker; +} // namespace page_load_metrics + namespace android_webview { namespace { @@ -22,6 +30,9 @@ bool IsNewTabPageUrl(const GURL& url) override; bool IsPrerender(content::WebContents* web_contents) override; bool IsExtensionUrl(const GURL& url) override; + page_load_metrics::PageLoadMetricsMemoryTracker* + GetMemoryTrackerForBrowserContext( + content::BrowserContext* browser_context) override; protected: // page_load_metrics::PageLoadMetricsEmbedderBase: @@ -58,6 +69,12 @@ return false; } +page_load_metrics::PageLoadMetricsMemoryTracker* +PageLoadMetricsEmbedder::GetMemoryTrackerForBrowserContext( + content::BrowserContext* browser_context) { + return nullptr; +} + } // namespace void InitializePageLoadMetricsForWebContents(
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index 35cafd95..655058e8 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -726,6 +726,8 @@ "power/hid_battery_util.h", "projector/projector_controller.cc", "projector/projector_controller.h", + "projector/projector_feature_pod_controller.cc", + "projector/projector_feature_pod_controller.h", "projector/projector_metadata_controller.cc", "projector/projector_metadata_controller.h", "projector/projector_metadata_model.cc", @@ -1557,8 +1559,6 @@ "wm/event_client_impl.h", "wm/full_restore/full_restore_controller.cc", "wm/full_restore/full_restore_controller.h", - "wm/full_restore/full_restore_window_manager.cc", - "wm/full_restore/full_restore_window_manager.h", "wm/fullscreen_window_finder.cc", "wm/fullscreen_window_finder.h", "wm/gestures/back_gesture/back_gesture_affordance.cc", @@ -2239,7 +2239,6 @@ "system/message_center/ash_message_popup_collection_unittest.cc", "system/message_center/inactive_user_notification_blocker_unittest.cc", "system/message_center/message_center_ui_controller_unittest.cc", - "system/message_center/message_center_utils_unittest.cc", "system/message_center/notification_swipe_control_view_unittest.cc", "system/message_center/notifier_settings_view_unittest.cc", "system/message_center/session_state_notification_blocker_unittest.cc",
diff --git a/ash/app_list/views/app_list_folder_view.cc b/ash/app_list/views/app_list_folder_view.cc index da60e04..1d7e8dd4 100644 --- a/ash/app_list/views/app_list_folder_view.cc +++ b/ash/app_list/views/app_list_folder_view.cc
@@ -744,8 +744,9 @@ has_native_drag); } -bool AppListFolderView::IsPointOutsideOfFolderBoundary( - const gfx::Point& point) { +bool AppListFolderView::IsViewOutsideOfFolder(AppListItemView* view) { + gfx::Point point = view->GetLocalBounds().CenterPoint(); + ConvertPointToTarget(view, this, &point); return !GetLocalBounds().Contains(point); }
diff --git a/ash/app_list/views/app_list_folder_view.h b/ash/app_list/views/app_list_folder_view.h index 96c02ce..a0f8da2 100644 --- a/ash/app_list/views/app_list_folder_view.h +++ b/ash/app_list/views/app_list_folder_view.h
@@ -148,7 +148,7 @@ const gfx::Point& drag_point_in_folder_grid) override; void DispatchEndDragEventForReparent(bool events_forwarded_to_drag_drop_host, bool cancel_drag) override; - bool IsPointOutsideOfFolderBoundary(const gfx::Point& point) override; + bool IsViewOutsideOfFolder(AppListItemView* view) override; bool IsOEMFolder() const override; void SetRootLevelDragViewVisible(bool visible) override; void HandleKeyboardReparent(AppListItemView* reparented_view,
diff --git a/ash/app_list/views/apps_grid_view.cc b/ash/app_list/views/apps_grid_view.cc index e0dc519c..3f408c8 100644 --- a/ash/app_list/views/apps_grid_view.cc +++ b/ash/app_list/views/apps_grid_view.cc
@@ -1825,10 +1825,8 @@ // Calculate if the drag_view_ is dragged out of the folder's container // ink bubble. - gfx::Rect bounds_to_folder_view = ConvertRectToParent(drag_view_->bounds()); - gfx::Point pt = bounds_to_folder_view.CenterPoint(); bool is_item_dragged_out_of_folder = - folder_delegate_->IsPointOutsideOfFolderBoundary(pt); + folder_delegate_->IsViewOutsideOfFolder(drag_view_); if (is_item_dragged_out_of_folder) { if (!drag_out_of_folder_container_) { folder_item_reparent_timer_.Start(
diff --git a/ash/app_list/views/apps_grid_view_folder_delegate.h b/ash/app_list/views/apps_grid_view_folder_delegate.h index 9853aa3..a398ca8 100644 --- a/ash/app_list/views/apps_grid_view_folder_delegate.h +++ b/ash/app_list/views/apps_grid_view_folder_delegate.h
@@ -42,8 +42,9 @@ bool events_forwarded_to_drag_drop_host, bool cancel_drag) = 0; - // Returns true if |point| falls outside of the folder container ink bubble. - virtual bool IsPointOutsideOfFolderBoundary(const gfx::Point& point) = 0; + // Returns whether the |view| is within the folder view's bounds. + // The |view| is expected to be in the folder's apps grid view hierarchy. + virtual bool IsViewOutsideOfFolder(AppListItemView* view) = 0; // Returns true if the associated folder item is an OEM folder. virtual bool IsOEMFolder() const = 0;
diff --git a/ash/app_list/views/apps_grid_view_unittest.cc b/ash/app_list/views/apps_grid_view_unittest.cc index e94e55e3..54d7d6e8 100644 --- a/ash/app_list/views/apps_grid_view_unittest.cc +++ b/ash/app_list/views/apps_grid_view_unittest.cc
@@ -179,6 +179,36 @@ } // namespace +class TestAppsGridViewFolderDelegate : public AppsGridViewFolderDelegate { + public: + TestAppsGridViewFolderDelegate() = default; + TestAppsGridViewFolderDelegate(const TestAppsGridViewFolderDelegate&) = + delete; + TestAppsGridViewFolderDelegate& operator=( + const TestAppsGridViewFolderDelegate&) = delete; + ~TestAppsGridViewFolderDelegate() override = default; + + void ReparentItem(AppListItemView* original_drag_view, + const gfx::Point& drag_point_in_folder_grid, + bool has_native_drag) override {} + + void DispatchDragEventForReparent( + AppsGridView::Pointer pointer, + const gfx::Point& drag_point_in_folder_grid) override {} + + void DispatchEndDragEventForReparent(bool events_forwarded_to_drag_drop_host, + bool cancel_drag) override {} + + bool IsViewOutsideOfFolder(AppListItemView* view) override { return false; } + + bool IsOEMFolder() const override { return false; } + + void SetRootLevelDragViewVisible(bool visible) override {} + + void HandleKeyboardReparent(AppListItemView* reparented_item, + ui::KeyboardCode key_code) override {} +}; + class AppsGridViewTest : public views::ViewsTestBase, public testing::WithParamInterface<bool> { public: @@ -234,22 +264,40 @@ } protected: - AppListItemView* GetItemViewAt(int index) const { - return static_cast<AppListItemView*>(test_api_->GetViewAtModelIndex(index)); + AppListItemView* GetItemViewInAppsGridAt(int index, + AppsGridView* grid_view) const { + return grid_view->view_model()->view_at(index); } - AppListItemView* GetItemViewForPoint(const gfx::Point& point) const { - for (size_t i = 0; i < model_->top_level_item_list()->item_count(); ++i) { - AppListItemView* view = GetItemViewAt(i); + AppListItemView* GetItemViewInTopLevelGrid(int index) const { + return GetItemViewInAppsGridAt(index, apps_grid_view_); + } + + AppListItemView* GetItemViewInAppsGridForPoint( + const gfx::Point& point, + AppsGridView* grid_view) const { + std::unique_ptr<AppsGridViewTestApi> temp_test_api = + std::make_unique<AppsGridViewTestApi>(grid_view); + AppListItemList* item_list_ = temp_test_api->GetItemList(); + for (size_t i = 0; i < item_list_->item_count(); ++i) { + AppListItemView* view = GetItemViewInAppsGridAt(i, grid_view); gfx::Point view_origin = view->origin(); - views::View::ConvertPointToTarget(view->parent(), apps_grid_view_, - &view_origin); + // Covert point to target if we are working with the app list's apps grid + // view. + if (grid_view == apps_grid_view_) { + views::View::ConvertPointToTarget(view->parent(), grid_view, + &view_origin); + } if (gfx::Rect(view_origin, view->size()).Contains(point)) return view; } return nullptr; } + AppListItemView* GetItemViewForPoint(const gfx::Point& point) const { + return GetItemViewInAppsGridForPoint(point, apps_grid_view_); + } + gfx::Rect GetItemRectOnCurrentPageAt(int row, int col) const { DCHECK_GT(model_->top_level_item_list()->item_count(), 0u); return test_api_->GetItemTileRectOnCurrentPageAt(row, col); @@ -265,31 +313,69 @@ return contents_view_->apps_container_view()->app_list_folder_view(); } + AppsGridView* folder_apps_grid_view() const { + return app_list_folder_view()->items_grid_view(); + } + + AppListItemView* InitiateDrag(AppsGridView::Pointer pointer, + const gfx::Point& from, + AppsGridView* apps_grid_view) { + AppListItemView* view = GetItemViewInAppsGridForPoint(from, apps_grid_view); + DCHECK(view); + gfx::Point root_from(from); + gfx::NativeWindow window = app_list_view_->GetWidget()->GetNativeWindow(); + views::View::ConvertPointToWidget(apps_grid_view, &root_from); + aura::Window::ConvertPointToTarget(window, window->GetRootWindow(), + &root_from); + // Ensure that the |root_from| point is correct if RTL. + root_from.set_x(apps_grid_view->GetMirroredXInView(root_from.x())); + + apps_grid_view->InitiateDrag(view, pointer, root_from, root_from); + current_drag_location_ = root_from; + return view; + } + + // Updates the drag from the current drag location to the destination point + // |to|. These coordinates are relative the |apps_grid_view| which may belong + // to either the app list or an open folder view. + void UpdateDrag(AppsGridView::Pointer pointer, + const gfx::Point& to, + AppsGridView* apps_grid_view, + int steps = 1) { + // Check that the drag has been initialized. + DCHECK(current_drag_location_); + gfx::Point root_to(to); + gfx::NativeWindow window = apps_grid_view->GetWidget()->GetNativeWindow(); + views::View::ConvertPointToWidget(apps_grid_view, &root_to); + aura::Window::ConvertPointToTarget(window, window->GetRootWindow(), + &root_to); + // Ensure that the |root_to| point is correct if RTL. + root_to.set_x(apps_grid_view->GetMirroredXInView(root_to.x())); + + for (int step = 1; step <= steps; step += 1) { + gfx::Point drag_increment_point(*current_drag_location_); + drag_increment_point += gfx::Vector2d( + (root_to.x() - current_drag_location_->x()) * step / steps, + (root_to.y() - current_drag_location_->y()) * step / steps); + ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED, to, drag_increment_point, + ui::EventTimeForNow(), 0, 0); + apps_grid_view->UpdateDragFromItem(pointer, drag_event); + } + + current_drag_location_ = root_to; + } + + void EndDrag(AppsGridView* grid_view, bool cancel) { + grid_view->EndDrag(cancel); + current_drag_location_ = base::nullopt; + } + // Points are in |apps_grid_view_|'s coordinates, and fixed for RTL. AppListItemView* SimulateDrag(AppsGridView::Pointer pointer, const gfx::Point& from, const gfx::Point& to) { - AppListItemView* view = GetItemViewForPoint(from); - DCHECK(view); - - gfx::NativeWindow window = app_list_view_->GetWidget()->GetNativeWindow(); - gfx::Point root_from(from); - views::View::ConvertPointToWidget(apps_grid_view_, &root_from); - aura::Window::ConvertPointToTarget(window, window->GetRootWindow(), - &root_from); - // Ensure that the |root_from| point is correct if RTL. - root_from.set_x(apps_grid_view_->GetMirroredXInView(root_from.x())); - gfx::Point root_to(to); - views::View::ConvertPointToWidget(apps_grid_view_, &root_to); - aura::Window::ConvertPointToTarget(window, window->GetRootWindow(), - &root_to); - // Ensure that the |root_to| point is correct if RTL. - root_to.set_x(apps_grid_view_->GetMirroredXInView(root_to.x())); - apps_grid_view_->InitiateDrag(view, pointer, from, root_from); - - ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED, to, root_to, - ui::EventTimeForNow(), 0, 0); - apps_grid_view_->UpdateDragFromItem(pointer, drag_event); + AppListItemView* view = InitiateDrag(pointer, from, apps_grid_view_); + UpdateDrag(pointer, to, apps_grid_view_); return view; } @@ -355,6 +441,8 @@ bool create_as_tablet_mode_ = false; private: + base::Optional<gfx::Point> current_drag_location_; + // Restores the locale to default when destructor is called. base::test::ScopedRestoreICUDefaultLocale restore_locale_; @@ -366,37 +454,6 @@ INSTANTIATE_TEST_SUITE_P(All, AppsGridViewTest, testing::Bool()); -class TestAppsGridViewFolderDelegate : public AppsGridViewFolderDelegate { - public: - TestAppsGridViewFolderDelegate() = default; - ~TestAppsGridViewFolderDelegate() override = default; - - void ReparentItem(AppListItemView* original_drag_view, - const gfx::Point& drag_point_in_folder_grid, - bool has_native_drag) override {} - - void DispatchDragEventForReparent( - AppsGridView::Pointer pointer, - const gfx::Point& drag_point_in_folder_grid) override {} - - void DispatchEndDragEventForReparent(bool events_forwarded_to_drag_drop_host, - bool cancel_drag) override {} - - bool IsPointOutsideOfFolderBoundary(const gfx::Point& point) override { - return false; - } - - bool IsOEMFolder() const override { return false; } - - void SetRootLevelDragViewVisible(bool visible) override {} - - void HandleKeyboardReparent(AppListItemView* reparented_item, - ui::KeyboardCode key_code) override {} - - private: - DISALLOW_COPY_AND_ASSIGN(TestAppsGridViewFolderDelegate); -}; - TEST_P(AppsGridViewTest, CreatePage) { // Fully populates a page. const int kPages = 1; @@ -421,14 +478,14 @@ model_->PopulateApps(kTotalItems); - AppListItemView* last_view = GetItemViewAt(kLastItemIndex); + AppListItemView* last_view = GetItemViewInTopLevelGrid(kLastItemIndex); apps_grid_view_->SetSelectedView(last_view); model_->DeleteItem(model_->GetItemName(kLastItemIndex)); EXPECT_FALSE(apps_grid_view_->IsSelectedView(last_view)); // No crash happens. - AppListItemView* view = GetItemViewAt(0); + AppListItemView* view = GetItemViewInTopLevelGrid(0); apps_grid_view_->SetSelectedView(view); EXPECT_TRUE(apps_grid_view_->IsSelectedView(view)); } @@ -440,8 +497,8 @@ model_->PopulateApps(5); // Select the first app in grid and launch it. - contents_view_->GetAppListMainView()->ActivateApp(GetItemViewAt(0)->item(), - 0); + contents_view_->GetAppListMainView()->ActivateApp( + GetItemViewInTopLevelGrid(0)->item(), 0); // Test that histogram recorded app launch from grid. histogram_tester.ExpectBucketCount( @@ -465,12 +522,12 @@ ASSERT_LE(0, cols); model_->PopulateApps(cols * 2); - AppListItemView* view0 = GetItemViewAt(0); + AppListItemView* view0 = GetItemViewInTopLevelGrid(0); model_->top_level_item_list()->MoveItem(0, cols + 2); // Make sure the logical location of the view. - EXPECT_NE(view0, GetItemViewAt(0)); - EXPECT_EQ(view0, GetItemViewAt(cols + 2)); + EXPECT_NE(view0, GetItemViewInTopLevelGrid(0)); + EXPECT_EQ(view0, GetItemViewInTopLevelGrid(cols + 2)); // |view0| should be animating with layer. EXPECT_TRUE(view0->layer()); @@ -488,12 +545,12 @@ apps_grid_view_->GetWidget()->Hide(); - AppListItemView* view0 = GetItemViewAt(0); + AppListItemView* view0 = GetItemViewInTopLevelGrid(0); model_->top_level_item_list()->MoveItem(0, cols + 2); // Make sure the logical location of the view. - EXPECT_NE(view0, GetItemViewAt(0)); - EXPECT_EQ(view0, GetItemViewAt(cols + 2)); + EXPECT_NE(view0, GetItemViewInTopLevelGrid(0)); + EXPECT_EQ(view0, GetItemViewInTopLevelGrid(cols + 2)); // The item should be repositioned immediately when the widget is not visible. EXPECT_FALSE(view0->layer()); @@ -519,7 +576,7 @@ AppListItem* item = model_->CreateAndAddItem("Item with short name"); model_->SetItemNameAndShortName(item, expected_tooltip, expected_text); - AppListItemView* item_view = GetItemViewAt(0); + AppListItemView* item_view = GetItemViewInTopLevelGrid(0); ASSERT_TRUE(item_view); const views::Label* title_label = item_view->title(); EXPECT_EQ(base::ASCIIToUTF16(expected_tooltip), @@ -534,7 +591,7 @@ AppListItem* item = model_->CreateAndAddItem(title); model_->SetItemNameAndShortName(item, title, ""); - AppListItemView* item_view = GetItemViewAt(0); + AppListItemView* item_view = GetItemViewInTopLevelGrid(0); ASSERT_TRUE(item_view); const views::Label* title_label = item_view->title(); EXPECT_TRUE( @@ -784,7 +841,7 @@ TEST_F(AppsGridViewTest, AppIconSelectedWhenMenuIsShown) { model_->PopulateApps(1); ASSERT_EQ(1u, model_->top_level_item_list()->item_count()); - AppListItemView* app = GetItemViewAt(0); + AppListItemView* app = GetItemViewInTopLevelGrid(0); EXPECT_FALSE(apps_grid_view_->IsSelectedView(app)); // Send a mouse event which would show a context menu. @@ -820,11 +877,11 @@ std::vector<int> pages_to_check = {1, 0}; for (int i : pages_to_check) { - apps_grid_view_->pagination_model()->SelectPage(i, /*animate=*/false); + GetPaginationModel()->SelectPage(i, /*animate=*/false); for (size_t j = 0; j < kItemsInPage; ++j) { const size_t idx = kItemsInPage * i + j; - AppListItemView* item_view = GetItemViewAt(idx); + AppListItemView* item_view = GetItemViewInTopLevelGrid(idx); // Send a mouse event which would show a context menu. ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, gfx::Point(), @@ -860,7 +917,7 @@ model_->PopulateApps(kTotalItems); // Normally individual item-view does not have a layer. for (size_t i = 0; i < model_->top_level_item_list()->item_count(); ++i) - EXPECT_FALSE(GetItemViewAt(i)->layer()); + EXPECT_FALSE(GetItemViewInTopLevelGrid(i)->layer()); EXPECT_EQ(model_->top_level_item_list()->item_count(), kTotalItems); EXPECT_EQ(std::string("Item 0,Item 1,Item 2"), model_->GetModelContent()); @@ -871,13 +928,13 @@ SimulateDrag(AppsGridView::MOUSE, from, to); // Each item view has its own layer during the drag. for (size_t i = 0; i < model_->top_level_item_list()->item_count(); ++i) - EXPECT_TRUE(GetItemViewAt(i)->layer()); - apps_grid_view_->EndDrag(false); + EXPECT_TRUE(GetItemViewInTopLevelGrid(i)->layer()); + EndDrag(apps_grid_view_, false /*cancel*/); // The layer should be destroyed after the dragging. test_api_->WaitForItemMoveAnimationDone(); for (size_t i = 0; i < model_->top_level_item_list()->item_count(); ++i) - EXPECT_FALSE(GetItemViewAt(i)->layer()); + EXPECT_FALSE(GetItemViewInTopLevelGrid(i)->layer()); EXPECT_EQ(kTotalItems - 1, model_->top_level_item_list()->item_count()); EXPECT_EQ(AppListFolderItem::kItemType, model_->top_level_item_list()->item_at(0)->GetItemType()); @@ -896,7 +953,7 @@ // Dragging item_2 to the folder adds item_2 to the folder. SimulateDrag(AppsGridView::MOUSE, from, to); - apps_grid_view_->EndDrag(false); + EndDrag(apps_grid_view_, false /*cancel*/); EXPECT_EQ(kTotalItems - 2, model_->top_level_item_list()->item_count()); EXPECT_EQ(folder_item->id(), model_->GetModelContent()); @@ -913,6 +970,141 @@ test_api_->LayoutToIdealBounds(); } +TEST_P(AppsGridViewTest, MouseDragItemOutOfFolderFirstPage) { + // Creates a folder item. + const size_t kTotalItems = + AppListConfig::instance().max_folder_items_per_page(); + AppListFolderItem* folder_item = + model_->CreateAndPopulateFolderWithApps(kTotalItems); + EXPECT_EQ(1u, model_->top_level_item_list()->item_count()); + EXPECT_EQ(AppListFolderItem::kItemType, + model_->top_level_item_list()->item_at(0)->GetItemType()); + EXPECT_EQ(kTotalItems, folder_item->ChildItemCount()); + + // Open the folder and check it's contents. + test_api_->Update(); + test_api_->PressItemAt(0); + EXPECT_EQ(4, folder_apps_grid_view()->cols()); + EXPECT_EQ(4, folder_apps_grid_view()->rows_per_page()); + ash::PaginationModel* folder_pagination_model = + folder_apps_grid_view()->pagination_model(); + EXPECT_EQ(1, folder_pagination_model->total_pages()); + EXPECT_EQ(0, folder_pagination_model->selected_page()); + EXPECT_TRUE(folder_apps_grid_view()->is_in_folder()); + + AppsGridViewTestApi folder_grid_test_api(folder_apps_grid_view()); + + gfx::Point from = + folder_grid_test_api.GetItemTileRectOnCurrentPageAt(0, 0).CenterPoint(); + // Drag the first folder child out of the folder. + AppListItemView* drag_view = + InitiateDrag(AppsGridView::MOUSE, from, folder_apps_grid_view()); + // Calculate the target destination for our drag and update the drag to that + // location. + gfx::Point empty_space = + app_list_folder_view()->GetLocalBounds().bottom_center() + + gfx::Vector2d(0, drag_view->height() + /*padding to completely exit folder view*/); + + UpdateDrag(AppsGridView::MOUSE, empty_space, folder_apps_grid_view(), + 10 /*steps*/); + + // Fire the reparent timer that should be started when an item is dragged out + // of folder bounds. + ASSERT_TRUE(folder_apps_grid_view()->FireFolderItemReparentTimerForTest()); + // Calculate the coordinates for the drop point. Note that we we are dropping + // into the app list view not the folder view. The (0,1) spot is empty. + gfx::Point drop_point = GetItemRectOnCurrentPageAt(0, 1).CenterPoint(); + drop_point.set_x(apps_grid_view_->GetMirroredXInView(drop_point.x())); + views::View::ConvertPointToTarget(apps_grid_view_, folder_apps_grid_view(), + &drop_point); + UpdateDrag(AppsGridView::MOUSE, drop_point, folder_apps_grid_view(), + 5 /*steps*/); + + // End the drag and assert that the item has been dragged out of the folder + // and the app list's grid view has been updated accordingly. + EndDrag(folder_apps_grid_view(), false /*cancel*/); + AppListItem* item_0 = model_->FindItem("Item 0"); + AppListItem* item_1 = model_->FindItem("Item 1"); + EXPECT_FALSE(item_0->IsInFolder()); + EXPECT_TRUE(item_1->IsInFolder()); + EXPECT_EQ(folder_item->id(), item_1->folder_id()); + EXPECT_EQ(std::string(folder_item->id() + ",Item 0"), + model_->GetModelContent()); + EXPECT_EQ(kTotalItems - 1, folder_item->ChildItemCount()); +} + +TEST_P(AppsGridViewTest, MouseDragItemOutOfFolderSecondPage) { + // Creates a folder item with enough views to have a second page. + const size_t kTotalItems = + AppListConfig::instance().max_folder_items_per_page() + 1; + AppListFolderItem* folder_item = + model_->CreateAndPopulateFolderWithApps(kTotalItems); + EXPECT_EQ(1u, model_->top_level_item_list()->item_count()); + EXPECT_EQ(AppListFolderItem::kItemType, + model_->top_level_item_list()->item_at(0)->GetItemType()); + EXPECT_EQ(kTotalItems, folder_item->ChildItemCount()); + + // Open the folder and check it's contents. + test_api_->Update(); + test_api_->PressItemAt(0); + EXPECT_EQ(4, folder_apps_grid_view()->cols()); + EXPECT_EQ(4, folder_apps_grid_view()->rows_per_page()); + ash::PaginationModel* folder_pagination_model = + folder_apps_grid_view()->pagination_model(); + EXPECT_EQ(2, folder_pagination_model->total_pages()); + EXPECT_EQ(0, folder_pagination_model->selected_page()); + EXPECT_TRUE(folder_apps_grid_view()->is_in_folder()); + + // Switch to second page and check it's contents. + folder_pagination_model->SelectPage(1, false /*animate*/); + EXPECT_EQ(1, folder_pagination_model->selected_page()); + EXPECT_EQ(4, folder_apps_grid_view()->cols()); + EXPECT_EQ(4, folder_apps_grid_view()->rows_per_page()); + EXPECT_TRUE(folder_apps_grid_view()->is_in_folder()); + + AppsGridViewTestApi folder_grid_test_api(folder_apps_grid_view()); + + gfx::Point from = + folder_grid_test_api.GetItemTileRectOnCurrentPageAt(0, 0).CenterPoint(); + // Drag the first folder child on the second page out of the folder. + AppListItemView* drag_view = + InitiateDrag(AppsGridView::MOUSE, from, folder_apps_grid_view()); + // Calculate the target destination for our drag and update the drag to that + // location. + gfx::Point empty_space = + app_list_folder_view()->GetLocalBounds().bottom_center() + + gfx::Vector2d(0, drag_view->height() + /*padding to completely exit folder view*/); + + UpdateDrag(AppsGridView::MOUSE, empty_space, folder_apps_grid_view(), + 10 /*steps*/); + + // Fire the reparent timer that should be started when an item is dragged out + // of folder bounds. + ASSERT_TRUE(folder_apps_grid_view()->FireFolderItemReparentTimerForTest()); + // Calculate the coordinates for the drop point. Note that we we are dropping + // into the app list view not the folder view. The (0,1) spot is empty. + gfx::Point drop_point = GetItemRectOnCurrentPageAt(0, 1).CenterPoint(); + drop_point.set_x(apps_grid_view_->GetMirroredXInView(drop_point.x())); + views::View::ConvertPointToTarget(apps_grid_view_, folder_apps_grid_view(), + &drop_point); + UpdateDrag(AppsGridView::MOUSE, drop_point, folder_apps_grid_view(), + 5 /*steps*/); + + // End the drag and assert that the item has been dragged out of the folder + // and the app list's grid view has been updated accordingly. + EndDrag(folder_apps_grid_view(), false /*cancel*/); + AppListItem* item_0 = model_->FindItem("Item 0"); + AppListItem* item_1 = model_->FindItem("Item 1"); + EXPECT_FALSE(item_0->IsInFolder()); + EXPECT_TRUE(item_1->IsInFolder()); + EXPECT_EQ(folder_item->id(), item_1->folder_id()); + EXPECT_EQ(std::string(folder_item->id() + ",Item 0"), + model_->GetModelContent()); + EXPECT_EQ(kTotalItems - 1, folder_item->ChildItemCount()); +} + TEST_P(AppsGridViewTest, MouseDragMaxItemsInFolder) { // Create and add a folder with |kMaxFolderItemsFullscreen - 1| items. const size_t kMaxItems = @@ -941,7 +1133,7 @@ // Dragging one item into the folder, the folder should accept the item. SimulateDrag(AppsGridView::MOUSE, from, to); - apps_grid_view_->EndDrag(false); + EndDrag(apps_grid_view_, false /*cancel*/); EXPECT_EQ(2u, model_->top_level_item_list()->item_count()); EXPECT_EQ(folder_item->id(), model_->top_level_item_list()->item_at(0)->id()); EXPECT_EQ(kMaxItems, folder_item->ChildItemCount()); @@ -952,7 +1144,7 @@ // Dragging the last item over the folder, the folder won't accept the new // item. SimulateDrag(AppsGridView::MOUSE, from, to); - apps_grid_view_->EndDrag(false); + EndDrag(apps_grid_view_, false /*cancel*/); EXPECT_EQ(2u, model_->top_level_item_list()->item_count()); EXPECT_EQ(kMaxItems, folder_item->ChildItemCount()); test_api_->LayoutToIdealBounds(); @@ -1004,7 +1196,7 @@ ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED, translated_to, to, ui::EventTimeForNow(), 0, 0); apps_grid_view_->UpdateDragFromItem(AppsGridView::MOUSE, drag_event); - apps_grid_view_->EndDrag(false); + EndDrag(apps_grid_view_, false /*cancel*/); // The item should not have moved into the folder. EXPECT_EQ(2u, model_->top_level_item_list()->item_count()); @@ -1035,7 +1227,7 @@ // Drag left but stop before the folder dropping circle. drag_vector.set_x(-half_tile_width - 4); SimulateDrag(AppsGridView::MOUSE, top_right, top_right + drag_vector); - apps_grid_view_->EndDrag(false); + EndDrag(apps_grid_view_, false /*cancel*/); EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3,Item 4,Item 5,Item 6"), model_->GetModelContent()); TestAppListItemViewIndice(); @@ -1047,7 +1239,7 @@ 4); SimulateDrag(AppsGridView::MOUSE, top_right + last_drag_vector, top_right + drag_vector); - apps_grid_view_->EndDrag(false); + EndDrag(apps_grid_view_, false /*cancel*/); EXPECT_EQ(std::string("Item 1,Item 0,Item 2,Item 3,Item 4,Item 5,Item 6"), model_->GetModelContent()); TestAppListItemViewIndice(); @@ -1059,7 +1251,7 @@ drag_vector.set_y(tile_height); SimulateDrag(AppsGridView::MOUSE, top_right + last_drag_vector, top_right + drag_vector); - apps_grid_view_->EndDrag(false); + EndDrag(apps_grid_view_, false /*cancel*/); EXPECT_EQ(std::string("Item 0,Item 2,Item 3,Item 4,Item 5,Item 1,Item 6"), model_->GetModelContent()); TestAppListItemViewIndice(); @@ -1071,7 +1263,7 @@ drag_vector.set_y(0); SimulateDrag(AppsGridView::MOUSE, top_right + last_drag_vector, top_right + drag_vector); - apps_grid_view_->EndDrag(false); + EndDrag(apps_grid_view_, false /*cancel*/); EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3,Item 4,Item 5,Item 6"), model_->GetModelContent()); TestAppListItemViewIndice(); @@ -1082,7 +1274,7 @@ drag_vector.set_y(2 * tile_height); SimulateDrag(AppsGridView::MOUSE, top_right + last_drag_vector, top_right + drag_vector); - apps_grid_view_->EndDrag(false); + EndDrag(apps_grid_view_, false /*cancel*/); EXPECT_EQ(std::string("Item 0,Item 2,Item 3,Item 4,Item 5,Item 6,Item 1"), model_->GetModelContent()); TestAppListItemViewIndice(); @@ -1105,7 +1297,7 @@ // Dragging folder over item_1 should leads to re-ordering these two // items. SimulateDrag(AppsGridView::MOUSE, from, to); - apps_grid_view_->EndDrag(false); + EndDrag(apps_grid_view_, false /*cancel*/); EXPECT_EQ(2u, model_->top_level_item_list()->item_count()); EXPECT_EQ("Item 2", model_->top_level_item_list()->item_at(0)->id()); EXPECT_EQ(folder_item->id(), model_->top_level_item_list()->item_at(1)->id()); @@ -1125,7 +1317,7 @@ // Canceling drag should keep existing order. SimulateDrag(AppsGridView::MOUSE, from, to); - apps_grid_view_->EndDrag(true); + EndDrag(apps_grid_view_, true /*cancel*/); EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"), model_->GetModelContent()); test_api_->LayoutToIdealBounds(); @@ -1133,14 +1325,14 @@ // Deleting an item keeps remaining intact. SimulateDrag(AppsGridView::MOUSE, from, to); model_->DeleteItem(model_->GetItemName(2)); - apps_grid_view_->EndDrag(false); + EndDrag(apps_grid_view_, false /*cancel*/); EXPECT_EQ(std::string("Item 0,Item 1,Item 3"), model_->GetModelContent()); test_api_->LayoutToIdealBounds(); // Adding a launcher item cancels the drag and respects the order. SimulateDrag(AppsGridView::MOUSE, from, to); model_->CreateAndAddItem("Extra"); - apps_grid_view_->EndDrag(false); + EndDrag(apps_grid_view_, false /*cancel*/); EXPECT_EQ(std::string("Item 0,Item 1,Item 3,Extra"), model_->GetModelContent()); test_api_->LayoutToIdealBounds(); @@ -1150,7 +1342,7 @@ TEST_F(AppsGridViewTest, ControlArrowSwapsAppsWithinSamePage) { model_->PopulateApps(GetTilesPerPage(0)); - AppListItemView* moving_item = GetItemViewAt(0); + AppListItemView* moving_item = GetItemViewInTopLevelGrid(0); apps_grid_view_->GetFocusManager()->SetFocusedView(moving_item); // Test that moving left from 0,0 does not move the app. @@ -1162,39 +1354,41 @@ // Test that moving up from 0,0 does not move the app. SimulateKeyPress(ui::VKEY_UP, ui::EF_CONTROL_DOWN); - EXPECT_EQ(moving_item, GetItemViewAt(0)); + EXPECT_EQ(moving_item, GetItemViewInTopLevelGrid(0)); EXPECT_TRUE(apps_grid_view_->IsSelectedView(moving_item)); // Test that moving right from 0,0 results in a swap with the item adjacent. - AppListItemView* swapped_item = GetItemViewAt(1); + AppListItemView* swapped_item = GetItemViewInTopLevelGrid(1); SimulateKeyPress(ui::VKEY_RIGHT, ui::EF_CONTROL_DOWN); - EXPECT_EQ(moving_item, GetItemViewAt(1)); - EXPECT_EQ(swapped_item, GetItemViewAt(0)); + EXPECT_EQ(moving_item, GetItemViewInTopLevelGrid(1)); + EXPECT_EQ(swapped_item, GetItemViewInTopLevelGrid(0)); EXPECT_TRUE(apps_grid_view_->IsSelectedView(moving_item)); // Test that moving down from 0,1 results in a swap with the item at 1,1. - swapped_item = GetItemViewAt(apps_grid_view_->cols() + 1); + swapped_item = GetItemViewInTopLevelGrid(apps_grid_view_->cols() + 1); SimulateKeyPress(ui::VKEY_DOWN, ui::EF_CONTROL_DOWN); - EXPECT_EQ(moving_item, GetItemViewAt(apps_grid_view_->cols() + 1)); - EXPECT_EQ(swapped_item, GetItemViewAt(1)); + EXPECT_EQ(moving_item, + GetItemViewInTopLevelGrid(apps_grid_view_->cols() + 1)); + EXPECT_EQ(swapped_item, GetItemViewInTopLevelGrid(1)); EXPECT_TRUE(apps_grid_view_->IsSelectedView(moving_item)); // Test that moving left from 1,1 results in a swap with the item at 1,0. - swapped_item = GetItemViewAt(apps_grid_view_->cols()); + swapped_item = GetItemViewInTopLevelGrid(apps_grid_view_->cols()); SimulateKeyPress(ui::VKEY_LEFT, ui::EF_CONTROL_DOWN); - EXPECT_EQ(moving_item, GetItemViewAt(apps_grid_view_->cols())); - EXPECT_EQ(swapped_item, GetItemViewAt(apps_grid_view_->cols() + 1)); + EXPECT_EQ(moving_item, GetItemViewInTopLevelGrid(apps_grid_view_->cols())); + EXPECT_EQ(swapped_item, + GetItemViewInTopLevelGrid(apps_grid_view_->cols() + 1)); EXPECT_TRUE(apps_grid_view_->IsSelectedView(moving_item)); // Test that moving up from 1,0 results in a swap with the item at 0,0. - swapped_item = GetItemViewAt(0); + swapped_item = GetItemViewInTopLevelGrid(0); SimulateKeyPress(ui::VKEY_UP, ui::EF_CONTROL_DOWN); - EXPECT_EQ(moving_item, GetItemViewAt(0)); - EXPECT_EQ(swapped_item, GetItemViewAt(apps_grid_view_->cols())); + EXPECT_EQ(moving_item, GetItemViewInTopLevelGrid(0)); + EXPECT_EQ(swapped_item, GetItemViewInTopLevelGrid(apps_grid_view_->cols())); EXPECT_TRUE(apps_grid_view_->IsSelectedView(moving_item)); } @@ -1203,7 +1397,7 @@ base::HistogramTester histogram_tester; model_->PopulateApps(GetTilesPerPage(0)); - AppListItemView* moving_item = GetItemViewAt(0); + AppListItemView* moving_item = GetItemViewInTopLevelGrid(0); apps_grid_view_->GetFocusManager()->SetFocusedView(moving_item); // Make one move right and expect a histogram is recorded. @@ -1236,7 +1430,7 @@ base::HistogramTester histogram_tester; model_->PopulateApps(GetTilesPerPage(0)); - AppListItemView* moving_item = GetItemViewAt(0); + AppListItemView* moving_item = GetItemViewInTopLevelGrid(0); apps_grid_view_->GetFocusManager()->SetFocusedView(moving_item); // Make 2 no-op moves and one successful move from 0,0 ane expect a histogram @@ -1258,7 +1452,7 @@ base::HistogramTester histogram_tester; model_->PopulateApps(GetTilesPerPage(1) * 2); - AppListItemView* moving_item = GetItemViewAt(0); + AppListItemView* moving_item = GetItemViewInTopLevelGrid(0); apps_grid_view_->GetFocusManager()->SetFocusedView(moving_item); // Make that a series of moves when the control key is left pressed and expect @@ -1279,16 +1473,19 @@ model_->PopulateApps(apps_grid_view_->cols() + 1); // Select the far right item. - AppListItemView* moving_item = GetItemViewAt(apps_grid_view_->cols() - 1); - AppListItemView* swapped_item = GetItemViewAt(apps_grid_view_->cols()); + AppListItemView* moving_item = + GetItemViewInTopLevelGrid(apps_grid_view_->cols() - 1); + AppListItemView* swapped_item = + GetItemViewInTopLevelGrid(apps_grid_view_->cols()); apps_grid_view_->GetFocusManager()->SetFocusedView(moving_item); // Press down to move the app to the next row. It should take the place of the // app on the next row that is closes to the column of |moving_item|. SimulateKeyPress(ui::VKEY_DOWN, ui::EF_CONTROL_DOWN); - EXPECT_EQ(moving_item, GetItemViewAt(apps_grid_view_->cols())); - EXPECT_EQ(swapped_item, GetItemViewAt(apps_grid_view_->cols() - 1)); + EXPECT_EQ(moving_item, GetItemViewInTopLevelGrid(apps_grid_view_->cols())); + EXPECT_EQ(swapped_item, + GetItemViewInTopLevelGrid(apps_grid_view_->cols() - 1)); } // Tests that moving an app up/down/left/right to a full page results in the app @@ -1382,7 +1579,8 @@ model_->PopulateApps(kTilesPerPageStart); // Focus the last item on the page. - AppListItemView* moving_item = GetItemViewAt(kTilesPerPageStart - 1); + AppListItemView* moving_item = + GetItemViewInTopLevelGrid(kTilesPerPageStart - 1); apps_grid_view_->GetFocusManager()->SetFocusedView(moving_item); // Test that pressing control-right creates a new page. @@ -1422,7 +1620,8 @@ base::HistogramTester histogram_tester; // Move an app so it is by itself on page 1. model_->PopulateApps(GetTilesPerPage(0)); - AppListItemView* moving_item = GetItemViewAt(GetTilesPerPage(0) - 1); + AppListItemView* moving_item = + GetItemViewInTopLevelGrid(GetTilesPerPage(0) - 1); apps_grid_view_->GetFocusManager()->SetFocusedView(moving_item); SimulateKeyPress(ui::VKEY_DOWN, ui::EF_CONTROL_DOWN); histogram_tester.ExpectBucketCount("Apps.AppListPageSwitcherSource", 7, 1); @@ -1456,7 +1655,8 @@ base::HistogramTester histogram_tester; // Move an app so it is by itself on page 1. model_->PopulateApps(GetTilesPerPage(0)); - AppListItemView* moving_item = GetItemViewAt(GetTilesPerPage(0) - 1); + AppListItemView* moving_item = + GetItemViewInTopLevelGrid(GetTilesPerPage(0) - 1); apps_grid_view_->GetFocusManager()->SetFocusedView(moving_item); SimulateKeyPress(ui::VKEY_DOWN, ui::EF_CONTROL_DOWN); SimulateKeyReleased(ui::VKEY_DOWN, ui::EF_NONE); @@ -1491,7 +1691,8 @@ TEST_F(AppsGridViewTest, ControlArrowDownOrRightRemovesPage) { // Move an app so it is by itself on page 1, with another app on page 2. model_->PopulateApps(GetTilesPerPage(0)); - AppListItemView* moving_item = GetItemViewAt(GetTilesPerPage(0) - 1); + AppListItemView* moving_item = + GetItemViewInTopLevelGrid(GetTilesPerPage(0) - 1); apps_grid_view_->GetFocusManager()->SetFocusedView(moving_item); SimulateKeyPress(ui::VKEY_DOWN, ui::EF_CONTROL_DOWN); SimulateKeyPress(ui::VKEY_UP); @@ -1532,16 +1733,16 @@ base::HistogramTester histogram_tester; model_->PopulateApps(GetTilesPerPage(0)); // Select the first item in the grid, folder it with the item to the right. - AppListItemView* first_item = GetItemViewAt(0); + AppListItemView* first_item = GetItemViewInTopLevelGrid(0); const std::string first_item_id = first_item->item()->id(); - const std::string second_item_id = GetItemViewAt(1)->item()->id(); + const std::string second_item_id = GetItemViewInTopLevelGrid(1)->item()->id(); apps_grid_view_->GetFocusManager()->SetFocusedView(first_item); SimulateKeyPress(ui::VKEY_RIGHT, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN); // Test that the first item in the grid is now a folder with the first and // second items, and that the folder is the selected view. - AppListItemView* new_folder = GetItemViewAt(0); + AppListItemView* new_folder = GetItemViewInTopLevelGrid(0); ASSERT_TRUE(apps_grid_view_->IsSelectedView(new_folder)); AppListFolderItem* folder_item = static_cast<AppListFolderItem*>(new_folder->item()); @@ -1562,7 +1763,8 @@ // Move selection to the item to the right of the folder and put it in the // folder. - apps_grid_view_->GetFocusManager()->SetFocusedView(GetItemViewAt(1)); + apps_grid_view_->GetFocusManager()->SetFocusedView( + GetItemViewInTopLevelGrid(1)); SimulateKeyPress(ui::VKEY_LEFT, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN); @@ -1657,17 +1859,17 @@ model_->PopulateApps(kNumberOfApps); // Select the second to last item in the grid, folder it with the item to the // right. - AppListItemView* moving_item = GetItemViewAt(kNumberOfApps - 2); + AppListItemView* moving_item = GetItemViewInTopLevelGrid(kNumberOfApps - 2); const std::string first_item_id = moving_item->item()->id(); const std::string second_item_id = - GetItemViewAt(kNumberOfApps - 1)->item()->id(); + GetItemViewInTopLevelGrid(kNumberOfApps - 1)->item()->id(); apps_grid_view_->GetFocusManager()->SetFocusedView(moving_item); SimulateKeyPress(ui::VKEY_RIGHT, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN); // Test that the first item in the grid is now a folder with the first and // second items, and that the folder is the selected view. - AppListItemView* new_folder = GetItemViewAt(kNumberOfApps - 2); + AppListItemView* new_folder = GetItemViewInTopLevelGrid(kNumberOfApps - 2); ASSERT_TRUE(apps_grid_view_->IsSelectedView(new_folder)); AppListFolderItem* folder_item = static_cast<AppListFolderItem*>(new_folder->item()); @@ -1715,7 +1917,7 @@ // Cancel drag and put the dragged view back to its ideal position so that // the next drag would pick it up. - apps_grid_view_->EndDrag(true); + EndDrag(apps_grid_view_, false /*cancel*/); test_api_->LayoutToIdealBounds(); // Now drag to the top edge, and test the other direction. @@ -1734,7 +1936,7 @@ EXPECT_EQ(0, GetPaginationModel()->selected_page()); EXPECT_EQ(to, GetDragViewCenter()); - apps_grid_view_->EndDrag(true); + EndDrag(apps_grid_view_, false /*cancel*/); } TEST_F(AppsGridViewTest, UpdateFolderBackgroundOnCancelDrag) { @@ -1750,7 +1952,7 @@ // Starts a mouse drag and then cancels it. SimulateDrag(AppsGridView::MOUSE, mouse_from, mouse_to); - apps_grid_view_->EndDrag(true); + EndDrag(apps_grid_view_, true /*cancel*/); EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"), model_->GetModelContent()); } @@ -1772,7 +1974,7 @@ EXPECT_FALSE(search_box->HasFocus()); EXPECT_TRUE(item_view->HasFocus()); - apps_grid_view_->EndDrag(false); + EndDrag(apps_grid_view_, false /*cancel*/); EXPECT_FALSE(search_box->HasFocus()); EXPECT_TRUE(item_view->HasFocus()); } @@ -1861,7 +2063,7 @@ apps_grid_view_origin.x(), apps_grid_view_origin.y(), 0, base::TimeTicks(), ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END)); - AppListItemView* folder_view = GetItemViewAt(0); + AppListItemView* folder_view = GetItemViewInTopLevelGrid(0); ASSERT_TRUE(folder_view->is_folder()); ASSERT_FALSE(apps_grid_view_->layer()->layer_mask_layer()); @@ -1946,7 +2148,7 @@ while (test_api_->HasPendingPageFlip()) { page_flip_waiter_->Wait(); } - apps_grid_view_->EndDrag(false); + EndDrag(apps_grid_view_, false /*cancel*/); test_api_->LayoutToIdealBounds(); } @@ -2218,12 +2420,12 @@ model_->PopulateApps(2); // Select first app and move it with the keyboard down to create a new page. - AppListItemView* moving_item = GetItemViewAt(0); + AppListItemView* moving_item = GetItemViewInTopLevelGrid(0); apps_grid_view_->GetFocusManager()->SetFocusedView(moving_item); SimulateKeyPress(ui::VKEY_DOWN, ui::EF_CONTROL_DOWN); SimulateKeyReleased(ui::VKEY_DOWN, ui::EF_NONE); - ASSERT_EQ(apps_grid_view_->pagination_model()->total_pages(), 2); + ASSERT_EQ(GetPaginationModel()->total_pages(), 2); histogram_tester.ExpectBucketCount( "Apps.AppList.AppsGridAddPage", AppListPageCreationType::kMovingAppWithKeyboard, 1); @@ -2249,9 +2451,9 @@ while (test_api_->HasPendingPageFlip()) page_flip_waiter.Wait(); - apps_grid_view_->EndDrag(false /*cancel*/); + EndDrag(apps_grid_view_, false /*cancel*/); - ASSERT_EQ(apps_grid_view_->pagination_model()->total_pages(), 2); + ASSERT_EQ(GetPaginationModel()->total_pages(), 2); histogram_tester.ExpectBucketCount("Apps.AppList.AppsGridAddPage", AppListPageCreationType::kDraggingApp, 1); } @@ -2264,7 +2466,7 @@ // recorded. model_->CreateAndAddItem("Extra App"); - ASSERT_EQ(apps_grid_view_->pagination_model()->total_pages(), 2); + ASSERT_EQ(GetPaginationModel()->total_pages(), 2); histogram_tester.ExpectBucketCount("Apps.AppList.AppsGridAddPage", AppListPageCreationType::kSyncOrInstall, 1);
diff --git a/ash/app_list/views/test/apps_grid_view_test_api.h b/ash/app_list/views/test/apps_grid_view_test_api.h index 95e2380..cf20cfa9 100644 --- a/ash/app_list/views/test/apps_grid_view_test_api.h +++ b/ash/app_list/views/test/apps_grid_view_test_api.h
@@ -50,6 +50,10 @@ void WaitForItemMoveAnimationDone(); + void Update() { view_->Update(); } + + AppListItemList* GetItemList() { return view_->item_list_; } + private: AppsGridView* view_;
diff --git a/ash/app_menu/notification_item_view.cc b/ash/app_menu/notification_item_view.cc index f352705..0697dd0 100644 --- a/ash/app_menu/notification_item_view.cc +++ b/ash/app_menu/notification_item_view.cc
@@ -111,9 +111,9 @@ } gfx::Size NotificationItemView::CalculatePreferredSize() const { - return gfx::Size( - views::MenuConfig::instance().touchable_menu_width - kBorderStrokeWidth, - kNotificationItemViewHeight); + return gfx::Size(views::MenuConfig::instance().touchable_menu_min_width - + kBorderStrokeWidth, + kNotificationItemViewHeight); } void NotificationItemView::Layout() { @@ -122,7 +122,7 @@ // result of |text_container_| being too small to hold the full width of its // children labels. const gfx::Size text_container_size( - views::MenuConfig::instance().touchable_menu_width - + views::MenuConfig::instance().touchable_menu_min_width - kNotificationHorizontalPadding - kIconHorizontalPadding * 2 - kProportionalIconViewSize.width(), title_label_->GetPreferredSize().height() +
diff --git a/ash/app_menu/notification_menu_header_view.cc b/ash/app_menu/notification_menu_header_view.cc index e7a79c7f..ed30b80 100644 --- a/ash/app_menu/notification_menu_header_view.cc +++ b/ash/app_menu/notification_menu_header_view.cc
@@ -58,7 +58,7 @@ gfx::Size NotificationMenuHeaderView::CalculatePreferredSize() const { return gfx::Size( - views::MenuConfig::instance().touchable_menu_width, + views::MenuConfig::instance().touchable_menu_min_width, GetInsets().height() + notification_title_->GetPreferredSize().height()); }
diff --git a/ash/app_menu/notification_menu_view.cc b/ash/app_menu/notification_menu_view.cc index 5d4cbf7..ab166c4 100644 --- a/ash/app_menu/notification_menu_view.cc +++ b/ash/app_menu/notification_menu_view.cc
@@ -41,7 +41,7 @@ gfx::Size NotificationMenuView::CalculatePreferredSize() const { return gfx::Size( - views::MenuConfig::instance().touchable_menu_width, + views::MenuConfig::instance().touchable_menu_min_width, double_separator_->GetPreferredSize().height() + header_view_->GetPreferredSize().height() + kNotificationItemViewHeight + @@ -50,10 +50,10 @@ void NotificationMenuView::Layout() { int y = 0; - double_separator_->SetBoundsRect( - gfx::Rect(gfx::Point(0, y), - gfx::Size(views::MenuConfig::instance().touchable_menu_width, - double_separator_->GetPreferredSize().height()))); + double_separator_->SetBoundsRect(gfx::Rect( + gfx::Point(0, y), + gfx::Size(views::MenuConfig::instance().touchable_menu_min_width, + double_separator_->GetPreferredSize().height()))); y += double_separator_->GetPreferredSize().height(); header_view_->SetBoundsRect(
diff --git a/ash/app_menu/notification_overflow_view.cc b/ash/app_menu/notification_overflow_view.cc index a7d877a..6c28d88 100644 --- a/ash/app_menu/notification_overflow_view.cc +++ b/ash/app_menu/notification_overflow_view.cc
@@ -138,7 +138,7 @@ // padding on the bottom due to the corner radius of the root MenuItemView. If // the corner radius changes, |kOverflowSeparatorToIconPadding| must be // modified to vertically center the overflow icons. - return gfx::Size(views::MenuConfig::instance().touchable_menu_width, + return gfx::Size(views::MenuConfig::instance().touchable_menu_min_width, separator_->GetPreferredSize().height() + kOverflowSeparatorToIconPadding + kIconLayoutSize); }
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd index c4fa2c2..49ef314 100644 --- a/ash/ash_strings.grd +++ b/ash/ash_strings.grd
@@ -433,9 +433,6 @@ =1 {1 notification} other {# notifications}} </message> - <message name="IDS_ASH_STATUS_TRAY_HIDDEN_NOTIFICATION_COUNT_LABEL" desc="The label for the number of hidden notifications."> - +<ph name="COUNT">$1<ex>2</ex></ph> - </message> <message name="IDS_ASH_STATUS_TRAY_BLUETOOTH" desc="The label used as the header in the bluetooth popup. [CHAR_LIMIT=14]"> Bluetooth @@ -1232,6 +1229,9 @@ <message name="IDS_ASH_PHONE_HUB_ENABLE_HOTSPOT_NO_RECEPTION_STATE_TOOLTIP" desc="Tooltip message that indicates to the user that the Enable Hotspot feature is disabled because their phone does not have mobile data."> Your phone must have mobile data to provide a hotspot </message> + <message name="IDS_ASH_STATUS_TRAY_PROJECTOR_BUTTON_LABEL" desc="The label text for the button in the status tray to Projector."> + Presentation tools + </message> <message name="IDS_ASH_PROJECTOR_KEY_IDEA_MARKED" desc="Message content on the toast that appears when a key idea is marked"> Marked as a key idea </message> @@ -3254,7 +3254,7 @@ <message name="IDS_ASH_SCREEN_CAPTURE_BUTTON_EDIT" desc="The edit button label for the screen capture notification."> Edit </message> - <message name="IDS_ASH_SCREEN_CAPTURE_BUTTON_DELETE" desc="The delete button label for the screen capture notificaiton."> + <message name="IDS_ASH_SCREEN_CAPTURE_BUTTON_DELETE" desc="The delete button label for the screen capture notification."> Delete </message> <message name="IDS_ASH_SCREEN_CAPTURE_LABEL_FULLSCREEN_IMAGE_CAPTURE_CLAMSHELL" desc="The capture label message which shows in the middle of the screen when in fullscreen image capture mode in clamshell mode.">
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_HIDDEN_NOTIFICATION_COUNT_LABEL.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_HIDDEN_NOTIFICATION_COUNT_LABEL.png.sha1 deleted file mode 100644 index 55fb7c01fa..0000000 --- a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_HIDDEN_NOTIFICATION_COUNT_LABEL.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -3e74c9c2d78c09c2255dd22e5c25c8cd44964642 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_PROJECTOR_BUTTON_LABEL.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_PROJECTOR_BUTTON_LABEL.png.sha1 new file mode 100644 index 0000000..1c94037c --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_PROJECTOR_BUTTON_LABEL.png.sha1
@@ -0,0 +1 @@ +f0c469fa8e0e4e2ef41cdbda3f31cb47a482f8af \ No newline at end of file
diff --git a/ash/assistant/assistant_controller_impl.cc b/ash/assistant/assistant_controller_impl.cc index a4ff0ac..ff6c463 100644 --- a/ash/assistant/assistant_controller_impl.cc +++ b/ash/assistant/assistant_controller_impl.cc
@@ -88,7 +88,8 @@ assistant_feedback.assistant_debug_info_allowed = assistant_debug_info_allowed; assistant_feedback.description = feedback_description; - assistant_feedback.screenshot_png = screenshot_png; + assistant_feedback.screenshot_png = + std::vector<uint8_t>(screenshot_png.begin(), screenshot_png.end()); assistant_->SendAssistantFeedback(std::move(assistant_feedback)); }
diff --git a/ash/clipboard/views/clipboard_history_item_view.cc b/ash/clipboard/views/clipboard_history_item_view.cc index 1873b25da..ace01d90 100644 --- a/ash/clipboard/views/clipboard_history_item_view.cc +++ b/ash/clipboard/views/clipboard_history_item_view.cc
@@ -263,7 +263,7 @@ gfx::Size ClipboardHistoryItemView::CalculatePreferredSize() const { const int preferred_width = - views::MenuConfig::instance().touchable_menu_width; + views::MenuConfig::instance().touchable_menu_min_width; return gfx::Size(preferred_width, GetHeightForWidth(preferred_width)); }
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc index 8054648..f0163f2 100644 --- a/ash/constants/ash_features.cc +++ b/ash/constants/ash_features.cc
@@ -296,6 +296,10 @@ const base::Feature kEnableOobeChromeVoxHint{"EnableOobeChromeVoxHint", base::FEATURE_ENABLED_BY_DEFAULT}; +// Enables toggling Pciguard settings through Settings UI. +const base::Feature kEnablePciguardUi{"EnablePciguardUi", + base::FEATURE_DISABLED_BY_DEFAULT}; + // Enables Device End Of Lifetime warning notifications. const base::Feature kEolWarningNotifications{"EolWarningNotifications", base::FEATURE_ENABLED_BY_DEFAULT}; @@ -548,6 +552,10 @@ // Controls whether to enable projector. const base::Feature kProjector{"Projector", base::FEATURE_DISABLED_BY_DEFAULT}; +// Controls whether to enable projector in status tray. +const base::Feature kProjectorFeaturePod{"ProjectorFeaturePod", + base::FEATURE_DISABLED_BY_DEFAULT}; + // Controls whether to enable quick answers. const base::Feature kQuickAnswers{"QuickAnswers", base::FEATURE_DISABLED_BY_DEFAULT}; @@ -831,6 +839,10 @@ return base::FeatureList::IsEnabled(kImprovedKeyboardShortcuts); } +bool IsPciguardUiEnabled() { + return base::FeatureList::IsEnabled(kEnablePciguardUi); +} + bool IsPhoneHubEnabled() { return base::FeatureList::IsEnabled(kPhoneHub); } @@ -851,6 +863,11 @@ return base::FeatureList::IsEnabled(kProjector); } +bool IsProjectorFeaturePodEnabled() { + return IsProjectorEnabled() && + base::FeatureList::IsEnabled(kProjectorFeaturePod); +} + bool IsQuickAnswersDogfood() { return base::FeatureList::IsEnabled(kQuickAnswersDogfood); }
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h index 8d3674ab..f34f88a 100644 --- a/ash/constants/ash_features.h +++ b/ash/constants/ash_features.h
@@ -143,6 +143,8 @@ extern const base::Feature kEnableLocalSearchService; extern const base::Feature kEnableOobeChromeVoxHint; COMPONENT_EXPORT(ASH_CONSTANTS) +extern const base::Feature kEnablePciguardUi; +COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kEolWarningNotifications; COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kExoOrdinalMotion; @@ -248,6 +250,7 @@ COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kPrinterStatusDialog; COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kProjector; +COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kProjectorFeaturePod; COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kQuickAnswers; COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kQuickAnswersDogfood; @@ -364,6 +367,7 @@ bool IsClipboardHistoryContextMenuNudgeEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsOobeChromeVoxHintEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsOobeScreensPriorityEnabled(); +COMPONENT_EXPORT(ASH_CONSTANTS) bool IsPciguardUiEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsPhoneHubEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsPhoneHubUseBleEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsPinAutosubmitFeatureEnabled(); @@ -372,6 +376,7 @@ COMPONENT_EXPORT(ASH_CONSTANTS) bool IsPinAutosubmitBackfillFeatureEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsProjectorEnabled(); +COMPONENT_EXPORT(ASH_CONSTANTS) bool IsProjectorFeaturePodEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsQuickAnswersDogfood(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsQuickAnswersEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsQuickAnswersRichUiEnabled();
diff --git a/ash/projector/projector_controller.h b/ash/projector/projector_controller.h index 0d9709f6..6fd48b5 100644 --- a/ash/projector/projector_controller.h +++ b/ash/projector/projector_controller.h
@@ -56,6 +56,8 @@ void SetProjectorMetadataControllerForTest( std::unique_ptr<ProjectorMetadataController> metadata_controller); + ProjectorUiController* ui_controller() { return ui_controller_.get(); } + private: // Starts the speech recognition session. void StartSpeechRecognition();
diff --git a/ash/projector/projector_feature_pod_controller.cc b/ash/projector/projector_feature_pod_controller.cc new file mode 100644 index 0000000..0d388e10 --- /dev/null +++ b/ash/projector/projector_feature_pod_controller.cc
@@ -0,0 +1,54 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/projector/projector_feature_pod_controller.h" + +#include "ash/projector/projector_controller.h" +#include "ash/projector/projector_ui_controller.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/session/session_controller_impl.h" +#include "ash/shell.h" +#include "ash/strings/grit/ash_strings.h" +#include "ash/system/tray/system_tray_item_uma_type.h" +#include "ash/system/unified/feature_pod_button.h" +#include "ash/system/unified/unified_system_tray_controller.h" +#include "ui/base/l10n/l10n_util.h" + +namespace ash { + +ProjectorFeaturePodController::ProjectorFeaturePodController( + UnifiedSystemTrayController* tray_controller) + : tray_controller_(tray_controller) { + // TODO(llin): Observe Projector UI model to update the toggle state. +} + +ProjectorFeaturePodController::~ProjectorFeaturePodController() = default; + +FeaturePodButton* ProjectorFeaturePodController::CreateButton() { + DCHECK(!button_); + button_ = new FeaturePodButton(this, /*is_togglable=*/true); + button_->SetVectorIcon(kPaletteTrayIconProjectorIcon); + const auto label_text = + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_PROJECTOR_BUTTON_LABEL); + button_->SetLabel(label_text); + button_->icon_button()->SetTooltipText(label_text); + button_->SetLabelTooltip(label_text); + button_->SetVisible( + !Shell::Get()->session_controller()->IsUserSessionBlocked()); + // TODO(llin): Update toggle state based on Projector UI model. + return button_; +} + +void ProjectorFeaturePodController::OnIconPressed() { + // Close the system tray bubble. Deletes |this|. + tray_controller_->CloseBubble(); + + Shell::Get()->projector_controller()->ui_controller()->ToggleToolbar(); +} + +SystemTrayItemUmaType ProjectorFeaturePodController::GetUmaType() const { + return SystemTrayItemUmaType::UMA_PROJECTOR; +} + +} // namespace ash
diff --git a/ash/projector/projector_feature_pod_controller.h b/ash/projector/projector_feature_pod_controller.h new file mode 100644 index 0000000..31737b56 --- /dev/null +++ b/ash/projector/projector_feature_pod_controller.h
@@ -0,0 +1,37 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_PROJECTOR_PROJECTOR_FEATURE_POD_CONTROLLER_H_ +#define ASH_PROJECTOR_PROJECTOR_FEATURE_POD_CONTROLLER_H_ + +#include "ash/system/unified/feature_pod_controller_base.h" + +namespace ash { + +class UnifiedSystemTrayController; + +// Controller of a feature pod button that toggles Projector tools. +class ProjectorFeaturePodController : public FeaturePodControllerBase { + public: + explicit ProjectorFeaturePodController( + UnifiedSystemTrayController* controller); + ProjectorFeaturePodController(const ProjectorFeaturePodController&) = delete; + ProjectorFeaturePodController& operator=( + const ProjectorFeaturePodController&) = delete; + ~ProjectorFeaturePodController() override; + + // FeaturePodControllerBase: + FeaturePodButton* CreateButton() override; + void OnIconPressed() override; + SystemTrayItemUmaType GetUmaType() const override; + + private: + UnifiedSystemTrayController* const tray_controller_; + + FeaturePodButton* button_ = nullptr; +}; + +} // namespace ash + +#endif // ASH_PROJECTOR_PROJECTOR_FEATURE_POD_CONTROLLER_H_
diff --git a/ash/projector/projector_ui_controller.cc b/ash/projector/projector_ui_controller.cc index def69045..b954a5cc 100644 --- a/ash/projector/projector_ui_controller.cc +++ b/ash/projector/projector_ui_controller.cc
@@ -32,6 +32,8 @@ ProjectorUiController::~ProjectorUiController() = default; void ProjectorUiController::ShowToolbar() {} +void ProjectorUiController::CloseToolbar() {} +void ProjectorUiController::ToggleToolbar() {} void ProjectorUiController::OnKeyIdeaMarked() { ShowToast(kMarkedKeyIdeaToastId, IDS_ASH_PROJECTOR_KEY_IDEA_MARKED,
diff --git a/ash/projector/projector_ui_controller.h b/ash/projector/projector_ui_controller.h index 7f798ef..e0b67cdc 100644 --- a/ash/projector/projector_ui_controller.h +++ b/ash/projector/projector_ui_controller.h
@@ -20,8 +20,13 @@ ProjectorUiController& operator=(const ProjectorUiController&) = delete; virtual ~ProjectorUiController(); - // Virtual for testing. + // Show Projector toolbar. Virtual for testing. virtual void ShowToolbar(); + // Close Projector toolbar. Virtual for testing. + virtual void CloseToolbar(); + // Toggle Projector toolbar based on the toolbar visibility state. + // Virtual for testing. + virtual void ToggleToolbar(); // Invoked when key idea is marked to show a toast. Virtual for testing. virtual void OnKeyIdeaMarked(); // Invoked when transcription is available for rendering. Virtual for testing.
diff --git a/ash/public/cpp/ash_features.cc b/ash/public/cpp/ash_features.cc index ee40b1e4..ae26d37 100644 --- a/ash/public/cpp/ash_features.cc +++ b/ash/public/cpp/ash_features.cc
@@ -67,7 +67,7 @@ "InteractiveWindowCycleList", base::FEATURE_ENABLED_BY_DEFAULT}; const base::Feature kManagedDeviceUIRedesign{"ManagedDeviceUIRedesign", - base::FEATURE_DISABLED_BY_DEFAULT}; + base::FEATURE_ENABLED_BY_DEFAULT}; const base::Feature kMediaSessionNotification{"MediaSessionNotification", base::FEATURE_ENABLED_BY_DEFAULT}; @@ -125,9 +125,6 @@ const base::Feature kStylusBatteryStatus{"StylusBatteryStatus", base::FEATURE_DISABLED_BY_DEFAULT}; -const base::Feature kSystemTrayMicGainSetting{"SystemTrayMicGainSetting", - base::FEATURE_ENABLED_BY_DEFAULT}; - const base::Feature kWebUITabStripTabDragIntegration{ "WebUITabStripTabDragIntegration", base::FEATURE_DISABLED_BY_DEFAULT}; @@ -286,10 +283,6 @@ return base::FeatureList::IsEnabled(kStylusBatteryStatus); } -bool IsSystemTrayMicGainSettingEnabled() { - return base::FeatureList::IsEnabled(kSystemTrayMicGainSetting); -} - bool IsDisplayIdentificationEnabled() { return base::FeatureList::IsEnabled(kDisplayIdentification); }
diff --git a/ash/public/cpp/ash_features.h b/ash/public/cpp/ash_features.h index 2c477c3..93118c6f 100644 --- a/ash/public/cpp/ash_features.h +++ b/ash/public/cpp/ash_features.h
@@ -169,10 +169,6 @@ // Enables battery indicator for styluses in the palette tray ASH_PUBLIC_EXPORT extern const base::Feature kStylusBatteryStatus; -// Enables sliders for setting mic gain levels in the more audio settings -// section in the system tray. -ASH_PUBLIC_EXPORT extern const base::Feature kSystemTrayMicGainSetting; - // Enables special handling of Chrome tab drags from a WebUI tab strip. // These will be treated similarly to a window drag, showing split view // indicators in tablet mode, etc. The functionality is behind a flag @@ -257,8 +253,6 @@ ASH_PUBLIC_EXPORT bool AreContextualNudgesEnabled(); -ASH_PUBLIC_EXPORT bool IsSystemTrayMicGainSettingEnabled(); - ASH_PUBLIC_EXPORT bool IsStylusBatteryStatusEnabled(); ASH_PUBLIC_EXPORT bool IsDisplayIdentificationEnabled();
diff --git a/ash/public/cpp/login_accelerators.cc b/ash/public/cpp/login_accelerators.cc index c65442b..a530ed79 100644 --- a/ash/public/cpp/login_accelerators.cc +++ b/ash/public/cpp/login_accelerators.cc
@@ -58,6 +58,10 @@ kEnableConsumerKiosk, ui::VKEY_K, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, false, kScopeOobe, + }, { + kLaunchDiagnostics, + ui::VKEY_ESCAPE, ui::EF_CONTROL_DOWN | ui::EF_COMMAND_DOWN, + true, kScopeOobe | kScopeLogin, }, }; // clang-format on
diff --git a/ash/public/cpp/login_accelerators.h b/ash/public/cpp/login_accelerators.h index 350bd04..8ca1a37a 100644 --- a/ash/public/cpp/login_accelerators.h +++ b/ash/public/cpp/login_accelerators.h
@@ -38,6 +38,7 @@ kEditDeviceRequisition, kDeviceRequisitionRemora, kStartDemoMode, + kLaunchDiagnostics, }; struct LoginAcceleratorData {
diff --git a/ash/resources/vector_icons/BUILD.gn b/ash/resources/vector_icons/BUILD.gn index f8834c4..a4296e37 100644 --- a/ash/resources/vector_icons/BUILD.gn +++ b/ash/resources/vector_icons/BUILD.gn
@@ -57,6 +57,7 @@ "dictation_off_newui.icon", "dictation_on.icon", "dictation_on_newui.icon", + "do_not_disturb_disabled.icon", "dogfood.icon", "eight_files.icon", "files_app.icon", @@ -153,6 +154,7 @@ "palette_tray_icon_laser_pointer_light_mode.icon", "palette_tray_icon_magnify.icon", "palette_tray_icon_metalayer.icon", + "palette_tray_icon_projector.icon", "phone_hub_battery_saver.icon", "phone_hub_battery_saver_outline.icon", "phone_hub_default_favicon.icon",
diff --git a/ash/resources/vector_icons/do_not_disturb_disabled.icon b/ash/resources/vector_icons/do_not_disturb_disabled.icon new file mode 100644 index 0000000..7df1f39 --- /dev/null +++ b/ash/resources/vector_icons/do_not_disturb_disabled.icon
@@ -0,0 +1,40 @@ +// Copyright 2021 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. + +CANVAS_DIMENSIONS, 20, +MOVE_TO, 1.87f, 2.05f, +LINE_TO, 0.46f, 3.46f, +LINE_TO, 3.04f, 6.04f, +CUBIC_TO, 2.38f, 7.21f, 2, 8.56f, 2, 10, +CUBIC_TO, 2, 14.42f, 5.58f, 18, 10, 18, +CUBIC_TO, 11.44f, 18, 12.79f, 17.62f, 13.96f, 16.96f, +LINE_TO, 16.02f, 19.02f, +LINE_TO, 17.43f, 17.6f, +LINE_TO, 1.87f, 2.05f, +CLOSE, +MOVE_TO, 6, 9, +LINE_TO, 4.53f, 7.53f, +CUBIC_TO, 4.19f, 8.28f, 4, 9.12f, 4, 10, +CUBIC_TO, 4, 13.31f, 6.69f, 16, 10, 16, +CUBIC_TO, 10.88f, 16, 11.72f, 15.81f, 12.47f, 15.47f, +LINE_TO, 8, 11, +H_LINE_TO, 6, +LINE_TO, 6, 9, +CLOSE, +MOVE_TO, 16.55f, 14.6f, +CUBIC_TO, 17.46f, 13.3f, 18, 11.71f, 18, 10, +CUBIC_TO, 18, 5.58f, 14.42f, 2, 10, 2, +CUBIC_TO, 8.29f, 2, 6.7f, 2.54f, 5.4f, 3.45f, +LINE_TO, 6.85f, 4.9f, +CUBIC_TO, 7.76f, 4.33f, 8.84f, 4, 10, 4, +CUBIC_TO, 13.31f, 4, 16, 6.69f, 16, 10, +CUBIC_TO, 16, 11.16f, 15.67f, 12.24f, 15.1f, 13.15f, +LINE_TO, 16.55f, 14.6f, +CLOSE, +MOVE_TO, 12.95f, 11, +H_LINE_TO, 14, +V_LINE_TO, 9, +H_LINE_TO, 10.95f, +LINE_TO, 12.95f, 11, +CLOSE \ No newline at end of file
diff --git a/ash/resources/vector_icons/palette_tray_icon_projector.icon b/ash/resources/vector_icons/palette_tray_icon_projector.icon new file mode 100644 index 0000000..9cb36b0 --- /dev/null +++ b/ash/resources/vector_icons/palette_tray_icon_projector.icon
@@ -0,0 +1,37 @@ +// Copyright 2021 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. + +CANVAS_DIMENSIONS, 24, +MOVE_TO, 4.59f, 6.89f, +R_CUBIC_TO, 0.7f, -0.71f, 1.4f, -1.35f, 1.71f, -1.22f, +R_CUBIC_TO, 0.5f, 0.2f, 0, 1.03f, -0.3f, 1.52f, +R_CUBIC_TO, -0.25f, 0.42f, -2.86f, 3.89f, -2.86f, 6.31f, +R_CUBIC_TO, 0, 1.28f, 0.48f, 2.34f, 1.34f, 2.98f, +R_CUBIC_TO, 0.75f, 0.56f, 1.74f, 0.73f, 2.64f, 0.46f, +R_CUBIC_TO, 1.07f, -0.31f, 1.95f, -1.4f, 3.06f, -2.77f, +R_CUBIC_TO, 1.21f, -1.49f, 2.83f, -3.44f, 4.08f, -3.44f, +R_CUBIC_TO, 1.63f, 0, 1.65f, 1.01f, 1.76f, 1.79f, +R_CUBIC_TO, -3.78f, 0.64f, -5.38f, 3.67f, -5.38f, 5.37f, +R_CUBIC_TO, 0, 1.7f, 1.44f, 3.09f, 3.21f, 3.09f, +R_CUBIC_TO, 1.63f, 0, 4.29f, -1.33f, 4.69f, -6.1f, +H_LINE_TO, 21, +R_V_LINE_TO, -2.5f, +R_H_LINE_TO, -2.47f, +R_CUBIC_TO, -0.15f, -1.65f, -1.09f, -4.2f, -4.03f, -4.2f, +R_CUBIC_TO, -2.25f, 0, -4.18f, 1.91f, -4.94f, 2.84f, +R_CUBIC_TO, -0.58f, 0.73f, -2.06f, 2.48f, -2.29f, 2.72f, +R_CUBIC_TO, -0.25f, 0.3f, -0.68f, 0.84f, -1.11f, 0.84f, +R_CUBIC_TO, -0.45f, 0, -0.72f, -0.83f, -0.36f, -1.92f, +R_CUBIC_TO, 0.35f, -1.09f, 1.4f, -2.86f, 1.85f, -3.52f, +R_CUBIC_TO, 0.78f, -1.14f, 1.3f, -1.92f, 1.3f, -3.28f, +CUBIC_TO, 8.95f, 3.69f, 7.31f, 3, 6.44f, 3, +CUBIC_TO, 5.12f, 3, 3.97f, 4, 3.72f, 4.25f, +R_CUBIC_TO, -0.36f, 0.36f, -0.66f, 0.66f, -0.88f, 0.93f, +R_LINE_TO, 1.75f, 1.71f, +CLOSE, +R_MOVE_TO, 9.29f, 11.66f, +R_CUBIC_TO, -0.31f, 0, -0.74f, -0.26f, -0.74f, -0.72f, +R_CUBIC_TO, 0, -0.6f, 0.73f, -2.2f, 2.87f, -2.76f, +R_CUBIC_TO, -0.3f, 2.69f, -1.43f, 3.48f, -2.13f, 3.48f, +CLOSE \ No newline at end of file
diff --git a/ash/style/ash_color_provider.cc b/ash/style/ash_color_provider.cc index 05eabed..1603942 100644 --- a/ash/style/ash_color_provider.cc +++ b/ash/style/ash_color_provider.cc
@@ -106,6 +106,14 @@ return cros_colors::ResolveColor(TypeToColorName(type), is_dark_mode); } +// Notify all the other components to update on the color mode changes. Only +// Chrome browser is notified currently, will include WebUI, Arc etc later. +void NotifyColorModeChanges(bool is_dark_mode_enabled) { + auto* native_theme = ui::NativeTheme::GetInstanceForNativeUi(); + native_theme->set_use_dark_colors(is_dark_mode_enabled); + native_theme->NotifyObservers(); +} + } // namespace AshColorProvider::AshColorProvider() { @@ -161,6 +169,13 @@ NotifyColorModeThemedPrefChange(); } +void AshColorProvider::OnSessionStateChanged( + session_manager::SessionState state) { + if (!features::IsDarkLightModeEnabled()) + return; + NotifyColorModeChanges(IsDarkModeEnabled()); +} + SkColor AshColorProvider::GetShieldLayerColor(ShieldLayerType type) const { constexpr int kAlphas[] = {kAlpha20, kAlpha40, kAlpha60, kAlpha80, kAlpha90}; DCHECK_LT(static_cast<size_t>(type), base::size(kAlphas)); @@ -375,6 +390,7 @@ active_user_pref_service_->SetBoolean(prefs::kDarkModeEnabled, !IsDarkModeEnabled()); active_user_pref_service_->CommitPendingWrite(); + NotifyColorModeChanges(IsDarkModeEnabled()); } void AshColorProvider::UpdateColorModeThemed(bool is_themed) {
diff --git a/ash/style/ash_color_provider.h b/ash/style/ash_color_provider.h index c6eb437f..820ae56b 100644 --- a/ash/style/ash_color_provider.h +++ b/ash/style/ash_color_provider.h
@@ -57,6 +57,7 @@ // SessionObserver: void OnActiveUserPrefServiceChanged(PrefService* prefs) override; + void OnSessionStateChanged(session_manager::SessionState state) override; // ColorProvider: SkColor GetShieldLayerColor(ShieldLayerType type) const override;
diff --git a/ash/system/audio/audio_detailed_view.cc b/ash/system/audio/audio_detailed_view.cc index 534ab1a..a25ddb2 100644 --- a/ash/system/audio/audio_detailed_view.cc +++ b/ash/system/audio/audio_detailed_view.cc
@@ -163,10 +163,8 @@ AddScrollListCheckableItem(GetAudioDeviceName(device), device.active); device_map_[container] = device; - if (features::IsSystemTrayMicGainSettingEnabled()) { - AddScrollListChild(mic_gain_controller_->CreateMicGainSlider( - device.id, device.IsInternalMic())); - } + AddScrollListChild(mic_gain_controller_->CreateMicGainSlider( + device.id, device.IsInternalMic())); } scroll_content()->SizeToPreferredSize();
diff --git a/ash/system/audio/unified_audio_detailed_view_controller_unittest.cc b/ash/system/audio/unified_audio_detailed_view_controller_unittest.cc index 6df39400..e7d1273 100644 --- a/ash/system/audio/unified_audio_detailed_view_controller_unittest.cc +++ b/ash/system/audio/unified_audio_detailed_view_controller_unittest.cc
@@ -116,9 +116,6 @@ void SetUp() override { AshTestBase::SetUp(); - scoped_feature_list_.InitAndEnableFeature( - features::kSystemTrayMicGainSetting); - fake_manager_ = std::make_unique<FakeMediaControllerManager>(); tray_model_ = std::make_unique<UnifiedSystemTrayModel>(nullptr); tray_controller_ =
diff --git a/ash/system/audio/unified_volume_view.cc b/ash/system/audio/unified_volume_view.cc index 71f479ce..4440f8e 100644 --- a/ash/system/audio/unified_volume_view.cc +++ b/ash/system/audio/unified_volume_view.cc
@@ -185,14 +185,10 @@ SetLayoutManager(std::make_unique<views::BoxLayout>( views::BoxLayout::Orientation::kHorizontal, gfx::Insets((kTrayItemSize - - GetDefaultSizeOfVectorIcon(vector_icons::kHeadsetIcon)) / + GetDefaultSizeOfVectorIcon(kUnifiedMenuExpandIcon)) / 2), 2)); - if (!features::IsSystemTrayMicGainSettingEnabled()) { - headset_image_ = AddChildView(std::make_unique<views::ImageView>()); - headset_image_->SetCanProcessEventsWithinSubtree(false); - } more_image_ = AddChildView(std::make_unique<views::ImageView>()); more_image_->SetCanProcessEventsWithinSubtree(false); SetTooltipText(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_AUDIO)); @@ -205,10 +201,7 @@ void OnThemeChanged() override { UnifiedVolumeViewButton::OnThemeChanged(); const SkColor icon_color = GetIconColor(); - if (headset_image_) { - headset_image_->SetImage( - CreateVectorIcon(vector_icons::kHeadsetIcon, icon_color)); - } + DCHECK(more_image_); auto icon_rotation = base::i18n::IsRTL() ? SkBitmapOperations::ROTATION_270_CW @@ -218,7 +211,6 @@ } private: - views::ImageView* headset_image_ = nullptr; views::ImageView* more_image_ = nullptr; DISALLOW_COPY_AND_ASSIGN(MoreButton); @@ -285,10 +277,6 @@ Shell::Get()->session_controller()->GetActivePrefService()->GetBoolean( prefs::kLiveCaptionEnabled)); - more_button_->SetVisible(CrasAudioHandler::Get()->has_alternative_input() || - CrasAudioHandler::Get()->has_alternative_output() || - features::IsSystemTrayMicGainSettingEnabled()); - // Slider's value is in finer granularity than audio volume level(0.01), // there will be a small discrepancy between slider's value and volume level // on audio side. To avoid the jittering in slider UI, use the slider's
diff --git a/ash/system/holding_space/holding_space_item_chip_view.cc b/ash/system/holding_space/holding_space_item_chip_view.cc index a4a23899..e92157f 100644 --- a/ash/system/holding_space/holding_space_item_chip_view.cc +++ b/ash/system/holding_space/holding_space_item_chip_view.cc
@@ -18,6 +18,7 @@ #include "ui/gfx/skia_paint_util.h" #include "ui/views/background.h" #include "ui/views/border.h" +#include "ui/views/controls/button/image_button.h" #include "ui/views/controls/label.h" #include "ui/views/layout/box_layout.h" #include "ui/views/layout/fill_layout.h" @@ -25,6 +26,7 @@ #include "ui/views/painter.h" namespace ash { +namespace { // Appearance. constexpr int kChildSpacing = 8; @@ -65,56 +67,29 @@ const gfx::InsetsF insets_; }; -// LabelMaskLayerOwner --------------------------------------------------------- +// PaintCallbackLabel ---------------------------------------------------------- -class LabelMaskLayerOwner : public ui::LayerOwner, public ui::LayerDelegate { +class PaintCallbackLabel : public views::Label { public: - LabelMaskLayerOwner() - : ui::LayerOwner(std::make_unique<ui ::Layer>(ui::LAYER_TEXTURED)) { - layer()->set_delegate(this); - layer()->SetFillsBoundsOpaquely(false); - } + using PaintCallback = base::RepeatingCallback<void(gfx::Canvas* canvas)>; - LabelMaskLayerOwner(const LabelMaskLayerOwner&) = delete; - LabelMaskLayerOwner& operator=(const LabelMaskLayerOwner&) = delete; - ~LabelMaskLayerOwner() override = default; + explicit PaintCallbackLabel(PaintCallback callback) : callback_(callback) {} + PaintCallbackLabel(const PaintCallbackLabel&) = delete; + PaintCallbackLabel& operator=(const PaintCallbackLabel&) = delete; + ~PaintCallbackLabel() override = default; private: - // ui::LayerDelegate: - void OnPaintLayer(const ui::PaintContext& context) override { - const gfx::Size size = layer()->size(); - - views::PaintInfo paint_info = - views::PaintInfo::CreateRootPaintInfo(context, size); - const auto& paint_recording_size = paint_info.paint_recording_size(); - - // Pass the scale factor when constructing `PaintRecorder` so the mask layer - // size is not incorrectly rounded (see https://crbug.com/921274). - ui::PaintRecorder recorder( - context, paint_info.paint_recording_size(), - static_cast<float>(paint_recording_size.width()) / size.width(), - static_cast<float>(paint_recording_size.height()) / size.height(), - /*cache*/ nullptr); - - // Flip canvas for RTL. - gfx::ScopedCanvas canvas(recorder.canvas()); - canvas.FlipIfRTL(size.width()); - - cc::PaintFlags flags; - flags.setAntiAlias(false); - - gfx::Point gradient_end(size.width() - kHoldingSpaceIconSize, 0); - gfx::Point gradient_start(gradient_end.x() - kLabelMaskGradientWidth, 0); - flags.setShader(gfx::CreateGradientShader( - gradient_start, gradient_end, SK_ColorBLACK, SK_ColorTRANSPARENT)); - - recorder.canvas()->DrawRect(gfx::Rect(size), flags); + // views::Label: + void OnPaint(gfx::Canvas* canvas) override { + views::Label::OnPaint(canvas); + callback_.Run(canvas); } - void OnDeviceScaleFactorChanged(float old_device_scale_factor, - float new_device_scale_factor) override {} + PaintCallback callback_; }; +} // namespace + // HoldingSpaceItemChipView ---------------------------------------------------- HoldingSpaceItemChipView::HoldingSpaceItemChipView( @@ -128,6 +103,7 @@ SetPreferredSize(gfx::Size(kPreferredWidth, kPreferredHeight)); + // Image. image_ = AddChildView(std::make_unique<RoundedImageView>( kHoldingSpaceChipIconSize / 2, RoundedImageView::Alignment::kLeading)); @@ -144,28 +120,29 @@ UpdateImage(); - label_and_pin_button_container_ = + auto* label_and_pin_button_container = AddChildView(std::make_unique<views::View>()); - layout->SetFlexForView(label_and_pin_button_container_, 1); - - label_and_pin_button_container_->SetLayoutManager( + label_and_pin_button_container->SetLayoutManager( std::make_unique<views::FillLayout>()); + layout->SetFlexForView(label_and_pin_button_container, 1); - label_ = label_and_pin_button_container_->AddChildView( - holding_space_util::CreateLabel(holding_space_util::LabelStyle::kChip)); + // Label. + label_ = label_and_pin_button_container->AddChildView( + std::make_unique<PaintCallbackLabel>( + base::BindRepeating(&HoldingSpaceItemChipView::OnPaintLabelMask, + base::Unretained(this)))); label_->SetBorder(views::CreateEmptyBorder(kLabelMargins)); label_->SetElideBehavior(gfx::ELIDE_MIDDLE); label_->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT); label_->SetText(item->text()); - - label_mask_layer_owner_ = std::make_unique<LabelMaskLayerOwner>(); - label_->SetPaintToLayer(); label_->layer()->SetFillsBoundsOpaquely(false); - label_->layer()->SetMaskLayer(label_mask_layer_owner_->layer()); + holding_space_util::ApplyStyle(label_, holding_space_util::LabelStyle::kChip); + + // Pin. views::View* pin_button_container = - label_and_pin_button_container_->AddChildView( + label_and_pin_button_container->AddChildView( std::make_unique<views::View>()); auto* pin_layout = @@ -176,7 +153,7 @@ pin_layout->set_cross_axis_alignment( views::BoxLayout::CrossAxisAlignment::kCenter); - AddPin(/*parent=*/pin_button_container); + pin_ = AddPin(/*parent=*/pin_button_container); } HoldingSpaceItemChipView::~HoldingSpaceItemChipView() = default; @@ -196,14 +173,32 @@ } void HoldingSpaceItemChipView::OnPinVisiblityChanged(bool pin_visible) { - if (label_mask_layer_owner_->layer()->bounds() != - label_and_pin_button_container_->bounds()) { - // Mask layer has the same size as the label container so that the gradient - // ends at the end of the container. - label_mask_layer_owner_->layer()->SetBounds( - label_and_pin_button_container_->bounds()); + // The `label_` must be repainted to update its mask for `pin_` visibility. + label_->SchedulePaint(); +} + +void HoldingSpaceItemChipView::OnPaintLabelMask(gfx::Canvas* canvas) { + // When the `pin_` is not visible no masking is necessary. + if (!pin_->GetVisible()) + return; + + // When the `pin_` is visible, `label_` fades out its tail to avoid overlap. + gfx::Point gradient_start, gradient_end; + if (base::i18n::IsRTL()) { + gradient_end.set_x(pin_->width()); + gradient_start.set_x(gradient_end.x() + kLabelMaskGradientWidth); + } else { + gradient_end.set_x(label_->width() - pin_->width()); + gradient_start.set_x(gradient_end.x() - kLabelMaskGradientWidth); } - label_mask_layer_owner_->layer()->SetVisible(pin_visible); + + cc::PaintFlags flags; + flags.setAntiAlias(true); + flags.setBlendMode(SkBlendMode::kDstIn); + flags.setShader(gfx::CreateGradientShader( + gradient_start, gradient_end, SK_ColorBLACK, SK_ColorTRANSPARENT)); + + canvas->DrawRect(label_->GetLocalBounds(), flags); } void HoldingSpaceItemChipView::UpdateImage() {
diff --git a/ash/system/holding_space/holding_space_item_chip_view.h b/ash/system/holding_space/holding_space_item_chip_view.h index 2904271..f8e7a9e 100644 --- a/ash/system/holding_space/holding_space_item_chip_view.h +++ b/ash/system/holding_space/holding_space_item_chip_view.h
@@ -12,10 +12,6 @@ #include "ash/system/holding_space/holding_space_item_view.h" #include "ui/views/metadata/metadata_header_macros.h" -namespace ui { -class LayerOwner; -} // namespace ui - namespace views { class Label; } // namespace views @@ -44,13 +40,16 @@ void OnHoldingSpaceItemUpdated(const HoldingSpaceItem* item) override; void OnPinVisiblityChanged(bool pin_visible) override; + // Invoked during `label_`'s paint sequence to paint its optional mask. Note + // that `label_` is only masked when `pin_` is visible to avoid overlapping. + void OnPaintLabelMask(gfx::Canvas* canvas); + void UpdateImage(); - std::unique_ptr<ui::LayerOwner> label_mask_layer_owner_; - + // Owned by view hierarchy. RoundedImageView* image_ = nullptr; views::Label* label_ = nullptr; - views::View* label_and_pin_button_container_ = nullptr; + views::View* pin_ = nullptr; base::CallbackListSubscription image_subscription_; };
diff --git a/ash/system/holding_space/holding_space_tray.cc b/ash/system/holding_space/holding_space_tray.cc index 6fe12a78..fc4c854 100644 --- a/ash/system/holding_space/holding_space_tray.cc +++ b/ash/system/holding_space/holding_space_tray.cc
@@ -112,7 +112,7 @@ return icon; } -// TODO(crbug.com/1171059): Refine UI upon delivery of spec. +// TODO(crbug.com/1171059): Add ripple effects. // Creates the overlay to be drawn over all other child views to indicate that // the parent view is a drop target and is capable of handling the current drag // payload. @@ -122,16 +122,18 @@ drop_target_overlay->SetLayoutManager(std::make_unique<views::FillLayout>()); // Layer. - drop_target_overlay->SetPaintToLayer(ui::LAYER_SOLID_COLOR); - drop_target_overlay->layer()->SetColor(gfx::kGoogleGrey400); + drop_target_overlay->SetPaintToLayer(); + drop_target_overlay->layer()->SetFillsBoundsOpaquely(false); // Icon. auto* icon = drop_target_overlay->AddChildView(std::make_unique<views::ImageView>()); icon->SetHorizontalAlignment(views::ImageView::Alignment::kCenter); icon->SetVerticalAlignment(views::ImageView::Alignment::kCenter); - icon->SetImage(gfx::CreateVectorIcon(views::kUnpinIcon, kHoldingSpaceIconSize, - gfx::kGoogleGrey700)); + icon->SetImage(gfx::CreateVectorIcon( + views::kUnpinIcon, kHoldingSpaceIconSize, + AshColorProvider::Get()->GetContentLayerColor( + AshColorProvider::ContentLayerType::kIconColorPrimary))); icon->SetPaintToLayer(); icon->layer()->SetFillsBoundsOpaquely(false);
diff --git a/ash/system/holding_space/holding_space_util.cc b/ash/system/holding_space/holding_space_util.cc index f2eec46..c3b7ac0 100644 --- a/ash/system/holding_space/holding_space_util.cc +++ b/ash/system/holding_space/holding_space_util.cc
@@ -75,9 +75,7 @@ observer); } -std::unique_ptr<views::Label> CreateLabel(LabelStyle style, - const base::string16& text) { - auto label = std::make_unique<views::Label>(text); +void ApplyStyle(views::Label* label, LabelStyle style) { label->SetAutoColorReadabilityEnabled(false); label->SetEnabledColor(AshColorProvider::Get()->GetContentLayerColor( AshColorProvider::ContentLayerType::kTextColorPrimary)); @@ -100,7 +98,12 @@ gfx::Font::Weight::MEDIUM)); break; } +} +std::unique_ptr<views::Label> CreateLabel(LabelStyle style, + const base::string16& text) { + auto label = std::make_unique<views::Label>(text); + ApplyStyle(label.get(), style); return label; }
diff --git a/ash/system/holding_space/holding_space_util.h b/ash/system/holding_space/holding_space_util.h index f8e1fa8..a1e0b9c 100644 --- a/ash/system/holding_space/holding_space_util.h +++ b/ash/system/holding_space/holding_space_util.h
@@ -41,6 +41,9 @@ kHeader, }; +// Applies the specified `style` to the given `label`. +void ApplyStyle(views::Label* label, LabelStyle style); + // Creates a label with optional `text` matching the specified `style`. std::unique_ptr<views::Label> CreateLabel( LabelStyle style,
diff --git a/ash/system/message_center/message_center_utils.cc b/ash/system/message_center/message_center_utils.cc index 8a5af30..8af7c407 100644 --- a/ash/system/message_center/message_center_utils.cc +++ b/ash/system/message_center/message_center_utils.cc
@@ -4,9 +4,6 @@ #include "ash/system/message_center/message_center_utils.h" -#include "ash/media/media_notification_constants.h" -#include "ash/public/cpp/ash_features.h" -#include "ash/public/cpp/vm_camera_mic_constants.h" #include "ui/message_center/message_center.h" namespace ash { @@ -33,30 +30,6 @@ return sorted_notifications; } -size_t GetNotificationCount() { - // If flag is set, do not include media notifications in count. - // TODO(crbug.com/1111881) This code can be removed when OS media controls are - // launched (expected by M90). - const bool skip_media_notification = - base::FeatureList::IsEnabled(features::kMediaNotificationsCounter); - - size_t count = 0; - for (message_center::Notification* notification : - message_center::MessageCenter::Get()->GetVisibleNotifications()) { - const std::string& notifier = notification->notifier_id().id; - // Don't count these notifications since we have `CameraMicTrayItemView` to - // show indicators on the systray. - if (notifier == kVmCameraMicNotifierId) - continue; - - if (skip_media_notification && notifier == kMediaSessionNotifierId) - continue; - - ++count; - } - return count; -} - } // namespace message_center_utils } // namespace ash
diff --git a/ash/system/message_center/message_center_utils.h b/ash/system/message_center/message_center_utils.h index ca9758a..63fb97a69 100644 --- a/ash/system/message_center/message_center_utils.h +++ b/ash/system/message_center/message_center_utils.h
@@ -5,7 +5,6 @@ #ifndef ASH_SYSTEM_MESSAGE_CENTER_MESSAGE_CENTER_UTILS_H_ #define ASH_SYSTEM_MESSAGE_CENTER_MESSAGE_CENTER_UTILS_H_ -#include "ash/ash_export.h" #include "ui/message_center/public/cpp/notification.h" namespace ash { @@ -24,11 +23,6 @@ // CompareNotifications() above for the sorting order. std::vector<message_center::Notification*> GetSortedVisibleNotifications(); -// Returns total notifications count, with a filter to not count some of them -// (These notifications such as camera, media controls, etc. don't need an -// indicator in status area since they already have a dedicated tray item). -size_t ASH_EXPORT GetNotificationCount(); - } // namespace message_center_utils } // namespace ash
diff --git a/ash/system/message_center/message_center_utils_unittest.cc b/ash/system/message_center/message_center_utils_unittest.cc deleted file mode 100644 index 633411a9..0000000 --- a/ash/system/message_center/message_center_utils_unittest.cc +++ /dev/null
@@ -1,78 +0,0 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/message_center/message_center_utils.h" - -#include "ash/media/media_notification_constants.h" -#include "ash/public/cpp/ash_features.h" -#include "ash/public/cpp/vm_camera_mic_constants.h" -#include "ash/test/ash_test_base.h" -#include "base/strings/utf_string_conversions.h" -#include "base/test/scoped_feature_list.h" -#include "ui/message_center/message_center.h" - -namespace ash { - -namespace message_center_utils { - -namespace { - -void AddNotification(const std::string& notification_id, - const std::string& app_id) { - message_center::MessageCenter::Get()->AddNotification( - std::make_unique<message_center::Notification>( - message_center::NOTIFICATION_TYPE_BASE_FORMAT, notification_id, - base::UTF8ToUTF16("test_title"), base::UTF8ToUTF16("test message"), - gfx::Image(), /*display_source=*/base::string16(), GURL(), - message_center::NotifierId(message_center::NotifierType::APPLICATION, - app_id), - message_center::RichNotificationData(), - new message_center::NotificationDelegate())); -} - -} // namespace - -class MessageCenterUtilsTest : public AshTestBase, - public testing::WithParamInterface<bool> { - public: - MessageCenterUtilsTest() = default; - MessageCenterUtilsTest(const MessageCenterUtilsTest&) = delete; - MessageCenterUtilsTest& operator=(const MessageCenterUtilsTest&) = delete; - ~MessageCenterUtilsTest() override = default; - - // AshTestBase: - void SetUp() override { - AshTestBase::SetUp(); - scoped_feature_list_.InitWithFeatureState( - features::kMediaNotificationsCounter, - IsMediaNotificationsCounterEnabled()); - } - - bool IsMediaNotificationsCounterEnabled() { return GetParam(); } - - private: - base::test::ScopedFeatureList scoped_feature_list_; -}; - -INSTANTIATE_TEST_SUITE_P( - All, - MessageCenterUtilsTest, - testing::Bool() /* IsMediaNotificationsCounterEnabled() */); - -TEST_P(MessageCenterUtilsTest, TotalNotificationCount) { - EXPECT_EQ(0u, GetNotificationCount()); - - // VM camera/mic notifications are ignored by the counter. - AddNotification("0", kVmCameraMicNotifierId); - EXPECT_EQ(0u, GetNotificationCount()); - - AddNotification("1", kMediaSessionNotifierId); - // Counter should ignore media notifications when feature is enabled. - size_t expected_count = IsMediaNotificationsCounterEnabled() ? 0u : 1u; - EXPECT_EQ(expected_count, GetNotificationCount()); -} - -} // namespace message_center_utils - -} // namespace ash
diff --git a/ash/system/message_center/notifier_settings_view.cc b/ash/system/message_center/notifier_settings_view.cc index ca926c5..b0f96e35 100644 --- a/ash/system/message_center/notifier_settings_view.cc +++ b/ash/system/message_center/notifier_settings_view.cc
@@ -552,10 +552,10 @@ ContentLayerType::kIconColorPrimary); if (is_quiet_mode) { quiet_mode_icon_->SetImage(gfx::CreateVectorIcon( - kNotificationCenterDoNotDisturbOnIcon, kMenuIconSize, icon_color)); + kSystemTrayDoNotDisturbIcon, kMenuIconSize, icon_color)); } else { quiet_mode_icon_->SetImage(gfx::CreateVectorIcon( - kNotificationCenterDoNotDisturbOffIcon, kMenuIconSize, icon_color)); + kDoNotDisturbDisabledIcon, kMenuIconSize, icon_color)); } }
diff --git a/ash/system/tray/system_tray_item_uma_type.h b/ash/system/tray/system_tray_item_uma_type.h index 5529749f..e09e425 100644 --- a/ash/system/tray/system_tray_item_uma_type.h +++ b/ash/system/tray/system_tray_item_uma_type.h
@@ -46,7 +46,8 @@ UMA_PRIVACY_SCREEN = 29, UMA_DARK_MODE = 30, UMA_NEARBY_SHARE = 31, - UMA_COUNT = 32, + UMA_PROJECTOR = 32, + UMA_COUNT = 33, }; } // namespace ash
diff --git a/ash/system/unified/notification_counter_view.cc b/ash/system/unified/notification_counter_view.cc index 0bc4bd41..eadd00d 100644 --- a/ash/system/unified/notification_counter_view.cc +++ b/ash/system/unified/notification_counter_view.cc
@@ -14,11 +14,8 @@ #include "ash/shell.h" #include "ash/strings/grit/ash_strings.h" #include "ash/system/message_center/ash_message_center_lock_screen_controller.h" -#include "ash/system/message_center/message_center_utils.h" #include "ash/system/tray/tray_constants.h" #include "ash/system/tray/tray_utils.h" -#include "ash/system/unified/notification_icons_controller.h" -#include "ash/system/unified/unified_system_tray.h" #include "base/i18n/number_formatting.h" #include "ui/base/l10n/l10n_util.h" #include "ui/gfx/canvas.h" @@ -92,16 +89,11 @@ } // namespace -NotificationCounterView::NotificationCounterView( - UnifiedSystemTray* tray, - NotificationIconsController* controller) - : TrayItemView(tray->shelf()), controller_(controller) { - system_tray_model_observation_.Observe(tray->model()); +NotificationCounterView::NotificationCounterView(Shelf* shelf) + : TrayItemView(shelf) { CreateImageView(); SetVisible(false); Shell::Get()->session_controller()->AddObserver(this); - - OnSystemTrayButtonSizeChanged(tray->model()->GetSystemTrayButtonSize()); } NotificationCounterView::~NotificationCounterView() { @@ -112,14 +104,33 @@ SessionControllerImpl* session_controller = Shell::Get()->session_controller(); - size_t notification_count = message_center_utils::GetNotificationCount(); + // If flag is set, do not include media notifications in count. + // TODO(crbug.com/1111881) This code can be removed when OS media controls are + // launched (expected by M90). + const bool dont_count_media_notification = + base::FeatureList::IsEnabled(features::kMediaNotificationsCounter); - // If we are currently showing icons of some notifications in the tray, this - // counter should not be shown. - const bool tray_notification_icons_shown = - icons_view_visible_ && controller_ && - controller_->TrayItemHasNotification(); - if (notification_count == 0 || tray_notification_icons_shown || + const message_center::NotificationList::Notifications& visible = + message_center::MessageCenter::Get()->GetVisibleNotifications(); + + size_t notification_count = std::count_if( + visible.begin(), visible.end(), + [dont_count_media_notification]( + message_center::Notification* notification) { + const std::string& notifier = notification->notifier_id().id; + // Don't count these notifications since we have `CameraMicTrayItemView` + // to show indicators on the systray. + if (notifier == kVmCameraMicNotifierId) { + return false; + } + if (dont_count_media_notification && + notifier == kMediaSessionNotifierId) { + return false; + } + return true; + }); + + if (notification_count == 0 || message_center::MessageCenter::Get()->IsQuietMode() || !session_controller->ShouldShowNotificationTray() || (session_controller->IsScreenLocked() && @@ -153,37 +164,10 @@ Update(); } -void NotificationCounterView::OnSystemTrayButtonSizeChanged( - UnifiedSystemTrayModel::SystemTrayButtonSize system_tray_size) { - icons_view_visible_ = - system_tray_size != UnifiedSystemTrayModel::SystemTrayButtonSize::kSmall; - Update(); -} - const char* NotificationCounterView::GetClassName() const { return "NotificationCounterView"; } -HiddenNotificationCountView::HiddenNotificationCountView(Shelf* shelf) - : TrayItemView(shelf) { - CreateLabel(); - SetupLabelForTray(label()); - SetBorder(views::CreateEmptyBorder(kUnifiedTrayTextTopPadding, 0, 0, - kUnifiedTrayTextRightPadding)); - label()->SetEnabledColor(AshColorProvider::Get()->GetContentLayerColor( - AshColorProvider::ContentLayerType::kIconColorPrimary)); -} - -HiddenNotificationCountView::~HiddenNotificationCountView() = default; - -void HiddenNotificationCountView::HandleLocaleChange() { - // TODO(crbug.com/1161557): Finish this function. -} - -const char* HiddenNotificationCountView::GetClassName() const { - return "HiddenNotificationCountView"; -} - QuietModeView::QuietModeView(Shelf* shelf) : TrayItemView(shelf) { CreateImageView(); image_view()->SetTooltipText(
diff --git a/ash/system/unified/notification_counter_view.h b/ash/system/unified/notification_counter_view.h index fcc8de3..5fbf695 100644 --- a/ash/system/unified/notification_counter_view.h +++ b/ash/system/unified/notification_counter_view.h
@@ -8,31 +8,20 @@ #include "ash/ash_export.h" #include "ash/public/cpp/session/session_observer.h" #include "ash/system/tray/tray_item_view.h" -#include "ash/system/unified/unified_system_tray_model.h" #include "base/macros.h" -#include "base/scoped_observation.h" namespace ash { -class NotificationIconsController; -class UnifiedSystemTray; - // Maximum count of notification shown by a number label. "+" icon is shown // instead if it exceeds this limit. constexpr size_t kTrayNotificationMaxCount = 9; -// A notification counter view in UnifiedSystemTray button. This will be shown -// when there's notification and the tray doesn't show any notification icons. -class ASH_EXPORT NotificationCounterView - : public TrayItemView, - public SessionObserver, - public UnifiedSystemTrayModel::Observer { +// A notification counter view in UnifiedSystemTray button. +class ASH_EXPORT NotificationCounterView : public TrayItemView, + public SessionObserver { public: - NotificationCounterView(UnifiedSystemTray* tray, - NotificationIconsController* controller); + explicit NotificationCounterView(Shelf* shelf); ~NotificationCounterView() override; - NotificationCounterView(const NotificationCounterView&) = delete; - NotificationCounterView& operator=(const NotificationCounterView&) = delete; void Update(); @@ -45,10 +34,6 @@ // SessionObserver: void OnSessionStateChanged(session_manager::SessionState state) override; - // UnifiedSystemTrayModel::Observer: - void OnSystemTrayButtonSizeChanged( - UnifiedSystemTrayModel::SystemTrayButtonSize system_tray_size) override; - // views::TrayItemView: const char* GetClassName() const override; @@ -61,30 +46,7 @@ // |kTrayNotificationMaxCount| + 1 indicates the plus icon. int count_for_display_ = 0; - // Indicates if the notification icons view is set to be shown. Currently, we - // show the icon view in medium or large screen size. - bool icons_view_visible_ = false; - - NotificationIconsController* const controller_; - - base::ScopedObservation<UnifiedSystemTrayModel, - UnifiedSystemTrayModel::Observer> - system_tray_model_observation_{this}; -}; - -// An icon view to indicate the number of hidden notifications (besides from the -// notifications that are shown in tray). -class HiddenNotificationCountView : public TrayItemView { - public: - explicit HiddenNotificationCountView(Shelf* shelf); - ~HiddenNotificationCountView() override; - HiddenNotificationCountView(const HiddenNotificationCountView&) = delete; - HiddenNotificationCountView& operator=(const HiddenNotificationCountView&) = - delete; - - // TrayItemView: - void HandleLocaleChange() override; - const char* GetClassName() const override; + DISALLOW_COPY_AND_ASSIGN(NotificationCounterView); }; // A do-not-distrub icon view in UnifiedSystemTray button. @@ -92,8 +54,6 @@ public: explicit QuietModeView(Shelf* shelf); ~QuietModeView() override; - QuietModeView(const QuietModeView&) = delete; - QuietModeView& operator=(const QuietModeView&) = delete; void Update(); @@ -105,6 +65,9 @@ // views::TrayItemView: const char* GetClassName() const override; + + private: + DISALLOW_COPY_AND_ASSIGN(QuietModeView); }; } // namespace ash
diff --git a/ash/system/unified/notification_counter_view_unittest.cc b/ash/system/unified/notification_counter_view_unittest.cc index a6166c403..d598463 100644 --- a/ash/system/unified/notification_counter_view_unittest.cc +++ b/ash/system/unified/notification_counter_view_unittest.cc
@@ -4,9 +4,9 @@ #include "ash/system/unified/notification_counter_view.h" +#include "ash/media/media_notification_constants.h" #include "ash/public/cpp/ash_features.h" -#include "ash/system/unified/notification_icons_controller.h" -#include "ash/system/unified/unified_system_tray.h" +#include "ash/public/cpp/vm_camera_mic_constants.h" #include "ash/test/ash_test_base.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" @@ -21,8 +21,7 @@ namespace ash { -class NotificationCounterViewTest : public AshTestBase, - public testing::WithParamInterface<bool> { +class NotificationCounterViewTest : public AshTestBase { public: NotificationCounterViewTest() = default; NotificationCounterViewTest(const NotificationCounterViewTest&) = delete; @@ -33,46 +32,27 @@ // AshTestBase: void SetUp() override { AshTestBase::SetUp(); - scoped_feature_list_.InitWithFeatureState(features::kScalableStatusArea, - IsScalableStatusAreaEnabled()); - tray_ = std::make_unique<UnifiedSystemTray>(GetPrimaryShelf()); - - if (IsScalableStatusAreaEnabled()) { - notification_icons_controller_ = - std::make_unique<NotificationIconsController>(tray_.get()); - notification_icons_controller_->AddNotificationTrayItems( - tray_->tray_container()); - notification_counter_view_ = std::make_unique<NotificationCounterView>( - tray_.get(), notification_icons_controller_.get()); - } else { - notification_counter_view_ = - std::make_unique<NotificationCounterView>(tray_.get(), nullptr); - } + notification_counter_view_ = + std::make_unique<NotificationCounterView>(GetPrimaryShelf()); } - bool IsScalableStatusAreaEnabled() { return GetParam(); } - void TearDown() override { notification_counter_view_.reset(); - notification_icons_controller_.reset(); - tray_.reset(); AshTestBase::TearDown(); } protected: void AddNotification(const std::string& notification_id, - bool is_pinned = false) { - message_center::RichNotificationData rich_notification_data; - rich_notification_data.pinned = is_pinned; + const std::string& app_id = "app") { message_center::MessageCenter::Get()->AddNotification( std::make_unique<message_center::Notification>( message_center::NOTIFICATION_TYPE_BASE_FORMAT, notification_id, base::UTF8ToUTF16("test_title"), base::UTF8ToUTF16("test message"), gfx::Image(), /*display_source=*/base::string16(), GURL(), message_center::NotifierId( - message_center::NotifierType::APPLICATION, "app"), - rich_notification_data, + message_center::NotifierType::APPLICATION, app_id), + message_center::RichNotificationData(), new message_center::NotificationDelegate())); } @@ -81,17 +61,13 @@ } private: - base::test::ScopedFeatureList scoped_feature_list_; - std::unique_ptr<UnifiedSystemTray> tray_; - std::unique_ptr<NotificationIconsController> notification_icons_controller_; std::unique_ptr<NotificationCounterView> notification_counter_view_; }; -INSTANTIATE_TEST_SUITE_P(All, - NotificationCounterViewTest, - testing::Bool() /* IsScalableStatusAreaEnabled() */); +TEST_F(NotificationCounterViewTest, CountForDisplay) { + // VM camera/mic notifications are ignored by the counter. + AddNotification("camera & mic", kVmCameraMicNotifierId); -TEST_P(NotificationCounterViewTest, CountForDisplay) { // Not visible when count == 0. notification_counter_view()->Update(); EXPECT_EQ(0, notification_counter_view()->count_for_display_for_testing()); @@ -114,39 +90,27 @@ EXPECT_TRUE(notification_counter_view()->GetVisible()); } -TEST_P(NotificationCounterViewTest, DisplayChanged) { - AddNotification("0", false /* is_pinned */); - AddNotification("1", true /* is_pinned */); +// Media notifications are not included when flag is set. +TEST_F(NotificationCounterViewTest, MediaNotifications) { notification_counter_view()->Update(); - - // In medium size screen, the counter should not be displayed since pinned - // notification icon is shown (if the feature is enabled). - UpdateDisplay("800x800"); - EXPECT_EQ(IsScalableStatusAreaEnabled(), - !notification_counter_view()->GetVisible()); - - // The counter should be shown when we remove the pinned notification. - message_center::MessageCenter::Get()->RemoveNotification("1", - false /* by_user */); - notification_counter_view()->Update(); - EXPECT_TRUE(notification_counter_view()->GetVisible()); - - AddNotification("1", true /* is_pinned */); - notification_counter_view()->Update(); - - // In small display, the counter show be shown with pinned notification. - UpdateDisplay("600x600"); - EXPECT_TRUE(notification_counter_view()->GetVisible()); - - // In large screen size, expected the same behavior like medium screen size. - UpdateDisplay("1680x800"); - EXPECT_EQ(IsScalableStatusAreaEnabled(), - !notification_counter_view()->GetVisible()); - - message_center::MessageCenter::Get()->RemoveNotification("1", - false /* by_user */); - notification_counter_view()->Update(); - EXPECT_TRUE(notification_counter_view()->GetVisible()); + EXPECT_EQ(0, notification_counter_view()->count_for_display_for_testing()); + AddNotification("1", kMediaSessionNotifierId); + { + // Counter should ignore media notifications when feature is enabled. + base::test::ScopedFeatureList features; + features.InitAndEnableFeature(features::kMediaNotificationsCounter); + notification_counter_view()->Update(); + EXPECT_EQ(0, notification_counter_view()->count_for_display_for_testing()); + EXPECT_FALSE(notification_counter_view()->GetVisible()); + } + { + // Counter should show media notifications when feature is disabled. + base::test::ScopedFeatureList features; + features.InitAndDisableFeature(features::kMediaNotificationsCounter); + notification_counter_view()->Update(); + EXPECT_EQ(1, notification_counter_view()->count_for_display_for_testing()); + EXPECT_TRUE(notification_counter_view()->GetVisible()); + } } } // namespace ash
diff --git a/ash/system/unified/notification_icons_controller.cc b/ash/system/unified/notification_icons_controller.cc index af6c6fe..c441a5a 100644 --- a/ash/system/unified/notification_icons_controller.cc +++ b/ash/system/unified/notification_icons_controller.cc
@@ -5,21 +5,16 @@ #include "ash/system/unified/notification_icons_controller.h" #include "ash/resources/vector_icons/vector_icons.h" -#include "ash/strings/grit/ash_strings.h" #include "ash/system/message_center/message_center_utils.h" #include "ash/system/tray/tray_constants.h" #include "ash/system/tray/tray_container.h" -#include "ash/system/tray/tray_utils.h" -#include "ash/system/unified/notification_counter_view.h" #include "ash/system/unified/unified_system_tray.h" #include "ash/system/unified/unified_system_tray_model.h" -#include "ui/base/l10n/l10n_util.h" #include "ui/gfx/paint_vector_icon.h" #include "ui/message_center/message_center.h" #include "ui/message_center/public/cpp/notification.h" #include "ui/message_center/vector_icons.h" #include "ui/views/controls/image_view.h" -#include "ui/views/controls/separator.h" namespace ash { @@ -27,7 +22,6 @@ // Maximum number of notification icons shown in the system tray button. constexpr int kMaxNotificationIconsShown = 2; -constexpr int kSeparatorPadding = 3; // We only show notification icon in the tray if it is either: // * Pinned (generally used for background process such as sharing your @@ -39,25 +33,6 @@ message_center::SystemNotificationWarningLevel::CRITICAL_WARNING; } -class SeparatorTrayItemView : public TrayItemView { - public: - explicit SeparatorTrayItemView(Shelf* shelf) : TrayItemView(shelf) { - views::Separator* separator = new views::Separator(); - separator->SetColor(AshColorProvider::Get()->GetContentLayerColor( - AshColorProvider::ContentLayerType::kSeparatorColor)); - separator->SetBorder( - views::CreateEmptyBorder(gfx::Insets(kSeparatorPadding))); - AddChildView(separator); - } - ~SeparatorTrayItemView() override = default; - SeparatorTrayItemView(const SeparatorTrayItemView&) = delete; - SeparatorTrayItemView& operator=(const SeparatorTrayItemView&) = delete; - - // TrayItemView: - void HandleLocaleChange() override {} - const char* GetClassName() const override { return "SeparatorTrayItemView"; } -}; - } // namespace NotificationIconTrayItemView::NotificationIconTrayItemView(Shelf* shelf) @@ -133,44 +108,14 @@ std::make_unique<NotificationIconTrayItemView>(tray_->shelf()))); } - hidden_notification_count_view_ = tray_container->AddChildView( - std::make_unique<HiddenNotificationCountView>(tray_->shelf())); - - separator_ = tray_container->AddChildView( - std::make_unique<SeparatorTrayItemView>(tray_->shelf())); - OnSystemTrayButtonSizeChanged(tray_->model()->GetSystemTrayButtonSize()); } -void NotificationIconsController::UpdateHiddenNotificationCounter() { - if (!icons_view_visible_ || !TrayItemHasNotification()) { - hidden_notification_count_view_->SetVisible(false); - return; - } - - // `first_unused_item_index_` is also the total number of notification icons - // shown in the tray. - int hidden_notification_num = - message_center_utils::GetNotificationCount() - first_unused_item_index_; - if (hidden_notification_num != 0) - hidden_notification_count_view_->label()->SetText( - l10n_util::GetStringFUTF16Int( - IDS_ASH_STATUS_TRAY_HIDDEN_NOTIFICATION_COUNT_LABEL, - hidden_notification_num)); - - hidden_notification_count_view_->SetVisible(hidden_notification_num != 0); -} - -bool NotificationIconsController::TrayItemHasNotification() { - return first_unused_item_index_ != 0; -} - void NotificationIconsController::OnSystemTrayButtonSizeChanged( UnifiedSystemTrayModel::SystemTrayButtonSize system_tray_size) { icons_view_visible_ = system_tray_size != UnifiedSystemTrayModel::SystemTrayButtonSize::kSmall; - UpdateNotificationIcons(); - UpdateHiddenNotificationCounter(); + Update(); } void NotificationIconsController::OnNotificationAdded(const std::string& id) { @@ -181,7 +126,7 @@ // Reset the notification icons if a notification is added since we don't // know the position where its icon should be added. - UpdateNotificationIcons(); + Update(); } void NotificationIconsController::OnNotificationRemoved(const std::string& id, @@ -189,7 +134,7 @@ // If the notification removed is displayed in an icon, call update to show // another notification if needed. if (GetNotificationIconShownInTray(id)) - UpdateNotificationIcons(); + Update(); } void NotificationIconsController::OnNotificationUpdated(const std::string& id) { @@ -198,7 +143,7 @@ item->UpdateTooltipText(); } -void NotificationIconsController::UpdateNotificationIcons() { +void NotificationIconsController::Update() { auto it = tray_items_.begin(); for (message_center::Notification* notification : message_center_utils::GetSortedVisibleNotifications()) { @@ -217,7 +162,6 @@ (*it)->Reset(); (*it)->SetVisible(false); } - separator_->SetVisible(icons_view_visible_ && TrayItemHasNotification()); } NotificationIconTrayItemView*
diff --git a/ash/system/unified/notification_icons_controller.h b/ash/system/unified/notification_icons_controller.h index 33acae70..05532827 100644 --- a/ash/system/unified/notification_icons_controller.h +++ b/ash/system/unified/notification_icons_controller.h
@@ -75,12 +75,6 @@ // Initialize the view by adding items to the container of the tray. void AddNotificationTrayItems(TrayContainer* tray_container); - // Update the text and visibility of the hidden notification counter. - void UpdateHiddenNotificationCounter(); - - // Returns true if any item in `tray_items_` is containing a notification. - bool TrayItemHasNotification(); - // UnifiedSystemTrayModel::Observer: void OnSystemTrayButtonSizeChanged( UnifiedSystemTrayModel::SystemTrayButtonSize system_tray_size) override; @@ -95,11 +89,8 @@ } private: - friend class NotificationIconsControllerTest; - - // Iterate through the notifications in message center and update the icons - // shown accordingly. - void UpdateNotificationIcons(); + // Update the icons shown according to the notifications in message center. + void Update(); // If the notification with given id is currently shown in tray, returns the // pointer to that tray item. Otherwise, returns a null pointer. @@ -114,15 +105,11 @@ // icons tray item. All the items in previous index are used and visible. size_t first_unused_item_index_ = 0; - // Indicates if the notification icons view is set to be shown. Currently, we - // show the icon view in medium or large screen size. + // Indicates if the notification icons view is set to be shown. bool icons_view_visible_ = false; UnifiedSystemTray* tray_; - TrayItemView* hidden_notification_count_view_ = nullptr; - TrayItemView* separator_ = nullptr; - base::ScopedObservation<UnifiedSystemTrayModel, UnifiedSystemTrayModel::Observer> system_tray_model_observation_{this};
diff --git a/ash/system/unified/notification_icons_controller_unittest.cc b/ash/system/unified/notification_icons_controller_unittest.cc index 5ff8704..950ba38 100644 --- a/ash/system/unified/notification_icons_controller_unittest.cc +++ b/ash/system/unified/notification_icons_controller_unittest.cc
@@ -4,14 +4,10 @@ #include "ash/system/unified/notification_icons_controller.h" -#include "ash/media/media_notification_constants.h" -#include "ash/public/cpp/ash_features.h" #include "ash/public/cpp/notification_utils.h" -#include "ash/public/cpp/vm_camera_mic_constants.h" #include "ash/system/tray/tray_item_view.h" #include "ash/system/unified/unified_system_tray.h" #include "ash/test/ash_test_base.h" -#include "base/test/scoped_feature_list.h" #include "ui/message_center/message_center.h" #include "ui/message_center/public/cpp/notification.h" @@ -38,17 +34,7 @@ AshTestBase::TearDown(); } - TrayItemView* separator() { - return notification_icons_controller_->separator_; - } - - TrayItemView* hidden_notification_count_view() { - return notification_icons_controller_->hidden_notification_count_view_; - } - - std::string AddNotification(bool is_pinned, - bool is_critical_warning, - const std::string& app_id = "app") { + std::string AddNotification(bool is_pinned, bool is_critical_warning) { std::string id = base::NumberToString(notification_id_++); auto warning_level = @@ -64,7 +50,7 @@ base::UTF8ToUTF16("test_title"), base::UTF8ToUTF16("test message"), base::string16() /*display_source */, GURL() /* origin_url */, message_center::NotifierId( - message_center::NotifierType::SYSTEM_COMPONENT, app_id), + message_center::NotifierType::SYSTEM_COMPONENT, "ash.debug"), rich_notification_data, nullptr /* delegate */, gfx::VectorIcon(), warning_level)); notification_id_++; @@ -80,29 +66,20 @@ TEST_F(NotificationIconsControllerTest, DisplayChanged) { AddNotification(true /* is_pinned */, false /* is_critical_warning */); - AddNotification(false /* is_pinned */, false /* is_critical_warning */); - notification_icons_controller_->UpdateHiddenNotificationCounter(); - - // Notification icons should be shown in medium screen size. - UpdateDisplay("800x800"); - EXPECT_TRUE( - notification_icons_controller_->tray_items().front()->GetVisible()); - EXPECT_TRUE(separator()->GetVisible()); - EXPECT_TRUE(hidden_notification_count_view()->GetVisible()); // Notification icons should not be shown in small screen size. UpdateDisplay("600x600"); EXPECT_FALSE( notification_icons_controller_->tray_items().front()->GetVisible()); - EXPECT_FALSE(separator()->GetVisible()); - EXPECT_FALSE(hidden_notification_count_view()->GetVisible()); - // Notification icons should be shown in large screen size. + // Notification icons should be shown in medium and large screen size. + UpdateDisplay("800x800"); + EXPECT_TRUE( + notification_icons_controller_->tray_items().front()->GetVisible()); + UpdateDisplay("1680x800"); EXPECT_TRUE( notification_icons_controller_->tray_items().front()->GetVisible()); - EXPECT_TRUE(separator()->GetVisible()); - EXPECT_TRUE(hidden_notification_count_view()->GetVisible()); } TEST_F(NotificationIconsControllerTest, ShowNotificationIcons) { @@ -111,13 +88,11 @@ // If there's no notification, no notification icons should be shown. EXPECT_FALSE(notification_icons_controller_->tray_items()[0]->GetVisible()); EXPECT_FALSE(notification_icons_controller_->tray_items()[1]->GetVisible()); - EXPECT_FALSE(separator()->GetVisible()); // Same case for non pinned or non critical warning notification. AddNotification(false /* is_pinned */, false /* is_critical_warning */); EXPECT_FALSE(notification_icons_controller_->tray_items()[0]->GetVisible()); EXPECT_FALSE(notification_icons_controller_->tray_items()[1]->GetVisible()); - EXPECT_FALSE(separator()->GetVisible()); // Notification icons should be shown when pinned or critical warning // notification is added. @@ -125,13 +100,11 @@ AddNotification(true /* is_pinned */, false /* is_critical_warning */); EXPECT_TRUE(notification_icons_controller_->tray_items()[0]->GetVisible()); EXPECT_FALSE(notification_icons_controller_->tray_items()[1]->GetVisible()); - EXPECT_TRUE(separator()->GetVisible()); std::string id1 = AddNotification(false /* is_pinned */, true /* is_critical_warning */); EXPECT_TRUE(notification_icons_controller_->tray_items()[0]->GetVisible()); EXPECT_TRUE(notification_icons_controller_->tray_items()[1]->GetVisible()); - EXPECT_TRUE(separator()->GetVisible()); // Remove the critical warning notification should make the tray show only one // icon. @@ -139,47 +112,12 @@ false /* by_user */); EXPECT_TRUE(notification_icons_controller_->tray_items()[0]->GetVisible()); EXPECT_FALSE(notification_icons_controller_->tray_items()[1]->GetVisible()); - EXPECT_TRUE(separator()->GetVisible()); // Remove the pinned notification, no icon is shown. message_center::MessageCenter::Get()->RemoveNotification(id0, false /* by_user */); EXPECT_FALSE(notification_icons_controller_->tray_items()[0]->GetVisible()); EXPECT_FALSE(notification_icons_controller_->tray_items()[1]->GetVisible()); - EXPECT_FALSE(separator()->GetVisible()); -} - -TEST_F(NotificationIconsControllerTest, HiddenNotificationCount) { - UpdateDisplay("800x800"); - - // If there's no notification, the counter should be hidden by default. - EXPECT_FALSE(hidden_notification_count_view()->GetVisible()); - - int hidden_notification_num = 5; - base::string16 expected_text = base::UTF8ToUTF16("+5"); - - // The counter should not be shown if no icon is displayed in the tray (a.k.a - // no important notification). - for (int i = 0; i < hidden_notification_num; ++i) { - AddNotification(false /* is_pinned */, false /* is_critical_warning */); - } - notification_icons_controller_->UpdateHiddenNotificationCounter(); - EXPECT_FALSE(hidden_notification_count_view()->GetVisible()); - - // Added a pinned notification, the counter should now be shown with the - // expected text. - std::string id0 = - AddNotification(true /* is_pinned */, false /* is_critical_warning */); - notification_icons_controller_->UpdateHiddenNotificationCounter(); - EXPECT_TRUE(hidden_notification_count_view()->GetVisible()); - EXPECT_EQ(expected_text, - hidden_notification_count_view()->label()->GetText()); - - // Remove the pinned notification should make the counter switch to hidden. - message_center::MessageCenter::Get()->RemoveNotification(id0, - false /* by_user */); - notification_icons_controller_->UpdateHiddenNotificationCounter(); - EXPECT_FALSE(hidden_notification_count_view()->GetVisible()); } } // namespace ash
diff --git a/ash/system/unified/unified_system_tray.cc b/ash/system/unified/unified_system_tray.cc index 092a7c3a..b2ac971 100644 --- a/ash/system/unified/unified_system_tray.cc +++ b/ash/system/unified/unified_system_tray.cc
@@ -137,9 +137,7 @@ CameraMicTrayItemView::Type::kCamera)), mic_view_( new CameraMicTrayItemView(shelf, CameraMicTrayItemView::Type::kMic)), - notification_counter_item_( - new NotificationCounterView(this, - notification_icons_controller_.get())), + notification_counter_item_(new NotificationCounterView(shelf)), quiet_mode_view_(new QuietModeView(shelf)), time_view_(new tray::TimeTrayItemView(shelf, model())) { tray_container()->SetMargin( @@ -495,8 +493,6 @@ void UnifiedSystemTray::UpdateNotificationAfterDelay() { notification_counter_item_->Update(); quiet_mode_view_->Update(); - if (notification_icons_controller_) - notification_icons_controller_->UpdateHiddenNotificationCounter(); } message_center::MessagePopupView*
diff --git a/ash/system/unified/unified_system_tray_controller.cc b/ash/system/unified/unified_system_tray_controller.cc index e2220263..ad2e516a 100644 --- a/ash/system/unified/unified_system_tray_controller.cc +++ b/ash/system/unified/unified_system_tray_controller.cc
@@ -5,8 +5,10 @@ #include "ash/system/unified/unified_system_tray_controller.h" #include "ash/capture_mode/capture_mode_feature_pod_controller.h" +#include "ash/constants/ash_features.h" #include "ash/metrics/user_metrics_action.h" #include "ash/metrics/user_metrics_recorder.h" +#include "ash/projector/projector_feature_pod_controller.h" #include "ash/public/cpp/ash_features.h" #include "ash/public/cpp/metrics_util.h" #include "ash/public/cpp/pagination/pagination_controller.h" @@ -438,9 +440,10 @@ AddFeaturePodItem(std::make_unique<AccessibilityFeaturePodController>(this)); AddFeaturePodItem(std::make_unique<QuietModeFeaturePodController>(this)); AddFeaturePodItem(std::make_unique<RotationLockFeaturePodController>()); - AddFeaturePodItem(std::make_unique<PrivacyScreenFeaturePodController>()); if (features::IsCaptureModeEnabled()) AddFeaturePodItem(std::make_unique<CaptureModeFeaturePodController>(this)); + if (chromeos::features::IsProjectorFeaturePodEnabled()) + AddFeaturePodItem(std::make_unique<ProjectorFeaturePodController>(this)); AddFeaturePodItem(std::make_unique<NearbyShareFeaturePodController>(this)); AddFeaturePodItem(std::make_unique<NightLightFeaturePodController>(this)); AddFeaturePodItem(std::make_unique<CastFeaturePodController>(this));
diff --git a/ash/wm/desks/desk.cc b/ash/wm/desks/desk.cc index f96f8c9..c50f730 100644 --- a/ash/wm/desks/desk.cc +++ b/ash/wm/desks/desk.cc
@@ -239,7 +239,8 @@ NotifyContentChanged(); // Update the window's workspace to this parent desk. - if (features::IsBentoEnabled() && !is_desk_being_removed_) { + if ((features::IsBentoEnabled() || features::IsFullRestoreEnabled()) && + !is_desk_being_removed_) { auto* desks_controller = DesksController::Get(); window->SetProperty(aura::client::kWindowWorkspaceKey, desks_controller->GetDeskIndex(this));
diff --git a/ash/wm/desks/desk_preview_view.cc b/ash/wm/desks/desk_preview_view.cc index 8a9cc957..6dd53b2 100644 --- a/ash/wm/desks/desk_preview_view.cc +++ b/ash/wm/desks/desk_preview_view.cc
@@ -376,7 +376,8 @@ // them in the layer tree if |this| is not the preview view for the active // desk. visible_on_all_desks_windows_to_mirror = - Shell::Get()->desks_controller()->visible_on_all_desks_windows(); + Shell::Get()->desks_controller()->GetVisibleOnAllDesksWindowsOnRoot( + mini_view_->root_window()); for (auto* window : visible_on_all_desks_windows_to_mirror) GetLayersData(window, &layers_data); }
diff --git a/ash/wm/desks/desks_controller.cc b/ash/wm/desks/desks_controller.cc index 2731ad9..eceeac0 100644 --- a/ash/wm/desks/desks_controller.cc +++ b/ash/wm/desks/desks_controller.cc
@@ -264,6 +264,18 @@ return active_desk(); } +base::flat_set<aura::Window*> +DesksController::GetVisibleOnAllDesksWindowsOnRoot( + aura::Window* root_window) const { + DCHECK(root_window->IsRootWindow()); + base::flat_set<aura::Window*> filtered_visible_on_all_desks_windows; + for (auto* visible_on_all_desks_window : visible_on_all_desks_windows_) { + if (visible_on_all_desks_window->GetRootWindow() == root_window) + filtered_visible_on_all_desks_windows.insert(visible_on_all_desks_window); + } + return filtered_visible_on_all_desks_windows; +} + void DesksController::RestorePrimaryUserActiveDeskIndex(int active_desk_index) { DCHECK_GE(active_desk_index, 0); DCHECK_LT(active_desk_index, int{desks_.size()});
diff --git a/ash/wm/desks/desks_controller.h b/ash/wm/desks/desks_controller.h index 6d6a669..c14a619 100644 --- a/ash/wm/desks/desks_controller.h +++ b/ash/wm/desks/desks_controller.h
@@ -90,6 +90,10 @@ // switch animation is in progress. const Desk* GetTargetActiveDesk() const; + // Returns the visible on all desks windows that reside on |root_window|. + base::flat_set<aura::Window*> GetVisibleOnAllDesksWindowsOnRoot( + aura::Window* root_window) const; + // Restores the primary user's activate desk at active_desk_index. void RestorePrimaryUserActiveDeskIndex(int active_desk_index);
diff --git a/ash/wm/full_restore/full_restore_controller.cc b/ash/wm/full_restore/full_restore_controller.cc index df63d95..86810883 100644 --- a/ash/wm/full_restore/full_restore_controller.cc +++ b/ash/wm/full_restore/full_restore_controller.cc
@@ -4,10 +4,15 @@ #include "ash/wm/full_restore/full_restore_controller.h" +#include "ash/public/cpp/app_types.h" +#include "ash/public/cpp/shell_window_ids.h" #include "ash/shell.h" -#include "ash/wm/full_restore/full_restore_window_manager.h" +#include "ash/wm/mru_window_tracker.h" +#include "ash/wm/window_state.h" #include "base/check_op.h" +#include "components/full_restore/full_restore_utils.h" #include "components/prefs/pref_service.h" +#include "ui/aura/client/aura_constants.h" namespace ash { @@ -15,11 +20,33 @@ FullRestoreController* g_instance = nullptr; +// Callback for testing which is run when SaveWindowImpl triggers a write to +// file. +FullRestoreController::SaveWindowCallback g_save_window_callback_for_testing; + +// The list of possible app window parents. +// TODO(crbug.com/1164472): Support the rest of the desk containers which +// are currently not always created depending on whether the bento feature +// is enabled. +constexpr ShellWindowId kAppParentContainers[5] = { + kShellWindowId_DefaultContainerDeprecated, + kShellWindowId_DeskContainerB, + kShellWindowId_DeskContainerC, + kShellWindowId_DeskContainerD, + kShellWindowId_AlwaysOnTopContainer, +}; + +// The types of apps currently supported by full restore. +// TODO(crbug.com/1164472): Add ARC apps when they are supported. +// TODO(crbug.com/1164472): Checking app type is temporary solution until we +// can get windows which are allowed to full restore from the +// FullRestoreService. +constexpr AppType kSupportedAppTypes[2] = {AppType::BROWSER, + AppType::CHROME_APP}; + } // namespace -FullRestoreController::FullRestoreController() - : full_restore_window_manager_( - std::make_unique<FullRestoreWindowManager>()) { +FullRestoreController::FullRestoreController() { DCHECK_EQ(nullptr, g_instance); g_instance = this; @@ -33,32 +60,97 @@ // static FullRestoreController* FullRestoreController::Get() { - DCHECK(g_instance); return g_instance; } -void FullRestoreController::SaveWindows() { - ++save_windows_count_for_testing_; +void FullRestoreController::SaveWindow(WindowState* window_state) { + SaveWindowImpl(window_state, /*activation_index=*/base::nullopt); +} - // TODO(crbug.com/1164472): Hook up to full_restore::FullRestoreSaveHandler. +void FullRestoreController::SaveAllWindows() { + auto windows = + Shell::Get()->mru_window_tracker()->BuildMruWindowList(kAllDesks); + for (int i = 0; i < int{windows.size()}; ++i) { + WindowState* window_state = WindowState::Get(windows[i]); + + // Flip the index so that larger values are associated with more recently + // used windows. See SaveWindowImpl for more details. + const int activation_index = windows.size() - 1 - i; + SaveWindowImpl(window_state, activation_index); + } } void FullRestoreController::OnActiveUserPrefServiceChanged( PrefService* pref_service) { - // TODO(crbug.com/1164472): Register and the check the pref service and call - // FullRestoreWindowManager::SetEnabled accordingly. + // TODO(crbug.com/1164472): Register and the check the pref service. } void FullRestoreController::OnTabletModeStarted() { - SaveWindows(); + SaveAllWindows(); } void FullRestoreController::OnTabletModeEnded() { - SaveWindows(); + SaveAllWindows(); } void FullRestoreController::OnTabletControllerDestroyed() { tablet_mode_observeration_.Reset(); } +void FullRestoreController::SaveWindowImpl( + WindowState* window_state, + base::Optional<int> activation_index) { + DCHECK(window_state); + aura::Window* window = window_state->window(); + + if (!base::Contains(kAppParentContainers, window->parent()->id())) + return; + + // Only some app types can be saved. + if (!base::Contains( + kSupportedAppTypes, + static_cast<AppType>(window->GetProperty(aura::client::kAppType)))) { + return; + } + + int window_activation_index; + if (activation_index) { + window_activation_index = *activation_index; + } else { + // The returned MRU list has the more recently used windows have a smaller + // index. We want to flip it so that larger values are associated with + // more recently used windows instead. This is because when creating + // windows, we will add them into a aura::Window hierarichy, whose + // children are stacked such that the highest indexed children are stacked + // closest to the top. We reverse the order here since we have access to + // the full MRU list, as opposed to on read when we will not have enough + // info when the first couple of windows get added. Due to there being + // equal or more windows in the MRU list than app windows, the activation + // indexes may not be consecutive, but the relative order will be correct. + auto windows = + Shell::Get()->mru_window_tracker()->BuildMruWindowList(kAllDesks); + std::reverse(windows.begin(), windows.end()); + auto it = std::find(windows.begin(), windows.end(), window); + if (it != windows.end()) + window_activation_index = it - windows.begin(); + } + + full_restore::WindowInfo window_info; + window_info.activation_index = window_activation_index; + window_info.window = window; + window_info.desk_id = window->GetProperty(aura::client::kWindowWorkspaceKey); + window_info.restore_bounds = window_state->GetRestoreBoundsInScreen(); + window_info.current_bounds = window->GetBoundsInScreen(); + window_info.window_state_type = window_state->GetStateType(); + full_restore::SaveWindowInfo(window_info); + + if (g_save_window_callback_for_testing) + g_save_window_callback_for_testing.Run(window_info); +} + +void FullRestoreController::SetSaveWindowCallbackForTesting( + SaveWindowCallback callback) { + g_save_window_callback_for_testing = std::move(callback); +} + } // namespace ash
diff --git a/ash/wm/full_restore/full_restore_controller.h b/ash/wm/full_restore/full_restore_controller.h index eb21a083..72cbaad 100644 --- a/ash/wm/full_restore/full_restore_controller.h +++ b/ash/wm/full_restore/full_restore_controller.h
@@ -10,16 +10,20 @@ #include "ash/public/cpp/tablet_mode_observer.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "base/scoped_observation.h" +#include "components/full_restore/window_info.h" class PrefService; namespace ash { -class FullRestoreWindowManager; +class WindowState; class ASH_EXPORT FullRestoreController : public SessionObserver, public TabletModeObserver { public: + using SaveWindowCallback = + base::RepeatingCallback<void(const full_restore::WindowInfo&)>; + FullRestoreController(); FullRestoreController(const FullRestoreController&) = delete; FullRestoreController& operator=(const FullRestoreController&) = delete; @@ -29,10 +33,12 @@ // Shell. static FullRestoreController* Get(); - // Calls full_restore::FullRestoreSaveHandler to save to the database. The - // handler has timer to prevent too many writes, but we should limit calls - // regardless if possible. - void SaveWindows(); + // Calls SaveWindowImpl for |window_state|. The activation index will be + // calculated in SaveWindowImpl. + void SaveWindow(WindowState* window_state); + + // Saves all windows in the MRU window tracker. + void SaveAllWindows(); // SessionObserver: void OnActiveUserPrefServiceChanged(PrefService* pref_service) override; @@ -45,10 +51,19 @@ private: friend class FullRestoreControllerTest; - // Tracks how many times SaveWindows has been called. - int save_windows_count_for_testing_ = 0; + // Calls full_restore::FullRestoreSaveHandler to save to file. The handler has + // timer to prevent too many writes, but we should limit calls regardless if + // possible. Optionally passes |activation_index|, which is calculated with + // respect to the MRU tracker. Calling SaveAllWindows will iterate through + // the MRU tracker list, so we can pass the activation index during that loop + // instead of building the MRU list again for each window. + void SaveWindowImpl(WindowState* window_state, + base::Optional<int> activation_index); - std::unique_ptr<FullRestoreWindowManager> full_restore_window_manager_; + // Sets a callback for testing that will be fired immediately when + // SaveWindowImpl is about to notify the full restore component we want to + // write to file. + void SetSaveWindowCallbackForTesting(SaveWindowCallback callback); base::ScopedObservation<TabletModeController, TabletModeObserver> tablet_mode_observeration_{this};
diff --git a/ash/wm/full_restore/full_restore_controller_unittest.cc b/ash/wm/full_restore/full_restore_controller_unittest.cc index 88cd71f..fe51456 100644 --- a/ash/wm/full_restore/full_restore_controller_unittest.cc +++ b/ash/wm/full_restore/full_restore_controller_unittest.cc
@@ -11,7 +11,9 @@ #include "ash/wm/desks/desks_controller.h" #include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h" #include "ash/wm/window_state.h" +#include "base/containers/flat_map.h" #include "base/test/scoped_feature_list.h" +#include "ui/wm/core/window_util.h" namespace ash { @@ -27,58 +29,82 @@ class FullRestoreControllerTest : public AshTestBase { public: + // Struct which is the data in our fake full restore file. + struct WindowInfo { + int call_count = 0; + int activation_index = 0; + }; + FullRestoreControllerTest() = default; FullRestoreControllerTest(const FullRestoreControllerTest&) = delete; FullRestoreControllerTest& operator=(const FullRestoreControllerTest&) = delete; ~FullRestoreControllerTest() override = default; - int GetSaveWindowsCount() const { - return FullRestoreController::Get()->save_windows_count_for_testing_; + // Returns the number of times |window| has been saved to file since the last + // ResetSaveWindowsCount call. + int GetSaveWindowsCount(aura::Window* window) const { + if (!base::Contains(fake_full_restore_file_, window)) + return 0; + return fake_full_restore_file_.at(window).call_count; + } + + // Returns the total number of saves since the last ResetSaveWindowsCount + // call. + int GetTotalSaveWindowsCount() const { + int count = 0; + for (const std::pair<aura::Window*, WindowInfo>& member : + fake_full_restore_file_) { + count += member.second.call_count; + } + return count; } void ResetSaveWindowsCount() { - FullRestoreController::Get()->save_windows_count_for_testing_ = 0; + for (std::pair<aura::Window*, WindowInfo>& member : fake_full_restore_file_) + member.second.call_count = 0; + } + + // Returns the stored activation index for |window|. + int GetActivationIndex(aura::Window* window) const { + if (!base::Contains(fake_full_restore_file_, window)) + return -1; + return fake_full_restore_file_.at(window).activation_index; } // AshTestBase: void SetUp() override { scoped_feature_list_.InitAndEnableFeature(features::kFullRestore); + AshTestBase::SetUp(); + + FullRestoreController::Get()->SetSaveWindowCallbackForTesting( + base::BindRepeating(&FullRestoreControllerTest::OnSaveWindow, + base::Unretained(this))); } private: + // Called when FullRestoreController saves a window to the file. Immediately + // writes to our fake file |fake_full_restore_file_|. + void OnSaveWindow(const full_restore::WindowInfo& window_info) { + aura::Window* window = window_info.window; + DCHECK(window_info.activation_index); + + if (fake_full_restore_file_.contains(window)) { + fake_full_restore_file_[window].call_count++; + fake_full_restore_file_[window].activation_index = + *window_info.activation_index; + } else { + fake_full_restore_file_[window] = {0, *window_info.activation_index}; + } + } + + // A map which is a fake representation of the full restore file. + base::flat_map<aura::Window*, WindowInfo> fake_full_restore_file_; + base::test::ScopedFeatureList scoped_feature_list_; }; -// Tests that data gets saved when an application window is created and the data -// gets removed when the application is closed. -TEST_F(FullRestoreControllerTest, AppWindowAddedClosed) { - const gfx::Rect bounds(200, 200); - auto browser_window = CreateAppWindow(bounds, AppType::BROWSER); - auto chrome_app_window = CreateAppWindow(bounds, AppType::CHROME_APP); - - // For now, creating a window will trigger two saves, one when adding the - // window to its parent and one when the window gets its initial bounds set. - // The actual writing to the database is throttled, so this is ok. - EXPECT_EQ(4, GetSaveWindowsCount()); - - // Tests we save each time a viable app window is destroyed. - browser_window.reset(); - chrome_app_window.reset(); - EXPECT_EQ(6, GetSaveWindowsCount()); - - // Test that creating and destroying a system app writes nothing to the - // database. - // TODO(crbug.com/1164472): Checking app type is temporary solution until we - // can get windows which are allowed to full restore from the - // FullRestoreService. - ResetSaveWindowsCount(); - auto system_window = CreateAppWindow(bounds, AppType::SYSTEM_APP); - system_window.reset(); - EXPECT_EQ(0, GetSaveWindowsCount()); -} - // Tests that data gets saved when changing a window's window state. TEST_F(FullRestoreControllerTest, WindowStateChanged) { auto window = CreateAppWindow(gfx::Rect(600, 600), AppType::BROWSER); @@ -86,23 +112,25 @@ auto* window_state = WindowState::Get(window.get()); window_state->Minimize(); - EXPECT_EQ(1, GetSaveWindowsCount()); + EXPECT_EQ(1, GetSaveWindowsCount(window.get())); window_state->Unminimize(); - EXPECT_EQ(2, GetSaveWindowsCount()); + EXPECT_EQ(2, GetSaveWindowsCount(window.get())); + + window_state->Activate(); + EXPECT_EQ(3, GetSaveWindowsCount(window.get())); // Maximize and restore will invoke two calls to SaveWindows because // their animations also change the bounds of the window. The actual writing // to the database is throttled, so this is ok. - window_state->Activate(); window_state->Maximize(); - EXPECT_EQ(4, GetSaveWindowsCount()); + EXPECT_EQ(5, GetSaveWindowsCount(window.get())); window_state->Restore(); - EXPECT_EQ(6, GetSaveWindowsCount()); + EXPECT_EQ(7, GetSaveWindowsCount(window.get())); PerformAcceleratorAction(WINDOW_CYCLE_SNAP_LEFT, {}); - EXPECT_EQ(7, GetSaveWindowsCount()); + EXPECT_EQ(8, GetSaveWindowsCount(window.get())); } // Tests that data gets saved when moving a window to another desk. @@ -122,7 +150,7 @@ DESKS_MOVE_ACTIVE_ITEM, {ui::VKEY_OEM_6, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN}); ASSERT_NE(previous_parent, window->parent()); - EXPECT_EQ(1, GetSaveWindowsCount()); + EXPECT_EQ(1, GetSaveWindowsCount(window.get())); } // Tests that data gets saved when moving a window to another display using the @@ -138,7 +166,7 @@ PerformAcceleratorAction(MOVE_ACTIVE_WINDOW_BETWEEN_DISPLAYS, {}); ASSERT_TRUE( gfx::Rect(801, 0, 800, 800).Contains(window->GetBoundsInScreen())); - EXPECT_EQ(1, GetSaveWindowsCount()); + EXPECT_EQ(1, GetSaveWindowsCount(window.get())); } // Tests that data gets saved when dragging a window. @@ -146,24 +174,43 @@ auto window = CreateAppWindow(gfx::Rect(400, 400), AppType::BROWSER); ResetSaveWindowsCount(); + // Test that even if we move n times, we will only save to file once. const gfx::Point point_on_frame(200, 16); auto* event_generator = GetEventGenerator(); event_generator->set_current_screen_location(point_on_frame); event_generator->PressLeftButton(); - event_generator->MoveMouseBy(15, 15); - event_generator->MoveMouseBy(15, 15); - event_generator->MoveMouseBy(15, 15); + for (int i = 0; i < 5; ++i) + event_generator->MoveMouseBy(15, 15); event_generator->ReleaseLeftButton(); - EXPECT_EQ(3, GetSaveWindowsCount()); + EXPECT_EQ(1, GetSaveWindowsCount(window.get())); } TEST_F(FullRestoreControllerTest, TabletModeChange) { + // Tests that with no windows, nothing gets save when entering or exiting + // tablet mode. TabletModeControllerTestApi().EnterTabletMode(); - EXPECT_EQ(1, GetSaveWindowsCount()); + EXPECT_EQ(0, GetTotalSaveWindowsCount()); TabletModeControllerTestApi().LeaveTabletMode(); - EXPECT_EQ(2, GetSaveWindowsCount()); + EXPECT_EQ(0, GetTotalSaveWindowsCount()); + + auto window1 = CreateAppWindow(gfx::Rect(400, 400), AppType::BROWSER); + auto window2 = CreateAppWindow(gfx::Rect(400, 400), AppType::BROWSER); + ResetSaveWindowsCount(); + + // Tests that we save each window when entering or exiting tablet mode. Due to + // many possible things changing during a tablet switch (window state, bounds, + // etc.), we cannot determine exactly how many saves there will be, but there + // should be more than one per window. + TabletModeControllerTestApi().EnterTabletMode(); + EXPECT_GT(GetSaveWindowsCount(window1.get()), 1); + EXPECT_GT(GetSaveWindowsCount(window2.get()), 1); + + ResetSaveWindowsCount(); + TabletModeControllerTestApi().LeaveTabletMode(); + EXPECT_GT(GetSaveWindowsCount(window1.get()), 1); + EXPECT_GT(GetSaveWindowsCount(window2.get()), 1); } TEST_F(FullRestoreControllerTest, DisplayAddRemove) { @@ -179,17 +226,37 @@ display::ManagedDisplayInfo second_info = display_manager()->GetDisplayInfo(second_id); - // Remove the secondary display. + // Remove the secondary display. Doing so will change both the bounds of the + // window and activate it, resulting in a double save. std::vector<display::ManagedDisplayInfo> display_info_list; display_info_list.push_back(primary_info); display_manager()->OnNativeDisplaysChanged(display_info_list); - EXPECT_EQ(1, GetSaveWindowsCount()); + EXPECT_EQ(2, GetSaveWindowsCount(window.get())); // Reconnect the secondary display. PersistentWindowController will move the // window back to the secondary display, so a save should be triggered. display_info_list.push_back(second_info); display_manager()->OnNativeDisplaysChanged(display_info_list); - EXPECT_EQ(2, GetSaveWindowsCount()); + EXPECT_EQ(3, GetSaveWindowsCount(window.get())); +} + +TEST_F(FullRestoreControllerTest, Activation) { + auto window1 = CreateAppWindow(gfx::Rect(400, 400), AppType::BROWSER); + auto window2 = CreateAppWindow(gfx::Rect(400, 400), AppType::BROWSER); + auto window3 = CreateAppWindow(gfx::Rect(400, 400), AppType::BROWSER); + ResetSaveWindowsCount(); + + // Tests that an activation will save once for each window. + wm::ActivateWindow(window1.get()); + EXPECT_EQ(3, GetTotalSaveWindowsCount()); + + // Tests that most recently used windows have the highest activation index. + wm::ActivateWindow(window1.get()); + wm::ActivateWindow(window2.get()); + wm::ActivateWindow(window3.get()); + EXPECT_EQ(0, GetActivationIndex(window1.get())); + EXPECT_EQ(1, GetActivationIndex(window2.get())); + EXPECT_EQ(2, GetActivationIndex(window3.get())); } } // namespace ash
diff --git a/ash/wm/full_restore/full_restore_window_manager.cc b/ash/wm/full_restore/full_restore_window_manager.cc deleted file mode 100644 index f3d57dc..0000000 --- a/ash/wm/full_restore/full_restore_window_manager.cc +++ /dev/null
@@ -1,166 +0,0 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/full_restore/full_restore_window_manager.h" - -#include "ash/public/cpp/app_types.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/shell.h" -#include "ash/wm/full_restore/full_restore_controller.h" -#include "ui/aura/client/aura_constants.h" - -namespace ash { - -namespace { - -// The list of possible app window parents. -// TODO(crbug.com/1164472): Support the rest of the desk containers which -// are currently not always created depending on whether the bento feature -// is enabled. -constexpr ShellWindowId kAppParentContainers[5] = { - kShellWindowId_DefaultContainerDeprecated, - kShellWindowId_DeskContainerB, - kShellWindowId_DeskContainerC, - kShellWindowId_DeskContainerD, - kShellWindowId_AlwaysOnTopContainer, -}; - -// The types of apps currently supported by full restore. -// TODO(crbug.com/1164472): Add ARC apps when they are supported. -// TODO(crbug.com/1164472): Checking app type is temporary solution until we -// can get windows which are allowed to full restore from the -// FullRestoreService. -constexpr AppType kSupportedAppTypes[2] = {AppType::BROWSER, - AppType::CHROME_APP}; - -} // namespace - -FullRestoreWindowManager::FullRestoreWindowManager() { - // TODO(crbug.com/1164472): SetEnabled should be called from - // FullRestoreController. For now this is ok as the feature is disabled by - // default. - SetEnabled(true); -} - -FullRestoreWindowManager::~FullRestoreWindowManager() { - StopObserving(); -} - -void FullRestoreWindowManager::SetEnabled(bool enabled) { - if (enabled_ == enabled) - return; - - enabled_ = enabled; - - if (!enabled) { - // TODO(crbug.com/1164472): Clear database. - StopObserving(); - return; - } - - DCHECK(!app_window_parents_observations_.IsObservingAnySource()); - for (aura::Window* root_window : Shell::GetAllRootWindows()) { - for (ShellWindowId id : kAppParentContainers) { - aura::Window* child = root_window->GetChildById(id); - DCHECK(child); - app_window_parents_observations_.AddObservation(child); - } - } - - // TODO(crbug.com/1164472): Start observing and save existing app windows in - // the MRU list to the database. -} - -void FullRestoreWindowManager::OnWindowAdded(aura::Window* new_window) { - DCHECK(app_window_parents_observations_.IsObservingAnySource()); - DCHECK(new_window->parent()); - - if (!app_window_parents_observations_.IsObservingSource(new_window->parent())) - return; - - // TODO(crbug.com/1164472): For browser and chrome apps, the window property - // is set after the window is created. Change those apps to set the property - // using Widget's |init_properties_container| so the property can be extracted - // at this time. - if (!base::Contains(kSupportedAppTypes, - static_cast<AppType>( - new_window->GetProperty(aura::client::kAppType)))) { - return; - } - - // The window is already observed if it is switching containers (i.e. moving - // window between desks). - if (!app_window_observations_.IsObservingSource(new_window)) { - app_window_observations_.AddObservation(new_window); - - auto* new_window_state = WindowState::Get(new_window); - DCHECK(!app_window_state_observations_.IsObservingSource(new_window_state)); - app_window_state_observations_.AddObservation(new_window_state); - } - - FullRestoreController::Get()->SaveWindows(); -} - -void FullRestoreWindowManager::OnWindowDestroying(aura::Window* window) { - // Do nothing if windows in |app_window_parents_| are destroyed. |this| will - // be destroyed shortly and their observers will be cleaned up then. - if (app_window_parents_observations_.IsObservingSource(window)) { - app_window_parents_observations_.RemoveObservation(window); - return; - } - - auto* window_state = WindowState::Get(window); - DCHECK(app_window_observations_.IsObservingSource(window)); - DCHECK(app_window_state_observations_.IsObservingSource(window_state)); - - app_window_observations_.RemoveObservation(window); - app_window_state_observations_.RemoveObservation(window_state); - - FullRestoreController::Get()->SaveWindows(); -} - -void FullRestoreWindowManager::OnWindowBoundsChanged( - aura::Window* window, - const gfx::Rect& old_bounds, - const gfx::Rect& new_bounds, - ui::PropertyChangeReason reason) { - if (!app_window_observations_.IsObservingSource(window)) - return; - - if (reason == ui::PropertyChangeReason::FROM_ANIMATION) - return; - - // TODO(crbug.com/1164472): Investigate if we can skip bounds change updates - // that happen during a window drag. - - FullRestoreController::Get()->SaveWindows(); -} - -void FullRestoreWindowManager::OnWindowRemovingFromRootWindow( - aura::Window* window, - aura::Window* new_root) { - if (!app_window_observations_.IsObservingSource(window)) - return; - - FullRestoreController::Get()->SaveWindows(); -} - -void FullRestoreWindowManager::OnPostWindowStateTypeChange( - WindowState* window_state, - chromeos::WindowStateType old_type) { - DCHECK(app_window_state_observations_.IsObservingSource(window_state)); - - // TODO(crbug.com/1164472): We may not be interested in all window state - // changes. - - FullRestoreController::Get()->SaveWindows(); -} - -void FullRestoreWindowManager::StopObserving() { - app_window_parents_observations_.RemoveAllObservations(); - app_window_observations_.RemoveAllObservations(); - app_window_state_observations_.RemoveAllObservations(); -} - -} // namespace ash
diff --git a/ash/wm/full_restore/full_restore_window_manager.h b/ash/wm/full_restore/full_restore_window_manager.h deleted file mode 100644 index c8e5d66..0000000 --- a/ash/wm/full_restore/full_restore_window_manager.h +++ /dev/null
@@ -1,80 +0,0 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_FULL_RESTORE_FULL_RESTORE_WINDOW_MANAGER_H_ -#define ASH_WM_FULL_RESTORE_FULL_RESTORE_WINDOW_MANAGER_H_ - -#include "ash/ash_export.h" -#include "ash/wm/window_state.h" -#include "ash/wm/window_state_observer.h" -#include "base/scoped_multi_source_observation.h" -#include "chromeos/ui/base/window_state_type.h" -#include "ui/aura/window.h" -#include "ui/aura/window_observer.h" -#include "ui/gfx/geometry/rect.h" - -namespace ash { - -// Observes windows that are can be full restored and notifies -// FullRestoreController to write to the database when interesting changes are -// made to the windows. -class FullRestoreWindowManager : public aura::WindowObserver, - public WindowStateObserver { - public: - FullRestoreWindowManager(); - FullRestoreWindowManager(const FullRestoreWindowManager&) = delete; - FullRestoreWindowManager& operator=(const FullRestoreWindowManager&) = delete; - ~FullRestoreWindowManager() override; - - // Called when the user turns full restore on or off via the os setting. - // Starts observing and notifies FullRestoreService to save all current app - // windows to the database if |enabled| is true. Stops observing and notifies - // FullRestoreService to remove all current app windows from the database if - // |enabled| is false. - void SetEnabled(bool enabled); - - // aura::WindowObserver: - void OnWindowAdded(aura::Window* new_window) override; - void OnWindowDestroying(aura::Window* window) override; - void OnWindowBoundsChanged(aura::Window* window, - const gfx::Rect& old_bounds, - const gfx::Rect& new_bounds, - ui::PropertyChangeReason reason) override; - void OnWindowRemovingFromRootWindow(aura::Window* window, - aura::Window* new_root) override; - - // WindowStateObserver: - void OnPostWindowStateTypeChange(WindowState* window_state, - chromeos::WindowStateType old_type) override; - - private: - void StopObserving(); - - // If false, we do not observe any windows since the user chose to not use the - // full restore feature. - bool enabled_ = false; - - // The windows that can be the parent of an app windows. This includes the - // desk containers and the always on top container. All windows in this set - // are observed for when a child gets added or removed. Empty if the full - // restore setting is disabled. - base::ScopedMultiSourceObservation<aura::Window, aura::WindowObserver> - app_window_parents_observations_{this}; - - // The app windows we are currently observing. Empty if the full restore - // setting is disabled. - base::ScopedMultiSourceObservation<aura::Window, aura::WindowObserver> - app_window_observations_{this}; - - // The app window states we are currently observing. This should match the - // size of |app_window_observations_|. - // TODO(crbug.com/1164472): We may just want to call - // FullRestoreController::SaveWindows in WindowState.. - base::ScopedMultiSourceObservation<WindowState, WindowStateObserver> - app_window_state_observations_{this}; -}; - -} // namespace ash - -#endif // ASH_WM_FULL_RESTORE_FULL_RESTORE_WINDOW_MANAGER_H_
diff --git a/ash/wm/mru_window_tracker.cc b/ash/wm/mru_window_tracker.cc index 456fa4e..79559a3 100644 --- a/ash/wm/mru_window_tracker.cc +++ b/ash/wm/mru_window_tracker.cc
@@ -7,12 +7,14 @@ #include <algorithm> #include "ash/public/cpp/app_types.h" +#include "ash/public/cpp/ash_features.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/public/cpp/window_properties.h" #include "ash/session/session_controller_impl.h" #include "ash/shell.h" #include "ash/wm/ash_focus_rules.h" #include "ash/wm/desks/desks_util.h" +#include "ash/wm/full_restore/full_restore_controller.h" #include "ash/wm/switchable_windows.h" #include "ash/wm/window_state.h" #include "ash/wm/window_util.h" @@ -289,8 +291,13 @@ void MruWindowTracker::OnWindowActivated(ActivationReason reason, aura::Window* gained_active, aura::Window* lost_active) { - if (!ignore_window_activations_) - SetActiveWindow(gained_active); + if (ignore_window_activations_) + return; + + SetActiveWindow(gained_active); + + if (gained_active && features::IsFullRestoreEnabled()) + FullRestoreController::Get()->SaveAllWindows(); } void MruWindowTracker::OnWindowDestroyed(aura::Window* window) {
diff --git a/ash/wm/window_state.cc b/ash/wm/window_state.cc index 26373ef..faf5ddc 100644 --- a/ash/wm/window_state.cc +++ b/ash/wm/window_state.cc
@@ -10,6 +10,7 @@ #include "ash/focus_cycler.h" #include "ash/metrics/pip_uma.h" #include "ash/public/cpp/app_types.h" +#include "ash/public/cpp/ash_features.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/public/cpp/window_animation_types.h" #include "ash/public/cpp/window_properties.h" @@ -17,6 +18,7 @@ #include "ash/shell.h" #include "ash/wm/collision_detection/collision_detection_utils.h" #include "ash/wm/default_state.h" +#include "ash/wm/full_restore/full_restore_controller.h" #include "ash/wm/pip/pip_positioner.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "ash/wm/window_animations.h" @@ -175,6 +177,16 @@ base::TimeDelta::FromHours(10), 50); } +// Notifies the full restore controller to write to file. +void SaveWindowForFullRestore(WindowState* window_state) { + if (!features::IsFullRestoreEnabled()) + return; + + auto* controller = FullRestoreController::Get(); + if (controller) + controller->SaveWindow(window_state); +} + } // namespace constexpr base::TimeDelta WindowState::kBoundsChangeSlideDuration; @@ -524,6 +536,7 @@ DCHECK(drag_details_); if (delegate_) delegate_->OnDragFinished(/*canceled=*/false, location); + SaveWindowForFullRestore(this); } void WindowState::OnRevertDrag(const gfx::PointF& location) { @@ -668,6 +681,7 @@ for (auto& observer : observer_list_) observer.OnPostWindowStateTypeChange(this, old_window_state_type); OnPostPipStateChange(old_window_state_type); + SaveWindowForFullRestore(this); } void WindowState::OnPostPipStateChange(WindowStateType old_window_state_type) { @@ -910,6 +924,16 @@ } return; } + if (key == aura::client::kWindowWorkspaceKey) { + // Save the window for full restore purposes unless + // |ignore_property_change_| is true. Note that moving windows across + // displays will also trigger a property change, even if the value stays the + // same, so we do not need to save the window when it changes root windows + // (OnWindowAddedToRootWindow). + if (!ignore_property_change_) + SaveWindowForFullRestore(this); + return; + } // The shelf visibility should be updated if kHideShelfWhenFullscreenKey or // kImmersiveIsActive change - these property affect the shelf behavior, and @@ -957,6 +981,9 @@ window_->GetProperty(ash::kWindowManagerManagesOpacityKey)) { window_->SetOpaqueRegionsForOcclusion({gfx::Rect(new_bounds.size())}); } + + if (reason != ui::PropertyChangeReason::FROM_ANIMATION && !is_dragged()) + SaveWindowForFullRestore(this); } } // namespace ash
diff --git a/base/allocator/partition_allocator/address_pool_manager.cc b/base/allocator/partition_allocator/address_pool_manager.cc index 8ca8a3e..673967bc 100644 --- a/base/allocator/partition_allocator/address_pool_manager.cc +++ b/base/allocator/partition_allocator/address_pool_manager.cc
@@ -265,14 +265,14 @@ size_t length) { uintptr_t ptr_as_uintptr = reinterpret_cast<uintptr_t>(address); AutoLock guard(AddressPoolManagerBitmap::GetLock()); - if (handle == kNonBRPPoolHandle) { - SetBitmap(AddressPoolManagerBitmap::non_brp_pool_bits_, + if (handle == kDirectMapHandle) { + SetBitmap(AddressPoolManagerBitmap::directmap_bits_, ptr_as_uintptr / PageAllocationGranularity(), length / PageAllocationGranularity()); } else { - PA_DCHECK(handle == kBRPPoolHandle); + PA_DCHECK(handle == kNormalBucketHandle); PA_DCHECK(!(length & kSuperPageOffsetMask)); - SetBitmap(AddressPoolManagerBitmap::brp_pool_bits_, + SetBitmap(AddressPoolManagerBitmap::normal_bucket_bits_, ptr_as_uintptr >> kSuperPageShift, length >> kSuperPageShift); } } @@ -281,25 +281,24 @@ uintptr_t address, size_t length) { AutoLock guard(AddressPoolManagerBitmap::GetLock()); - // Currently, address regions allocated by kBRPPoolHandle are never freed - // in PartitionAlloc, because only normal buckets are allocated from there. - // Thus we have LIKELY for kNonBRPPoolHandle - if (LIKELY(handle == kNonBRPPoolHandle)) { - ResetBitmap(AddressPoolManagerBitmap::non_brp_pool_bits_, + // Currently, address regions allocated by kNormalBucketHandle are never freed + // in PartitionAlloc. Thus we have LIKELY for kDirectMapHandle + if (LIKELY(handle == kDirectMapHandle)) { + ResetBitmap(AddressPoolManagerBitmap::directmap_bits_, address / PageAllocationGranularity(), length / PageAllocationGranularity()); } else { - PA_DCHECK(handle == kBRPPoolHandle); + PA_DCHECK(handle == kNormalBucketHandle); PA_DCHECK(!(length & kSuperPageOffsetMask)); - ResetBitmap(AddressPoolManagerBitmap::brp_pool_bits_, + ResetBitmap(AddressPoolManagerBitmap::normal_bucket_bits_, address >> kSuperPageShift, length >> kSuperPageShift); } } void AddressPoolManager::ResetForTesting() { AutoLock guard(AddressPoolManagerBitmap::GetLock()); - AddressPoolManagerBitmap::non_brp_pool_bits_.reset(); - AddressPoolManagerBitmap::brp_pool_bits_.reset(); + AddressPoolManagerBitmap::directmap_bits_.reset(); + AddressPoolManagerBitmap::normal_bucket_bits_.reset(); } #endif // defined(PA_HAS_64_BITS_POINTERS)
diff --git a/base/allocator/partition_allocator/address_pool_manager.h b/base/allocator/partition_allocator/address_pool_manager.h index 2802acb..95188d1 100644 --- a/base/allocator/partition_allocator/address_pool_manager.h +++ b/base/allocator/partition_allocator/address_pool_manager.h
@@ -32,15 +32,14 @@ // // (32bit version) // AddressPoolManager wraps AllocPages and FreePages and remembers allocated -// address regions using bitmaps. IsManagedByPartitionAllocNonBRPPool and -// IsManagedByPartitionAllocBRPPool use the bitmaps to judge whether a given -// address is in a pool that supports BackupRefPtr or in a pool that doesn't. -// All PartitionAlloc allocations must be in either of the pools. +// address regions using bitmaps. IsManagedByPartitionAllocDirectMap and +// IsManagedByPartitionAllocNormalBuckets use the bitmaps to judge whether a +// given address is managed by the direct map or normal buckets. class BASE_EXPORT AddressPoolManager { static constexpr uint64_t kGiB = 1024 * 1024 * 1024ull; public: - static constexpr uint64_t kBRPPoolMaxSize = + static constexpr uint64_t kNormalBucketMaxSize = #if defined(PA_HAS_64_BITS_POINTERS) 16 * kGiB; #else @@ -60,12 +59,12 @@ void ResetForTesting(); #if !defined(PA_HAS_64_BITS_POINTERS) - static bool IsManagedByNonBRPPool(const void* address) { - return AddressPoolManagerBitmap::IsManagedByNonBRPPool(address); + static bool IsManagedByDirectMapPool(const void* address) { + return AddressPoolManagerBitmap::IsManagedByDirectMapPool(address); } - static bool IsManagedByBRPPool(const void* address) { - return AddressPoolManagerBitmap::IsManagedByBRPPool(address); + static bool IsManagedByNormalBucketPool(const void* address) { + return AddressPoolManagerBitmap::IsManagedByNormalBucketPool(address); } #endif @@ -89,7 +88,7 @@ private: // The bitset stores the allocation state of the address pool. 1 bit per // super-page: 1 = allocated, 0 = free. - static constexpr size_t kMaxBits = kBRPPoolMaxSize / kSuperPageSize; + static constexpr size_t kMaxBits = kNormalBucketMaxSize / kSuperPageSize; base::Lock lock_; std::bitset<kMaxBits> alloc_bitset_ GUARDED_BY(lock_); @@ -119,12 +118,10 @@ void MarkUsed(pool_handle handle, const char* address, size_t size); void MarkUnused(pool_handle handle, uintptr_t address, size_t size); - // BRP stands for BackupRefPtr. GigaCage is split into pools, one which - // supports BackupRefPtr and one that doesn't. - static constexpr pool_handle kNonBRPPoolHandle = 1; - static constexpr pool_handle kBRPPoolHandle = 2; - friend internal::pool_handle GetNonBRPPool(); - friend internal::pool_handle GetBRPPool(); + static constexpr pool_handle kDirectMapHandle = 1; + static constexpr pool_handle kNormalBucketHandle = 2; + friend internal::pool_handle GetDirectMapPool(); + friend internal::pool_handle GetNormalBucketPool(); #endif // defined(PA_HAS_64_BITS_POINTERS) friend struct base::LazyInstanceTraitsBase<AddressPoolManager>; @@ -132,12 +129,12 @@ }; #if !defined(PA_HAS_64_BITS_POINTERS) -ALWAYS_INLINE internal::pool_handle GetNonBRPPool() { - return AddressPoolManager::kNonBRPPoolHandle; +ALWAYS_INLINE internal::pool_handle GetDirectMapPool() { + return AddressPoolManager::kDirectMapHandle; } -ALWAYS_INLINE internal::pool_handle GetBRPPool() { - return AddressPoolManager::kBRPPoolHandle; +ALWAYS_INLINE internal::pool_handle GetNormalBucketPool() { + return AddressPoolManager::kNormalBucketHandle; } #endif
diff --git a/base/allocator/partition_allocator/address_pool_manager_bitmap.cc b/base/allocator/partition_allocator/address_pool_manager_bitmap.cc index af8f1c6b..6f0c002 100644 --- a/base/allocator/partition_allocator/address_pool_manager_bitmap.cc +++ b/base/allocator/partition_allocator/address_pool_manager_bitmap.cc
@@ -21,11 +21,12 @@ return g_lock.Get(); } -std::bitset<AddressPoolManagerBitmap::kNonBRPPoolBits> - AddressPoolManagerBitmap::non_brp_pool_bits_; // GUARDED_BY(GetLock()) -std::bitset<AddressPoolManagerBitmap::kBRPPoolBits> - AddressPoolManagerBitmap::brp_pool_bits_; // GUARDED_BY(GetLock()) +std::bitset<AddressPoolManagerBitmap::kDirectMapBits> + AddressPoolManagerBitmap::directmap_bits_; // GUARDED_BY(GetLock()) +std::bitset<AddressPoolManagerBitmap::kNormalBucketBits> + AddressPoolManagerBitmap::normal_bucket_bits_; // GUARDED_BY(GetLock()) } // namespace internal } // namespace base + #endif // !defined(PA_HAS_64_BITS_POINTERS)
diff --git a/base/allocator/partition_allocator/address_pool_manager_bitmap.h b/base/allocator/partition_allocator/address_pool_manager_bitmap.h index 6cff449..8448c5e 100644 --- a/base/allocator/partition_allocator/address_pool_manager_bitmap.h +++ b/base/allocator/partition_allocator/address_pool_manager_bitmap.h
@@ -16,37 +16,32 @@ namespace internal { -// AddressPoolManagerBitmap is a set of bitmaps that track whether a given -// address is in a pool that supports BackupRefPtr, or in a pool that doesn't -// support it. All PartitionAlloc allocations must be in either of the pools. -// -// This code is specific to 32-bit systems. +// AddressPoolManagerBitmap is the bitmap that tracks whether a given address is +// managed by the direct map or normal buckets. class BASE_EXPORT AddressPoolManagerBitmap { public: static constexpr uint64_t kGiB = 1024 * 1024 * 1024ull; static constexpr uint64_t kAddressSpaceSize = 4ull * kGiB; - // Non-BRP pool includes, among others, direct map allocations, which reserve - // address space at PageAllocationGranularity(). BRP pool only supports normal - // bucket allocations, which always reserve address space at 2MB granularity. - static constexpr size_t kNonBRPPoolBits = + static constexpr size_t kNormalBucketBits = + kAddressSpaceSize / kSuperPageSize; + static constexpr size_t kDirectMapBits = kAddressSpaceSize / PageAllocationGranularity(); - static constexpr size_t kBRPPoolBits = kAddressSpaceSize / kSuperPageSize; - static bool IsManagedByNonBRPPool(const void* address) { + static bool IsManagedByDirectMapPool(const void* address) { uintptr_t address_as_uintptr = reinterpret_cast<uintptr_t>(address); - // It is safe to read |non_brp_pool_bits_| without a lock since the caller - // is responsible for guaranteeing that the address is inside a valid + // It is safe to read |directmap_bits_| without a lock since the caller is + // responsible for guaranteeing that the address is inside a valid // allocation and the deallocation call won't race with this call. - return TS_UNCHECKED_READ(non_brp_pool_bits_) + return TS_UNCHECKED_READ(directmap_bits_) .test(address_as_uintptr / PageAllocationGranularity()); } - static bool IsManagedByBRPPool(const void* address) { + static bool IsManagedByNormalBucketPool(const void* address) { uintptr_t address_as_uintptr = reinterpret_cast<uintptr_t>(address); - // It is safe to read |brp_pool_bits_| without a lock since the caller + // It is safe to read |normal_bucket_bits_| without a lock since the caller // is responsible for guaranteeing that the address is inside a valid // allocation and the deallocation call won't race with this call. - return TS_UNCHECKED_READ(brp_pool_bits_) + return TS_UNCHECKED_READ(normal_bucket_bits_) .test(address_as_uintptr >> kSuperPageShift); } @@ -55,18 +50,20 @@ static Lock& GetLock(); - static std::bitset<kNonBRPPoolBits> non_brp_pool_bits_ GUARDED_BY(GetLock()); - static std::bitset<kBRPPoolBits> brp_pool_bits_ GUARDED_BY(GetLock()); + static std::bitset<kDirectMapBits> directmap_bits_ GUARDED_BY(GetLock()); + static std::bitset<kNormalBucketBits> normal_bucket_bits_ + GUARDED_BY(GetLock()); }; } // namespace internal -ALWAYS_INLINE bool IsManagedByPartitionAllocNonBRPPool(const void* address) { - return internal::AddressPoolManagerBitmap::IsManagedByNonBRPPool(address); +ALWAYS_INLINE bool IsManagedByPartitionAllocDirectMap(const void* address) { + return internal::AddressPoolManagerBitmap::IsManagedByDirectMapPool(address); } -ALWAYS_INLINE bool IsManagedByPartitionAllocBRPPool(const void* address) { - return internal::AddressPoolManagerBitmap::IsManagedByBRPPool(address); +ALWAYS_INLINE bool IsManagedByPartitionAllocNormalBuckets(const void* address) { + return internal::AddressPoolManagerBitmap::IsManagedByNormalBucketPool( + address); } } // namespace base
diff --git a/base/allocator/partition_allocator/address_pool_manager_unittest.cc b/base/allocator/partition_allocator/address_pool_manager_unittest.cc index b7d0d8c..f8d90c7 100644 --- a/base/allocator/partition_allocator/address_pool_manager_unittest.cc +++ b/base/allocator/partition_allocator/address_pool_manager_unittest.cc
@@ -168,13 +168,14 @@ #else // defined(PA_HAS_64_BITS_POINTERS) -TEST_F(AddressPoolManagerTest, IsManagedByNonBRPPool) { +TEST_F(AddressPoolManagerTest, IsManagedByDirectMapPool) { constexpr size_t kAllocCount = 8; static const size_t kNumPages[kAllocCount] = {1, 4, 7, 8, 13, 16, 31, 60}; void* addrs[kAllocCount]; for (size_t i = 0; i < kAllocCount; ++i) { addrs[i] = AddressPoolManager::GetInstance()->Reserve( - GetNonBRPPool(), nullptr, PageAllocationGranularity() * kNumPages[i]); + GetDirectMapPool(), nullptr, + PageAllocationGranularity() * kNumPages[i]); EXPECT_TRUE(addrs[i]); EXPECT_TRUE( !(reinterpret_cast<uintptr_t>(addrs[i]) & kSuperPageOffsetMask)); @@ -186,30 +187,31 @@ PageAllocationGranularity(); for (size_t j = 0; j < num_pages; ++j) { if (j < kNumPages[i]) { - EXPECT_TRUE(AddressPoolManager::IsManagedByNonBRPPool(ptr)); + EXPECT_TRUE(AddressPoolManager::IsManagedByDirectMapPool(ptr)); } else { - EXPECT_FALSE(AddressPoolManager::IsManagedByNonBRPPool(ptr)); + EXPECT_FALSE(AddressPoolManager::IsManagedByDirectMapPool(ptr)); } - EXPECT_FALSE(AddressPoolManager::IsManagedByBRPPool(ptr)); + EXPECT_FALSE(AddressPoolManager::IsManagedByNormalBucketPool(ptr)); ptr += PageAllocationGranularity(); } } for (size_t i = 0; i < kAllocCount; ++i) { AddressPoolManager::GetInstance()->UnreserveAndDecommit( - GetNonBRPPool(), addrs[i], PageAllocationGranularity() * kNumPages[i]); - EXPECT_FALSE(AddressPoolManager::IsManagedByNonBRPPool(addrs[i])); - EXPECT_FALSE(AddressPoolManager::IsManagedByBRPPool(addrs[i])); + GetDirectMapPool(), addrs[i], + PageAllocationGranularity() * kNumPages[i]); + EXPECT_FALSE(AddressPoolManager::IsManagedByDirectMapPool(addrs[i])); + EXPECT_FALSE(AddressPoolManager::IsManagedByNormalBucketPool(addrs[i])); } } -TEST_F(AddressPoolManagerTest, IsManagedByBRPPool) { +TEST_F(AddressPoolManagerTest, IsManagedByNormalBucketPool) { constexpr size_t kAllocCount = 4; // Totally (1+3+7+11) * 2MB = 44MB allocation static const size_t kNumPages[kAllocCount] = {1, 3, 7, 11}; void* addrs[kAllocCount]; for (size_t i = 0; i < kAllocCount; ++i) { addrs[i] = AddressPoolManager::GetInstance()->Reserve( - GetBRPPool(), nullptr, kSuperPageSize * kNumPages[i]); + GetNormalBucketPool(), nullptr, kSuperPageSize * kNumPages[i]); EXPECT_TRUE(addrs[i]); EXPECT_TRUE( !(reinterpret_cast<uintptr_t>(addrs[i]) & kSuperPageOffsetMask)); @@ -218,16 +220,16 @@ const char* ptr = reinterpret_cast<const char*>(addrs[i]); size_t num_system_pages = kNumPages[i] * kSuperPageSize / SystemPageSize(); for (size_t j = 0; j < num_system_pages; ++j) { - EXPECT_TRUE(AddressPoolManager::IsManagedByBRPPool(ptr)); - EXPECT_FALSE(AddressPoolManager::IsManagedByNonBRPPool(ptr)); + EXPECT_TRUE(AddressPoolManager::IsManagedByNormalBucketPool(ptr)); + EXPECT_FALSE(AddressPoolManager::IsManagedByDirectMapPool(ptr)); ptr += SystemPageSize(); } } for (size_t i = 0; i < kAllocCount; ++i) { AddressPoolManager::GetInstance()->UnreserveAndDecommit( - GetBRPPool(), addrs[i], kSuperPageSize * kNumPages[i]); - EXPECT_FALSE(AddressPoolManager::IsManagedByNonBRPPool(addrs[i])); - EXPECT_FALSE(AddressPoolManager::IsManagedByBRPPool(addrs[i])); + GetNormalBucketPool(), addrs[i], kSuperPageSize * kNumPages[i]); + EXPECT_FALSE(AddressPoolManager::IsManagedByDirectMapPool(addrs[i])); + EXPECT_FALSE(AddressPoolManager::IsManagedByNormalBucketPool(addrs[i])); } } #endif // defined(PA_HAS_64_BITS_POINTERS)
diff --git a/base/allocator/partition_allocator/partition_address_space.cc b/base/allocator/partition_allocator/partition_address_space.cc index 2d7f311c..61bf1d8b 100644 --- a/base/allocator/partition_allocator/partition_address_space.cc +++ b/base/allocator/partition_allocator/partition_address_space.cc
@@ -22,12 +22,13 @@ // reserved address space. Therefore, set *_pool_base_address_ initially to // k*PoolOffsetMask, so that PartitionAddressSpace::IsIn*Pool() always returns // false. -uintptr_t PartitionAddressSpace::non_brp_pool_base_address_ = - kNonBRPPoolOffsetMask; -uintptr_t PartitionAddressSpace::brp_pool_base_address_ = kBRPPoolOffsetMask; +uintptr_t PartitionAddressSpace::direct_map_pool_base_address_ = + kDirectMapPoolOffsetMask; +uintptr_t PartitionAddressSpace::normal_bucket_pool_base_address_ = + kNormalBucketPoolOffsetMask; -pool_handle PartitionAddressSpace::non_brp_pool_ = 0; -pool_handle PartitionAddressSpace::brp_pool_ = 0; +pool_handle PartitionAddressSpace::direct_map_pool_ = 0; +pool_handle PartitionAddressSpace::normal_bucket_pool_ = 0; void PartitionAddressSpace::Init() { if (IsInitialized()) @@ -40,25 +41,25 @@ uintptr_t current = reserved_base_address_; - non_brp_pool_base_address_ = current; - non_brp_pool_ = internal::AddressPoolManager::GetInstance()->Add( - current, kNonBRPPoolSize); - PA_DCHECK(non_brp_pool_); - PA_DCHECK(!IsInNonBRPPool(reinterpret_cast<void*>(current - 1))); - PA_DCHECK(IsInNonBRPPool(reinterpret_cast<void*>(current))); - current += kNonBRPPoolSize; - PA_DCHECK(IsInNonBRPPool(reinterpret_cast<void*>(current - 1))); - PA_DCHECK(!IsInNonBRPPool(reinterpret_cast<void*>(current))); + direct_map_pool_base_address_ = current; + direct_map_pool_ = internal::AddressPoolManager::GetInstance()->Add( + current, kDirectMapPoolSize); + PA_DCHECK(direct_map_pool_); + PA_DCHECK(!IsInDirectMapPool(reinterpret_cast<void*>(current - 1))); + PA_DCHECK(IsInDirectMapPool(reinterpret_cast<void*>(current))); + current += kDirectMapPoolSize; + PA_DCHECK(IsInDirectMapPool(reinterpret_cast<void*>(current - 1))); + PA_DCHECK(!IsInDirectMapPool(reinterpret_cast<void*>(current))); - brp_pool_base_address_ = current; - brp_pool_ = - internal::AddressPoolManager::GetInstance()->Add(current, kBRPPoolSize); - PA_DCHECK(brp_pool_); - PA_DCHECK(!IsInBRPPool(reinterpret_cast<void*>(current - 1))); - PA_DCHECK(IsInBRPPool(reinterpret_cast<void*>(current))); - current += kBRPPoolSize; - PA_DCHECK(IsInBRPPool(reinterpret_cast<void*>(current - 1))); - PA_DCHECK(!IsInBRPPool(reinterpret_cast<void*>(current))); + normal_bucket_pool_base_address_ = current; + normal_bucket_pool_ = internal::AddressPoolManager::GetInstance()->Add( + current, kNormalBucketPoolSize); + PA_DCHECK(normal_bucket_pool_); + PA_DCHECK(!IsInNormalBucketPool(reinterpret_cast<void*>(current - 1))); + PA_DCHECK(IsInNormalBucketPool(reinterpret_cast<void*>(current))); + current += kNormalBucketPoolSize; + PA_DCHECK(IsInNormalBucketPool(reinterpret_cast<void*>(current - 1))); + PA_DCHECK(!IsInNormalBucketPool(reinterpret_cast<void*>(current))); PA_DCHECK(reserved_base_address_ + kDesiredAddressSpaceSize == current); } @@ -67,10 +68,10 @@ FreePages(reinterpret_cast<void*>(reserved_base_address_), kReservedAddressSpaceAlignment); reserved_base_address_ = 0; - non_brp_pool_base_address_ = kNonBRPPoolOffsetMask; - brp_pool_base_address_ = kBRPPoolOffsetMask; - non_brp_pool_ = 0; - brp_pool_ = 0; + direct_map_pool_base_address_ = kDirectMapPoolOffsetMask; + normal_bucket_pool_base_address_ = kNormalBucketPoolOffsetMask; + direct_map_pool_ = 0; + normal_bucket_pool_ = 0; internal::AddressPoolManager::GetInstance()->ResetForTesting(); }
diff --git a/base/allocator/partition_allocator/partition_address_space.h b/base/allocator/partition_allocator/partition_address_space.h index 75604d6..5795f5d 100644 --- a/base/allocator/partition_allocator/partition_address_space.h +++ b/base/allocator/partition_allocator/partition_address_space.h
@@ -28,15 +28,15 @@ // Reserves address space for PartitionAllocator. class BASE_EXPORT PartitionAddressSpace { public: - // BRP stands for BackupRefPtr. GigaCage is split into pools, one which - // supports BackupRefPtr and one that doesn't. - static ALWAYS_INLINE internal::pool_handle GetNonBRPPool() { - return non_brp_pool_; + static ALWAYS_INLINE constexpr uintptr_t NormalBucketPoolBaseMask() { + return kNormalBucketPoolBaseMask; } - static ALWAYS_INLINE internal::pool_handle GetBRPPool() { return brp_pool_; } - static ALWAYS_INLINE constexpr uintptr_t BRPPoolBaseMask() { - return kBRPPoolBaseMask; + static ALWAYS_INLINE internal::pool_handle GetDirectMapPool() { + return direct_map_pool_; + } + static ALWAYS_INLINE internal::pool_handle GetNormalBucketPool() { + return normal_bucket_pool_; } static void Init(); @@ -44,27 +44,27 @@ static ALWAYS_INLINE bool IsInitialized() { if (reserved_base_address_) { - PA_DCHECK(non_brp_pool_ != 0); - PA_DCHECK(brp_pool_ != 0); + PA_DCHECK(direct_map_pool_ != 0); + PA_DCHECK(normal_bucket_pool_ != 0); return true; } - PA_DCHECK(non_brp_pool_ == 0); - PA_DCHECK(brp_pool_ == 0); + PA_DCHECK(direct_map_pool_ == 0); + PA_DCHECK(normal_bucket_pool_ == 0); return false; } - static ALWAYS_INLINE bool IsInNonBRPPool(const void* address) { - return (reinterpret_cast<uintptr_t>(address) & kNonBRPPoolBaseMask) == - non_brp_pool_base_address_; + static ALWAYS_INLINE bool IsInDirectMapPool(const void* address) { + return (reinterpret_cast<uintptr_t>(address) & kDirectMapPoolBaseMask) == + direct_map_pool_base_address_; } - static ALWAYS_INLINE bool IsInBRPPool(const void* address) { - return (reinterpret_cast<uintptr_t>(address) & kBRPPoolBaseMask) == - brp_pool_base_address_; + static ALWAYS_INLINE bool IsInNormalBucketPool(const void* address) { + return (reinterpret_cast<uintptr_t>(address) & kNormalBucketPoolBaseMask) == + normal_bucket_pool_base_address_; } - static ALWAYS_INLINE uintptr_t BRPPoolBase() { - return brp_pool_base_address_; + static ALWAYS_INLINE uintptr_t NormalBucketPoolBase() { + return normal_bucket_pool_base_address_; } // PartitionAddressSpace is static_only class. @@ -75,8 +75,8 @@ private: // Partition Alloc Address Space - // Reserves 32GiB address space for one pool that supports BackupRefPtr and - // one that doesn't, 16GiB each. + // Reserves 32GiB address space for one direct map pool and one normal bucket + // pool, 16GiB each. // TODO(bartekn): Look into devices with 39-bit address space that have 256GiB // user-mode space. Libraries loaded at random addresses may stand in the way // of reserving a contiguous 48GiB region (even though we're requesting only @@ -84,19 +84,18 @@ // alignment requirements). // // +----------------+ reserved_base_address_ (16GiB aligned) - // | non-BRP | == non_brp_pool_base_address_ + // | direct map | == direct_map_pool_base_address_ // | pool | // +----------------+ reserved_base_address_ + 16GiB - // | BRP | == brp_pool_base_address_ + // | normal bucket | == normal_bucket_pool_base_address_ // | pool | // +----------------+ reserved_base_address_ + 32GiB // - // NOTE! On 64-bit systems with BackupRefPtr enabled, the non-BRP pool must - // precede the BRP pool. This is to prevent a pointer immediately past a - // non-GigaCage allocation from falling into the BRP pool, thus triggering - // BackupRefPtr mechanism and likely crashing. - // TODO(bartekn): Add a guard page at the end of direct map allocations to - // prevent pointers immediately past those from falling into the BRP pool. + // NOTE! On 64-bit systems with BackupRefPtr enabled, the direct map pool must + // precede normal bucket pool. This is to prevent a pointer immediately past a + // non-GigaCage allocation from falling into the normal bucket pool, thus + // triggering BackupRefPtr mechanism and likely crashing. + // TODO(bartekn): Add a guard page at the end of direct map allocations. static constexpr size_t kGigaBytes = 1024 * 1024 * 1024; @@ -108,59 +107,60 @@ // // For example, [16GiB,8GiB] would work, but [8GiB,16GiB] wouldn't (the 2nd // pool is aligned on 8GiB but needs 16GiB), and [8GiB,8GiB,16GiB,1GiB] would. - static constexpr size_t kNonBRPPoolSize = 16 * kGigaBytes; - static constexpr size_t kBRPPoolSize = 16 * kGigaBytes; + static constexpr size_t kDirectMapPoolSize = 16 * kGigaBytes; + static constexpr size_t kNormalBucketPoolSize = 16 * kGigaBytes; static constexpr size_t kDesiredAddressSpaceSize = - kNonBRPPoolSize + kBRPPoolSize; + kDirectMapPoolSize + kNormalBucketPoolSize; static constexpr size_t kReservedAddressSpaceAlignment = - std::max(kNonBRPPoolSize, kBRPPoolSize); + std::max(kDirectMapPoolSize, kNormalBucketPoolSize); - static_assert(bits::IsPowerOfTwo(kNonBRPPoolSize) && - bits::IsPowerOfTwo(kBRPPoolSize), + static_assert(bits::IsPowerOfTwo(kDirectMapPoolSize) && + bits::IsPowerOfTwo(kNormalBucketPoolSize), "Each pool size should be a power of two."); static_assert(bits::IsPowerOfTwo(kReservedAddressSpaceAlignment), "kReservedAddressSpaceAlignment should be a power of two."); - static_assert(kReservedAddressSpaceAlignment >= kNonBRPPoolSize && - kReservedAddressSpaceAlignment >= kBRPPoolSize, + static_assert(kReservedAddressSpaceAlignment >= kDirectMapPoolSize && + kReservedAddressSpaceAlignment >= kNormalBucketPoolSize, "kReservedAddressSpaceAlignment should be larger or equal to " "each pool size."); - static_assert(kReservedAddressSpaceAlignment % kNonBRPPoolSize == 0 && - (kReservedAddressSpaceAlignment + kNonBRPPoolSize) % - kBRPPoolSize == + static_assert(kReservedAddressSpaceAlignment % kDirectMapPoolSize == 0 && + (kReservedAddressSpaceAlignment + kDirectMapPoolSize) % + kNormalBucketPoolSize == 0, "Each pool should be aligned to its own size"); // Masks used to easy determine belonging to a pool. - static constexpr uintptr_t kNonBRPPoolOffsetMask = - static_cast<uintptr_t>(kNonBRPPoolSize) - 1; - static constexpr uintptr_t kNonBRPPoolBaseMask = ~kNonBRPPoolOffsetMask; - static constexpr uintptr_t kBRPPoolOffsetMask = - static_cast<uintptr_t>(kBRPPoolSize) - 1; - static constexpr uintptr_t kBRPPoolBaseMask = ~kBRPPoolOffsetMask; + static constexpr uintptr_t kDirectMapPoolOffsetMask = + static_cast<uintptr_t>(kDirectMapPoolSize) - 1; + static constexpr uintptr_t kDirectMapPoolBaseMask = ~kDirectMapPoolOffsetMask; + static constexpr uintptr_t kNormalBucketPoolOffsetMask = + static_cast<uintptr_t>(kNormalBucketPoolSize) - 1; + static constexpr uintptr_t kNormalBucketPoolBaseMask = + ~kNormalBucketPoolOffsetMask; // See the comment describing the address layout above. static uintptr_t reserved_base_address_; - static uintptr_t non_brp_pool_base_address_; - static uintptr_t brp_pool_base_address_; + static uintptr_t direct_map_pool_base_address_; + static uintptr_t normal_bucket_pool_base_address_; - static internal::pool_handle non_brp_pool_; - static internal::pool_handle brp_pool_; + static internal::pool_handle direct_map_pool_; + static internal::pool_handle normal_bucket_pool_; }; -ALWAYS_INLINE internal::pool_handle GetNonBRPPool() { +ALWAYS_INLINE internal::pool_handle GetDirectMapPool() { // This file is included from checked_ptr.h. This will result in a cycle if it // includes partition_alloc_features.h where IsPartitionAllocGigaCageEnabled // resides, because it includes Finch headers which may include checked_ptr.h. // TODO(bartekn): Uncomment once Finch is no longer used there. // PA_DCHECK(IsPartitionAllocGigaCageEnabled()); - return PartitionAddressSpace::GetNonBRPPool(); + return PartitionAddressSpace::GetDirectMapPool(); } -ALWAYS_INLINE internal::pool_handle GetBRPPool() { +ALWAYS_INLINE internal::pool_handle GetNormalBucketPool() { // TODO(bartekn): Uncomment once Finch is no longer used there (see above). // PA_DCHECK(IsPartitionAllocGigaCageEnabled()); - return PartitionAddressSpace::GetBRPPool(); + return PartitionAddressSpace::GetNormalBucketPool(); } #endif // defined(PA_HAS_64_BITS_POINTERS) @@ -168,12 +168,12 @@ } // namespace internal #if defined(PA_HAS_64_BITS_POINTERS) -ALWAYS_INLINE bool IsManagedByPartitionAllocNonBRPPool(const void* address) { - return internal::PartitionAddressSpace::IsInNonBRPPool(address); +ALWAYS_INLINE bool IsManagedByPartitionAllocDirectMap(const void* address) { + return internal::PartitionAddressSpace::IsInDirectMapPool(address); } -ALWAYS_INLINE bool IsManagedByPartitionAllocBRPPool(const void* address) { - return internal::PartitionAddressSpace::IsInBRPPool(address); +ALWAYS_INLINE bool IsManagedByPartitionAllocNormalBuckets(const void* address) { + return internal::PartitionAddressSpace::IsInNormalBucketPool(address); } #endif
diff --git a/base/allocator/partition_allocator/partition_alloc_unittest.cc b/base/allocator/partition_allocator/partition_alloc_unittest.cc index 617dd8e..c04f3215 100644 --- a/base/allocator/partition_allocator/partition_alloc_unittest.cc +++ b/base/allocator/partition_allocator/partition_alloc_unittest.cc
@@ -2841,7 +2841,7 @@ #endif size_t alignment = PageAllocationGranularity(); #if defined(PA_HAS_64_BITS_POINTERS) - if (features::IsPartitionAllocGigaCageEnabled()) + if (root.UsesGigaCage()) alignment = kSuperPageSize; #endif size_t expected_direct_map_size =
diff --git a/base/allocator/partition_allocator/partition_bucket.cc b/base/allocator/partition_allocator/partition_bucket.cc index 8591dda..e7c2b4a2 100644 --- a/base/allocator/partition_allocator/partition_bucket.cc +++ b/base/allocator/partition_allocator/partition_bucket.cc
@@ -38,11 +38,10 @@ PA_DCHECK(slot_size <= map_size); char* ptr = nullptr; - // Allocate from GigaCage, if enabled. In this case, use non-BRP pool, because - // BackupRefPtr isn't supported in direct maps. + // Allocate from GigaCage, if enabled. if (features::IsPartitionAllocGigaCageEnabled()) { ptr = internal::AddressPoolManager::GetInstance()->Reserve( - GetNonBRPPool(), nullptr, reserved_size); + GetDirectMapPool(), nullptr, reserved_size); } else { ptr = reinterpret_cast<char*>( AllocPages(nullptr, reserved_size, kSuperPageAlignment, @@ -237,12 +236,13 @@ // architectures. char* requested_address = root->next_super_page; char* super_page = nullptr; - // Allocate from GigaCage, if enabled. Route to the appropriate GigaCage pool - // based on BackupRefPtr support. - if (features::IsPartitionAllocGigaCageEnabled()) { + // Allocate from GigaCage, if enabled. However, the exception to this is when + // ref-count isn't allowed, as CheckedPtr assumes that everything inside + // GigaCage uses ref-count (specifically, inside the GigaCage's normal bucket + // pool). + if (root->UsesGigaCage()) { super_page = AddressPoolManager::GetInstance()->Reserve( - root->SupportsBRP() ? GetBRPPool() : GetNonBRPPool(), requested_address, - kSuperPageSize); + GetNormalBucketPool(), requested_address, kSuperPageSize); } else { super_page = reinterpret_cast<char*>( AllocPages(requested_address, kSuperPageSize, kSuperPageAlignment,
diff --git a/base/allocator/partition_allocator/partition_page.cc b/base/allocator/partition_allocator/partition_page.cc index 553270d..83686fa 100644 --- a/base/allocator/partition_allocator/partition_page.cc +++ b/base/allocator/partition_allocator/partition_page.cc
@@ -210,11 +210,10 @@ void DeferredUnmap::Unmap() { PA_DCHECK(ptr && size > 0); if (features::IsPartitionAllocGigaCageEnabled()) { - // Currently this function is only called for direct-mapped allocations, - // which always belong to the non-BRP pool, provided that GigaCage is used. - PA_DCHECK(IsManagedByPartitionAllocNonBRPPool(ptr)); + // Currently this function is only called for direct-mapped allocations. + PA_DCHECK(IsManagedByPartitionAllocDirectMap(ptr)); internal::AddressPoolManager::GetInstance()->UnreserveAndDecommit( - internal::GetNonBRPPool(), ptr, size); + internal::GetDirectMapPool(), ptr, size); } else { FreePages(ptr, size); }
diff --git a/base/allocator/partition_allocator/partition_page.h b/base/allocator/partition_allocator/partition_page.h index bf38e274..0c91354 100644 --- a/base/allocator/partition_allocator/partition_page.h +++ b/base/allocator/partition_allocator/partition_page.h
@@ -312,10 +312,8 @@ return super_page_base + kSuperPageSize - PartitionPageSize(); } -// CAUTION! Use only for normal buckets. Using on direct-mapped allocations may -// lead to undefined behavior. ALWAYS_INLINE bool IsWithinSuperPagePayload(char* ptr, bool with_quarantine) { - // TODO(bartekn): Add a "is in normal buckets" DCHECK. + PA_DCHECK(!IsManagedByPartitionAllocDirectMap(ptr)); char* super_page_base = reinterpret_cast<char*>( reinterpret_cast<uintptr_t>(ptr) & kSuperPageBaseMask); char* payload_start = SuperPagePayloadBegin(super_page_base, with_quarantine); @@ -327,15 +325,12 @@ // an existing slot span. The function may return a pointer even inside a // decommitted or free slot span, it's the caller responsibility to check if // memory is actually allocated. -// -// CAUTION! Use only for normal buckets. Using on direct-mapped allocations may -// lead to undefined behavior. -// -// Furthermore, |maybe_inner_ptr| must point to payload of a valid super page. +// The precondition is that |maybe_inner_ptr| must point to payload of a valid +// super page. template <bool thread_safe> ALWAYS_INLINE char* GetSlotStartInSuperPage(char* maybe_inner_ptr) { #if DCHECK_IS_ON() - // TODO(bartekn): Add a "is in normal buckets" DCHECK. + PA_DCHECK(!IsManagedByPartitionAllocDirectMap(maybe_inner_ptr)); char* super_page_ptr = reinterpret_cast<char*>( reinterpret_cast<uintptr_t>(maybe_inner_ptr) & kSuperPageBaseMask); auto* extent = reinterpret_cast<PartitionSuperPageExtentEntry<thread_safe>*>( @@ -584,13 +579,11 @@ enum class QuarantineBitmapType { kMutator, kScanner }; -// CAUTION! Use only for normal buckets. Using on direct-mapped allocations may -// lead to undefined behavior. ALWAYS_INLINE QuarantineBitmap* QuarantineBitmapFromPointer( QuarantineBitmapType type, size_t pcscan_epoch, void* ptr) { - // TODO(bartekn): Add a "is in normal buckets" DCHECK. + PA_DCHECK(!IsManagedByPartitionAllocDirectMap(ptr)); auto* super_page_base = reinterpret_cast<char*>( reinterpret_cast<uintptr_t>(ptr) & kSuperPageBaseMask); auto* first_bitmap = SuperPageQuarantineBitmaps(super_page_base);
diff --git a/base/allocator/partition_allocator/partition_root.cc b/base/allocator/partition_allocator/partition_root.cc index ad468d4..96f48bc2 100644 --- a/base/allocator/partition_allocator/partition_root.cc +++ b/base/allocator/partition_allocator/partition_root.cc
@@ -4,10 +4,8 @@ #include "base/allocator/partition_allocator/partition_root.h" -#include "base/allocator/partition_allocator/address_pool_manager_bitmap.h" #include "base/allocator/partition_allocator/oom.h" #include "base/allocator/partition_allocator/page_allocator.h" -#include "base/allocator/partition_allocator/partition_address_space.h" #include "base/allocator/partition_allocator/partition_alloc_check.h" #include "base/allocator/partition_allocator/partition_alloc_features.h" #include "base/allocator/partition_allocator/partition_bucket.h" @@ -389,8 +387,10 @@ } #if DCHECK_IS_ON() -void DCheckIfManagedByPartitionAllocBRPPool(const void* ptr) { - PA_DCHECK(IsManagedByPartitionAllocBRPPool(ptr)); +void DCheckIfManagedByPartitionAllocNormalBuckets(const void* ptr) { + if (features::IsPartitionAllocGigaCageEnabled()) { + PA_DCHECK(IsManagedByPartitionAllocNormalBuckets(ptr)); + } } #endif
diff --git a/base/allocator/partition_allocator/partition_root.h b/base/allocator/partition_allocator/partition_root.h index dc5e278..60cbd86 100644 --- a/base/allocator/partition_allocator/partition_root.h +++ b/base/allocator/partition_allocator/partition_root.h
@@ -73,11 +73,11 @@ namespace internal { // Avoid including partition_address_space.h from this .h file, by moving the -// call to IsManagedByPartitionAllocBRPPool into the .cc file. +// call to IfManagedByPartitionAllocNormalBuckets into the .cc file. #if DCHECK_IS_ON() -BASE_EXPORT void DCheckIfManagedByPartitionAllocBRPPool(const void* ptr); +BASE_EXPORT void DCheckIfManagedByPartitionAllocNormalBuckets(const void* ptr); #else -ALWAYS_INLINE void DCheckIfManagedByPartitionAllocBRPPool(const void*) {} +ALWAYS_INLINE void DCheckIfManagedByPartitionAllocNormalBuckets(const void*) {} #endif } // namespace internal @@ -244,7 +244,7 @@ ALWAYS_INLINE static bool IsValidSlotSpan(SlotSpan* slot_span); ALWAYS_INLINE static PartitionRoot* FromSlotSpan(SlotSpan* slot_span); ALWAYS_INLINE static PartitionRoot* FromSuperPage(char* super_page); - ALWAYS_INLINE static PartitionRoot* FromPointer(char* ptr); + ALWAYS_INLINE static PartitionRoot* FromPointerInNormalBucketPool(char* ptr); ALWAYS_INLINE void IncreaseCommittedPages(size_t len); ALWAYS_INLINE void DecreaseCommittedPages(size_t len); @@ -332,12 +332,12 @@ return total_size_of_committed_pages.load(std::memory_order_relaxed); } - bool SupportsBRP() const { - // Return the same value regardless of BUILDFLAG(USE_BACKUP_REF_PTR), so - // that the same choices are made in either configuration (though this may - // be not true in the BUILDFLAG(ENABLE_RUNTIME_BACKUP_REF_PTR_CONTROL) - // case). - return allow_ref_count; + bool UsesGigaCage() const { + return features::IsPartitionAllocGigaCageEnabled() +#if BUILDFLAG(USE_BACKUP_REF_PTR) + && allow_ref_count +#endif + ; } ALWAYS_INLINE bool IsQuarantineAllowed() const { @@ -631,15 +631,12 @@ } // Gets the SlotSpanMetadata object of the slot span that contains |ptr|. It's -// used with intention to do obtain the slot size. -// -// CAUTION! Use only for normal buckets. Using on direct-mapped allocations may -// lead to undefined behavior. +// used with intention to do obtain the slot size. CAUTION! It works well for +// normal buckets, but for direct-mapped allocations it'll only work if |ptr| is +// in the first partition page of the allocation. template <bool thread_safe> ALWAYS_INLINE internal::SlotSpanMetadata<thread_safe>* PartitionAllocGetSlotSpanForSizeQuery(void* ptr) { - // TODO(bartekn): Add a "is in normal buckets" DCHECK. - // No need to lock here. Only |ptr| being freed by another thread could // cause trouble, and the caller is responsible for that not happening. auto* slot_span = @@ -672,8 +669,7 @@ // care of that detail. ptr = reinterpret_cast<char*>(ptr) - kPartitionPastAllocationAdjustment; - internal::DCheckIfManagedByPartitionAllocBRPPool(ptr); - + internal::DCheckIfManagedByPartitionAllocNormalBuckets(ptr); auto* slot_span = internal::PartitionAllocGetSlotSpanForSizeQuery<internal::ThreadSafe>( ptr); @@ -808,15 +804,17 @@ // On Android, malloc() interception is more fragile than on other // platforms, as we use wrapped symbols. However, the GigaCage allows us to - // quickly tell that a pointer was allocated with PartitionAlloc. + // quickly tell that a pointer was allocated with PartitionAlloc. GigaCage + // is unfortunately not used for the aligned partition when BackupRefPtr is + // enabled, yielding the set of conditions below. // // This is a crash to detect imperfect symbol interception. However, we can // forward allocations we don't own to the system malloc() implementation in // these rare cases, assuming that some remain. -#if defined(OS_ANDROID) && BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) - PA_DCHECK(features::IsPartitionAllocGigaCageEnabled()); - PA_CHECK(IsManagedByPartitionAllocBRPPool(ptr) || - IsManagedByPartitionAllocNonBRPPool(ptr)); +#if defined(OS_ANDROID) && BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && \ + !BUILDFLAG(USE_BACKUP_REF_PTR) + PA_CHECK(IsManagedByPartitionAllocNormalBuckets(ptr) || + IsManagedByPartitionAllocDirectMap(ptr)); #endif // Call FromSlotInnerPtr instead of FromSlotStartPtr because the pointer @@ -887,8 +885,7 @@ #if BUILDFLAG(USE_BACKUP_REF_PTR) if (allow_ref_count) { - if (LIKELY(!slot_span->bucket->is_direct_mapped() && - features::IsPartitionAllocGigaCageEnabled())) { + if (LIKELY(!slot_span->bucket->is_direct_mapped())) { auto* ref_count = internal::PartitionRefCountPointer(slot_start); // If we are holding the last reference to the allocation, it can be freed // immediately. Otherwise, defer the operation and zap the memory to turn @@ -993,12 +990,10 @@ return root; } -// CAUTION! Use only for normal buckets. Using on direct-mapped allocations may -// lead to undefined behavior. template <bool thread_safe> ALWAYS_INLINE PartitionRoot<thread_safe>* -PartitionRoot<thread_safe>::FromPointer(char* ptr) { - // TODO(bartekn): Add a "is in normal buckets" DCHECK. +PartitionRoot<thread_safe>::FromPointerInNormalBucketPool(char* ptr) { + PA_DCHECK(!IsManagedByPartitionAllocDirectMap(ptr)); char* super_page = reinterpret_cast<char*>(reinterpret_cast<uintptr_t>(ptr) & kSuperPageBaseMask); return FromSuperPage(super_page); @@ -1296,8 +1291,7 @@ #if BUILDFLAG(USE_BACKUP_REF_PTR) bool is_direct_mapped = raw_size > kMaxBucketed; // LIKELY: Direct mapped allocations are large and rare. - if (allow_ref_count && LIKELY(!is_direct_mapped && - features::IsPartitionAllocGigaCageEnabled())) { + if (allow_ref_count && LIKELY(!is_direct_mapped)) { new (internal::PartitionRefCountPointer(slot_start)) internal::PartitionRefCount(); }
diff --git a/base/allocator/partition_allocator/pcscan.cc b/base/allocator/partition_allocator/pcscan.cc index 88f8bdc..cf64e2e 100644 --- a/base/allocator/partition_allocator/pcscan.cc +++ b/base/allocator/partition_allocator/pcscan.cc
@@ -213,8 +213,7 @@ using LargeScanAreas = std::vector<LargeScanArea, MetadataAllocator<LargeScanArea>>; - // BRP pool is guaranteed to have only normal buckets, so everything there - // deals in super pages. + // Super pages only correspond to normal buckets. // TODO(bikineev): Consider flat containers since the number of elements is // relatively small. This requires making base containers allocator-aware. using SuperPages = @@ -226,33 +225,35 @@ for (uintptr_t super_page_base : super_pages) { #if DCHECK_IS_ON() PA_DCHECK(!(super_page_base % kSuperPageAlignment)); - PA_DCHECK(IsManagedByPartitionAllocBRPPool( + PA_DCHECK(IsManagedByPartitionAllocNormalBuckets( reinterpret_cast<char*>(super_page_base))); #endif - bitset_.Set(BRPPoolOffset(super_page_base)); + bitset_.Set(NormalBucketPoolOffset(super_page_base)); } } ALWAYS_INLINE bool Test(uintptr_t maybe_ptr) const { #if DCHECK_IS_ON() - PA_DCHECK( - IsManagedByPartitionAllocBRPPool(reinterpret_cast<char*>(maybe_ptr))); + PA_DCHECK(IsManagedByPartitionAllocNormalBuckets( + reinterpret_cast<char*>(maybe_ptr))); #endif - return bitset_.Test(BRPPoolOffset(maybe_ptr)); + return bitset_.Test(NormalBucketPoolOffset(maybe_ptr)); } private: static constexpr size_t kBitmapSize = - AddressPoolManager::kBRPPoolMaxSize >> kSuperPageShift; + AddressPoolManager::kNormalBucketMaxSize >> kSuperPageShift; - ALWAYS_INLINE static constexpr size_t BRPPoolOffset(uintptr_t ptr) { - constexpr uintptr_t kBRPPoolMask = + ALWAYS_INLINE static constexpr size_t NormalBucketPoolOffset( + uintptr_t ptr) { + constexpr uintptr_t kNormalBucketPoolMask = #if defined(PA_HAS_64_BITS_POINTERS) - PartitionAddressSpace::BRPPoolBaseMask(); + PartitionAddressSpace::NormalBucketPoolBaseMask(); #else 0; #endif - return static_cast<size_t>((ptr & ~kBRPPoolMask) >> kSuperPageShift); + return static_cast<size_t>((ptr & ~kNormalBucketPoolMask) >> + kSuperPageShift); } SimpleBitset<kBitmapSize> bitset_; @@ -261,8 +262,8 @@ struct BitmapLookupPolicy { ALWAYS_INLINE bool TestOnHeapPointer(uintptr_t maybe_ptr) const { #if DCHECK_IS_ON() - PA_DCHECK( - IsManagedByPartitionAllocBRPPool(reinterpret_cast<void*>(maybe_ptr))); + PA_DCHECK(IsManagedByPartitionAllocNormalBuckets( + reinterpret_cast<void*>(maybe_ptr))); #endif return task_.super_pages_bitmap_.Test(maybe_ptr); } @@ -285,7 +286,8 @@ // Lookup and marking functions. Return size of the object if marked or zero // otherwise. template <typename LookupPolicy> - ALWAYS_INLINE size_t TryMarkObjectInBRPPool(uintptr_t maybe_ptr) const; + ALWAYS_INLINE size_t + TryMarkObjectInNormalBucketPool(uintptr_t maybe_ptr) const; // Scans all registeres partitions and marks reachable quarantined objects. // Returns the size of marked objects. @@ -314,9 +316,7 @@ ALWAYS_INLINE QuarantineBitmap* PCScan<thread_safe>::PCScanTask::TryFindScannerBitmapForPointer( uintptr_t maybe_ptr) const { - // First, check if |maybe_ptr| points to a valid super page, containing normal - // buckets. If GigaCage is enabled, this will filter out addresses not in BRP - // pool (which are guaranteed to be normal buckets). + // First, check if |maybe_ptr| points to a valid super page. LookupPolicy lookup{*this}; if (!lookup.TestOnHeapPointer(maybe_ptr)) return nullptr; @@ -332,39 +332,28 @@ // Looks up and marks a potential dangling pointer. Returns the size of the slot // (which is then accounted as quarantined) or zero if no object is found. -// For super pages in BRP pool, PCScan uses two quarantine bitmaps, the +// For normal bucket super pages, PCScan uses two quarantine bitmaps, the // mutator and the scanner one. The former is used by mutators when objects are // freed, while the latter is used concurrently by the PCScan thread. The // bitmaps are swapped as soon as PCScan is triggered. Once a dangling pointer // (which points to an object in the scanner bitmap) is found, -// TryMarkObjectInBRPPool() marks it again in the bitmap and clears +// TryMarkObjectInNormalBucketPool() marks it again in the bitmap and clears // from the scanner bitmap. This way, when scanning is done, all uncleared // entries in the scanner bitmap correspond to unreachable objects. template <bool thread_safe> template <typename LookupPolicy> -ALWAYS_INLINE size_t PCScan<thread_safe>::PCScanTask::TryMarkObjectInBRPPool( +ALWAYS_INLINE size_t +PCScan<thread_safe>::PCScanTask::TryMarkObjectInNormalBucketPool( uintptr_t maybe_ptr) const { using AccessType = QuarantineBitmap::AccessType; - // Check if |maybe_ptr| points somewhere to the protected part of the heap - // (BRP pool if GigaCage is enabled, normal buckets otherwise). + // Check if maybe_ptr points somewhere to the heap. auto* scanner_bitmap = TryFindScannerBitmapForPointer<LookupPolicy>(maybe_ptr); if (!scanner_bitmap) return 0; -#if DCHECK_IS_ON() - // Out of necessity, skip the check if GigaCage isn't enabled, or it'd fail on - // RunUnvectorizedNoGigaCage path. This is ok because this function deals fine - // with all pointers to normal buckets, and TryFindScannerBitmapForPointer - // guarantees we wouldn't get here otherwise. - if (features::IsPartitionAllocGigaCageEnabled()) { - PA_DCHECK( - IsManagedByPartitionAllocBRPPool(reinterpret_cast<void*>(maybe_ptr))); - } - // TODO(bartekn): Add a "is in normal buckets" DCHECK in the |else| case. -#endif // DCHECK_IS_ON() - - auto* root = Root::FromPointer(reinterpret_cast<char*>(maybe_ptr)); + auto* root = + Root::FromPointerInNormalBucketPool(reinterpret_cast<char*>(maybe_ptr)); // Check if pointer was in the quarantine bitmap. const uintptr_t base = @@ -425,7 +414,7 @@ pcscan_task_(pcscan_task) #if defined(PA_HAS_64_BITS_POINTERS) , - brp_pool_base_(PartitionAddressSpace::BRPPoolBase()) + normal_bucket_pool_base_(PartitionAddressSpace::NormalBucketPoolBase()) #endif { } @@ -465,9 +454,9 @@ } #if defined(PA_HAS_64_BITS_POINTERS) - ALWAYS_INLINE bool IsInBRPPool(uintptr_t maybe_ptr) const { - return (maybe_ptr & PartitionAddressSpace::BRPPoolBaseMask()) == - brp_pool_base_; + ALWAYS_INLINE bool IsInNormalBucketPool(uintptr_t maybe_ptr) const { + return (maybe_ptr & PartitionAddressSpace::NormalBucketPoolBaseMask()) == + normal_bucket_pool_base_; } #endif @@ -484,9 +473,10 @@ // _mm_cmpeq_epi64), use packed doubles (not integers). Sticking to doubles // helps to avoid latency caused by "domain crossing penalties" (see bypass // delays in https://agner.org/optimize/microarchitecture.pdf). - const __m128d vbase = _mm_castsi128_pd(_mm_set1_epi64x(brp_pool_base_)); + const __m128d vbase = + _mm_castsi128_pd(_mm_set1_epi64x(normal_bucket_pool_base_)); const __m128d cage_mask = _mm_castsi128_pd( - _mm_set1_epi64x(PartitionAddressSpace::BRPPoolBaseMask())); + _mm_set1_epi64x(PartitionAddressSpace::NormalBucketPoolBaseMask())); size_t quarantine_size = 0; for (uintptr_t* payload = begin; payload < end; payload += kWordsInVector) { @@ -501,7 +491,7 @@ // avoid racing with the mutator. if (mask & 0b01) { quarantine_size += - pcscan_task_.TryMarkObjectInBRPPool<BitmapLookupPolicy>( + pcscan_task_.TryMarkObjectInNormalBucketPool<BitmapLookupPolicy>( _mm_cvtsi128_si64(_mm_castpd_si128(maybe_ptrs))); } if (mask & 0b10) { @@ -512,7 +502,7 @@ const __m128i shuffled = _mm_shuffle_epi32(_mm_castpd_si128(maybe_ptrs), kSecondWordMask); quarantine_size += - pcscan_task_.TryMarkObjectInBRPPool<BitmapLookupPolicy>( + pcscan_task_.TryMarkObjectInNormalBucketPool<BitmapLookupPolicy>( _mm_cvtsi128_si64(shuffled)); } } @@ -528,9 +518,9 @@ // throughput. For example, according to the Intel docs, on Broadwell and // Haswell the CPI of vmovdqa (_mm256_load_si256) is twice smaller (0.25) // than that of vmovapd (_mm256_load_pd). - const __m256i vbase = _mm256_set1_epi64x(brp_pool_base_); + const __m256i vbase = _mm256_set1_epi64x(normal_bucket_pool_base_); const __m256i cage_mask = - _mm256_set1_epi64x(PartitionAddressSpace::BRPPoolBaseMask()); + _mm256_set1_epi64x(PartitionAddressSpace::NormalBucketPoolBaseMask()); size_t quarantine_size = 0; uintptr_t* payload = begin; @@ -546,19 +536,19 @@ // avoid racing with the mutator. if (mask & 0b0001) quarantine_size += - pcscan_task_.TryMarkObjectInBRPPool<BitmapLookupPolicy>( + pcscan_task_.TryMarkObjectInNormalBucketPool<BitmapLookupPolicy>( _mm256_extract_epi64(maybe_ptrs, 0)); if (mask & 0b0010) quarantine_size += - pcscan_task_.TryMarkObjectInBRPPool<BitmapLookupPolicy>( + pcscan_task_.TryMarkObjectInNormalBucketPool<BitmapLookupPolicy>( _mm256_extract_epi64(maybe_ptrs, 1)); if (mask & 0b0100) quarantine_size += - pcscan_task_.TryMarkObjectInBRPPool<BitmapLookupPolicy>( + pcscan_task_.TryMarkObjectInNormalBucketPool<BitmapLookupPolicy>( _mm256_extract_epi64(maybe_ptrs, 2)); if (mask & 0b1000) quarantine_size += - pcscan_task_.TryMarkObjectInBRPPool<BitmapLookupPolicy>( + pcscan_task_.TryMarkObjectInNormalBucketPool<BitmapLookupPolicy>( _mm256_extract_epi64(maybe_ptrs, 3)); } @@ -574,17 +564,18 @@ for (; begin < end; ++begin) { uintptr_t maybe_ptr = *begin; #if defined(PA_HAS_64_BITS_POINTERS) - // On 64bit architectures, call IsInBRPPool instead of - // IsManagedByPartitionAllocBRPPool to avoid redundant load of - // PartitionAddressSpace::brp_pool_base_address_. - if (LIKELY(!IsInBRPPool(maybe_ptr))) + // On 64bit architectures, call IsInNormalBucketPool instead of + // IsManagedByPartitionAllocNormalBuckets to avoid redundant load of + // PartitionAddressSpace::normal_bucket_pool_base_address_. + if (LIKELY(!IsInNormalBucketPool(maybe_ptr))) #else - if (LIKELY(!IsManagedByPartitionAllocBRPPool( + if (LIKELY(!IsManagedByPartitionAllocNormalBuckets( reinterpret_cast<void*>(maybe_ptr)))) #endif continue; quarantine_size += - pcscan_task_.TryMarkObjectInBRPPool<BitmapLookupPolicy>(maybe_ptr); + pcscan_task_.TryMarkObjectInNormalBucketPool<BitmapLookupPolicy>( + maybe_ptr); } return quarantine_size; } @@ -598,7 +589,8 @@ if (!maybe_ptr) continue; quarantine_size += - pcscan_task_.TryMarkObjectInBRPPool<BinaryLookupPolicy>(maybe_ptr); + pcscan_task_.TryMarkObjectInNormalBucketPool<BinaryLookupPolicy>( + maybe_ptr); } return quarantine_size; } @@ -607,8 +599,8 @@ const PCScanTask& pcscan_task_; #if defined(PA_HAS_64_BITS_POINTERS) // Keep this a constant so that the compiler can remove redundant loads for - // the base of the BRP pool and hoist them out of the loops. - const uintptr_t brp_pool_base_; + // the base of the normal bucket pool and hoist them out of the loops. + const uintptr_t normal_bucket_pool_base_; #endif };
diff --git a/base/allocator/partition_allocator/pcscan_unittest.cc b/base/allocator/partition_allocator/pcscan_unittest.cc index 6c4afa2..95349e6 100644 --- a/base/allocator/partition_allocator/pcscan_unittest.cc +++ b/base/allocator/partition_allocator/pcscan_unittest.cc
@@ -23,7 +23,7 @@ allocator_.init({PartitionOptions::Alignment::kRegular, PartitionOptions::ThreadCache::kDisabled, PartitionOptions::Quarantine::kAllowed, - PartitionOptions::RefCount::kEnabled}); + PartitionOptions::RefCount::kDisabled}); PCScan<ThreadSafe>::Instance().RegisterScannableRoot(allocator_.root()); } ~PCScanTest() override { @@ -170,8 +170,8 @@ void TestDanglingReference(PCScanTest& test, SourceList* source, ValueList* value) { - auto* value_root = - ThreadSafePartitionRoot::FromPointer(reinterpret_cast<char*>(value)); + auto* value_root = ThreadSafePartitionRoot::FromPointerInNormalBucketPool( + reinterpret_cast<char*>(value)); { // Free |value| and leave the dangling reference in |source|. ValueList::Destroy(*value_root, value); @@ -315,11 +315,11 @@ ThreadSafePartitionRoot source_root({PartitionOptions::Alignment::kRegular, PartitionOptions::ThreadCache::kDisabled, PartitionOptions::Quarantine::kAllowed, - PartitionOptions::RefCount::kEnabled}); + PartitionOptions::RefCount::kDisabled}); ThreadSafePartitionRoot value_root({PartitionOptions::Alignment::kRegular, PartitionOptions::ThreadCache::kDisabled, PartitionOptions::Quarantine::kAllowed, - PartitionOptions::RefCount::kEnabled}); + PartitionOptions::RefCount::kDisabled}); PCScan<ThreadSafe>::Instance().RegisterScannableRoot(&source_root); PCScan<ThreadSafe>::Instance().RegisterScannableRoot(&value_root); @@ -338,11 +338,11 @@ ThreadSafePartitionRoot source_root({PartitionOptions::Alignment::kRegular, PartitionOptions::ThreadCache::kDisabled, PartitionOptions::Quarantine::kAllowed, - PartitionOptions::RefCount::kEnabled}); + PartitionOptions::RefCount::kDisabled}); ThreadSafePartitionRoot value_root({PartitionOptions::Alignment::kRegular, PartitionOptions::ThreadCache::kDisabled, PartitionOptions::Quarantine::kAllowed, - PartitionOptions::RefCount::kEnabled}); + PartitionOptions::RefCount::kDisabled}); PCScan<ThreadSafe>::Instance().RegisterScannableRoot(&source_root); PCScan<ThreadSafe>::Instance().RegisterNonScannableRoot(&value_root); @@ -362,12 +362,12 @@ {PartitionOptions::Alignment::kRegular, PartitionOptions::ThreadCache::kDisabled, base::PartitionOptions::Quarantine::kAllowed, - PartitionOptions::RefCount::kEnabled}); + PartitionOptions::RefCount::kDisabled}); ThreadSafePartitionRoot value_root( {PartitionOptions::Alignment::kRegular, PartitionOptions::ThreadCache::kDisabled, base::PartitionOptions::Quarantine::kAllowed, - PartitionOptions::RefCount::kEnabled}); + PartitionOptions::RefCount::kDisabled}); PCScan<ThreadSafe>::Instance().RegisterNonScannableRoot(&source_root); PCScan<ThreadSafe>::Instance().RegisterScannableRoot(&value_root);
diff --git a/base/android/jni_generator/jni_generator.py b/base/android/jni_generator/jni_generator.py index 18bcb29..4df3649 100755 --- a/base/android/jni_generator/jni_generator.py +++ b/base/android/jni_generator/jni_generator.py
@@ -1508,11 +1508,17 @@ return os.sep.join(script_components[base_index:]) -def _RemoveExistingHeaders(path): - if os.path.exists(path) and os.path.isdir(path): - for root, _, files in os.walk(path): - for f in files: - file_path = os.path.join(root, f) +def _RemoveStaleHeaders(path, output_files): + if not os.path.isdir(path): + return + # Do not remove output files so that timestamps on declared outputs are not + # modified unless their contents are changed (avoids reverse deps needing to + # be rebuilt). + preserve = set(output_files) + for root, _, files in os.walk(path): + for f in files: + file_path = os.path.join(root, f) + if file_path not in preserve: if os.path.isfile(file_path) and os.path.splitext(file_path)[1] == '.h': os.remove(file_path) @@ -1604,7 +1610,7 @@ # Remove existing headers so that moving .java source files but not updating # the corresponding C++ include will be a compile failure (otherwise # incremental builds will usually not catch this). - _RemoveExistingHeaders(output_dir) + _RemoveStaleHeaders(output_dir, output_files) else: output_files = [None] * len(input_files) temp_dir = tempfile.mkdtemp()
diff --git a/base/atomicops.h b/base/atomicops.h index 3784289e..d3265dd 100644 --- a/base/atomicops.h +++ b/base/atomicops.h
@@ -104,7 +104,6 @@ Atomic32 NoBarrier_Load(volatile const Atomic32* ptr); Atomic32 Acquire_Load(volatile const Atomic32* ptr); -Atomic32 Release_Load(volatile const Atomic32* ptr); // 64-bit atomic operations (only available on 64-bit processors). #ifdef ARCH_CPU_64_BITS @@ -125,7 +124,6 @@ void Release_Store(volatile Atomic64* ptr, Atomic64 value); Atomic64 NoBarrier_Load(volatile const Atomic64* ptr); Atomic64 Acquire_Load(volatile const Atomic64* ptr); -Atomic64 Release_Load(volatile const Atomic64* ptr); #endif // ARCH_CPU_64_BITS } // namespace subtle
diff --git a/base/atomicops_internals_atomicword_compat.h b/base/atomicops_internals_atomicword_compat.h index d066ef4..69e1514 100644 --- a/base/atomicops_internals_atomicword_compat.h +++ b/base/atomicops_internals_atomicword_compat.h
@@ -86,11 +86,6 @@ reinterpret_cast<volatile const Atomic32*>(ptr)); } -inline AtomicWord Release_Load(volatile const AtomicWord* ptr) { - return base::subtle::Release_Load( - reinterpret_cast<volatile const Atomic32*>(ptr)); -} - } // namespace subtle } // namespace base
diff --git a/base/atomicops_internals_portable.h b/base/atomicops_internals_portable.h index 3fd4567..2c4f5af 100644 --- a/base/atomicops_internals_portable.h +++ b/base/atomicops_internals_portable.h
@@ -19,11 +19,6 @@ // * Compare exchange's failure ordering is always the same as the success one // (except for release, which fails as relaxed): using a weaker ordering is // only valid under certain uses of compare exchange. -// * Acquire store doesn't exist in the C11 memory model, it is instead -// implemented as a relaxed store followed by a sequentially consistent -// fence. -// * Release load doesn't exist in the C11 memory model, it is instead -// implemented as sequentially consistent fence followed by a relaxed load. // * Atomic increment is expected to return the post-incremented value, whereas // C11 fetch add returns the previous value. The implementation therefore // needs to increment twice (which the compiler should be able to detect and @@ -119,11 +114,6 @@ return ((AtomicLocation32)ptr)->load(std::memory_order_acquire); } -inline Atomic32 Release_Load(volatile const Atomic32* ptr) { - std::atomic_thread_fence(std::memory_order_seq_cst); - return ((AtomicLocation32)ptr)->load(std::memory_order_relaxed); -} - #if defined(ARCH_CPU_64_BITS) typedef volatile std::atomic<Atomic64>* AtomicLocation64; @@ -197,11 +187,6 @@ return ((AtomicLocation64)ptr)->load(std::memory_order_acquire); } -inline Atomic64 Release_Load(volatile const Atomic64* ptr) { - std::atomic_thread_fence(std::memory_order_seq_cst); - return ((AtomicLocation64)ptr)->load(std::memory_order_relaxed); -} - #endif // defined(ARCH_CPU_64_BITS) } // namespace subtle } // namespace base
diff --git a/base/atomicops_internals_x86_msvc.h b/base/atomicops_internals_x86_msvc.h index 102d071..32d0792b 100644 --- a/base/atomicops_internals_x86_msvc.h +++ b/base/atomicops_internals_x86_msvc.h
@@ -79,11 +79,6 @@ return value; } -inline Atomic32 Release_Load(volatile const Atomic32* ptr) { - std::atomic_thread_fence(std::memory_order_seq_cst); - return *ptr; -} - #if defined(_WIN64) // 64-bit low-level operations on 64-bit platform. @@ -143,11 +138,6 @@ return value; } -inline Atomic64 Release_Load(volatile const Atomic64* ptr) { - std::atomic_thread_fence(std::memory_order_seq_cst); - return *ptr; -} - inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr, Atomic64 old_value, Atomic64 new_value) {
diff --git a/base/atomicops_unittest.cc b/base/atomicops_unittest.cc index 8305ee6..375e4366 100644 --- a/base/atomicops_unittest.cc +++ b/base/atomicops_unittest.cc
@@ -205,11 +205,6 @@ EXPECT_EQ(kVal1, base::subtle::Acquire_Load(&value)); value = kVal2; EXPECT_EQ(kVal2, base::subtle::Acquire_Load(&value)); - - value = kVal1; - EXPECT_EQ(kVal1, base::subtle::Release_Load(&value)); - value = kVal2; - EXPECT_EQ(kVal2, base::subtle::Release_Load(&value)); } TEST(AtomicOpsTest, Inc) {
diff --git a/base/fuchsia/intl_profile_watcher_unittest.cc b/base/fuchsia/intl_profile_watcher_unittest.cc index 889d41a3..27d403e 100644 --- a/base/fuchsia/intl_profile_watcher_unittest.cc +++ b/base/fuchsia/intl_profile_watcher_unittest.cc
@@ -119,19 +119,17 @@ delete; ~FakePropertyProviderAsync() = default; - void Close() { - property_provider_.Post(FROM_HERE, &FakePropertyProvider::Close); - } + void Close() { property_provider_.AsyncCall(&FakePropertyProvider::Close); } void SetTimeZones(const std::vector<std::string>& zone_ids) { - property_provider_.Post(FROM_HERE, &FakePropertyProvider::SetTimeZones, - zone_ids); + property_provider_.AsyncCall(&FakePropertyProvider::SetTimeZones) + .WithArgs(zone_ids); } void SetLocales(const std::vector<std::string>& locale_ids) { - property_provider_.Post(FROM_HERE, &FakePropertyProvider::SetLocales, - locale_ids); + property_provider_.AsyncCall(&FakePropertyProvider::SetLocales) + .WithArgs(locale_ids); } void NotifyChange() { - property_provider_.Post(FROM_HERE, &FakePropertyProvider::NotifyChange); + property_provider_.AsyncCall(&FakePropertyProvider::NotifyChange); } private:
diff --git a/base/memory/checked_ptr.cc b/base/memory/checked_ptr.cc index 19d28cac..ef4451a 100644 --- a/base/memory/checked_ptr.cc +++ b/base/memory/checked_ptr.cc
@@ -4,7 +4,6 @@ #include "base/memory/checked_ptr.h" -#include "base/check.h" #include "base/partition_alloc_buildflags.h" // USE_BACKUP_REF_PTR implies USE_PARTITION_ALLOC, needed for code under @@ -18,23 +17,17 @@ namespace internal { void BackupRefPtrImpl::AcquireInternal(void* ptr) { - DCHECK(features::IsPartitionAllocGigaCageEnabled() && - IsManagedByPartitionAllocBRPPool(ptr)); void* slot_start = PartitionAllocGetSlotStart(ptr); PartitionRefCountPointer(slot_start)->Acquire(); } void BackupRefPtrImpl::ReleaseInternal(void* ptr) { - DCHECK(features::IsPartitionAllocGigaCageEnabled() && - IsManagedByPartitionAllocBRPPool(ptr)); void* slot_start = PartitionAllocGetSlotStart(ptr); if (PartitionRefCountPointer(slot_start)->Release()) PartitionAllocFreeForRefCounting(slot_start); } bool BackupRefPtrImpl::IsPointeeAlive(void* ptr) { - DCHECK(features::IsPartitionAllocGigaCageEnabled() && - IsManagedByPartitionAllocBRPPool(ptr)); void* slot_start = PartitionAllocGetSlotStart(ptr); return PartitionRefCountPointer(slot_start)->IsAlive(); }
diff --git a/base/memory/checked_ptr.h b/base/memory/checked_ptr.h index 112c32fd..db52b27 100644 --- a/base/memory/checked_ptr.h +++ b/base/memory/checked_ptr.h
@@ -107,27 +107,28 @@ static ALWAYS_INLINE bool IsSupportedAndNotNull(void* ptr) { // There is a problem on 32-bit systems, where the fake "GigaCage" has many - // BRP pool regions spread throughout the address space. A pointer - // immediately past an allocation may accidentally fall into the BRP pool, + // normal bucket pool regions spread throughout the address space. A pointer + // immediately past an allocation may fall into the normal bucket pool, // hence check if |ptr-1| belongs to that pool. However, checking only // |ptr-1| causes a problem with pointers to the beginning of an // out-of-the-pool allocation that happen to be where the pool ends, so // checking for |ptr| is also necessary. // - // Note, if |ptr| is in the BRP pool, |ptr-1| will not fall out of it, - // thanks to the leading guard pages (i.e. |ptr| will never point to the + // Note, if |ptr| is in the normal bucket pool, |ptr-1| will not fall out of + // it, thanks to the leading guard pages (i.e. |ptr| will never point to the // beginning of GigaCage). // - // 64-bit systems don't have this problem, because there is only one BRP - // pool region, positioned *after* the non-BRP pool. - bool is_in_brp_pool = true; + // 64-bit systems don't have this problem, because there is only one normal + // bucket pool region, positioned after the direct map pool. + bool is_in_normal_buckets = true; #if !(defined(ARCH_CPU_64_BITS) && !defined(OS_NACL)) auto* adjusted_ptr = reinterpret_cast<char*>(ptr) - 1; - is_in_brp_pool &= IsManagedByPartitionAllocBRPPool(adjusted_ptr); + is_in_normal_buckets &= + IsManagedByPartitionAllocNormalBuckets(adjusted_ptr); #endif // This covers the nullptr case, as address 0 is never in GigaCage. - is_in_brp_pool &= IsManagedByPartitionAllocBRPPool(ptr); - return is_in_brp_pool; + is_in_normal_buckets &= IsManagedByPartitionAllocNormalBuckets(ptr); + return is_in_normal_buckets; } // Wraps a pointer, and returns its uintptr_t representation. @@ -213,7 +214,7 @@ // We've evaluated several strategies (inline nothing, various parts, or // everything in |Wrap()| and |Release()|) using the Speedometer2 benchmark // to measure performance. The best results were obtained when only the - // lightweight |IsManagedByPartitionAllocBRPPool()| check was inlined. + // lightweight |IsManagedByPartitionAllocNormalBuckets()| check was inlined. // Therefore, we've extracted the rest into the functions below and marked // them as NOINLINE to prevent unintended LTO effects. static BASE_EXPORT NOINLINE void AcquireInternal(void* ptr);
diff --git a/base/message_loop/message_pump_win.cc b/base/message_loop/message_pump_win.cc index ef08004c..d9bc848 100644 --- a/base/message_loop/message_pump_win.cc +++ b/base/message_loop/message_pump_win.cc
@@ -781,9 +781,15 @@ // Save this item for later completed_io_.push_back(item); } else { - TRACE_EVENT2("base,toplevel", "IOHandler::OnIOCompleted", "dest_file", - item.handler->io_handler_location().file_name(), "dest_func", - item.handler->io_handler_location().function_name()); + TRACE_EVENT( + "base,toplevel", "IOHandler::OnIOCompleted", + [&](perfetto::EventContext ctx) { + ctx.event()->set_chrome_message_pump()->set_io_handler_location_iid( + base::trace_event::InternedSourceLocation::Get( + &ctx, base::trace_event::TraceSourceLocation( + item.handler->io_handler_location()))); + }); + item.handler->OnIOCompleted(item.context, item.bytes_transfered, item.error); }
diff --git a/base/threading/sequence_bound.h b/base/threading/sequence_bound.h index a30e254..c1690fa6 100644 --- a/base/threading/sequence_bound.h +++ b/base/threading/sequence_bound.h
@@ -200,18 +200,6 @@ return AsyncCallBuilder<R (T::*)(Args...) const>(this, &location, method); } - // Post a call to `method` to `impl_task_runner_`. - // TODO(dcheng): Deprecate this in favor of `AsyncCall()`. - template <typename... MethodArgs, typename... Args> - void Post(const base::Location& from_here, - void (T::*method)(MethodArgs...), - Args&&... args) const { - DCHECK(t_); - impl_task_runner_->PostTask(from_here, - base::BindOnce(method, base::Unretained(t_), - std::forward<Args>(args)...)); - } - // Posts `task` to `impl_task_runner_`, passing it a reference to the wrapped // object. This allows arbitrary logic to be safely executed on the object's // task runner. The object is guaranteed to remain alive for the duration of
diff --git a/base/threading/sequence_bound_unittest.cc b/base/threading/sequence_bound_unittest.cc index f907458..8fd4f6fdf 100644 --- a/base/threading/sequence_bound_unittest.cc +++ b/base/threading/sequence_bound_unittest.cc
@@ -107,12 +107,12 @@ }; #if defined(OS_IOS) && !TARGET_OS_SIMULATOR -#define MAYBE_ConstructThenPostThenReset FLAKY_ConstructThenPostThenReset +#define MAYBE_ConstructAsyncCallReset FLAKY_ConstructAsyncCallReset #else -#define MAYBE_ConstructThenPostThenReset ConstructThenPostThenReset +#define MAYBE_ConstructAsyncCallReset ConstructAsyncCallReset #endif // https://crbug.com/899779 tracks test flakiness on iOS. -TEST_F(SequenceBoundTest, MAYBE_ConstructThenPostThenReset) { +TEST_F(SequenceBoundTest, MAYBE_ConstructAsyncCallReset) { auto derived = SequenceBound<Derived>(task_runner_, &value_); EXPECT_FALSE(derived.is_null()); EXPECT_TRUE(derived); @@ -123,7 +123,7 @@ EXPECT_EQ(value_, kDerivedCtorValue); // Post now that the object has been constructed. - derived.Post(FROM_HERE, &Derived::SetValue, kDifferentValue); + derived.AsyncCall(&Derived::SetValue).WithArgs(kDifferentValue); EXPECT_EQ(value_, kDerivedCtorValue); base::RunLoop().RunUntilIdle(); EXPECT_EQ(value_, kDifferentValue); @@ -142,7 +142,7 @@ // Construct an object and post a message to it, before construction has been // run on |task_runner_|. auto derived = SequenceBound<Derived>(task_runner_, &value_); - derived.Post(FROM_HERE, &Derived::SetValue, kDifferentValue); + derived.AsyncCall(&Derived::SetValue).WithArgs(kDifferentValue); EXPECT_EQ(value_, kInitialValue); // Both construction and SetValue should run. base::RunLoop().RunUntilIdle(); @@ -294,7 +294,7 @@ // Cast to Other, the left base. SequenceBound<Other> other(std::move(mderived)); - other.Post(FROM_HERE, &Other::SetValue, kDifferentValue); + other.AsyncCall(&Other::SetValue).WithArgs(kDifferentValue); base::RunLoop().RunUntilIdle(); @@ -313,7 +313,7 @@ SequenceBound<MultiplyDerived>(task_runner_, &value1, &value2); SequenceBound<Derived> derived(std::move(mderived)); - derived.Post(FROM_HERE, &Derived::SetValue, kDifferentValue); + derived.AsyncCall(&Derived::SetValue).WithArgs(kDifferentValue); base::RunLoop().RunUntilIdle(); @@ -349,7 +349,7 @@ Value* value_ptr = &value; SequenceBound<Derived> derived(task_runner_, value_ptr); { - derived.Post(FROM_HERE, &Derived::SetValue, kDifferentValue); + derived.AsyncCall(&Derived::SetValue).WithArgs(kDifferentValue); base::RunLoop run_loop; task_runner_->PostTask(FROM_HERE, run_loop.QuitClosure()); run_loop.Run(); @@ -390,8 +390,8 @@ // Verify that the callback passed to ResetWithCallbackAfterDestruction always // does happen *after* destruction. bool destroyed = false; - value.Post(FROM_HERE, &BoxedValue::set_destruction_callback, - base::BindLambdaForTesting([&] { destroyed = true; })); + value.AsyncCall(&BoxedValue::set_destruction_callback) + .WithArgs(base::BindLambdaForTesting([&] { destroyed = true; })); base::RunLoop loop; value.ResetWithCallbackAfterDestruction(base::BindLambdaForTesting([&] {
diff --git a/base/threading/thread_restrictions.h b/base/threading/thread_restrictions.h index cc4c9bd4..ce16488c 100644 --- a/base/threading/thread_restrictions.h +++ b/base/threading/thread_restrictions.h
@@ -98,11 +98,15 @@ // that's okay. class BrowserProcessImpl; +class ChromeJsErrorReportProcessor; class ChromeNSSCryptoModuleDelegate; class HistogramSynchronizer; class KeyStorageLinux; class NativeBackendKWallet; class NativeDesktopMediaList; +class Profile; + +Profile* GetLastProfileMac(); namespace android_webview { class AwFormDatabaseService; @@ -419,6 +423,7 @@ friend class weblayer::WebLayerPathProvider; friend bool PathProviderWin(int, FilePath*); + friend Profile* ::GetLastProfileMac(); // crbug.com/1176734 ScopedAllowBlocking(const Location& from_here = Location::Current()); ~ScopedAllowBlocking(); @@ -467,6 +472,7 @@ friend class blink::scheduler::WorkerThread; friend class chrome_cleaner::ResetShortcutsComponent; friend class chrome_cleaner::SystemReportComponent; + friend class ::ChromeJsErrorReportProcessor; friend class content::BrowserMainLoop; friend class content::BrowserProcessSubThread; friend class content::ServiceWorkerContextClient;
diff --git a/base/trace_event/base_tracing.h b/base/trace_event/base_tracing.h index ae3c60e7..299d23f 100644 --- a/base/trace_event/base_tracing.h +++ b/base/trace_event/base_tracing.h
@@ -17,6 +17,7 @@ // TODO(crbug/1006541): Switch to perfetto for trace event implementation. #include "base/trace_event/blame_context.h" #include "base/trace_event/heap_profiler.h" +#include "base/trace_event/interned_args_helper.h" #include "base/trace_event/memory_allocator_dump_guid.h" #include "base/trace_event/memory_dump_provider.h" #include "base/trace_event/task_execution_macros.h"
diff --git a/base/trace_event/interned_args_helper.h b/base/trace_event/interned_args_helper.h index f2a1a53..0a18438 100644 --- a/base/trace_event/interned_args_helper.h +++ b/base/trace_event/interned_args_helper.h
@@ -8,6 +8,7 @@ #include "base/base_export.h" #include "base/containers/span.h" #include "base/hash/hash.h" +#include "base/location.h" #include "third_party/perfetto/include/perfetto/tracing/track_event_interned_data_index.h" #include "third_party/perfetto/protos/perfetto/trace/interned_data/interned_data.pbzero.h" @@ -30,6 +31,13 @@ : function_name(function_name), file_name(file_name), line_number(line_number) {} + // Construct a new source location from an existing base::Location, the only + // attributes that are read are |function_name|, |file_name| and + // |line_number|. + explicit TraceSourceLocation(const base::Location& location) + : function_name(location.function_name()), + file_name(location.file_name()), + line_number(location.line_number()) {} bool operator==(const TraceSourceLocation& other) const { return file_name == other.file_name &&
diff --git a/base/trace_event/task_execution_macros.h b/base/trace_event/task_execution_macros.h index 110776b9..104d4798 100644 --- a/base/trace_event/task_execution_macros.h +++ b/base/trace_event/task_execution_macros.h
@@ -18,10 +18,8 @@ TRACE_EVENT("toplevel", run_function, [&](perfetto::EventContext ctx) { \ ctx.event()->set_task_execution()->set_posted_from_iid( \ base::trace_event::InternedSourceLocation::Get( \ - &ctx, base::trace_event::TraceSourceLocation( \ - (task).posted_from.function_name(), \ - (task).posted_from.file_name(), \ - (task).posted_from.line_number()))); \ + &ctx, \ + base::trace_event::TraceSourceLocation((task).posted_from))); \ }); \ TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION INTERNAL_TRACE_EVENT_UID( \ task_event)((task).posted_from.file_name()); \
diff --git a/base/trace_event/typed_macros_unittest.cc b/base/trace_event/typed_macros_unittest.cc index 3c455c3..3140ffdfb 100644 --- a/base/trace_event/typed_macros_unittest.cc +++ b/base/trace_event/typed_macros_unittest.cc
@@ -193,6 +193,15 @@ size_t iid3 = InternedSourceLocation::Get(&ctx, location2); EXPECT_NE(0u, iid3); EXPECT_NE(iid, iid3); + + // Test getting an interned ID directly from a base::Location object, the + // only attributes that are compared are function_name, file_name and + // line_number. + base::Location base_location = + base::Location::Current("TestFunction", "test.cc", 123); + TraceSourceLocation location3(base_location); + size_t iid4 = InternedSourceLocation::Get(&ctx, location3); + EXPECT_EQ(iid, iid4); }); auto serialized_data =
diff --git a/build/android/gyp/proguard.py b/build/android/gyp/proguard.py index 0973e06e..62c2c2d 100755 --- a/build/android/gyp/proguard.py +++ b/build/android/gyp/proguard.py
@@ -489,6 +489,13 @@ third_party/android_sdk/public/build-tools/*/dexdump -d \ out/Release/apks/YourApk.apk > dex.txt """ + stderr + + if 'FragmentActivity' in stderr: + stderr += """ +You may need to update build configs to run FragmentActivityReplacer for +additional targets. See +https://chromium.googlesource.com/chromium/src.git/+/master/docs/ui/android/bytecode_rewriting.md. +""" elif had_unfiltered_items: # Left only with empty headings. All indented items filtered out. stderr = ''
diff --git a/build/android/pylib/local/device/local_device_instrumentation_test_run.py b/build/android/pylib/local/device/local_device_instrumentation_test_run.py index 8bd5a00..be88524 100644 --- a/build/android/pylib/local/device/local_device_instrumentation_test_run.py +++ b/build/android/pylib/local/device/local_device_instrumentation_test_run.py
@@ -1205,6 +1205,9 @@ # We've tried to disable retries in the past with mixed results. # See crbug.com/619055 for historical context and crbug.com/797002 # for ongoing efforts. + if 'Batch' in test['annotations'] and test['annotations']['Batch'][ + 'value'] == 'UnitTests': + return False del test, result return True
diff --git a/build/android/test_wrapper/logdog_wrapper.py b/build/android/test_wrapper/logdog_wrapper.py index fda9f14..fdb3fd3 100755 --- a/build/android/test_wrapper/logdog_wrapper.py +++ b/build/android/test_wrapper/logdog_wrapper.py
@@ -34,11 +34,17 @@ def CommandParser(): # Parses the command line arguments being passed in parser = argparse.ArgumentParser() - parser.add_argument( + wrapped = parser.add_mutually_exclusive_group() + wrapped.add_argument( '--target', - help='The test target to be run. If not set, any extra ' - 'args passed to this script are assumed to be the ' - 'full test command to run.') + help='The test target to be run. If neither target nor script are set,' + ' any extra args passed to this script are assumed to be the' + ' full test command to run.') + wrapped.add_argument( + '--script', + help='The script target to be run. If neither target nor script are set,' + ' any extra args passed to this script are assumed to be the' + ' full test command to run.') parser.add_argument('--logdog-bin-cmd', required=True, help='The logdog bin cmd.') return parser @@ -73,6 +79,9 @@ if args.target: test_cmd = [os.path.join('bin', 'run_%s' % args.target), '-v'] test_cmd += extra_cmd_args + elif args.script: + test_cmd = [args.script] + test_cmd += extra_cmd_args else: test_cmd = extra_cmd_args
diff --git a/build/chromeos/test_runner.py b/build/chromeos/test_runner.py index b6fb649..be0a389be 100755 --- a/build/chromeos/test_runner.py +++ b/build/chromeos/test_runner.py
@@ -740,11 +740,11 @@ test_env = setup_env() if args.deploy_chrome: + # Mounting ash-chrome gives it enough disk space to not need stripping. + cros_run_test_cmd.extend(['--deploy-lacros'] if args.deploy_lacros else + ['--deploy', '--mount', '--nostrip']) + cros_run_test_cmd += [ - '--deploy', - # Mounting ash-chrome gives it enough disk space to not need stripping. - '--mount', - '--nostrip', '--build-dir', os.path.abspath(args.path_to_outdir), ] @@ -861,6 +861,10 @@ action='store_true', help='Will deploy a locally built ash-chrome binary to the device before ' 'running the host-cmd.') + host_cmd_parser.add_argument( + '--deploy-lacros', + action='store_true', + help='Deploy a lacros-chrome instead of ash-chrome.') # GTest args. # TODO(bpastene): Rename 'vm-test' arg to 'gtest'.
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni index ca50d6a2..1d99d52 100644 --- a/build/config/android/internal_rules.gni +++ b/build/config/android/internal_rules.gni
@@ -3937,7 +3937,7 @@ } if (_build_host_jar || _build_device_jar) { - _process_prebuilt_target_name = "${target_name}_process" + _process_prebuilt_target_name = "${target_name}__process" process_java_prebuilt(_process_prebuilt_target_name) { forward_variables_from(invoker, [
diff --git a/build/config/clang/BUILD.gn b/build/config/clang/BUILD.gn index 8ac3166c..21739874 100644 --- a/build/config/clang/BUILD.gn +++ b/build/config/clang/BUILD.gn
@@ -46,9 +46,10 @@ data = [ "$clang_base_path/bin/llvm-symbolizer.exe" ] } else { data = [ "$clang_base_path/bin/llvm-symbolizer" ] - } - if (is_linux) { - # llvm-symbolizer uses libstdc++ from the clang package. - data += [ "$clang_base_path/lib/libstdc++.so.6" ] + + if (!is_apple) { + # llvm-symbolizer uses libstdc++ from the clang package. + data += [ "$clang_base_path/lib/libstdc++.so.6" ] + } } }
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1 index f99a1d4..a88e36b 100644 --- a/build/fuchsia/linux.sdk.sha1 +++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@ -0.20210210.0.1 +0.20210210.1.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1 index f99a1d4..a88e36b 100644 --- a/build/fuchsia/mac.sdk.sha1 +++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@ -0.20210210.0.1 +0.20210210.1.1
diff --git a/build/skia_gold_common/skia_gold_session.py b/build/skia_gold_common/skia_gold_session.py index 7966e40..cb737ec5 100644 --- a/build/skia_gold_common/skia_gold_session.py +++ b/build/skia_gold_common/skia_gold_session.py
@@ -44,7 +44,13 @@ self.local_diff_closest_image = None self.local_diff_diff_image = None - def __init__(self, working_dir, gold_properties, keys_file, corpus, instance): + def __init__(self, + working_dir, + gold_properties, + keys_file, + corpus, + instance, + bucket=None): """Abstract class to handle all aspects of image comparison via Skia Gold. A single SkiaGoldSession is valid for a single instance/corpus/keys_file @@ -59,11 +65,14 @@ configuration the images will be produced on. corpus: The corpus that images that will be compared belong to. instance: The name of the Skia Gold instance to interact with. + bucket: Overrides the formulaic Google Storage bucket name generated by + goldctl """ self._working_dir = working_dir self._gold_properties = gold_properties self._corpus = corpus self._instance = instance + self._bucket = bucket self._triage_link_file = tempfile.NamedTemporaryFile(suffix='.txt', dir=working_dir, delete=False).name @@ -214,6 +223,8 @@ '--commit', self._gold_properties.git_revision, ] + if self._bucket: + init_cmd.extend(['--bucket', self._bucket]) if self._gold_properties.IsTryjobRun(): init_cmd.extend([ '--issue',
diff --git a/build/skia_gold_common/skia_gold_session_manager.py b/build/skia_gold_common/skia_gold_session_manager.py index b1732f4..d4166e1 100644 --- a/build/skia_gold_common/skia_gold_session_manager.py +++ b/build/skia_gold_common/skia_gold_session_manager.py
@@ -24,7 +24,11 @@ self._gold_properties = gold_properties self._sessions = {} - def GetSkiaGoldSession(self, keys_input, corpus=None, instance=None): + def GetSkiaGoldSession(self, + keys_input, + corpus=None, + instance=None, + bucket=None): """Gets a SkiaGoldSession for the given arguments. Lazily creates one if necessary. @@ -36,8 +40,10 @@ file containing JSON to read. corpus: A string containing the corpus the session is for. If None, the corpus will be determined using available information. - instance: The name of the Skia Gold instance to interact with. It None, + instance: The name of the Skia Gold instance to interact with. If None, will use whatever default the subclass sets. + bucket: Overrides the formulaic Google Storage bucket name generated by + goldctl """ instance = instance or self._GetDefaultInstance() keys_dict = _GetKeysAsDict(keys_input) @@ -53,7 +59,7 @@ working_dir = tempfile.mkdtemp(dir=self._working_dir) keys_file = _GetKeysAsJson(keys_input, working_dir) session = self.GetSessionClass()(working_dir, self._gold_properties, - keys_file, corpus, instance) + keys_file, corpus, instance, bucket) self._sessions[instance][corpus][keys_string] = session return session
diff --git a/build/skia_gold_common/skia_gold_session_unittest.py b/build/skia_gold_common/skia_gold_session_unittest.py index 302210e..76c07999 100755 --- a/build/skia_gold_common/skia_gold_session_unittest.py +++ b/build/skia_gold_common/skia_gold_session_unittest.py
@@ -423,13 +423,15 @@ sgp, self._json_keys, 'corpus', - instance='instance') + instance='instance', + bucket='bucket') session.Initialize() call_args = cmd_mock.call_args[0][0] self.assertIn('imgtest', call_args) self.assertIn('init', call_args) self.assertIn('--passfail', call_args) assertArgWith(self, call_args, '--instance', 'instance') + assertArgWith(self, call_args, '--bucket', 'bucket') assertArgWith(self, call_args, '--corpus', 'corpus') # The keys file should have been copied to the working directory. assertArgWith(self, call_args, '--keys-file',
diff --git a/buildtools/DEPS b/buildtools/DEPS index 62f132b..ec68f93 100644 --- a/buildtools/DEPS +++ b/buildtools/DEPS
@@ -20,7 +20,7 @@ 'checkout_reclient': False, # reclient CIPD package version - 'reclient_version': 're_client_version:0.19.3.3b3042c', + 'reclient_version': 're_client_version:0.20.1.c4bbd2f', # When changing these, also update the svn revisions in deps_revisions.gni # TODO(crbug.com/1166332) rename to clang_format_revision.
diff --git a/cc/test/pixel_test.cc b/cc/test/pixel_test.cc index 9aa6819..b440d3b 100644 --- a/cc/test/pixel_test.cc +++ b/cc/test/pixel_test.cc
@@ -29,7 +29,9 @@ #include "components/viz/common/quads/compositor_frame_metadata.h" #include "components/viz/common/resources/bitmap_allocation.h" #include "components/viz/common/resources/shared_bitmap.h" -#include "components/viz/service/display/display_resource_provider.h" +#include "components/viz/service/display/display_resource_provider_gl.h" +#include "components/viz/service/display/display_resource_provider_skia.h" +#include "components/viz/service/display/display_resource_provider_software.h" #include "components/viz/service/display/gl_renderer.h" #include "components/viz/service/display/output_surface_client.h" #include "components/viz/service/display/software_output_device.h" @@ -266,10 +268,6 @@ output_surface_->BindToClient(output_surface_client_.get()); shared_bitmap_manager_ = std::make_unique<viz::TestSharedBitmapManager>(); - resource_provider_ = std::make_unique<viz::DisplayResourceProvider>( - viz::DisplayResourceProvider::kGpu, output_surface_->context_provider(), - shared_bitmap_manager_.get()); - child_context_provider_ = base::MakeRefCounted<viz::TestInProcessContextProvider>( /*enable_gpu_rasterization=*/false, @@ -281,9 +279,12 @@ void PixelTest::SetUpGLRenderer(gfx::SurfaceOrigin output_surface_origin) { SetUpGLWithoutRenderer(output_surface_origin); + auto resource_provider = std::make_unique<viz::DisplayResourceProviderGL>( + output_surface_->context_provider(), shared_bitmap_manager_.get()); renderer_ = std::make_unique<viz::GLRenderer>( &renderer_settings_, &debug_settings_, output_surface_.get(), - resource_provider_.get(), nullptr, base::ThreadTaskRunnerHandle::Get()); + resource_provider.get(), nullptr, base::ThreadTaskRunnerHandle::Get()); + resource_provider_ = std::move(resource_provider); renderer_->Initialize(); renderer_->SetVisible(true); } @@ -303,14 +304,13 @@ output_surface_->BindToClient(output_surface_client_.get()); static_cast<viz::SkiaOutputSurfaceImpl*>(output_surface_.get()) ->SetCapabilitiesForTesting(output_surface_origin); - resource_provider_ = std::make_unique<viz::DisplayResourceProvider>( - viz::DisplayResourceProvider::kGpu, - /*compositor_context_provider=*/nullptr, + auto resource_provider = std::make_unique<viz::DisplayResourceProviderSkia>( /*shared_bitmap_manager=*/nullptr); renderer_ = std::make_unique<viz::SkiaRenderer>( &renderer_settings_, &debug_settings_, output_surface_.get(), - resource_provider_.get(), nullptr, + resource_provider.get(), nullptr, static_cast<viz::SkiaOutputSurface*>(output_surface_.get())); + resource_provider_ = std::move(resource_provider); renderer_->Initialize(); renderer_->SetVisible(true); @@ -346,14 +346,15 @@ std::make_unique<viz::SoftwareOutputDevice>())); output_surface_->BindToClient(output_surface_client_.get()); shared_bitmap_manager_ = std::make_unique<viz::TestSharedBitmapManager>(); - resource_provider_ = std::make_unique<viz::DisplayResourceProvider>( - viz::DisplayResourceProvider::kSoftware, nullptr, - shared_bitmap_manager_.get()); + auto resource_provider = + std::make_unique<viz::DisplayResourceProviderSoftware>( + shared_bitmap_manager_.get()); child_resource_provider_ = std::make_unique<viz::ClientResourceProvider>(); auto renderer = std::make_unique<viz::SoftwareRenderer>( &renderer_settings_, &debug_settings_, output_surface_.get(), - resource_provider_.get(), nullptr); + resource_provider.get(), nullptr); + resource_provider_ = std::move(resource_provider); software_renderer_ = renderer.get(); renderer_ = std::move(renderer); renderer_->Initialize();
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index c40a958..3488232 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -1838,7 +1838,7 @@ } android_assets("${_variant}_locale_pak_assets") { - disable_compression = _is_bundle_module + disable_compression = true renaming_sources = [] renaming_destinations = []
diff --git a/chrome/android/expectations/monochrome_public_bundle.AndroidManifest.expected b/chrome/android/expectations/monochrome_public_bundle.AndroidManifest.expected index 1b632a59..7733ffc 100644 --- a/chrome/android/expectations/monochrome_public_bundle.AndroidManifest.expected +++ b/chrome/android/expectations/monochrome_public_bundle.AndroidManifest.expected
@@ -406,6 +406,15 @@ android:theme="@style/Theme.Chromium.TabbedMode" android:windowSoftInputMode="adjustResize"> </activity> # DIFF-ANCHOR: 9023f153 + <activity # DIFF-ANCHOR: e86e2b49 + android:autoRemoveFromRecents="true" + android:documentLaunchMode="always" + android:excludeFromRecents="true" + android:exported="false" + android:name="org.chromium.chrome.browser.notifications.NotificationIntentInterceptor$TrampolineActivity" + android:noHistory="true" + android:theme="@android:style/Theme.NoDisplay"> + </activity> # DIFF-ANCHOR: e86e2b49 <activity # DIFF-ANCHOR: bec48e1f android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize" android:enabled="false"
diff --git a/chrome/android/expectations/trichrome_chrome_bundle.AndroidManifest.expected b/chrome/android/expectations/trichrome_chrome_bundle.AndroidManifest.expected index 61f7bfa6..24d31898 100644 --- a/chrome/android/expectations/trichrome_chrome_bundle.AndroidManifest.expected +++ b/chrome/android/expectations/trichrome_chrome_bundle.AndroidManifest.expected
@@ -379,6 +379,15 @@ android:theme="@style/Theme.Chromium.TabbedMode" android:windowSoftInputMode="adjustResize"> </activity> # DIFF-ANCHOR: 9023f153 + <activity # DIFF-ANCHOR: e86e2b49 + android:autoRemoveFromRecents="true" + android:documentLaunchMode="always" + android:excludeFromRecents="true" + android:exported="false" + android:name="org.chromium.chrome.browser.notifications.NotificationIntentInterceptor$TrampolineActivity" + android:noHistory="true" + android:theme="@android:style/Theme.NoDisplay"> + </activity> # DIFF-ANCHOR: e86e2b49 <activity # DIFF-ANCHOR: bec48e1f android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize" android:enabled="false"
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/PasswordChangeFixtureSingleRunTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/PasswordChangeFixtureSingleRunTest.java index dbe7e147..01e32ed 100644 --- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/PasswordChangeFixtureSingleRunTest.java +++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/PasswordChangeFixtureSingleRunTest.java
@@ -249,6 +249,26 @@ logPasswordStoreCredentials(mPasswordStoreBridge, "Final password store state"); } + /** + * Runs the password change flow for all credentials in the store and validates the changes. + */ + @Test + @Manual + public void testMultipleCredentials() throws Exception { + for (int run = 0; run < mParameters.getNumRuns(); run++) { + // Maintain a reference to the current set of credentials. + PasswordStoreCredential[] initialCredentials = mCredentials; + // Run password change for all credentials. + for (int i = 0; i < initialCredentials.length; i++) { + // Run and test script. + testSingleRun(initialCredentials[i].getUsername()); + } + Log.i(TAG, "[EVENT: Run #%s succeded]", String.valueOf(run + 1)); + } + + logPasswordStoreCredentials(mPasswordStoreBridge, "Final password store state"); + } + @Override public void onSavedPasswordsChanged(int count) { logPasswordStoreCredentials(
diff --git a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java index e94055e..9850609d 100644 --- a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java +++ b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java
@@ -4,6 +4,7 @@ package org.chromium.chrome.browser.autofill_assistant; +import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Build; @@ -74,15 +75,17 @@ /** * Starts Autofill Assistant. - * @param activity {@link ChromeActivity} the activity on which the Autofill Assistant is being + * @param activity {@link Activity} the activity on which the Autofill Assistant is being * started. * @param bundleExtras {@link Bundle} the extras which were used to start the Autofill * Assistant. * @param initialUrl the initial URL the Autofill Assistant should be started on. */ - public static void start( - ChromeActivity activity, @Nullable Bundle bundleExtras, String initialUrl) { - start(activity, + public static void start(Activity activity, @Nullable Bundle bundleExtras, String initialUrl) { + // TODO(crbug.com/1155809): Remove ChromeActivity reference. + assert activity instanceof ChromeActivity; + ChromeActivity chromeActivity = (ChromeActivity) activity; + start(chromeActivity, AutofillAssistantArguments.newBuilder() .fromBundle(bundleExtras) .withInitialUrl(initialUrl)
diff --git a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java index 333f689..b56b59e 100644 --- a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java +++ b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java
@@ -46,6 +46,8 @@ import android.widget.ImageView; import androidx.recyclerview.widget.RecyclerView; +import androidx.test.espresso.UiController; +import androidx.test.espresso.ViewAction; import androidx.test.espresso.contrib.RecyclerViewActions; import androidx.test.espresso.matcher.BoundedMatcher; import androidx.test.filters.SmallTest; @@ -126,6 +128,8 @@ import org.chromium.chrome.test.util.browser.Features; import org.chromium.chrome.test.util.browser.Features.DisableFeatures; import org.chromium.chrome.test.util.browser.Features.EnableFeatures; +import org.chromium.chrome.test.util.browser.suggestions.SuggestionsDependenciesRule; +import org.chromium.chrome.test.util.browser.suggestions.mostvisited.FakeMostVisitedSites; import org.chromium.components.user_prefs.UserPrefs; import org.chromium.content_public.browser.test.util.TestThreadUtils; import org.chromium.content_public.browser.test.util.TestTouchUtils; @@ -171,6 +175,9 @@ @Rule public ErrorCollector collector = new ErrorCollector(); + @Rule + public SuggestionsDependenciesRule mSuggestionsDeps = new SuggestionsDependenciesRule(); + /** * Parameter set controlling whether Feed v2 is enabled. */ @@ -680,7 +687,7 @@ CriteriaHelper.pollUiThread(() -> allCardsHaveThumbnail(recyclerView)); // TODO(crbug.com/1065314): Tab group cards should not have favicons. mRenderTestRule.render(mActivityTestRule.getActivity().findViewById(R.id.tab_list_view), - "tabSwitcher_tabGroups"); + "tabSwitcher_tabGroups_aspect_ratio_point85"); // Resume native initialization and make sure the GTS looks the same. startAndWaitNativeInitialization(); @@ -1123,18 +1130,7 @@ "/exclude_mv_tiles/false"}) public void renderSingleAsHomepage_MVTiles() throws IOException, InterruptedException { // clang-format on - // Get old file and ensure to delete it. - File oldFile = MostVisitedSitesMetadataUtils.getOrCreateTopSitesDirectory(); - Assert.assertTrue(oldFile.delete() && !oldFile.exists()); - - // Save suggestion lists to file. - final CountDownLatch latch = new CountDownLatch(1); - MostVisitedSitesMetadataUtils.saveSuggestionListsToFile( - createFakeSiteSuggestionTiles(), latch::countDown); - - // Wait util the file has been saved. - latch.await(); - + saveSiteSuggestionTilesToFile(); startMainActivityFromLauncher(); CriteriaHelper.pollUiThread( () -> mActivityTestRule.getActivity().getLayoutManager().overviewVisible()); @@ -1145,7 +1141,7 @@ ViewUtils.onViewWaiting( allOf(withId(R.id.tile_view_title), withText("0 TOP_SITES"), isDisplayed())); ChromeRenderTestRule.sanitize(surface); - mRenderTestRule.render(surface, "singlePane_MV"); + mRenderTestRule.render(surface, "singlePane_MV_withTopSitesView"); } @Test @@ -1213,6 +1209,63 @@ }); } + @Test + @SmallTest + @Restriction({UiRestriction.RESTRICTION_TYPE_PHONE}) + // clang-format off + @EnableFeatures({ChromeFeatureList.TAB_SWITCHER_ON_RETURN + "<Study,", + ChromeFeatureList.START_SURFACE_ANDROID + "<Study", ChromeFeatureList.EXPLORE_SITES}) + @CommandLineFlags.Add({ChromeSwitches.DISABLE_NATIVE_INITIALIZATION, + "force-fieldtrials=Study/Group", + IMMEDIATE_RETURN_PARAMS + + "/start_surface_variation/single/exclude_mv_tiles/false"}) + public void testExploreTopSites() throws InterruptedException { + // clang-format on + // When showing MV tiles pre-native, explore top sites view is already rendered with a + // non-null icon. This test is for ensuring explore top sites view is built and clickable + // after native initialization. + saveSiteSuggestionTilesToFile(); + + FakeMostVisitedSites mostVisitedSites = new FakeMostVisitedSites(); + mostVisitedSites.setTileSuggestions(createFakeSiteSuggestions()); + mSuggestionsDeps.getFactory().mostVisitedSites = mostVisitedSites; + + startMainActivityFromLauncher(); + CriteriaHelper.pollUiThread( + () -> mActivityTestRule.getActivity().getLayoutManager().overviewVisible()); + + // Initializes native. + startAndWaitNativeInitialization(); + + waitForTabModel(); + assertEquals(0, + mActivityTestRule.getActivity().getTabModelSelector().getCurrentModel().getCount()); + + OverviewModeBehaviorWatcher hideWatcher = + TabUiTestHelper.createOverviewHideWatcher(mActivityTestRule.getActivity()); + onViewWaiting(withId(org.chromium.chrome.tab_ui.R.id.mv_tiles_layout)) + .perform(new ViewAction() { + @Override + public Matcher<View> getConstraints() { + return isDisplayed(); + } + + @Override + public String getDescription() { + return "Click explore top sites view in MV tiles."; + } + + @Override + public void perform(UiController uiController, View view) { + ViewGroup mvTilesContainer = (ViewGroup) view; + mvTilesContainer.getChildAt(1).performClick(); + } + }); + hideWatcher.waitForBehavior(); + assertEquals(1, + mActivityTestRule.getActivity().getTabModelSelector().getCurrentModel().getCount()); + } + /** * Toggles the header and checks whether the header has the right status. * @@ -1273,17 +1326,38 @@ } private static List<Tile> createFakeSiteSuggestionTiles() { + List<SiteSuggestion> siteSuggestions = createFakeSiteSuggestions(); List<Tile> suggestionTiles = new ArrayList<>(); - SiteSuggestion data = new SiteSuggestion("0 TOP_SITES", new GURL("https://www.foo.com"), "", - TileTitleSource.TITLE_TAG, TileSource.TOP_SITES, TileSectionType.PERSONALIZED, - new Date()); - suggestionTiles.add(new Tile(data, 0)); - - data = new SiteSuggestion("1 ALLOWLIST", new GURL("https://www.bar.com"), "", - TileTitleSource.UNKNOWN, TileSource.ALLOWLIST, TileSectionType.PERSONALIZED, - new Date()); - suggestionTiles.add(new Tile(data, 1)); - + for (int i = 0; i < siteSuggestions.size(); i++) { + suggestionTiles.add(new Tile(siteSuggestions.get(i), i)); + } return suggestionTiles; } + + private static List<SiteSuggestion> createFakeSiteSuggestions() { + List<SiteSuggestion> siteSuggestions = new ArrayList<>(); + siteSuggestions.add(new SiteSuggestion("0 TOP_SITES", new GURL("https://www.foo.com"), "", + TileTitleSource.TITLE_TAG, TileSource.TOP_SITES, TileSectionType.PERSONALIZED, + new Date())); + + siteSuggestions.add(new SiteSuggestion("1 ALLOWLIST", new GURL("https://www.bar.com"), "", + TileTitleSource.UNKNOWN, TileSource.EXPLORE, TileSectionType.PERSONALIZED, + new Date())); + + return siteSuggestions; + } + + private static void saveSiteSuggestionTilesToFile() throws InterruptedException { + // Get old file and ensure to delete it. + File oldFile = MostVisitedSitesMetadataUtils.getOrCreateTopSitesDirectory(); + Assert.assertTrue(oldFile.delete() && !oldFile.exists()); + + // Save suggestion lists to file. + final CountDownLatch latch = new CountDownLatch(1); + MostVisitedSitesMetadataUtils.saveSuggestionListsToFile( + createFakeSiteSuggestionTiles(), latch::countDown); + + // Wait util the file has been saved. + latch.await(); + } }
diff --git a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutTest.java b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutTest.java index 98a80dc..0ce8c3aa 100644 --- a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutTest.java +++ b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutTest.java
@@ -182,7 +182,7 @@ @Rule public ChromeRenderTestRule mRenderTestRule = - ChromeRenderTestRule.Builder.withPublicCorpus().build(); + ChromeRenderTestRule.Builder.withPublicCorpus().setRevision(1).build(); @SuppressWarnings("FieldCanBeLocal") private EmbeddedTestServer mTestServer; @@ -731,7 +731,6 @@ @DisableIf.Build(sdk_is_less_than = Build.VERSION_CODES.M, message = "https://crbug.com/1023833") public void testIncognitoToggle_thumbnailFetchCount() throws InterruptedException { - mActivityTestRule.loadUrl(mUrl); ChromeTabbedActivity cta = mActivityTestRule.getActivity(); int oldFetchCount = mTabListDelegate.getBitmapFetchCountForTesting(); @@ -820,7 +819,8 @@ @EnableFeatures(ChromeFeatureList.CLOSE_TAB_SUGGESTIONS + "<Study") // clang-format off @CommandLineFlags.Add({BASE_PARAMS + "/baseline_tab_suggestions/true" + - "/baseline_close_tab_suggestions/true/min_time_between_prefetches/0"}) + "/baseline_close_tab_suggestions/true/min_time_between_prefetches/0/" + + "thumbnail_aspect_ratio/1.0"}) public void testTabSuggestionMessageCard_dismiss() throws InterruptedException { // clang-format on prepareTabs(3, 0, null); @@ -850,7 +850,8 @@ @EnableFeatures(ChromeFeatureList.CLOSE_TAB_SUGGESTIONS + "<Study") // clang-format off @CommandLineFlags.Add({BASE_PARAMS + "/baseline_tab_suggestions/true" + - "/baseline_close_tab_suggestions/true/min_time_between_prefetches/0"}) + "/baseline_close_tab_suggestions/true/min_time_between_prefetches/0" + + "/thumbnail_aspect_ratio/1.0"}) public void testTabSuggestionMessageCard_review() throws InterruptedException { // clang-format on prepareTabs(3, 0, null); @@ -880,7 +881,8 @@ @EnableFeatures({ChromeFeatureList.CLOSE_TAB_SUGGESTIONS + "<Study"}) // clang-format off @CommandLineFlags.Add({BASE_PARAMS + "/baseline_tab_suggestions/true" + - "/baseline_close_tab_suggestions/true/min_time_between_prefetches/0"}) + "/baseline_close_tab_suggestions/true/min_time_between_prefetches/0/" + + "thumbnail_aspect_ratio/1.0"}) public void testShowOnlyOneTabSuggestionMessageCard_withSoftCleanup() throws InterruptedException { // clang-format on @@ -893,7 +895,8 @@ @EnableFeatures({ChromeFeatureList.CLOSE_TAB_SUGGESTIONS + "<Study"}) // clang-format off @CommandLineFlags.Add({BASE_PARAMS + "/baseline_tab_suggestions/true" + - "/baseline_close_tab_suggestions/true/min_time_between_prefetches/0"}) + "/baseline_close_tab_suggestions/true/min_time_between_prefetches/0/" + + "thumbnail_aspect_ratio/1.0"}) public void testShowOnlyOneTabSuggestionMessageCard_withHardCleanup() throws InterruptedException { // clang-format on @@ -906,7 +909,8 @@ @EnableFeatures({ChromeFeatureList.CLOSE_TAB_SUGGESTIONS + "<Study"}) // clang-format off @CommandLineFlags.Add({BASE_PARAMS + "/baseline_tab_suggestions/true" + - "/baseline_close_tab_suggestions/true/min_time_between_prefetches/0"}) + "/baseline_close_tab_suggestions/true/min_time_between_prefetches/0/" + + "thumbnail_aspect_ratio/1.0"}) public void testTabSuggestionMessageCardDismissAfterTabClosing() throws InterruptedException { // clang-format on prepareTabs(3, 0, mUrl); @@ -992,7 +996,8 @@ @EnableFeatures(ChromeFeatureList.CLOSE_TAB_SUGGESTIONS + "<Study") // clang-format off @CommandLineFlags.Add({BASE_PARAMS + "/baseline_tab_suggestions/true" + - "/baseline_close_tab_suggestions/true/min_time_between_prefetches/0"}) + "/baseline_close_tab_suggestions/true/min_time_between_prefetches/0/" + + "thumbnail_aspect_ratio/1.0"}) public void testTabSuggestionMessageCard_orientation() throws InterruptedException { // clang-format on ChromeTabbedActivity cta = mActivityTestRule.getActivity(); @@ -1326,8 +1331,8 @@ @Feature({"RenderTest"}) // clang-format off @EnableFeatures({ChromeFeatureList.TAB_GROUPS_ANDROID}) - @CommandLineFlags.Add({BASE_PARAMS + "/thumbnail_aspect_ratio/0.85"}) - public void testRenderGrid_withAspectRatioPoint85() throws IOException { + @CommandLineFlags.Add({BASE_PARAMS + "/thumbnail_aspect_ratio/1.0"}) + public void testRenderGrid_withAspectRatioOfOne() throws IOException { // clang-format on ChromeTabbedActivity cta = mActivityTestRule.getActivity(); prepareTabs(3, 0, "about:blank"); @@ -1337,7 +1342,7 @@ createTabGroup(cta, false, tabGroup); // Make sure all tabs have thumbnail. enterGTSWithThumbnailRetry(); - mRenderTestRule.render(cta.findViewById(R.id.tab_list_view), "aspect_ratio_point_85"); + mRenderTestRule.render(cta.findViewById(R.id.tab_list_view), "aspect_ratio_of_one"); } @Test @@ -1804,12 +1809,14 @@ @Test @MediumTest + @Feature("TabSuggestion") // clang-format off @EnableFeatures({ChromeFeatureList.TAB_GROUPS_ANDROID, ChromeFeatureList.CLOSE_TAB_SUGGESTIONS + "<Study"}) @DisableFeatures(ChromeFeatureList.TAB_TO_GTS_ANIMATION + "<Study") @CommandLineFlags.Add({BASE_PARAMS + "/baseline_tab_suggestions/true" + - "/baseline_close_tab_suggestions/true/min_time_between_prefetches/0"}) + "/baseline_close_tab_suggestions/true/min_time_between_prefetches/0" + + "/thumbnail_aspect_ratio/1.0"}) public void testTabGroupManualSelection_AfterReviewTabSuggestion() throws InterruptedException { // clang-format on ChromeTabbedActivity cta = mActivityTestRule.getActivity();
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/MostVisitedListCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/MostVisitedListCoordinator.java index 64f9067..aff0fd4 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/MostVisitedListCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/MostVisitedListCoordinator.java
@@ -8,6 +8,7 @@ import android.view.View; import android.view.ViewGroup; +import org.chromium.base.Log; import org.chromium.base.supplier.Supplier; import org.chromium.chrome.browser.app.ChromeActivity; import org.chromium.chrome.browser.offlinepages.OfflinePageBridge; @@ -45,6 +46,7 @@ * TODO(mattsimmons): Move logic and view manipulation into the mediator/viewbinder. (and add tests) */ class MostVisitedListCoordinator implements TileGroup.Observer, TileGroup.TileSetupDelegate { + private static final String TAG = "TopSites"; private static final int TITLE_LINES = 1; // There's a limit of 12 in {@link MostVisitedSitesBridge#setObserver}. @@ -83,7 +85,7 @@ mRenderer.renderTileSection(tiles, mParent, this); } } catch (IOException e) { - e.printStackTrace(); + Log.i(TAG, "No cached MV tiles file."); } } }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/PriceWelcomeMessageService.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/PriceWelcomeMessageService.java index 3c18079..268b4ab8 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/PriceWelcomeMessageService.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/PriceWelcomeMessageService.java
@@ -47,13 +47,6 @@ */ public interface PriceWelcomeMessageProvider { /** - * This method gets the information of the first tab showing price card. - * - * @return The PriceTabData including the tab ID and the price drop. - */ - PriceTabData getFirstTabShowingPriceCard(); - - /** * This method gets the tab index from tab ID. * * @param tabId The tab ID to search for. @@ -75,11 +68,11 @@ */ public interface PriceWelcomeMessageReviewActionProvider { /** - * This method scrolls to the binding tab of the PriceWelcomeMessage. + * This method scrolls to the tab at given index. * - * @param tabIndex The index of the {@link Tab} that is binding to PriceWelcomeMessage. + * @param tabIndex The index of the {@link Tab} which we will scroll to. */ - void scrollToBindingTab(int tabIndex); + void scrollToTab(int tabIndex); } /** @@ -144,13 +137,8 @@ mPriceWelcomeMessageReviewActionProvider = priceWelcomeMessageReviewActionProvider; } - void preparePriceMessage() { - if (PriceTrackingUtilities.isPriceWelcomeMessageCardDisabled()) return; - PriceTabData priceTabData = mPriceWelcomeMessageProvider.getFirstTabShowingPriceCard(); - if (priceTabData == null) { - invalidateMessage(); - return; - } + void preparePriceMessage(PriceTabData priceTabData) { + assert priceTabData != null; PriceTrackingUtilities.increasePriceWelcomeMessageCardShowCount(); if (PriceTrackingUtilities.getPriceWelcomeMessageCardShowCount() > MAX_PRICE_WELCOME_MESSAGE_SHOW_COUNT @@ -180,14 +168,16 @@ assert mPriceTabData != null; int bindingTabIndex = mPriceWelcomeMessageProvider.getTabIndexFromTabId(mPriceTabData.bindingTabId); - mPriceWelcomeMessageReviewActionProvider.scrollToBindingTab(bindingTabIndex); + mPriceWelcomeMessageReviewActionProvider.scrollToTab(bindingTabIndex); mPriceWelcomeMessageProvider.showPriceDropTooltip(bindingTabIndex); PriceTrackingUtilities.disablePriceWelcomeMessageCard(); + mPriceTabData = null; } @VisibleForTesting public void dismiss() { PriceTrackingUtilities.disablePriceWelcomeMessageCard(); + mPriceTabData = null; } @VisibleForTesting
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogCoordinator.java index bc45ef7..02f127c 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogCoordinator.java
@@ -82,7 +82,7 @@ : TabListCoordinator.TabListMode.GRID, context, tabModelSelector, tabContentManager::getTabThumbnailWithCallback, null, false, gridCardOnClickListenerProvider, mMediator.getTabGridDialogHandler(), - TabProperties.UiType.CLOSABLE, null, containerView, false, mComponentName); + TabProperties.UiType.CLOSABLE, null, null, containerView, false, mComponentName); TabListRecyclerView recyclerView = mTabListCoordinator.getContainerView(); TabGroupUiToolbarView toolbarView =
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridViewBinder.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridViewBinder.java index a49a25e..c61dae8d 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridViewBinder.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridViewBinder.java
@@ -226,20 +226,15 @@ if (shoppingPersistedTabData == null || shoppingPersistedTabData.getPriceDrop() == null) { priceCardView.setVisibility(View.GONE); - model.set(TabProperties.PRICE_DROP, null); } else { priceCardView.setPriceStrings( shoppingPersistedTabData.getPriceDrop().price, shoppingPersistedTabData.getPriceDrop().previousPrice); priceCardView.setVisibility(View.VISIBLE); - model.set(TabProperties.PRICE_DROP, - shoppingPersistedTabData.getPriceDrop()); } }); } else { priceCardView.setVisibility(View.GONE); - // TODO(crbug.com/1157578): Update the model in mediator. - model.set(TabProperties.PRICE_DROP, null); } } else if (TabProperties.SHOULD_SHOW_PRICE_DROP_TOOLTIP == propertyKey) { if (model.get(TabProperties.SHOULD_SHOW_PRICE_DROP_TOOLTIP)) {
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiCoordinator.java index ea05d9d..acbc104 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiCoordinator.java
@@ -102,7 +102,8 @@ boolean actionOnAllRelatedTabs = TabUiFeatureUtilities.isConditionalTabStripEnabled(); mTabStripCoordinator = new TabListCoordinator(TabListCoordinator.TabListMode.STRIP, mContext, tabModelSelector, null, null, actionOnAllRelatedTabs, null, null, - TabProperties.UiType.STRIP, null, mTabListContainerView, true, COMPONENT_NAME); + TabProperties.UiType.STRIP, null, null, mTabListContainerView, true, + COMPONENT_NAME); mTabStripCoordinator.initWithNative( mActivity.getCompositorViewHolder().getDynamicResourceLoader());
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListCoordinator.java index 8a19869..d6c02fd 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListCoordinator.java
@@ -30,7 +30,6 @@ import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tasks.pseudotab.PseudoTab; -import org.chromium.chrome.browser.tasks.tab_management.PriceWelcomeMessageService.PriceTabData; import org.chromium.chrome.browser.tasks.tab_management.TabProperties.UiType; import org.chromium.chrome.features.start_surface.StartSurfaceConfiguration; import org.chromium.chrome.tab_ui.R; @@ -100,6 +99,7 @@ * @param itemType The item type to put in the list of tabs. * @param selectionDelegateProvider Provider to provide selected Tabs for a selectable tab list. * It's NULL when selection is not possible. + * @param priceWelcomeMessageController A controller to show PriceWelcomeMessage. * @param parentView {@link ViewGroup} The root view of the UI. * @param attachToParent Whether the UI should attach to root view. * @param componentName A unique string uses to identify different components for UMA recording. @@ -113,6 +113,8 @@ .GridCardOnClickListenerProvider gridCardOnClickListenerProvider, @Nullable TabListMediator.TabGridDialogHandler dialogHandler, @UiType int itemType, @Nullable TabListMediator.SelectionDelegateProvider selectionDelegateProvider, + @Nullable TabSwitcherMediator + .PriceWelcomeMessageController priceWelcomeMessageController, @NonNull ViewGroup parentView, boolean attachToParent, String componentName) { mMode = mode; mItemType = itemType; @@ -241,7 +243,7 @@ mMediator = new TabListMediator(context, mModel, mMode, tabModelSelector, thumbnailProvider, titleProvider, tabListFaviconProvider, actionOnRelatedTabs, selectionDelegateProvider, gridCardOnClickListenerProvider, dialogHandler, - componentName, itemType); + priceWelcomeMessageController, componentName, itemType); if (mMode == TabListMode.GRID) { GridLayoutManager gridLayoutManager = @@ -456,11 +458,6 @@ // PriceWelcomeMessageService.PriceWelcomeMessageProvider implementation. @Override - public PriceTabData getFirstTabShowingPriceCard() { - return mModel.getFirstTabShowingPriceCard(); - } - - @Override public int getTabIndexFromTabId(int tabId) { return mModel.indexFromId(tabId); }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java index f3d15cf..36e51b6 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java
@@ -61,8 +61,10 @@ import org.chromium.chrome.browser.tasks.tab_groups.EmptyTabGroupModelFilterObserver; import org.chromium.chrome.browser.tasks.tab_groups.TabGroupModelFilter; import org.chromium.chrome.browser.tasks.tab_groups.TabGroupUtils; +import org.chromium.chrome.browser.tasks.tab_management.PriceWelcomeMessageService.PriceTabData; import org.chromium.chrome.browser.tasks.tab_management.TabListCoordinator.TabListMode; import org.chromium.chrome.browser.tasks.tab_management.TabProperties.UiType; +import org.chromium.chrome.browser.tasks.tab_management.TabSwitcherMediator.PriceWelcomeMessageController; import org.chromium.chrome.tab_ui.R; import org.chromium.components.browser_ui.widget.selectable_list.SelectionDelegate; import org.chromium.components.embedder_support.util.UrlUtilities; @@ -171,12 +173,20 @@ */ static class ShoppingPersistedTabDataFetcher { protected Tab mTab; + protected TabListModel mModel; + protected PriceWelcomeMessageController mPriceWelcomeMessageController; /** - * @param tab {@link Tab} {@link ShoppingPersistedTabData} will be acquired for + * @param tab {@link Tab} {@link ShoppingPersistedTabData} will be acquired for. + * @param model {@link TabListModel} to check if we already have the price welcome message + * in the model. + * @param priceWelcomeMessageController to show the price welcome message. */ - ShoppingPersistedTabDataFetcher(Tab tab) { + ShoppingPersistedTabDataFetcher(Tab tab, @Nullable TabListModel model, + @Nullable PriceWelcomeMessageController priceWelcomeMessageController) { mTab = tab; + mModel = model; + mPriceWelcomeMessageController = priceWelcomeMessageController; } /** @@ -184,7 +194,29 @@ * @param callback {@link Callback} to pass {@link ShoppingPersistedTabData} back in */ public void fetch(Callback<ShoppingPersistedTabData> callback) { - ShoppingPersistedTabData.from(mTab, (res) -> { callback.onResult(res); }); + ShoppingPersistedTabData.from(mTab, (res) -> { + callback.onResult(res); + maybeShowPriceWelcomeMessage(res); + }); + } + + @VisibleForTesting + void maybeShowPriceWelcomeMessage( + @Nullable ShoppingPersistedTabData shoppingPersistedTabData) { + // Avoid inserting message while RecyclerView is computing a layout. + new Handler().post(() -> { + if (PriceTrackingUtilities.isPriceWelcomeMessageCardDisabled() || (mModel == null) + || (mPriceWelcomeMessageController == null) + || (shoppingPersistedTabData == null) + || (shoppingPersistedTabData.getPriceDrop() == null) + || (mModel.lastIndexForMessageItemFromType( + MessageService.MessageType.PRICE_WELCOME) + != TabModel.INVALID_TAB_INDEX)) { + return; + } + mPriceWelcomeMessageController.showPriceWelcomeMessage( + new PriceTabData(mTab.getId(), shoppingPersistedTabData.getPriceDrop())); + }); } } @@ -291,6 +323,7 @@ private final TabGridDialogHandler mTabGridDialogHandler; private final String mComponentName; private final TabListFaviconProvider mTabListFaviconProvider; + private final PriceWelcomeMessageController mPriceWelcomeMessageController; private ThumbnailProvider mThumbnailProvider; private boolean mActionsOnAllRelatedTabs; @@ -467,6 +500,7 @@ * @param gridCardOnClickListenerProvider Provides the onClickListener for opening dialog when * click on a grid card. * @param dialogHandler A handler to handle requests about updating TabGridDialog. + * @param priceWelcomeMessageController A controller to show PriceWelcomeMessage. * @param componentName This is a unique string to identify different components. * @param uiType The type of UI this mediator should be building. */ @@ -476,8 +510,9 @@ TabListFaviconProvider tabListFaviconProvider, boolean actionOnRelatedTabs, @Nullable SelectionDelegateProvider selectionDelegateProvider, @Nullable GridCardOnClickListenerProvider gridCardOnClickListenerProvider, - @Nullable TabGridDialogHandler dialogHandler, String componentName, - @UiType int uiType) { + @Nullable TabGridDialogHandler dialogHandler, + @Nullable PriceWelcomeMessageController priceWelcomeMessageController, + String componentName, @UiType int uiType) { mContext = context; mTabModelSelector = tabModelSelector; mThumbnailProvider = thumbnailProvider; @@ -491,6 +526,7 @@ mTabGridDialogHandler = dialogHandler; mActionsOnAllRelatedTabs = actionOnRelatedTabs; mUiType = uiType; + mPriceWelcomeMessageController = priceWelcomeMessageController; mTabModelObserver = new TabModelObserver() { @Override @@ -1116,7 +1152,8 @@ if (mMode == TabListMode.GRID && pseudoTab.hasRealTab() && !pseudoTab.isIncognito() && PriceTrackingUtilities.isTrackPricesOnTabsEnabled()) { mModel.get(index).model.set(TabProperties.SHOPPING_PERSISTED_TAB_DATA_FETCHER, - new ShoppingPersistedTabDataFetcher(pseudoTab.getTab())); + new ShoppingPersistedTabDataFetcher( + pseudoTab.getTab(), mModel, mPriceWelcomeMessageController)); } else { mModel.get(index).model.set(TabProperties.SHOPPING_PERSISTED_TAB_DATA_FETCHER, null); } @@ -1331,7 +1368,6 @@ .with(TabProperties.TABSTRIP_FAVICON_BACKGROUND_COLOR_ID, tabstripFaviconBackgroundDrawableId) .with(TabProperties.ACCESSIBILITY_DELEGATE, mAccessibilityDelegate) - .with(TabProperties.PRICE_DROP, null) .with(TabProperties.SHOULD_SHOW_PRICE_DROP_TOOLTIP, false) .with(CARD_TYPE, TAB) .build(); @@ -1649,7 +1685,8 @@ int getPriceWelcomeMessageInsertionIndex() { assert mGridLayoutManager != null; int spanCount = mGridLayoutManager.getSpanCount(); - int selectedTabIndex = mModel.getIndexForSelectedTab(); + int selectedTabIndex = mModel.indexOfNthTabCard( + mTabModelSelector.getTabModelFilterProvider().getCurrentTabModelFilter().index()); int indexBelowSelectedTab = (selectedTabIndex / spanCount + 1) * spanCount; int indexAfterLastTab = mModel.getTabIndexBefore(mModel.size()) + 1; return Math.min(indexBelowSelectedTab, indexAfterLastTab);
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListModel.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListModel.java index e230557..2a42b92 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListModel.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListModel.java
@@ -19,7 +19,6 @@ import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tabmodel.TabModel; -import org.chromium.chrome.browser.tasks.tab_management.PriceWelcomeMessageService.PriceTabData; import org.chromium.ui.modelutil.MVCListAdapter; import org.chromium.ui.modelutil.MVCListAdapter.ModelList; import org.chromium.ui.modelutil.PropertyListModel; @@ -131,28 +130,6 @@ } /** - * Get the index of currently selected tab in TabListModel. - * @return The index within the model. - */ - public int getIndexForSelectedTab() { - int selectedTabCount = 0; - int tabCount = 0; - int firstSelectedTabIndex = TabModel.INVALID_TAB_INDEX; - for (int i = size() - 1; i >= 0; i--) { - PropertyModel model = get(i).model; - if (model.get(CARD_TYPE) != TAB) continue; - if (model.get(TabProperties.IS_SELECTED)) { - selectedTabCount++; - firstSelectedTabIndex = i; - } - tabCount++; - } - assert (selectedTabCount == 1 || tabCount == 0) - : "There should be exactly one selected tab or no tabs at all when calling this method"; - return firstSelectedTabIndex; - } - - /** * Get the index that matches a message item that has the given message type. * @param messageType The message type to match. * @return The index within the model. @@ -286,18 +263,4 @@ get(index).model.set(TabProperties.CARD_ANIMATION_STATUS, status); } - - /** - * Get the first tab showing price card. - */ - public PriceTabData getFirstTabShowingPriceCard() { - for (int i = 0; i < size(); i++) { - PropertyModel model = get(i).model; - if ((model.get(CARD_TYPE) == TAB) && (model.get(TabProperties.PRICE_DROP) != null)) { - return new PriceTabData( - model.get(TabProperties.TAB_ID), model.get(TabProperties.PRICE_DROP)); - } - } - return null; - } }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabProperties.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabProperties.java index c27e915..b7a08ca 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabProperties.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabProperties.java
@@ -13,7 +13,6 @@ import androidx.annotation.IntDef; -import org.chromium.chrome.browser.tab.state.ShoppingPersistedTabData; import org.chromium.components.browser_ui.widget.selectable_list.SelectionDelegate; import org.chromium.ui.modelutil.PropertyKey; import org.chromium.ui.modelutil.PropertyModel; @@ -119,10 +118,6 @@ public static final WritableObjectPropertyKey<String> CLOSE_BUTTON_DESCRIPTION_STRING = new WritableObjectPropertyKey<>(); - - public static final WritableObjectPropertyKey<ShoppingPersistedTabData.PriceDrop> PRICE_DROP = - new WritableObjectPropertyKey<>(); - public static final WritableBooleanPropertyKey SHOULD_SHOW_PRICE_DROP_TOOLTIP = new WritableBooleanPropertyKey(); @@ -135,7 +130,7 @@ SELECTABLE_TAB_ACTION_BUTTON_SELECTED_BACKGROUND, URL_DOMAIN, ACCESSIBILITY_DELEGATE, SEARCH_QUERY, PAGE_INFO_LISTENER, PAGE_INFO_ICON_DRAWABLE_ID, CARD_TYPE, CONTENT_DESCRIPTION_STRING, CLOSE_BUTTON_DESCRIPTION_STRING, - SHOPPING_PERSISTED_TAB_DATA_FETCHER, PRICE_DROP, SHOULD_SHOW_PRICE_DROP_TOOLTIP}; + SHOPPING_PERSISTED_TAB_DATA_FETCHER, SHOULD_SHOW_PRICE_DROP_TOOLTIP}; public static final PropertyKey[] ALL_KEYS_TAB_STRIP = new PropertyKey[] {TAB_ID, TAB_SELECTED_LISTENER, TAB_CLOSED_LISTENER, FAVICON,
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorCoordinator.java index e644141..4c6ca72f 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorCoordinator.java
@@ -131,7 +131,7 @@ mTabListCoordinator = new TabListCoordinator(mode, context, mTabModelSelector, tabContentManager::getTabThumbnailWithCallback, null, false, null, null, - TabProperties.UiType.SELECTABLE, this::getSelectionDelegate, + TabProperties.UiType.SELECTABLE, this::getSelectionDelegate, null, mTabSelectionEditorLayout, false, COMPONENT_NAME); // Note: The TabSelectionEditorCoordinator is always created after native is initialized.
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java index 9ff1c51..695ca36 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java
@@ -176,7 +176,7 @@ mTabListCoordinator = new TabListCoordinator(mode, context, tabModelSelector, mMultiThumbnailCardProvider, titleProvider, true, mMediator, null, - TabProperties.UiType.CLOSABLE, null, container, true, COMPONENT_NAME); + TabProperties.UiType.CLOSABLE, null, this, container, true, COMPONENT_NAME); mContainerViewChangeProcessor = PropertyModelChangeProcessor.create(containerViewModel, mTabListCoordinator.getContainerView(), TabListContainerViewBinder::bind); @@ -461,6 +461,11 @@ public boolean resetWithTabs( @Nullable List<PseudoTab> tabs, boolean quickMode, boolean mruMode) { mMediator.registerFirstMeaningfulPaintRecorder(); + // Invalidate price welcome message for every reset so that the stale message won't be + // restored by mistake (e.g. from tabClosureUndone in TabSwitcherMediator). + if (mPriceWelcomeMessageService != null) { + mPriceWelcomeMessageService.invalidateMessage(); + } boolean showQuickly = mTabListCoordinator.resetWithListOfTabs(tabs, quickMode, mruMode); if (showQuickly) { mTabListCoordinator.removeSpecialListItem(TabProperties.UiType.NEW_TAB_TILE, 0); @@ -475,11 +480,6 @@ } if (tabs != null && tabs.size() > 0) { - // TODO(crbug.com/1157578): Auto update the PriceWelcomeMessageService instead of - // updating it based on the client caller. - if (mPriceWelcomeMessageService != null) { - mPriceWelcomeMessageService.preparePriceMessage(); - } appendMessagesTo(cardsCount); } @@ -500,14 +500,11 @@ List<MessageCardProviderMediator.Message> messages = mMessageCardProviderCoordinator.getMessageItems(); for (int i = 0; i < messages.size(); i++) { - if (messages.get(i).type == MessageService.MessageType.PRICE_WELCOME) { - mTabListCoordinator.addSpecialListItem( - mTabListCoordinator.getPriceWelcomeMessageInsertionIndex(), - TabProperties.UiType.PRICE_WELCOME, messages.get(i).model); - } else { - mTabListCoordinator.addSpecialListItemToEnd( - TabProperties.UiType.MESSAGE, messages.get(i).model); - } + // The restore of PRICE_WELCOME message is handled in the restorePriceWelcomeMessage() + // below. + if (messages.get(i).type == MessageService.MessageType.PRICE_WELCOME) continue; + mTabListCoordinator.addSpecialListItemToEnd( + TabProperties.UiType.MESSAGE, messages.get(i).model); } sAppendedMessagesForTesting = messages.size() > 0; } @@ -524,20 +521,31 @@ appendNextMessage(MessageService.MessageType.PRICE_WELCOME); } + @Override + public void showPriceWelcomeMessage(PriceWelcomeMessageService.PriceTabData priceTabData) { + if (mPriceWelcomeMessageService == null + || PriceTrackingUtilities.isPriceWelcomeMessageCardDisabled()) { + return; + } + mPriceWelcomeMessageService.preparePriceMessage(priceTabData); + appendNextMessage(MessageService.MessageType.PRICE_WELCOME); + // To make the message card in view when user enters tab switcher, we should scroll to + // current tab with 0 offset. See {@link TabSwitcherMediator#setInitialScrollIndexOffset} + // for more details. + mMediator.scrollToTab( + mTabModelSelector.getTabModelFilterProvider().getCurrentTabModelFilter().index()); + } + private void appendMessagesTo(int index) { if (mMultiWindowModeStateDispatcher.isInMultiWindowMode()) return; sAppendedMessagesForTesting = false; List<MessageCardProviderMediator.Message> messages = mMessageCardProviderCoordinator.getMessageItems(); for (int i = 0; i < messages.size(); i++) { - if (messages.get(i).type == MessageService.MessageType.PRICE_WELCOME) { - mTabListCoordinator.addSpecialListItem( - mTabListCoordinator.getPriceWelcomeMessageInsertionIndex(), - TabProperties.UiType.PRICE_WELCOME, messages.get(i).model); - } else { - mTabListCoordinator.addSpecialListItem( - index + i, TabProperties.UiType.MESSAGE, messages.get(i).model); - } + if (messages.get(i).type == MessageService.MessageType.PRICE_WELCOME) continue; + mTabListCoordinator.addSpecialListItem( + index, TabProperties.UiType.MESSAGE, messages.get(i).model); + index++; } if (messages.size() > 0) sAppendedMessagesForTesting = true; }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java index 514b3d1f..7e934b3 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java
@@ -206,6 +206,12 @@ * when the closure of the binding tab in tab switcher is undone. */ void restorePriceWelcomeMessage(); + + /** + * Show the price welcome message in tab switcher. This is used when any open tab in tab + * switcher has a price drop. + */ + void showPriceWelcomeMessage(PriceWelcomeMessageService.PriceTabData priceTabData); } /** @@ -323,7 +329,8 @@ public void tabClosureUndone(Tab tab) { if (mTabModelSelector.getCurrentModel().getCount() == 1) { messageItemsController.restoreAllAppendedMessage(); - } else if (mPriceWelcomeMessageService != null + } + if (mPriceWelcomeMessageService != null && mPriceWelcomeMessageService.getBindingTabId() == tab.getId()) { priceWelcomeMessageController.restorePriceWelcomeMessage(); } @@ -834,7 +841,7 @@ } @Override - public void scrollToBindingTab(int tabIndex) { + public void scrollToTab(int tabIndex) { mContainerViewModel.set(TabListContainerProperties.INITIAL_SCROLL_INDEX, tabIndex); }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiFeatureUtilities.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiFeatureUtilities.java index f29b4de..b438954 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiFeatureUtilities.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiFeatureUtilities.java
@@ -44,7 +44,7 @@ public static final String THUMBNAIL_ASPECT_RATIO_PARAM = "thumbnail_aspect_ratio"; public static final DoubleCachedFieldTrialParameter THUMBNAIL_ASPECT_RATIO = new DoubleCachedFieldTrialParameter( - ChromeFeatureList.TAB_GRID_LAYOUT_ANDROID, THUMBNAIL_ASPECT_RATIO_PARAM, 1.0); + ChromeFeatureList.TAB_GRID_LAYOUT_ANDROID, THUMBNAIL_ASPECT_RATIO_PARAM, 0.85); private static final String SEARCH_CHIP_PARAM = "enable_search_term_chip"; public static final BooleanCachedFieldTrialParameter ENABLE_SEARCH_CHIP =
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java index ef529aa4..b3e3674 100644 --- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java +++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java
@@ -43,7 +43,6 @@ import org.chromium.chrome.browser.tab.state.LevelDBPersistedDataStorage; import org.chromium.chrome.browser.tab.state.LevelDBPersistedDataStorageJni; import org.chromium.chrome.browser.tab.state.ShoppingPersistedTabData; -import org.chromium.chrome.browser.tab.state.ShoppingPersistedTabData.PriceDrop; import org.chromium.chrome.tab_ui.R; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.components.browser_ui.widget.selectable_list.SelectionDelegate; @@ -686,8 +685,6 @@ mGridModel.set(TabProperties.SHOPPING_PERSISTED_TAB_DATA_FETCHER, null); PriceCardView priceCardView = mTabGridView.findViewById(R.id.price_info_box_outer); Assert.assertEquals(View.GONE, priceCardView.getVisibility()); - // TODO(crbug.com/1157578): Update the model in mediator. - Assert.assertNull(mGridModel.get(TabProperties.PRICE_DROP)); } private void testPriceString(Tab tab, MockShoppingPersistedTabDataFetcher fetcher, @@ -704,7 +701,6 @@ Assert.assertEquals(expectedCurrentPrice, currentPrice.getText()); Assert.assertEquals(expectedPreviousPrice, previousPrice.getText()); } - Assert.assertEquals(fetcher.getPriceDrop(), mGridModel.get(TabProperties.PRICE_DROP)); } static class MockShoppingPersistedTabData extends ShoppingPersistedTabData { @@ -731,7 +727,7 @@ extends TabListMediator.ShoppingPersistedTabDataFetcher { private ShoppingPersistedTabData mShoppingPersistedTabData; MockShoppingPersistedTabDataFetcher(Tab tab) { - super(tab); + super(tab, null, null); } public void setPriceStrings(String priceString, String previousPriceString) { @@ -744,11 +740,6 @@ mShoppingPersistedTabData = new MockShoppingPersistedTabData(mTab); } - public PriceDrop getPriceDrop() { - if (mShoppingPersistedTabData == null) return null; - return ((MockShoppingPersistedTabData) mShoppingPersistedTabData).getPriceDrop(); - } - @Override public void fetch(Callback<ShoppingPersistedTabData> callback) { callback.onResult(mShoppingPersistedTabData);
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSuggestionMessageCardTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSuggestionMessageCardTest.java index fd12762f..fd8d80c 100644 --- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSuggestionMessageCardTest.java +++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSuggestionMessageCardTest.java
@@ -68,7 +68,7 @@ // clang-format on private static final String BASE_PARAMS = "force-fieldtrial-params=" + "Study.Group:baseline_tab_suggestions/true/enable_launch_polish/true" - + "/min_time_between_prefetches/0"; + + "/min_time_between_prefetches/0/thumbnail_aspect_ratio/1.0"; private static final String ENABLE_CLOSE_SUGGESTION_PARAM = "/baseline_close_tab_suggestions/true"; private static final String ENABLE_GROUP_SUGGESTION_PARAM =
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherThumbnailTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherThumbnailTest.java index 26b3a7d..ba5d73bc 100644 --- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherThumbnailTest.java +++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherThumbnailTest.java
@@ -75,7 +75,7 @@ @Test @MediumTest - @CommandLineFlags.Add({BASE_PARAMS}) + @CommandLineFlags.Add({BASE_PARAMS + "/thumbnail_aspect_ratio/1.0"}) public void testThumbnailAspectRatio_one() { int tabCounts = 11; TabUiTestHelper.prepareTabsWithThumbnail(mActivityTestRule, tabCounts, 0, "about:blank"); @@ -90,7 +90,7 @@ @Test @MediumTest - @CommandLineFlags.Add({BASE_PARAMS + "/thumbnail_aspect_ratio/0.85"}) + @CommandLineFlags.Add({BASE_PARAMS}) public void testThumbnailAspectRatio_point85() { int tabCounts = 11; TabUiTestHelper.prepareTabsWithThumbnail(mActivityTestRule, tabCounts, 0, "about:blank"); @@ -105,7 +105,7 @@ int tabCounts = 11; TabUiTestHelper.prepareTabsWithThumbnail(mActivityTestRule, tabCounts, 0, "about:blank"); TabUiTestHelper.enterTabSwitcher(mActivityTestRule.getActivity()); - verifyAllThumbnailHeightWithAspectRatio(tabCounts, 1.f); + verifyAllThumbnailHeightWithAspectRatio(tabCounts, .85f); // With soft cleanup. TabUiTestHelper.leaveTabSwitcher(mActivityTestRule.getActivity()); @@ -113,7 +113,7 @@ // There is a chance this will fail without the current changes. Soft cleanup sets the // fetcher to null, which triggers TabGridViewBinder#releaseThumbnail. If the view still // under measuring, then its height can be zero after measurement. - verifyAllThumbnailHeightWithAspectRatio(tabCounts, 1.f); + verifyAllThumbnailHeightWithAspectRatio(tabCounts, .85f); } private void verifyAllThumbnailHeightWithAspectRatio(int tabCounts, float ratio) {
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/PriceWelcomeMessageServiceUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/PriceWelcomeMessageServiceUnitTest.java index 0c1c81f1..4f4273d 100644 --- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/PriceWelcomeMessageServiceUnitTest.java +++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/PriceWelcomeMessageServiceUnitTest.java
@@ -67,7 +67,6 @@ mPriceTabData = new PriceTabData( BINDING_TAB_ID, new ShoppingPersistedTabData.PriceDrop(PRICE, PREVIOUS_PRICE)); - doReturn(mPriceTabData).when(mMessageProvider).getFirstTabShowingPriceCard(); doNothing().when(mMessageObserver).messageReady(anyInt(), any()); doNothing().when(mMessageObserver).messageInvalidate(anyInt()); @@ -81,33 +80,16 @@ mMessageService.addObserver(mMessageObserver); } - @Test - public void testPrepareMessage_messageCardDisabled() { - PriceTrackingUtilities.SHARED_PREFERENCES_MANAGER.writeBoolean( - PriceTrackingUtilities.PRICE_WELCOME_MESSAGE_CARD, false); - mMessageService.preparePriceMessage(); - verify(mMessageProvider, times(0)).getFirstTabShowingPriceCard(); - PriceTrackingUtilities.SHARED_PREFERENCES_MANAGER.writeBoolean( - PriceTrackingUtilities.PRICE_WELCOME_MESSAGE_CARD, true); - mMessageService.preparePriceMessage(); - verify(mMessageProvider, times(1)).getFirstTabShowingPriceCard(); - } - - @Test - public void testPrepareMessage_noTabShowingPriceCard() { - doReturn(null).when(mMessageProvider).getFirstTabShowingPriceCard(); - mMessageService.preparePriceMessage(); - assertNull(mMessageService.getPriceTabDataForTesting()); - verify(mMessageObserver, times(1)).messageInvalidate(eq(MessageType.PRICE_WELCOME)); - assertEquals( - INITIAL_SHOW_COUNT, PriceTrackingUtilities.getPriceWelcomeMessageCardShowCount()); + @Test(expected = AssertionError.class) + public void testPrepareMessage_nullPriceTabData() { + mMessageService.preparePriceMessage(null); } @Test public void testPrepareMessage_exceedMaxShowCount() { PriceTrackingUtilities.SHARED_PREFERENCES_MANAGER.writeInt( PriceTrackingUtilities.PRICE_WELCOME_MESSAGE_CARD_SHOW_COUNT, MAX_SHOW_COUNT); - mMessageService.preparePriceMessage(); + mMessageService.preparePriceMessage(mPriceTabData); assertEquals( MAX_SHOW_COUNT + 1, PriceTrackingUtilities.getPriceWelcomeMessageCardShowCount()); assertNull(mMessageService.getPriceTabDataForTesting()); @@ -117,9 +99,8 @@ @Test public void testPrepareMessage_hasTabShowingPriceCard() { - doReturn(mPriceTabData).when(mMessageProvider).getFirstTabShowingPriceCard(); InOrder inOrder = Mockito.inOrder(mMessageObserver); - mMessageService.preparePriceMessage(); + mMessageService.preparePriceMessage(mPriceTabData); assertEquals(mPriceTabData, mMessageService.getPriceTabDataForTesting()); inOrder.verify(mMessageObserver, times(1)).messageInvalidate(eq(MessageType.PRICE_WELCOME)); inOrder.verify(mMessageObserver, times(1)) @@ -128,7 +109,7 @@ // We sendAvailabilityNotification only if the newly obtained priceTabData is different from // currently existing priceTabData. - mMessageService.preparePriceMessage(); + mMessageService.preparePriceMessage(mPriceTabData); assertEquals(mPriceTabData, mMessageService.getPriceTabDataForTesting()); verify(mMessageObserver, times(1)).messageInvalidate(eq(MessageType.PRICE_WELCOME)); verify(mMessageObserver, times(1)) @@ -137,8 +118,7 @@ PriceTabData priceTabData = new PriceTabData( BINDING_TAB_ID + 1, new ShoppingPersistedTabData.PriceDrop(PRICE, PREVIOUS_PRICE)); - doReturn(priceTabData).when(mMessageProvider).getFirstTabShowingPriceCard(); - mMessageService.preparePriceMessage(); + mMessageService.preparePriceMessage(priceTabData); assertEquals(priceTabData, mMessageService.getPriceTabDataForTesting()); verify(mMessageObserver, times(2)).messageInvalidate(eq(MessageType.PRICE_WELCOME)); verify(mMessageObserver, times(2)) @@ -148,32 +128,41 @@ @Test public void testReview() { + mMessageService.preparePriceMessage(mPriceTabData); + assertEquals(mPriceTabData, mMessageService.getPriceTabDataForTesting()); + verify(mMessageObserver, times(1)).messageInvalidate(eq(MessageType.PRICE_WELCOME)); + int index = 1; doReturn(index).when(mMessageProvider).getTabIndexFromTabId(BINDING_TAB_ID); - doNothing().when(mReviewActionProvider).scrollToBindingTab(anyInt()); - mMessageService.preparePriceMessage(); + doNothing().when(mReviewActionProvider).scrollToTab(anyInt()); mMessageService.review(); - verify(mReviewActionProvider).scrollToBindingTab(index); + verify(mReviewActionProvider).scrollToTab(index); verify(mMessageProvider).showPriceDropTooltip(index); assertTrue(PriceTrackingUtilities.isPriceWelcomeMessageCardDisabled()); + assertNull(mMessageService.getPriceTabDataForTesting()); } @Test public void testDismiss() { + mMessageService.preparePriceMessage(mPriceTabData); + assertEquals(mPriceTabData, mMessageService.getPriceTabDataForTesting()); + verify(mMessageObserver, times(1)).messageInvalidate(eq(MessageType.PRICE_WELCOME)); + mMessageService.dismiss(); assertTrue(PriceTrackingUtilities.isPriceWelcomeMessageCardDisabled()); + assertNull(mMessageService.getPriceTabDataForTesting()); } @Test public void testGetBindingTabId() { assertEquals(Tab.INVALID_TAB_ID, mMessageService.getBindingTabId()); - mMessageService.preparePriceMessage(); + mMessageService.preparePriceMessage(mPriceTabData); assertEquals(BINDING_TAB_ID, mMessageService.getBindingTabId()); } @Test public void testInvalidateMessage() { - mMessageService.preparePriceMessage(); + mMessageService.preparePriceMessage(mPriceTabData); assertEquals(mPriceTabData, mMessageService.getPriceTabDataForTesting()); verify(mMessageObserver, times(1)).messageInvalidate(eq(MessageType.PRICE_WELCOME)); mMessageService.invalidateMessage();
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java index 3666ec0..9fb04568 100644 --- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java +++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java
@@ -120,7 +120,9 @@ import org.chromium.chrome.browser.tasks.pseudotab.PseudoTab; import org.chromium.chrome.browser.tasks.pseudotab.TabAttributeCache; import org.chromium.chrome.browser.tasks.tab_groups.TabGroupModelFilter; +import org.chromium.chrome.browser.tasks.tab_management.PriceWelcomeMessageService.PriceTabData; import org.chromium.chrome.browser.tasks.tab_management.TabListCoordinator.TabListMode; +import org.chromium.chrome.browser.tasks.tab_management.TabListMediator.ShoppingPersistedTabDataFetcher; import org.chromium.chrome.browser.tasks.tab_management.TabProperties.UiType; import org.chromium.chrome.tab_ui.R; import org.chromium.chrome.test.util.browser.Features; @@ -251,6 +253,10 @@ TabListMediator.TabGridAccessibilityHelper mTabGridAccessibilityHelper; @Mock TemplateUrlService mTemplateUrlService; + @Mock + TabSwitcherMediator.PriceWelcomeMessageController mPriceWelcomeMessageController; + @Mock + ShoppingPersistedTabData mShoppingPersistedTabData; @Captor ArgumentCaptor<TabModelObserver> mTabModelObserverCaptor; @@ -279,6 +285,8 @@ private View mItemView2 = mock(View.class); private TabModelObserver mMediatorTabModelObserver; private TabGroupModelFilter.Observer mMediatorTabGroupModelFilterObserver; + private PriceDrop mPriceDrop; + private PriceTabData mPriceTabData; @Before public void setUp() { @@ -364,7 +372,7 @@ TemplateUrlServiceFactory.setInstanceForTesting(mTemplateUrlService); mMediator = new TabListMediator(mContext, mModel, TabListMode.GRID, mTabModelSelector, mTabContentManager::getTabThumbnailWithCallback, mTitleProvider, - mTabListFaviconProvider, false, null, mGridCardOnClickListenerProvider, null, + mTabListFaviconProvider, false, null, mGridCardOnClickListenerProvider, null, null, getClass().getSimpleName(), UiType.CLOSABLE); mMediator.registerOrientationListener(mGridLayoutManager); TrackerFactory.setTrackerForTests(mTracker); @@ -1575,23 +1583,6 @@ } @Test - public void testGetFirstTabShowingPriceCard() { - initAndAssertAllProperties(); - mModel.get(0).model.set(TabProperties.PRICE_DROP, null); - mModel.get(1).model.set(TabProperties.PRICE_DROP, null); - assertNull(mModel.getFirstTabShowingPriceCard()); - - PriceDrop priceDrop1 = new PriceDrop("$1", "$2"); - PriceDrop priceDrop2 = new PriceDrop("$3", "$4"); - mModel.get(1).model.set(TabProperties.PRICE_DROP, priceDrop2); - assertEquals(TAB2_ID, mModel.getFirstTabShowingPriceCard().bindingTabId); - assertEquals(priceDrop2, mModel.getFirstTabShowingPriceCard().priceDrop); - mModel.get(0).model.set(TabProperties.PRICE_DROP, priceDrop1); - assertEquals(TAB1_ID, mModel.getFirstTabShowingPriceCard().bindingTabId); - assertEquals(priceDrop1, mModel.getFirstTabShowingPriceCard().priceDrop); - } - - @Test @Features.DisableFeatures({TAB_GROUPS_ANDROID}) public void testUrlUpdated_forSingleTab_GTS_GroupNotEnabled() { initAndAssertAllProperties(); @@ -1914,6 +1905,7 @@ assertThat(mModel.get(0).model.get(TabProperties.SEARCH_QUERY), equalTo(searchTerm1)); } + // TODO(crbug.com/1177036): the assertThat in fetch callback is never reached. @Test public void testPriceTrackingProperty() { TabUiFeatureUtilities.ENABLE_PRICE_TRACKING.setForTesting(true); @@ -2169,7 +2161,7 @@ // Re-initialize the mediator to setup TemplateUrlServiceObserver if needed. mMediator = new TabListMediator(mContext, mModel, TabListMode.GRID, mTabModelSelector, mTabContentManager::getTabThumbnailWithCallback, mTitleProvider, - mTabListFaviconProvider, true, null, null, null, getClass().getSimpleName(), + mTabListFaviconProvider, true, null, null, null, null, getClass().getSimpleName(), TabProperties.UiType.CLOSABLE); mMediator.registerOrientationListener(mGridLayoutManager); mMediator.initWithNative(mProfile); @@ -2194,7 +2186,7 @@ // Re-initialize the mediator to setup TemplateUrlServiceObserver if needed. mMediator = new TabListMediator(mContext, mModel, TabListMode.GRID, mTabModelSelector, mTabContentManager::getTabThumbnailWithCallback, mTitleProvider, - mTabListFaviconProvider, true, null, null, null, getClass().getSimpleName(), + mTabListFaviconProvider, true, null, null, null, null, getClass().getSimpleName(), TabProperties.UiType.CLOSABLE); mMediator.registerOrientationListener(mGridLayoutManager); mMediator.initWithNative(mProfile); @@ -2333,33 +2325,11 @@ } @Test - public void testGetIndexForSelectedTab() { - initAndAssertAllProperties(); - assertThat(mModel.getIndexForSelectedTab(), equalTo(0)); - } - - @Test(expected = AssertionError.class) - public void testGetIndexForSelectedTab_multipleSelectedTabs() { - initAndAssertAllProperties(); - mModel.get(0).model.set(TabProperties.IS_SELECTED, true); - mModel.get(1).model.set(TabProperties.IS_SELECTED, true); - mModel.getIndexForSelectedTab(); - } - - @Test(expected = AssertionError.class) - public void testGetIndexForSelectedTab_noSelectedTabs() { - initAndAssertAllProperties(); - mModel.get(0).model.set(TabProperties.IS_SELECTED, false); - mModel.get(1).model.set(TabProperties.IS_SELECTED, false); - mModel.getIndexForSelectedTab(); - } - - @Test public void testListObserver_OnItemRangeInserted() { TabUiFeatureUtilities.ENABLE_PRICE_TRACKING.setForTesting(true); mMediator = new TabListMediator(mContext, mModel, TabListMode.GRID, mTabModelSelector, mTabContentManager::getTabThumbnailWithCallback, mTitleProvider, - mTabListFaviconProvider, true, null, null, null, getClass().getSimpleName(), + mTabListFaviconProvider, true, null, null, null, null, getClass().getSimpleName(), TabProperties.UiType.CLOSABLE); mMediator.registerOrientationListener(mGridLayoutManager); mMediator.initWithNative(mProfile); @@ -2377,7 +2347,7 @@ TabUiFeatureUtilities.ENABLE_PRICE_TRACKING.setForTesting(true); mMediator = new TabListMediator(mContext, mModel, TabListMode.GRID, mTabModelSelector, mTabContentManager::getTabThumbnailWithCallback, mTitleProvider, - mTabListFaviconProvider, true, null, null, null, getClass().getSimpleName(), + mTabListFaviconProvider, true, null, null, null, null, getClass().getSimpleName(), TabProperties.UiType.CLOSABLE); mMediator.registerOrientationListener(mGridLayoutManager); mMediator.initWithNative(mProfile); @@ -2393,6 +2363,68 @@ } @Test + public void testMaybeShowPriceWelcomeMessage() { + prepareTestMaybeShowPriceWelcomeMessage(); + ShoppingPersistedTabDataFetcher fetcher = + new ShoppingPersistedTabDataFetcher(mTab1, mModel, mPriceWelcomeMessageController); + fetcher.maybeShowPriceWelcomeMessage(mShoppingPersistedTabData); + verify(mPriceWelcomeMessageController, times(1)).showPriceWelcomeMessage(mPriceTabData); + } + + @Test + public void testMaybeShowPriceWelcomeMessage_MessageDisabled() { + prepareTestMaybeShowPriceWelcomeMessage(); + ShoppingPersistedTabDataFetcher fetcher = + new ShoppingPersistedTabDataFetcher(mTab1, mModel, mPriceWelcomeMessageController); + + PriceTrackingUtilities.SHARED_PREFERENCES_MANAGER.writeBoolean( + PriceTrackingUtilities.PRICE_WELCOME_MESSAGE_CARD, false); + assertThat(PriceTrackingUtilities.isPriceWelcomeMessageCardDisabled(), equalTo(true)); + fetcher.maybeShowPriceWelcomeMessage(mShoppingPersistedTabData); + verify(mPriceWelcomeMessageController, times(0)).showPriceWelcomeMessage(mPriceTabData); + } + + @Test + public void testMaybeShowPriceWelcomeMessage_NullParameter() { + prepareTestMaybeShowPriceWelcomeMessage(); + + new ShoppingPersistedTabDataFetcher(mTab1, null, mPriceWelcomeMessageController) + .maybeShowPriceWelcomeMessage(mShoppingPersistedTabData); + verify(mPriceWelcomeMessageController, times(0)).showPriceWelcomeMessage(mPriceTabData); + + new ShoppingPersistedTabDataFetcher(mTab1, mModel, null) + .maybeShowPriceWelcomeMessage(mShoppingPersistedTabData); + verify(mPriceWelcomeMessageController, times(0)).showPriceWelcomeMessage(mPriceTabData); + } + + @Test + public void testMaybeShowPriceWelcomeMessage_NoPriceDrop() { + prepareTestMaybeShowPriceWelcomeMessage(); + ShoppingPersistedTabDataFetcher fetcher = + new ShoppingPersistedTabDataFetcher(mTab1, mModel, mPriceWelcomeMessageController); + + fetcher.maybeShowPriceWelcomeMessage(null); + verify(mPriceWelcomeMessageController, times(0)).showPriceWelcomeMessage(mPriceTabData); + + doReturn(null).when(mShoppingPersistedTabData).getPriceDrop(); + fetcher.maybeShowPriceWelcomeMessage(mShoppingPersistedTabData); + verify(mPriceWelcomeMessageController, times(0)).showPriceWelcomeMessage(mPriceTabData); + } + + @Test + public void testMaybeShowPriceWelcomeMessage_AlreadyHasMessage() { + prepareTestMaybeShowPriceWelcomeMessage(); + ShoppingPersistedTabDataFetcher fetcher = + new ShoppingPersistedTabDataFetcher(mTab1, mModel, mPriceWelcomeMessageController); + + // Simulate that we already has the message. + addSpecialItem(1, TabProperties.UiType.PRICE_WELCOME, PRICE_WELCOME); + + fetcher.maybeShowPriceWelcomeMessage(mShoppingPersistedTabData); + verify(mPriceWelcomeMessageController, times(0)).showPriceWelcomeMessage(mPriceTabData); + } + + @Test @Features.EnableFeatures({TAB_GROUPS_CONTINUATION_ANDROID}) public void testUpdateFaviconForGroup() { setUpForTabGroupOperation(TabListMediatorType.TAB_SWITCHER); @@ -2731,7 +2763,7 @@ mMediator = new TabListMediator(mContext, mModel, TabListMode.GRID, mTabModelSelector, mTabContentManager::getTabThumbnailWithCallback, mTitleProvider, - mTabListFaviconProvider, actionOnRelatedTabs, null, null, handler, + mTabListFaviconProvider, actionOnRelatedTabs, null, null, handler, null, getClass().getSimpleName(), uiType); mMediator.registerOrientationListener(mGridLayoutManager); @@ -2811,4 +2843,15 @@ doReturn(1).when(mSpanSizeLookup).getSpanSize(anyInt()); mMediator.addSpecialItemToModel(index, uiType, model); } + + private void prepareTestMaybeShowPriceWelcomeMessage() { + initAndAssertAllProperties(); + PriceTrackingUtilities.SHARED_PREFERENCES_MANAGER.writeBoolean( + PriceTrackingUtilities.PRICE_WELCOME_MESSAGE_CARD, true); + mPriceDrop = new PriceDrop("1", "2"); + mPriceTabData = new PriceTabData(TAB1_ID, mPriceDrop); + doReturn(mPriceDrop).when(mShoppingPersistedTabData).getPriceDrop(); + assertThat(mModel.lastIndexForMessageItemFromType(PRICE_WELCOME), + equalTo(TabModel.INVALID_TAB_INDEX)); + } }
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediatorUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediatorUnitTest.java index fe23957..3935675 100644 --- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediatorUnitTest.java +++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediatorUnitTest.java
@@ -587,16 +587,11 @@ doReturn(1).when(mTabModel).getCount(); doReturn(TAB1_ID).when(mPriceWelcomeMessageService).getBindingTabId(); mTabModelObserverCaptor.getValue().tabClosureUndone(mTab1); - verify(mPriceWelcomeMessageController, times(0)).restorePriceWelcomeMessage(); + verify(mPriceWelcomeMessageController, times(1)).restorePriceWelcomeMessage(); doReturn(2).when(mTabModel).getCount(); doReturn(TAB2_ID).when(mPriceWelcomeMessageService).getBindingTabId(); mTabModelObserverCaptor.getValue().tabClosureUndone(mTab1); - verify(mPriceWelcomeMessageController, times(0)).restorePriceWelcomeMessage(); - - doReturn(2).when(mTabModel).getCount(); - doReturn(TAB1_ID).when(mPriceWelcomeMessageService).getBindingTabId(); - mTabModelObserverCaptor.getValue().tabClosureUndone(mTab1); verify(mPriceWelcomeMessageController, times(1)).restorePriceWelcomeMessage(); } @@ -614,6 +609,15 @@ } @Test + public void testScrollToTab() { + initAndAssertAllProperties(); + mMediator.scrollToTab(0); + assertThat(mModel.get(TabListContainerProperties.INITIAL_SCROLL_INDEX), equalTo(0)); + mMediator.scrollToTab(1); + assertThat(mModel.get(TabListContainerProperties.INITIAL_SCROLL_INDEX), equalTo(1)); + } + + @Test public void showOverviewDoesNotUpdateResetHandlerBeforeRestoreCompleted() { initAndAssertAllProperties(); doReturn(false).when(mTabModelSelector).isTabStateInitialized();
diff --git a/chrome/android/feed/README.md b/chrome/android/feed/README.md deleted file mode 100644 index 9f47f17..0000000 --- a/chrome/android/feed/README.md +++ /dev/null
@@ -1,12 +0,0 @@ -# Feed Host UI - -The feed Java package provides support for showing a list of article -suggestions rendered by the third party -[Feed](https://chromium.googlesource.com/feed) library in Chrome UI. - -This directory contains two mirrored packages that provide real and dummy -implementations of classes to facilitate compiling out dependencies on -[//third_party/feed_library/](../../../third_party/feed_library/) and -[//components/feed/](../../../components/feed/) when the `enable_feed_in_chrome` -build flag is disabled. The public classes and methods in real/dummy used by -[//chrome/android/java/](../java/) must have identical signatures. \ No newline at end of file
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/client/knowncontent/ContentMetadataTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/client/knowncontent/ContentMetadataTest.java deleted file mode 100644 index 165f064..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/client/knowncontent/ContentMetadataTest.java +++ /dev/null
@@ -1,85 +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. - -package org.chromium.chrome.browser.feed.library.api.client.knowncontent; - -import static com.google.common.truth.Truth.assertThat; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.components.feed.core.proto.ui.stream.StreamStructureProto.OfflineMetadata; -import org.chromium.components.feed.core.proto.ui.stream.StreamStructureProto.RepresentationData; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link ContentMetadata}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ContentMetadataTest { - private static final String TITLE = "title"; - private static final String SNIPPET = "snippet"; - private static final String FAVICON_URL = "favicon.com"; - private static final String IMAGE_URL = "image.com"; - private static final String PUBLISHER = "publisher"; - private static final String URL = "url.com"; - private static final long TIME_PUBLISHED = 6L; - - private static final RepresentationData REPRESENTATION_DATA = - RepresentationData.newBuilder() - .setUri(URL) - .setPublishedTimeSeconds(TIME_PUBLISHED) - .build(); - private static final RepresentationData REPRESENTATION_DATA_NO_URL = - REPRESENTATION_DATA.toBuilder().clearUri().build(); - private static final RepresentationData REPRESENTATION_DATA_NO_TIME_PUBLISHED = - REPRESENTATION_DATA.toBuilder().clearPublishedTimeSeconds().build(); - - private static final OfflineMetadata OFFLINE_METADATA = OfflineMetadata.newBuilder() - .setFaviconUrl(FAVICON_URL) - .setImageUrl(IMAGE_URL) - .setPublisher(PUBLISHER) - .setSnippet(SNIPPET) - .setTitle(TITLE) - .build(); - private static final OfflineMetadata OFFLINE_METADATA_NO_TITLE = - OFFLINE_METADATA.toBuilder().clearTitle().build(); - - @Test - public void testMaybeCreate() { - ContentMetadata created = - ContentMetadata.maybeCreateContentMetadata(OFFLINE_METADATA, REPRESENTATION_DATA); - - assertThat(created.getTitle()).isEqualTo(TITLE); - assertThat(created.getSnippet()).isEqualTo(SNIPPET); - assertThat(created.getFaviconUrl()).isEqualTo(FAVICON_URL); - assertThat(created.getImageUrl()).isEqualTo(IMAGE_URL); - assertThat(created.getPublisher()).isEqualTo(PUBLISHER); - assertThat(created.getUrl()).isEqualTo(URL); - assertThat(created.getTimePublished()).isEqualTo(TIME_PUBLISHED); - } - - @Test - public void testMaybeCreate_noUrl() { - assertThat(ContentMetadata.maybeCreateContentMetadata( - OFFLINE_METADATA, REPRESENTATION_DATA_NO_URL)) - .isNull(); - } - - @Test - public void testMaybeCreate_noTitle() { - assertThat(ContentMetadata.maybeCreateContentMetadata( - OFFLINE_METADATA_NO_TITLE, REPRESENTATION_DATA)) - .isNull(); - } - - @Test - public void testMaybeCreate_noTimePublished() { - assertThat(ContentMetadata - .maybeCreateContentMetadata( - OFFLINE_METADATA, REPRESENTATION_DATA_NO_TIME_PUBLISHED) - .getTimePublished()) - .isEqualTo(ContentMetadata.UNKNOWN_TIME_PUBLISHED); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/client/scope/ProcessScopeBuilderTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/client/scope/ProcessScopeBuilderTest.java deleted file mode 100644 index 8544aa9fe..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/client/scope/ProcessScopeBuilderTest.java +++ /dev/null
@@ -1,192 +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. - -package org.chromium.chrome.browser.feed.library.api.client.scope; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.mockito.Mockito.withSettings; -import static org.mockito.MockitoAnnotations.initMocks; - -import android.app.Activity; -import android.content.Context; - -import com.google.common.util.concurrent.MoreExecutors; - -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestRule; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.base.test.util.JniMocker; -import org.chromium.chrome.browser.feed.library.api.host.config.ApplicationInfo; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration.ConfigKey; -import org.chromium.chrome.browser.feed.library.api.host.config.DebugBehavior; -import org.chromium.chrome.browser.feed.library.api.host.logging.BasicLoggingApi; -import org.chromium.chrome.browser.feed.library.api.host.network.NetworkClient; -import org.chromium.chrome.browser.feed.library.api.host.proto.ProtoExtensionProvider; -import org.chromium.chrome.browser.feed.library.api.host.scheduler.SchedulerApi; -import org.chromium.chrome.browser.feed.library.api.host.storage.ContentStorage; -import org.chromium.chrome.browser.feed.library.api.host.storage.ContentStorageDirect; -import org.chromium.chrome.browser.feed.library.api.host.storage.JournalStorage; -import org.chromium.chrome.browser.feed.library.api.host.storage.JournalStorageDirect; -import org.chromium.chrome.browser.feed.library.api.host.stream.TooltipSupportedApi; -import org.chromium.chrome.browser.feed.library.api.internal.common.ThreadUtils; -import org.chromium.chrome.browser.feed.library.common.concurrent.MainThreadRunner; -import org.chromium.chrome.browser.flags.ChromeFeatureList; -import org.chromium.chrome.browser.profiles.Profile; -import org.chromium.chrome.browser.signin.services.IdentityServicesProvider; -import org.chromium.chrome.browser.signin.services.IdentityServicesProviderJni; -import org.chromium.chrome.test.util.browser.Features; -import org.chromium.components.signin.identitymanager.IdentityManager; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.ArrayList; - -/** Tests for {@link ProcessScopeBuilder}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -@Features.DisableFeatures(ChromeFeatureList.REPORT_FEED_USER_ACTIONS) -public class ProcessScopeBuilderTest { - // Mocks for required fields - @Mock - private BasicLoggingApi mBasicLoggingApi; - @Mock - private NetworkClient mNetworkClient; - @Mock - private SchedulerApi mSchedulerApi; - @Mock - private ApplicationInfo mApplicationInfo; - @Mock - private TooltipSupportedApi mTooltipSupportedApi; - @Mock - private IdentityServicesProvider.Natives mIdentityServicesProviderJniMock; - @Mock - private Profile mProfileMock; - @Mock - private IdentityManager mIdentifiyManagerMock; - - // Mocks for optional fields - @Mock - private ThreadUtils mThreadUtils; - - private final ProtoExtensionProvider mProtoExtensionProvider = ArrayList::new; - private Configuration mConfiguration = new Configuration.Builder().build(); - private Context mContext; - - @Rule - public JniMocker jniMocker = new JniMocker(); - - @Rule - public TestRule mFeaturesProcessorRule = new Features.JUnitProcessor(); - - @Before - public void setUp() { - initMocks(this); - mContext = Robolectric.buildActivity(Activity.class).get(); - - Profile.setLastUsedProfileForTesting(mProfileMock); - jniMocker.mock(IdentityServicesProviderJni.TEST_HOOKS, mIdentityServicesProviderJniMock); - when(mIdentityServicesProviderJniMock.getIdentityManager(mProfileMock)) - .thenReturn(mIdentifiyManagerMock); - } - - @After - public void tearDown() { - Profile.setLastUsedProfileForTesting(null); - } - - @Test - public void testBasicBuild() { - // No crash should happen. - ProcessScope processScope = - new ProcessScopeBuilder(mConfiguration, MoreExecutors.newDirectExecutorService(), - mBasicLoggingApi, mNetworkClient, mSchedulerApi, DebugBehavior.VERBOSE, - mContext, mApplicationInfo, mTooltipSupportedApi) - .setJournalStorageDirect(mock(JournalStorageDirect.class)) - .setContentStorageDirect(mock(ContentStorageDirect.class)) - .build(); - - assertThat(processScope.getRequestManager()).isNotNull(); - assertThat(processScope.getAppLifecycleListener()).isNotNull(); - assertThat(processScope.getKnownContent()).isNotNull(); - assertThat(processScope.getAppLifecycleListener()).isNotNull(); - } - - @Test - public void testComplexBuild() { - // No crash should happen. - ProcessScope processScope = - new ProcessScopeBuilder(mConfiguration, MoreExecutors.newDirectExecutorService(), - mBasicLoggingApi, mNetworkClient, mSchedulerApi, DebugBehavior.VERBOSE, - mContext, mApplicationInfo, mTooltipSupportedApi) - .setProtoExtensionProvider(mProtoExtensionProvider) - .setJournalStorageDirect(mock(JournalStorageDirect.class)) - .setContentStorageDirect(mock(ContentStorageDirect.class)) - .build(); - - assertThat(processScope.getRequestManager()).isNotNull(); - assertThat(processScope.getAppLifecycleListener()).isNotNull(); - assertThat(processScope.getAppLifecycleListener()).isNotNull(); - } - - @Test - public void testDirectStorage() { - ContentStorageDirect contentStorageDirect = mock(ContentStorageDirect.class); - JournalStorageDirect journalStorageDirect = mock(JournalStorageDirect.class); - ProcessScopeBuilder builder = - new ProcessScopeBuilder(mConfiguration, MoreExecutors.newDirectExecutorService(), - mBasicLoggingApi, mNetworkClient, mSchedulerApi, DebugBehavior.VERBOSE, - mContext, mApplicationInfo, mTooltipSupportedApi) - .setContentStorageDirect(contentStorageDirect) - .setJournalStorageDirect(journalStorageDirect); - assertThat(builder.mContentStorage).isEqualTo(contentStorageDirect); - assertThat(builder.mJournalStorage).isEqualTo(journalStorageDirect); - } - - @Test - public void testStorage_direct() { - mConfiguration = - new Configuration.Builder().put(ConfigKey.USE_DIRECT_STORAGE, true).build(); - ContentStorage contentStorageDirect = mock( - ContentStorage.class, withSettings().extraInterfaces(ContentStorageDirect.class)); - JournalStorage journalStorageDirect = mock( - JournalStorage.class, withSettings().extraInterfaces(JournalStorageDirect.class)); - ProcessScopeBuilder builder = - new ProcessScopeBuilder(mConfiguration, MoreExecutors.newDirectExecutorService(), - mBasicLoggingApi, mNetworkClient, mSchedulerApi, DebugBehavior.VERBOSE, - mContext, mApplicationInfo, mTooltipSupportedApi) - .setContentStorage(contentStorageDirect) - .setJournalStorage(journalStorageDirect); - MainThreadRunner mainThreadRunner = new MainThreadRunner(); - assertThat(builder.buildContentStorage(mainThreadRunner)).isEqualTo(contentStorageDirect); - assertThat(builder.buildJournalStorage(mainThreadRunner)).isEqualTo(journalStorageDirect); - } - - @Test - public void testStorage_wrapped() { - mConfiguration = - new Configuration.Builder().put(ConfigKey.USE_DIRECT_STORAGE, false).build(); - ContentStorage contentStorageDirect = mock( - ContentStorage.class, withSettings().extraInterfaces(ContentStorageDirect.class)); - JournalStorage journalStorageDirect = mock( - JournalStorage.class, withSettings().extraInterfaces(JournalStorageDirect.class)); - ProcessScopeBuilder builder = - new ProcessScopeBuilder(mConfiguration, MoreExecutors.newDirectExecutorService(), - mBasicLoggingApi, mNetworkClient, mSchedulerApi, DebugBehavior.VERBOSE, - mContext, mApplicationInfo, mTooltipSupportedApi) - .setContentStorage(contentStorageDirect) - .setJournalStorage(journalStorageDirect); - assertThat(builder.mContentStorage).isNotEqualTo(contentStorageDirect); - assertThat(builder.mJournalStorage).isNotEqualTo(journalStorageDirect); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/client/scope/StreamScopeBuilderTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/client/scope/StreamScopeBuilderTest.java deleted file mode 100644 index 416a627ab..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/client/scope/StreamScopeBuilderTest.java +++ /dev/null
@@ -1,185 +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. - -package org.chromium.chrome.browser.feed.library.api.client.scope; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import android.app.Activity; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.action.ActionApi; -import org.chromium.chrome.browser.feed.library.api.host.config.ApplicationInfo; -import org.chromium.chrome.browser.feed.library.api.host.config.ApplicationInfo.BuildType; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration.ConfigKey; -import org.chromium.chrome.browser.feed.library.api.host.config.DebugBehavior; -import org.chromium.chrome.browser.feed.library.api.host.imageloader.ImageLoaderApi; -import org.chromium.chrome.browser.feed.library.api.host.logging.BasicLoggingApi; -import org.chromium.chrome.browser.feed.library.api.host.offlineindicator.OfflineIndicatorApi; -import org.chromium.chrome.browser.feed.library.api.host.stream.CardConfiguration; -import org.chromium.chrome.browser.feed.library.api.host.stream.SnackbarApi; -import org.chromium.chrome.browser.feed.library.api.host.stream.StreamConfiguration; -import org.chromium.chrome.browser.feed.library.api.host.stream.TooltipApi; -import org.chromium.chrome.browser.feed.library.api.host.stream.TooltipSupportedApi; -import org.chromium.chrome.browser.feed.library.api.internal.actionmanager.ActionManager; -import org.chromium.chrome.browser.feed.library.api.internal.common.ThreadUtils; -import org.chromium.chrome.browser.feed.library.api.internal.knowncontent.FeedKnownContent; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProviderFactory; -import org.chromium.chrome.browser.feed.library.api.internal.protocoladapter.ProtocolAdapter; -import org.chromium.chrome.browser.feed.library.api.internal.sessionmanager.FeedSessionManager; -import org.chromium.chrome.browser.feed.library.api.internal.stream.StreamFactory; -import org.chromium.chrome.browser.feed.library.common.concurrent.MainThreadRunner; -import org.chromium.chrome.browser.feed.library.common.concurrent.TaskQueue; -import org.chromium.chrome.browser.feed.library.common.protoextensions.FeedExtensionRegistry; -import org.chromium.chrome.browser.feed.library.common.time.Clock; -import org.chromium.chrome.browser.feed.library.common.time.TimingUtils; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.piet.host.CustomElementProvider; -import org.chromium.chrome.browser.feed.library.piet.host.HostBindingProvider; -import org.chromium.chrome.browser.feed.shared.stream.Stream; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link StreamScopeBuilder}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class StreamScopeBuilderTest { - @BuildType - private static final int BUILD_TYPE = BuildType.ALPHA; - public static final DebugBehavior DEBUG_BEHAVIOR = DebugBehavior.VERBOSE; - - // Mocks for required fields - @Mock - private ActionApi mActionApi; - @Mock - private ImageLoaderApi mImageLoaderApi; - @Mock - private TooltipSupportedApi mTooltipSupportedApi; - - // Mocks for optional fields - @Mock - private ProtocolAdapter mProtocolAdapter; - @Mock - private FeedSessionManager mFeedSessionManager; - @Mock - private Stream mStream; - @Mock - private StreamConfiguration mStreamConfiguration; - @Mock - private CardConfiguration mCardConfiguration; - @Mock - private ModelProviderFactory mModelProviderFactory; - @Mock - private CustomElementProvider mCustomElementProvider; - @Mock - private HostBindingProvider mHostBindingProvider; - @Mock - private ActionManager mActionManager; - @Mock - private Configuration mConfig; - @Mock - private SnackbarApi mSnackbarApi; - @Mock - private BasicLoggingApi mBasicLoggingApi; - @Mock - private OfflineIndicatorApi mOfflineIndicatorApi; - @Mock - private FeedKnownContent mFeedKnownContent; - @Mock - private TaskQueue mTaskQueue; - @Mock - private TooltipApi mTooltipApi; - @Mock - private FeedExtensionRegistry mFeedExtensionRegistry; - - private Activity mActivity; - private MainThreadRunner mMainThreadRunner; - private ThreadUtils mThreadUtils; - private TimingUtils mTimingUtils; - private Clock mClock; - private ApplicationInfo mApplicationInfo; - private StreamFactory mStreamFactory; - - @Before - public void setUp() { - initMocks(this); - mActivity = Robolectric.buildActivity(Activity.class).get(); - mMainThreadRunner = new MainThreadRunner(); - mThreadUtils = new ThreadUtils(); - mTimingUtils = new TimingUtils(); - mClock = new FakeClock(); - mApplicationInfo = new ApplicationInfo.Builder(mActivity).setBuildType(BUILD_TYPE).build(); - when(mConfig.getValueOrDefault( - eq(ConfigKey.LOGGING_IMMEDIATE_CONTENT_THRESHOLD_MS), anyLong())) - .thenReturn(1000L); - when(mConfig.getValueOrDefault(eq(ConfigKey.FADE_IMAGE_THRESHOLD_MS), anyLong())) - .thenReturn(80L); - } - - @Test - public void testBasicBuild() { - StreamScope streamScope = new StreamScopeBuilder(mActivity, mActionApi, mImageLoaderApi, - mProtocolAdapter, mFeedSessionManager, mThreadUtils, mTimingUtils, mTaskQueue, - mMainThreadRunner, mClock, DEBUG_BEHAVIOR, mStreamConfiguration, mCardConfiguration, - mActionManager, mConfig, mSnackbarApi, mBasicLoggingApi, mOfflineIndicatorApi, - mFeedKnownContent, mTooltipApi, mTooltipSupportedApi, mApplicationInfo, - mFeedExtensionRegistry) - .build(); - assertThat(streamScope.getStream()).isNotNull(); - assertThat(streamScope.getModelProviderFactory()).isNotNull(); - } - - @Test - public void testComplexBuild() { - StreamScope streamScope = new StreamScopeBuilder(mActivity, mActionApi, mImageLoaderApi, - mProtocolAdapter, mFeedSessionManager, mThreadUtils, mTimingUtils, mTaskQueue, - mMainThreadRunner, mClock, DEBUG_BEHAVIOR, mStreamConfiguration, mCardConfiguration, - mActionManager, mConfig, mSnackbarApi, mBasicLoggingApi, mOfflineIndicatorApi, - mFeedKnownContent, mTooltipApi, mTooltipSupportedApi, mApplicationInfo, - mFeedExtensionRegistry) - .setModelProviderFactory(mModelProviderFactory) - .setCustomElementProvider(mCustomElementProvider) - .setHostBindingProvider(new HostBindingProvider()) - .build(); - assertThat(streamScope.getStream()).isNotNull(); - assertThat(streamScope.getModelProviderFactory()).isEqualTo(mModelProviderFactory); - } - - @Test - public void testStreamFactoryBuild() { - setupStreamFactory(mStream); - - StreamScope streamScope = new StreamScopeBuilder(mActivity, mActionApi, mImageLoaderApi, - mProtocolAdapter, mFeedSessionManager, mThreadUtils, mTimingUtils, mTaskQueue, - mMainThreadRunner, mClock, DEBUG_BEHAVIOR, mStreamConfiguration, mCardConfiguration, - mActionManager, mConfig, mSnackbarApi, mBasicLoggingApi, mOfflineIndicatorApi, - mFeedKnownContent, mTooltipApi, mTooltipSupportedApi, mApplicationInfo, - mFeedExtensionRegistry) - .setStreamFactory(mStreamFactory) - .setCustomElementProvider(mCustomElementProvider) - .setHostBindingProvider(mHostBindingProvider) - .build(); - assertThat(streamScope.getStream()).isEqualTo(mStream); - } - - private void setupStreamFactory(Stream streamToReturn) { - mStreamFactory = (actionParserFactory, context, buildType, cardConfiguration, - imageLoaderApi, customElementProvider, debugBehavior, clock, modelProviderFactory, - hostBindingProvider, offlineIndicatorApi, configuration, actionApi, actionManager, - snackbarApi, streamConfiguration, feedExtensionRegistry, basicLoggingApi, - mainThreadRunner, isBackgroundDark, tooltipApi, threadUtils, knownContentApi, - isPlaceholderShown) -> streamToReturn; - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/common/MutationContextTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/common/MutationContextTest.java deleted file mode 100644 index c88ce0e..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/common/MutationContextTest.java +++ /dev/null
@@ -1,45 +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. - -package org.chromium.chrome.browser.feed.library.api.common; - -import static com.google.common.truth.Truth.assertThat; - -import com.google.protobuf.ByteString; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamToken; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.nio.charset.Charset; - -/** Tests of the {@link MutationContext} class. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class MutationContextTest { - @Test - public void testBuilder() { - ByteString tokenBytes = ByteString.copyFrom("token", Charset.defaultCharset()); - StreamToken token = StreamToken.newBuilder().setNextPageToken(tokenBytes).build(); - String sessionId = "session:1"; - MutationContext mutationContext = new MutationContext.Builder() - .setContinuationToken(token) - .setRequestingSessionId(sessionId) - .build(); - assertThat(mutationContext).isNotNull(); - assertThat(mutationContext.getContinuationToken()).isEqualTo(token); - assertThat(mutationContext.getRequestingSessionId()).isEqualTo(sessionId); - assertThat(mutationContext.isUserInitiated()).isFalse(); - } - - @Test - public void testUserInitiated_true() { - MutationContext mutationContext = - new MutationContext.Builder().setUserInitiated(true).build(); - assertThat(mutationContext.isUserInitiated()).isTrue(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/host/config/ConfigurationTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/host/config/ConfigurationTest.java deleted file mode 100644 index 07007d9..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/host/config/ConfigurationTest.java +++ /dev/null
@@ -1,94 +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. - -package org.chromium.chrome.browser.feed.library.api.host.config; - -import static com.google.common.truth.Truth.assertThat; - -import static junit.framework.Assert.fail; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration.ConfigKey; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests of the {@link Configuration}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ConfigurationTest { - @ConfigKey - private static final String CONFIG_KEY_WITH_DEFAULT = "config-test"; - - private static final boolean CONFIG_KEY_WITH_DEFAULT_VALUE = false; - - @Test - public void defaultConfig_hasDefaultValues() { - Configuration configuration = - new Configuration.Builder() - .put(CONFIG_KEY_WITH_DEFAULT, CONFIG_KEY_WITH_DEFAULT_VALUE) - .build(); - - boolean valueOrDefault = configuration.getValueOrDefault( - CONFIG_KEY_WITH_DEFAULT, !CONFIG_KEY_WITH_DEFAULT_VALUE); - - assertThat(valueOrDefault).isEqualTo(CONFIG_KEY_WITH_DEFAULT_VALUE); - } - - @Test - public void hasValue_forValueThatDoesNotExist_returnsFalse() { - Configuration configuration = new Configuration.Builder().build(); - - assertThat(configuration.hasValue(ConfigKey.FEED_SERVER_ENDPOINT)).isFalse(); - } - - @Test - public void getValueOrDefault_forValueThatDoesNotExist_returnsSpecifiedDefault() { - final String defaultString = "defaultString"; - Configuration configuration = new Configuration.Builder().build(); - - assertThat(configuration.getValueOrDefault(ConfigKey.FEED_SERVER_ENDPOINT, defaultString)) - .isEqualTo(defaultString); - } - - @Test - public void getValueOrDefault_forValueThatExists_returnsValue() { - final String someValue = "someValue"; - Configuration configuration = - new Configuration.Builder().put(ConfigKey.FEED_SERVER_ENDPOINT, someValue).build(); - - assertThat(configuration.getValueOrDefault(ConfigKey.FEED_SERVER_ENDPOINT, "")) - .isEqualTo(someValue); - } - - @Test - public void getValueOrDefaultWithWrongType_throwsClassCastException() { - Configuration configuration = new Configuration.Builder() - .put(ConfigKey.FEED_SERVER_ENDPOINT, "someString") - .build(); - - try { - @SuppressWarnings("unused") // Used for type inference - Boolean ignored = - configuration.getValueOrDefault(ConfigKey.FEED_SERVER_ENDPOINT, false); - fail(); - } catch (ClassCastException ignored) { - // expected - } - } - - @Test - public void getValue_forValueThatWasOverridden_ReturnsOverriddenValue() { - Configuration configuration = - new Configuration.Builder() - .put(CONFIG_KEY_WITH_DEFAULT, !CONFIG_KEY_WITH_DEFAULT_VALUE) - .build(); - - boolean valueOrDefault = configuration.getValueOrDefault( - CONFIG_KEY_WITH_DEFAULT, !CONFIG_KEY_WITH_DEFAULT_VALUE); - - assertThat(valueOrDefault).isEqualTo(!CONFIG_KEY_WITH_DEFAULT_VALUE); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/host/network/HttpHeaderTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/host/network/HttpHeaderTest.java deleted file mode 100644 index a41dcda..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/host/network/HttpHeaderTest.java +++ /dev/null
@@ -1,30 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.feed.library.api.host.network; - -import static com.google.common.truth.Truth.assertThat; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.network.HttpHeader.HttpHeaderName; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Test class for {@link HttpHeader} */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class HttpHeaderTest { - private static final String HEADER_VALUE = "Hello world"; - - @Test - public void testConstructor() { - HttpHeader header = - new HttpHeader(HttpHeaderName.X_PROTOBUFFER_REQUEST_PAYLOAD, HEADER_VALUE); - - assertThat(header.getName()).isEqualTo(HttpHeaderName.X_PROTOBUFFER_REQUEST_PAYLOAD); - assertThat(header.getValue()).isEqualTo(HEADER_VALUE); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/host/network/HttpRequestTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/host/network/HttpRequestTest.java deleted file mode 100644 index 17ffa3a..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/host/network/HttpRequestTest.java +++ /dev/null
@@ -1,97 +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. - -package org.chromium.chrome.browser.feed.library.api.host.network; - -import static com.google.common.truth.Truth.assertThat; - -import static org.chromium.chrome.browser.feed.library.common.testing.RunnableSubject.assertThatRunnable; - -import android.net.Uri; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.network.HttpHeader.HttpHeaderName; -import org.chromium.chrome.browser.feed.library.api.host.network.HttpRequest.HttpMethod; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.Collections; -import java.util.List; - -/** Test class for {@link HttpRequest} */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class HttpRequestTest { - public static final String HELLO_WORLD = "hello world"; - - @Test - public void testConstructor() throws Exception { - Uri uri = Uri.EMPTY; - String httpMethod = HttpMethod.GET; - HttpRequest httpRequest = - new HttpRequest(uri, httpMethod, Collections.emptyList(), new byte[] {}); - - assertThat(httpRequest.getUri()).isEqualTo(uri); - assertThat(httpRequest.getMethod()).isEqualTo(httpMethod); - } - - @Test - public void testConstructor_withHeaders() throws Exception { - Uri uri = Uri.EMPTY; - String httpMethod = HttpMethod.POST; - List<HttpHeader> headers = Collections.singletonList( - new HttpHeader(HttpHeaderName.X_PROTOBUFFER_REQUEST_PAYLOAD, HELLO_WORLD)); - HttpRequest httpRequest = new HttpRequest(uri, httpMethod, headers, new byte[] {}); - - assertThat(httpRequest.getUri()).isEqualTo(uri); - assertThat(httpRequest.getMethod()).isEqualTo(httpMethod); - assertThat(httpRequest.getHeaders()).isEqualTo(headers); - } - - @Test - public void testConstructor_withBody() throws Exception { - Uri uri = Uri.EMPTY; - byte[] bytes = new byte[] {}; - String httpMethod = HttpMethod.POST; - HttpRequest httpRequest = new HttpRequest(uri, httpMethod, Collections.emptyList(), bytes); - - assertThat(httpRequest.getUri()).isEqualTo(uri); - assertThat(httpRequest.getBody()).isEqualTo(bytes); - assertThat(httpRequest.getMethod()).isEqualTo(httpMethod); - } - - @Test - public void testConstructor_withHeadersAndBody() throws Exception { - Uri uri = Uri.EMPTY; - byte[] bytes = new byte[] {}; - String httpMethod = HttpMethod.POST; - List<HttpHeader> headers = Collections.singletonList( - new HttpHeader(HttpHeaderName.X_PROTOBUFFER_REQUEST_PAYLOAD, HELLO_WORLD)); - HttpRequest httpRequest = new HttpRequest(uri, httpMethod, headers, bytes); - - assertThat(httpRequest.getUri()).isEqualTo(uri); - assertThat(httpRequest.getBody()).isEqualTo(bytes); - assertThat(httpRequest.getMethod()).isEqualTo(httpMethod); - assertThat(httpRequest.getHeaders()).isEqualTo(headers); - } - - @Test - public void immutableHeaders() { - Uri uri = Uri.EMPTY; - byte[] bytes = new byte[] {}; - String httpMethod = HttpMethod.POST; - HttpHeader header = - new HttpHeader(HttpHeaderName.X_PROTOBUFFER_REQUEST_PAYLOAD, HELLO_WORLD); - List<HttpHeader> headers = Collections.singletonList(header); - HttpRequest httpRequest = new HttpRequest(uri, httpMethod, headers, bytes); - - List<HttpHeader> requestHeaders = httpRequest.getHeaders(); - assertThatRunnable(() -> requestHeaders.add(new HttpHeader("test", "testValue"))) - .throwsAnExceptionOfType(UnsupportedOperationException.class); - assertThatRunnable(() -> requestHeaders.remove(header)) - .throwsAnExceptionOfType(UnsupportedOperationException.class); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/host/storage/CommitResultTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/host/storage/CommitResultTest.java deleted file mode 100644 index 8db01286..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/host/storage/CommitResultTest.java +++ /dev/null
@@ -1,41 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.feed.library.api.host.storage; - -import static com.google.common.truth.Truth.assertThat; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.storage.CommitResult.Result; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Test class for {@link CommitResult} */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class CommitResultTest { - @Test - public void testSuccess() { - assertThat(CommitResult.SUCCESS.getResult()).isEqualTo(Result.SUCCESS); - } - - @Test - public void testSuccessSingleton() { - CommitResult success = CommitResult.SUCCESS; - assertThat(success).isEqualTo(CommitResult.SUCCESS); - } - - @Test - public void testFailure() { - assertThat(CommitResult.FAILURE.getResult()).isEqualTo(Result.FAILURE); - } - - @Test - public void testFailureSingleton() { - CommitResult failure = CommitResult.FAILURE; - assertThat(failure).isEqualTo(CommitResult.FAILURE); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/internal/common/ThreadUtilsTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/internal/common/ThreadUtilsTest.java deleted file mode 100644 index d5804da..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/internal/common/ThreadUtilsTest.java +++ /dev/null
@@ -1,43 +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. - -package org.chromium.chrome.browser.feed.library.api.internal.common; - -import static com.google.common.truth.Truth.assertThat; - -import static org.chromium.chrome.browser.feed.library.common.testing.RunnableSubject.assertThatRunnable; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** - * Tests of the {@link ThreadUtils} class. Robolectric runs everything on the main thread, so the - * tests are written to test the checks properly. - */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ThreadUtilsTest { - @Test - public void testOnMainThread() { - ThreadUtils threadUtils = new ThreadUtils(); - assertThat(threadUtils.isMainThread()).isTrue(); - } - - @Test - public void testCheckMainThread() { - ThreadUtils threadUtils = new ThreadUtils(); - // expect no exception - threadUtils.checkMainThread(); - } - - @Test() - public void testCheckNotMainThread() { - final ThreadUtils threadUtils = new ThreadUtils(); - assertThatRunnable(threadUtils::checkNotMainThread) - .throwsAnExceptionOfType(IllegalStateException.class); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/internal/modelprovider/RemoveTrackingTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/internal/modelprovider/RemoveTrackingTest.java deleted file mode 100644 index 338c12e..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/internal/modelprovider/RemoveTrackingTest.java +++ /dev/null
@@ -1,86 +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. - -package org.chromium.chrome.browser.feed.library.api.internal.modelprovider; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.base.Consumer; -import org.chromium.base.Function; -import org.chromium.chrome.browser.feed.library.api.internal.common.PayloadWithId; -import org.chromium.chrome.browser.feed.library.api.internal.common.testing.ContentIdGenerators; -import org.chromium.chrome.browser.feed.library.api.internal.common.testing.InternalProtocolBuilder; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamFeature; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.List; - -/** Tests of the {@link RemoveTracking} class. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class RemoveTrackingTest { - private final ContentIdGenerators mIdGenerators = new ContentIdGenerators(); - private final String mRootContentId = mIdGenerators.createRootContentId(0); - - @Before - public void setUp() { - initMocks(this); - } - - @Test - public void testEmpty() { - RemoveTracking<String> removeTracking = getRemoveTracking( - this::simpleTransform, (contentIds) -> assertThat(contentIds).hasSize(0)); - removeTracking.triggerConsumerUpdate(); - } - - @Test - public void testMatch() { - RemoveTracking<String> removeTracking = getRemoveTracking( - this::simpleTransform, (contentIds) -> assertThat(contentIds).hasSize(1)); - InternalProtocolBuilder protocolBuilder = new InternalProtocolBuilder(); - protocolBuilder.addFeature(mIdGenerators.createFeatureContentId(0), mRootContentId); - List<PayloadWithId> payloads = protocolBuilder.buildAsPayloadWithId(); - for (PayloadWithId payload : payloads) { - assertThat(payload.payload.hasStreamFeature()).isTrue(); - removeTracking.filterStreamFeature(payload.payload.getStreamFeature()); - } - removeTracking.triggerConsumerUpdate(); - } - - @Test - public void testNoMatch() { - RemoveTracking<String> removeTracking = getRemoveTracking( - this::nullTransform, (contentIds) -> assertThat(contentIds).hasSize(0)); - InternalProtocolBuilder protocolBuilder = new InternalProtocolBuilder(); - protocolBuilder.addFeature(mIdGenerators.createFeatureContentId(0), mRootContentId); - List<PayloadWithId> payloads = protocolBuilder.buildAsPayloadWithId(); - for (PayloadWithId payload : payloads) { - assertThat(payload.payload.hasStreamFeature()).isTrue(); - removeTracking.filterStreamFeature(payload.payload.getStreamFeature()); - } - removeTracking.triggerConsumerUpdate(); - } - - private RemoveTracking<String> getRemoveTracking( - Function<StreamFeature, String> transformer, Consumer<List<String>> consumer) { - return new RemoveTracking<>(transformer, consumer); - } - - @SuppressWarnings("unused") - private String nullTransform(StreamFeature streamFeature) { - return null; - } - - private String simpleTransform(StreamFeature streamFeature) { - return streamFeature.getContentId(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/internal/modelprovider/TokenCompletedTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/internal/modelprovider/TokenCompletedTest.java deleted file mode 100644 index 1daa7b8..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/internal/modelprovider/TokenCompletedTest.java +++ /dev/null
@@ -1,36 +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. - -package org.chromium.chrome.browser.feed.library.api.internal.modelprovider; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests of the {@link TokenCompleted} class. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class TokenCompletedTest { - @Mock - private ModelCursor mModelCursor; - - @Before - public void setUp() { - initMocks(this); - } - - @Test - public void testTokenChange() { - TokenCompleted tokenCompleted = new TokenCompleted(mModelCursor); - assertThat(tokenCompleted.getCursor()).isEqualTo(mModelCursor); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/internal/scope/ClearAllListenerTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/internal/scope/ClearAllListenerTest.java deleted file mode 100644 index 45bdf54..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/internal/scope/ClearAllListenerTest.java +++ /dev/null
@@ -1,85 +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. - -package org.chromium.chrome.browser.feed.library.api.internal.scope; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.logging.RequestReason; -import org.chromium.chrome.browser.feed.library.api.internal.lifecycle.Resettable; -import org.chromium.chrome.browser.feed.library.api.internal.sessionmanager.FeedSessionManager; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeTaskQueue; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeThreadUtils; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.feedapplifecyclelistener.FeedAppLifecycleListener; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.UiContext; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests of the {@link ClearAllListener} class. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ClearAllListenerTest { - private final FakeClock mFakeClock = new FakeClock(); - private final FakeThreadUtils mFakeThreadUtils = FakeThreadUtils.withThreadChecks(); - - @Mock - private Resettable mStore; - @Mock - private FeedSessionManager mSessionManager; - private FakeTaskQueue mFakeTaskQueue; - private FeedAppLifecycleListener mFeedAppLifecycleListener; - - @Before - public void setUp() { - initMocks(this); - mFakeTaskQueue = new FakeTaskQueue(mFakeClock, mFakeThreadUtils); - mFakeTaskQueue.initialize(() -> {}); - mFeedAppLifecycleListener = new FeedAppLifecycleListener(mFakeThreadUtils); - } - - @Test - public void testClearAll() { - setupClearAllListener(); - mFeedAppLifecycleListener.onClearAll(); - verify(mSessionManager).reset(); - verify(mStore).reset(); - assertThat(mFakeTaskQueue.resetWasCalled()).isTrue(); - assertThat(mFakeTaskQueue.completeResetWasCalled()).isTrue(); - } - - @Test - public void testClearAllWithRefresh() { - setupClearAllListener(); - mFeedAppLifecycleListener.onClearAllWithRefresh(); - verify(mSessionManager).reset(); - verify(mSessionManager) - .triggerRefresh(null, RequestReason.CLEAR_ALL, UiContext.getDefaultInstance()); - verify(mStore).reset(); - assertThat(mFakeTaskQueue.resetWasCalled()).isTrue(); - assertThat(mFakeTaskQueue.completeResetWasCalled()).isTrue(); - } - - @Test - public void testNonClearLifecycld() { - setupClearAllListener(); - mFeedAppLifecycleListener.onEnterForeground(); - verifyZeroInteractions(mSessionManager); - verifyZeroInteractions(mStore); - } - - private void setupClearAllListener() { - new ClearAllListener(mFakeTaskQueue, mSessionManager, mStore, mFakeThreadUtils, - mFeedAppLifecycleListener); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/internal/scope/FeedProcessScopeTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/internal/scope/FeedProcessScopeTest.java deleted file mode 100644 index f13175e8..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/api/internal/scope/FeedProcessScopeTest.java +++ /dev/null
@@ -1,99 +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. - -package org.chromium.chrome.browser.feed.library.api.internal.scope; - -import static org.mockito.Mockito.verify; -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.client.lifecycle.AppLifecycleListener; -import org.chromium.chrome.browser.feed.library.api.client.requestmanager.RequestManager; -import org.chromium.chrome.browser.feed.library.api.host.config.ApplicationInfo; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration; -import org.chromium.chrome.browser.feed.library.api.host.config.DebugBehavior; -import org.chromium.chrome.browser.feed.library.api.host.logging.BasicLoggingApi; -import org.chromium.chrome.browser.feed.library.api.host.network.NetworkClient; -import org.chromium.chrome.browser.feed.library.api.host.stream.TooltipSupportedApi; -import org.chromium.chrome.browser.feed.library.api.internal.actionmanager.ActionManager; -import org.chromium.chrome.browser.feed.library.api.internal.common.ThreadUtils; -import org.chromium.chrome.browser.feed.library.api.internal.knowncontent.FeedKnownContent; -import org.chromium.chrome.browser.feed.library.api.internal.protocoladapter.ProtocolAdapter; -import org.chromium.chrome.browser.feed.library.api.internal.sessionmanager.FeedSessionManager; -import org.chromium.chrome.browser.feed.library.api.internal.store.Store; -import org.chromium.chrome.browser.feed.library.common.concurrent.MainThreadRunner; -import org.chromium.chrome.browser.feed.library.common.concurrent.TaskQueue; -import org.chromium.chrome.browser.feed.library.common.feedobservable.FeedObservable; -import org.chromium.chrome.browser.feed.library.common.protoextensions.FeedExtensionRegistry; -import org.chromium.chrome.browser.feed.library.common.time.Clock; -import org.chromium.chrome.browser.feed.library.common.time.TimingUtils; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.feedapplifecyclelistener.FeedLifecycleListener; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link FeedProcessScope}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class FeedProcessScopeTest { - @Mock - private BasicLoggingApi mBasicLoggingApi; - @Mock - private NetworkClient mNetworkClient; - @Mock - private ApplicationInfo mApplicationInfo; - @Mock - private TooltipSupportedApi mTooltipSupportedApi; - @Mock - private ProtocolAdapter mProtocolAdapter; - @Mock - private RequestManager mRequestManager; - @Mock - private FeedSessionManager mFeedSessionManager; - @Mock - private Store mStore; - @Mock - private TaskQueue mTaskQueue; - @Mock - private AppLifecycleListener mAppLifecycleListener; - @Mock - private DebugBehavior mDebugBehavior; - @Mock - private ActionManager mActionManager; - @Mock - private FeedKnownContent mFeedKnownContent; - @Mock - private FeedExtensionRegistry mFeedExtensionRegistry; - @Mock - private FeedObservable<FeedLifecycleListener> mFeedLifecycleListenerFeedObservable; - - private final Clock mClock = new FakeClock(); - private final MainThreadRunner mMainThreadRunner = new MainThreadRunner(); - private final ThreadUtils mThreadUtils = new ThreadUtils(); - private final TimingUtils mTimingUtils = new TimingUtils(); - private Configuration mConfiguration = new Configuration.Builder().build(); - private ClearAllListener mClearAllListener; - - @Before - public void setUp() { - initMocks(this); - mClearAllListener = new ClearAllListener(mTaskQueue, mFeedSessionManager, null, - mThreadUtils, mFeedLifecycleListenerFeedObservable); - } - - @Test - public void testDestroy() throws Exception { - FeedProcessScope processScope = new FeedProcessScope(mBasicLoggingApi, mNetworkClient, - mProtocolAdapter, mRequestManager, mFeedSessionManager, mStore, mTimingUtils, - mThreadUtils, mTaskQueue, mMainThreadRunner, mAppLifecycleListener, mClock, - mDebugBehavior, mActionManager, mConfiguration, mFeedKnownContent, - mFeedExtensionRegistry, mClearAllListener, mTooltipSupportedApi, mApplicationInfo); - processScope.onDestroy(); - verify(mNetworkClient).close(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/BasicStreamTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/BasicStreamTest.java deleted file mode 100644 index 262b34f..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/BasicStreamTest.java +++ /dev/null
@@ -1,1464 +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. - -package org.chromium.chrome.browser.feed.library.basicstream; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import static org.chromium.chrome.browser.feed.library.common.testing.RunnableSubject.assertThatRunnable; -import static org.chromium.chrome.browser.feed.shared.stream.Stream.POSITION_NOT_KNOWN; - -import static java.nio.charset.StandardCharsets.UTF_8; - -import android.app.Activity; -import android.content.Context; -import android.util.Base64; -import android.view.View; -import android.widget.FrameLayout; - -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - -import com.google.protobuf.InvalidProtocolBufferException; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestRule; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; -import org.robolectric.shadow.api.Shadow; - -import org.chromium.base.Consumer; -import org.chromium.base.test.util.JniMocker; -import org.chromium.chrome.R; -import org.chromium.chrome.browser.feed.library.api.client.knowncontent.ContentMetadata; -import org.chromium.chrome.browser.feed.library.api.client.knowncontent.KnownContent; -import org.chromium.chrome.browser.feed.library.api.host.action.ActionApi; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration.ConfigKey; -import org.chromium.chrome.browser.feed.library.api.host.config.DebugBehavior; -import org.chromium.chrome.browser.feed.library.api.host.imageloader.ImageLoaderApi; -import org.chromium.chrome.browser.feed.library.api.host.logging.BasicLoggingApi; -import org.chromium.chrome.browser.feed.library.api.host.logging.RequestReason; -import org.chromium.chrome.browser.feed.library.api.host.logging.ZeroStateShowReason; -import org.chromium.chrome.browser.feed.library.api.host.offlineindicator.OfflineIndicatorApi; -import org.chromium.chrome.browser.feed.library.api.host.stream.CardConfiguration; -import org.chromium.chrome.browser.feed.library.api.host.stream.SnackbarApi; -import org.chromium.chrome.browser.feed.library.api.host.stream.StreamConfiguration; -import org.chromium.chrome.browser.feed.library.api.host.stream.TooltipApi; -import org.chromium.chrome.browser.feed.library.api.internal.actionmanager.ActionManager; -import org.chromium.chrome.browser.feed.library.api.internal.actionparser.ActionParserFactory; -import org.chromium.chrome.browser.feed.library.api.internal.common.ThreadUtils; -import org.chromium.chrome.browser.feed.library.api.internal.knowncontent.FeedKnownContent; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelError; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelError.ErrorType; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelFeature; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider.State; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider.ViewDepthProvider; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProviderFactory; -import org.chromium.chrome.browser.feed.library.basicstream.internal.StreamItemAnimator; -import org.chromium.chrome.browser.feed.library.basicstream.internal.StreamRecyclerViewAdapter; -import org.chromium.chrome.browser.feed.library.basicstream.internal.drivers.StreamDriver; -import org.chromium.chrome.browser.feed.library.basicstream.internal.scroll.BasicStreamScrollMonitor; -import org.chromium.chrome.browser.feed.library.basicstream.internal.scroll.ScrollRestorer; -import org.chromium.chrome.browser.feed.library.basicstream.internal.viewloggingupdater.ViewLoggingUpdater; -import org.chromium.chrome.browser.feed.library.common.concurrent.MainThreadRunner; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeMainThreadRunner; -import org.chromium.chrome.browser.feed.library.common.time.Clock; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.piet.PietManager; -import org.chromium.chrome.browser.feed.library.piet.host.CustomElementProvider; -import org.chromium.chrome.browser.feed.library.piet.host.HostBindingProvider; -import org.chromium.chrome.browser.feed.library.sharedstream.contentchanged.StreamContentChangedListener; -import org.chromium.chrome.browser.feed.library.sharedstream.contextmenumanager.ContextMenuManager; -import org.chromium.chrome.browser.feed.library.sharedstream.contextmenumanager.ContextMenuManagerImpl; -import org.chromium.chrome.browser.feed.library.sharedstream.deepestcontenttracker.DeepestContentTracker; -import org.chromium.chrome.browser.feed.library.sharedstream.offlinemonitor.StreamOfflineMonitor; -import org.chromium.chrome.browser.feed.library.sharedstream.piet.PietEventLogger; -import org.chromium.chrome.browser.feed.library.sharedstream.publicapi.menumeasurer.MenuMeasurer; -import org.chromium.chrome.browser.feed.library.sharedstream.publicapi.scroll.ScrollObservable; -import org.chromium.chrome.browser.feed.library.sharedstream.scroll.ScrollListenerNotifier; -import org.chromium.chrome.browser.feed.library.testing.shadows.ShadowRecycledViewPool; -import org.chromium.chrome.browser.feed.shared.stream.Header; -import org.chromium.chrome.browser.feed.shared.stream.Stream.ContentChangedListener; -import org.chromium.chrome.browser.feed.shared.stream.Stream.ScrollListener; -import org.chromium.chrome.browser.flags.ChromeFeatureList; -import org.chromium.chrome.browser.preferences.Pref; -import org.chromium.chrome.browser.profiles.Profile; -import org.chromium.chrome.test.util.browser.Features; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.UiContext; -import org.chromium.components.feed.core.proto.libraries.basicstream.internal.StreamSavedInstanceStateProto.StreamSavedInstanceState; -import org.chromium.components.feed.core.proto.libraries.sharedstream.ScrollStateProto.ScrollState; -import org.chromium.components.feed.core.proto.libraries.sharedstream.UiRefreshReasonProto.UiRefreshReason; -import org.chromium.components.feed.core.proto.libraries.sharedstream.UiRefreshReasonProto.UiRefreshReason.Reason; -import org.chromium.components.prefs.PrefService; -import org.chromium.components.user_prefs.UserPrefs; -import org.chromium.components.user_prefs.UserPrefsJni; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** Tests for {@link BasicStream}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE, shadows = {ShadowRecycledViewPool.class}) -@Features.DisableFeatures(ChromeFeatureList.INTEREST_FEEDV1_CLICKS_AND_VIEWS_CONDITIONAL_UPLOAD) -public class BasicStreamTest { - private static final int START_PADDING = 1; - private static final int END_PADDING = 2; - private static final int TOP_PADDING = 3; - private static final int BOTTOM_PADDING = 4; - private static final long LOGGING_IMMEDIATE_CONTENT_THRESHOLD_MS = 1000; - private static final int ADAPTER_HEADER_COUNT = 5; - - private static final String SESSION_ID = "session-id"; - private static final ScrollState SCROLL_STATE = - ScrollState.newBuilder().setOffset(10).setPosition(10).build(); - private static final StreamSavedInstanceState SAVED_INSTANCE_STATE = - StreamSavedInstanceState.newBuilder() - .setSessionId(SESSION_ID) - .setScrollState(SCROLL_STATE) - .build(); - private static final long SPINNER_DELAY_MS = 123L; - private static final long SPINNER_MINIMUM_SHOW_TIME_MS = 655L; - private static final Configuration CONFIGURATION = - new Configuration.Builder() - .put(ConfigKey.LOGGING_IMMEDIATE_CONTENT_THRESHOLD_MS, - LOGGING_IMMEDIATE_CONTENT_THRESHOLD_MS) - .put(ConfigKey.SPINNER_DELAY_MS, SPINNER_DELAY_MS) - .put(ConfigKey.SPINNER_MINIMUM_SHOW_TIME_MS, SPINNER_MINIMUM_SHOW_TIME_MS) - .build(); - - @Rule - public TestRule mFeaturesProcessorRule = new Features.JUnitProcessor(); - - @Rule - public JniMocker mocker = new JniMocker(); - - @Mock - private StreamConfiguration mStreamConfiguration; - @Mock - private ModelFeature mModelFeature; - @Mock - private ModelProviderFactory mModelProviderFactory; - @Mock - private ModelProvider mInitialModelProvider; - @Mock - private ModelProvider mModelProvider; - @Mock - private ModelProvider mRestoredModelProvider; - @Mock - private PietManager mPietManager; - @Mock - private SnackbarApi mSnackbarApi; - @Mock - private StreamDriver mStreamDriver; - @Mock - private StreamRecyclerViewAdapter mAdapter; - @Mock - private ScrollListenerNotifier mScrollListenerNotifier; - @Mock - private ScrollRestorer mNonRestoringScrollRestorer; - @Mock - private ScrollRestorer mScrollRestorer; - @Mock - private BasicLoggingApi mBasicLoggingApi; - @Mock - private ContextMenuManagerImpl mContextMenuManager; - @Mock - private ViewLoggingUpdater mViewLoggingUpdater; - @Mock - private TooltipApi mTooltipApi; - @Mock - private ActionManager mActionManager; - @Mock - private UserPrefs.Natives mUserPrefsJniMock; - @Mock - private Profile mProfile; - @Mock - private PrefService mPrefService; - - private FakeFeedKnownContent mFakeFeedKnownContent; - private LinearLayoutManagerWithFakePositioning mLayoutManager; - private Context mContext; - private FakeClock mClock; - private BasicStreamForTest mBasicStream; - private FakeMainThreadRunner mMainThreadRunner; - private List<Header> mHeaders; - - @Before - public void setUp() { - initMocks(this); - - mocker.mock(UserPrefsJni.TEST_HOOKS, mUserPrefsJniMock); - Profile.setLastUsedProfileForTesting(mProfile); - when(mUserPrefsJniMock.get(mProfile)).thenReturn(mPrefService); - when(mPrefService.getBoolean(Pref.HAS_REACHED_CLICK_AND_VIEW_ACTIONS_UPLOAD_CONDITIONS)) - .thenReturn(true); - - mFakeFeedKnownContent = new FakeFeedKnownContent(); - mHeaders = new ArrayList<>(); - mHeaders.add(mock(Header.class)); - - // TODO: Move header orchestration into separate class. - // Purposely using a different header count here as it is possible for size of headers to - // change due to swipe to dismiss. Adapter is source of truth for headers right now. - // Ideally we should have a drivers specifically for header management but we don't just - // yet. - when(mAdapter.getHeaderCount()).thenReturn(ADAPTER_HEADER_COUNT); - - when(mStreamConfiguration.getPaddingStart()).thenReturn(START_PADDING); - when(mStreamConfiguration.getPaddingEnd()).thenReturn(END_PADDING); - when(mStreamConfiguration.getPaddingTop()).thenReturn(TOP_PADDING); - when(mStreamConfiguration.getPaddingBottom()).thenReturn(BOTTOM_PADDING); - - when(mModelProviderFactory.createNew(any(ViewDepthProvider.class), any(UiContext.class))) - .thenReturn(mInitialModelProvider, mModelProvider); - - when(mInitialModelProvider.getSessionId()).thenReturn(SESSION_ID); - - when(mScrollRestorer.getScrollStateForScrollRestore(ADAPTER_HEADER_COUNT)) - .thenReturn(SCROLL_STATE); - - when(mStreamDriver.getLeafFeatureDrivers()).thenReturn(Collections.emptyList()); - - mContext = Robolectric.buildActivity(Activity.class).get(); - mClock = new FakeClock(); - mMainThreadRunner = FakeMainThreadRunner.create(mClock); - mLayoutManager = new LinearLayoutManagerWithFakePositioning(mContext); - - mBasicStream = createBasicStream(mLayoutManager); - mBasicStream.onCreate(null); - } - - @Test - @Features.EnableFeatures(ChromeFeatureList.INTEREST_FEEDV1_CLICKS_AND_VIEWS_CONDITIONAL_UPLOAD) - public void testOnCreate_setReachedUploadConditionsBitInActionManager_whenFeatureEnabled() { - verify(mActionManager, times(1)).setCanUploadClicksAndViewsWhenNoticeCardIsPresent(true); - } - - @Test - public void testRecyclerViewSetup() { - assertThat(getStreamRecyclerView().getId()).isEqualTo(R.id.feed_stream_recycler_view); - } - - @Test - public void testOnSessionStart() { - mBasicStream.onShow(); - reset(mAdapter); - - mBasicStream.onSessionStart(UiContext.getDefaultInstance()); - - verify(mStreamDriver).onDestroy(); - verify(mAdapter).setDriver(mStreamDriver); - assertThat(mBasicStream.mStreamDriverScrollRestorer).isSameInstanceAs(mScrollRestorer); - } - - @Test - public void testOnSessionStart_logsOnOpenedWithStreamContentAfterOnShow() { - mClock = mClock.set(10); - mBasicStream.onShow(); - - when(mStreamDriver.hasContent()).thenReturn(true); - mClock = mClock.set(40); - mBasicStream.onSessionStart(UiContext.getDefaultInstance()); - - verify(mBasicLoggingApi).onOpenedWithContent(30, 0); - } - - @Test - public void testOnSessionStart_logsOnOpenedWithStreamContentAfterOnShow_whenRestoring() { - mBasicStream.onShow(); - - String savedInstanceState = mBasicStream.getSavedInstanceStateString(); - - mBasicStream.onHide(); - mBasicStream.onDestroy(); - - when(mModelProviderFactory.create(SESSION_ID, UiContext.getDefaultInstance())) - .thenReturn(mRestoredModelProvider); - - mBasicStream = createBasicStream(new LinearLayoutManager(mContext)); - - mBasicStream.onCreate(savedInstanceState); - - mClock.set(15L); - mBasicStream.onShow(); - - when(mStreamDriver.hasContent()).thenReturn(true); - mClock.advance(5L); - mBasicStream.onSessionStart(UiContext.getDefaultInstance()); - - verify(mBasicLoggingApi).onOpenedWithContent(5, 0); - } - - @Test - public void testOnSessionStart_doesNotLogOnOpenedWithStreamContentAfterInitialOnShow() { - mBasicStream.onShow(); - mBasicStream.onSessionStart(UiContext.getDefaultInstance()); - reset(mBasicLoggingApi); - - mBasicStream.onSessionStart(UiContext.getDefaultInstance()); - - verify(mBasicLoggingApi, never()).onOpenedWithContent(anyInt(), anyInt()); - } - - @Test - public void testOnSessionStart_doesNotLogOnOpenedWithStreamContent_IfOnErrorLogsNoContent() { - mBasicStream.onShow(); - mBasicStream.onError( - new ModelError(ErrorType.NO_CARDS_ERROR, /* continuationToken= */ null)); - reset(mBasicLoggingApi); - - mBasicStream.onSessionStart(UiContext.getDefaultInstance()); - - verify(mBasicLoggingApi, never()).onOpenedWithContent(anyInt(), anyInt()); - } - - @Test - public void testOnSessionStart_logsOnOpenedWithNoContent_ifStreamDriverDoesNotHaveContent() { - mBasicStream.onShow(); - - mBasicStream.onSessionStart(UiContext.getDefaultInstance()); - - verify(mBasicLoggingApi).onOpenedWithNoContent(); - } - - @Test - public void - testOnSessionStart_doesNotUseNewStreamDriver_ifBothStreamDriversAreShowingZeroState() { - StreamDriver newStreamDriver = mock(StreamDriver.class); - mBasicStream.onShow(); - mBasicStream.onError( - new ModelError(ErrorType.NO_CARDS_ERROR, /* continuationToken= */ null)); - reset(mAdapter, mStreamDriver); - when(mStreamDriver.isZeroStateBeingShown()).thenReturn(true); - when(newStreamDriver.isZeroStateBeingShown()).thenReturn(true); - - mBasicStream.mStreamDriver = newStreamDriver; - mBasicStream.onSessionStart(UiContext.getDefaultInstance()); - - verify(mStreamDriver).setModelProviderForZeroState(mInitialModelProvider); - verify(mStreamDriver, never()).onDestroy(); - verify(newStreamDriver).onDestroy(); - verify(mAdapter, never()).setDriver(any(StreamDriver.class)); - } - - @Test - public void testOnSessionFinished() { - mBasicStream.onShow(); - reset(mStreamDriver); - mBasicStream.onSessionFinished(UiContext.getDefaultInstance()); - - verify(mScrollRestorer).abandonRestoringScroll(); - verify(mInitialModelProvider).unregisterObserver(mBasicStream); - verify(mModelProviderFactory, times(2)) - .createNew(any(ViewDepthProvider.class), any(UiContext.class)); - verify(mModelProvider).registerObserver(mBasicStream); - } - - @Test - public void testOnError_showsZeroState() { - mBasicStream.onShow(); - reset(mStreamDriver); - - mBasicStream.onError( - new ModelError(ErrorType.NO_CARDS_ERROR, /* continuationToken= */ null)); - - verify(mScrollRestorer).abandonRestoringScroll(); - verify(mStreamDriver).showZeroState(ZeroStateShowReason.ERROR); - } - - @Test - public void testOnError_logsOnOpenedWithNoContent() { - when(mStreamDriver.hasContent()).thenReturn(false); - mClock = mClock.set(10); - mBasicStream.onShow(); - - mClock = mClock.set(10 + LOGGING_IMMEDIATE_CONTENT_THRESHOLD_MS); - mBasicStream.onError( - new ModelError(ErrorType.NO_CARDS_ERROR, /* continuationToken= */ null)); - - verify(mBasicLoggingApi).onOpenedWithNoContent(); - } - - @Test - public void testOnError_doesNotDoubleLogOnOpenedWithNoContent() { - when(mInitialModelProvider.getCurrentState()).thenReturn(State.READY); - when(mInitialModelProvider.getRootFeature()).thenReturn(null); - - mBasicStream.onShow(); - // Trigger onOpenedWithNoContent logging through updating the driver. - mBasicStream.onSessionStart(UiContext.getDefaultInstance()); - reset(mBasicLoggingApi); - - mBasicStream.onError( - new ModelError(ErrorType.NO_CARDS_ERROR, /* continuationToken= */ null)); - - verify(mBasicLoggingApi, never()).onOpenedWithNoContent(); - } - - @Test - public void testOnSessionStart_logsOnOpenedWithNoImmediateContent() { - mBasicStream.onShow(); - - // Advance so that the spinner starts showing - mClock.advance(SPINNER_DELAY_MS); - - // Advance so that is has taken long enough that onOpenedWithNoImmediateContent is logged. - mClock.advance(LOGGING_IMMEDIATE_CONTENT_THRESHOLD_MS); - - mBasicStream.onSessionStart(UiContext.getDefaultInstance()); - - verify(mBasicLoggingApi).onOpenedWithNoImmediateContent(); - } - - @Test - public void testOnSessionStart_doesNotLogOnOpenedWithNoImmediateContent_ifNotWithinThreshold() { - mBasicStream.onShow(); - - mClock.advance(LOGGING_IMMEDIATE_CONTENT_THRESHOLD_MS - 1); - - mBasicStream.onSessionStart(UiContext.getDefaultInstance()); - - verify(mBasicLoggingApi, never()).onOpenedWithNoImmediateContent(); - } - - @Test - public void testOnSessionStart_logsOnOpenedWithNoContent() { - when(mInitialModelProvider.getCurrentState()).thenReturn(State.READY); - when(mInitialModelProvider.getRootFeature()).thenReturn(null); - mBasicStream.onShow(); - - mBasicStream.onSessionStart(UiContext.getDefaultInstance()); - - verify(mBasicLoggingApi).onOpenedWithNoContent(); - } - - @Test - public void testOnShow_doesNotLogOnOpenedWithNoContent_ifModelProviderNotReady() { - when(mInitialModelProvider.getCurrentState()).thenReturn(State.INITIALIZING); - when(mInitialModelProvider.getRootFeature()).thenReturn(null); - - mBasicStream.onShow(); - - verify(mBasicLoggingApi, never()).onOpenedWithNoContent(); - } - - @Test - public void testOnShow_doesNotLogOnOpenedWithNoContent_ifRootFeatureNotNull() { - when(mInitialModelProvider.getCurrentState()).thenReturn(State.READY); - when(mInitialModelProvider.getRootFeature()).thenReturn(mModelFeature); - - mBasicStream.onShow(); - - verify(mBasicLoggingApi, never()).onOpenedWithNoContent(); - } - - @Test - public void testOnSessionStart_doesNotDoubleLogOnOpenedWithNoContent() { - when(mInitialModelProvider.getCurrentState()).thenReturn(State.READY); - when(mInitialModelProvider.getRootFeature()).thenReturn(null); - - mBasicStream.onShow(); - // Trigger onOpenedWithNoContent logging through onError. - mBasicStream.onError( - new ModelError(ErrorType.NO_CARDS_ERROR, /* continuationToken= */ null)); - reset(mBasicLoggingApi); - - mBasicStream.onSessionStart(UiContext.getDefaultInstance()); - - verify(mBasicLoggingApi, never()).onOpenedWithNoContent(); - } - - @Test - public void testOnSessionStart_doesNotLogOnOpenedWithNoImmediateContentAfterInitialOnShow() { - mBasicStream.onShow(); - mBasicStream.onSessionStart(UiContext.getDefaultInstance()); - reset(mBasicLoggingApi); - - mBasicStream.onSessionStart(UiContext.getDefaultInstance()); - - verify(mBasicLoggingApi, never()).onOpenedWithNoImmediateContent(); - } - - @Test - public void testOnError_doesNotShowZeroState() { - mBasicStream.onShow(); - - assertThatRunnable( - () - -> mBasicStream.onError(new ModelError(ErrorType.PAGINATION_ERROR, - /* continuationToken= */ null))) - .throwsAnExceptionOfType(RuntimeException.class); - } - - @Test - public void testLifecycle_onCreateWithStringCalledOnlyOnce() { - // onCreate is called once in setup - assertThatRunnable(() -> mBasicStream.onCreate("")) - .throwsAnExceptionOfType(IllegalStateException.class); - } - - @Test - public void testLifecycle_getViewBeforeOnCreateCrashes() { - // create BasicStream that has not had onCreate() called. - mBasicStream = createBasicStream(new LinearLayoutManagerWithFakePositioning(mContext)); - assertThatRunnable(() -> mBasicStream.getView()) - .throwsAnExceptionOfType(IllegalStateException.class); - } - - @Test - public void testLifecycle_onCreate_onDestroy() { - mBasicStream.onDestroy(); - verify(mInitialModelProvider, never()).invalidate(); - } - - @Test - public void testLifecycle_onCreate_onShow_onHide_onDestroy() { - mBasicStream.onShow(); - mBasicStream.onHide(); - mBasicStream.onDestroy(); - verify(mAdapter).onDestroy(); - verify(mInitialModelProvider, never()).invalidate(); - verify(mInitialModelProvider).detachModelProvider(); - assertThat(mFakeFeedKnownContent.mListeners).isEmpty(); - } - - @Test - public void testOnDestroy_destroysStreamDriver() { - mBasicStream.onShow(); - mBasicStream.onSessionStart(UiContext.getDefaultInstance()); - reset(mStreamDriver); - - mBasicStream.onDestroy(); - - verify(mStreamDriver).onDestroy(); - } - - @Test - public void testOnDestroy_unregistersOnLayoutChangeListener() { - // initial layout from 0, 0 will not rebind. - getStreamRecyclerView().layout(0, 0, 100, 300); - // change the width / height to simulate device rotation - getStreamRecyclerView().layout(0, 0, 300, 100); - verify(mAdapter).rebind(); - - reset(mAdapter); - mBasicStream.onDestroy(); - - // change the width / height to simulate device rotation - getStreamRecyclerView().layout(0, 0, 100, 300); - verify(mAdapter, never()).rebind(); - } - - @Test - public void testOnLayoutChange_signalsViewActionManager() { - getStreamRecyclerView().layout(0, 0, 100, 300); - verify(mActionManager, times(1)).onLayoutChange(); // Initial layout. - - getStreamRecyclerView().layout(0, 0, 300, 100); // New layout. - verify(mActionManager, times(2)).onLayoutChange(); - } - - @Test - public void testOnDestroy_deregistersSessionListener() { - mBasicStream.onShow(); - - mBasicStream.onDestroy(); - - // Once for BasicStream, once for the session listener. - verify(mInitialModelProvider, times(2)).unregisterObserver(any()); - } - - @Test - @Features.EnableFeatures(ChromeFeatureList.INTEREST_FEEDV1_CLICKS_AND_VIEWS_CONDITIONAL_UPLOAD) - public void testOnDestroy_setReachedUploadConditionsBitInActionManager_whenFeatureEnabled() { - mBasicStream.onDestroy(); - - // Verify that the upload bit is updated one time on #setupRecyclerView and one time - // on #onDestroy. - verify(mActionManager, times(2)).setCanUploadClicksAndViewsWhenNoticeCardIsPresent(true); - } - - @Test - public void testGetSavedInstanceStateString_beforeShow() throws InvalidProtocolBufferException { - StreamSavedInstanceState savedInstanceState = StreamSavedInstanceState.parseFrom( - decodeSavedInstanceStateString(mBasicStream.getSavedInstanceStateString())); - assertThat(savedInstanceState.hasSessionId()).isFalse(); - assertThat(savedInstanceState.getScrollState()).isEqualTo(SCROLL_STATE); - } - - @Test - public void testGetSavedInstanceStateString_afterOnShow_beforeSessionStart() - throws InvalidProtocolBufferException { - when(mInitialModelProvider.getSessionId()).thenReturn(null); - - mBasicStream.onShow(); - - StreamSavedInstanceState savedInstanceState = StreamSavedInstanceState.parseFrom( - decodeSavedInstanceStateString(mBasicStream.getSavedInstanceStateString())); - assertThat(savedInstanceState.hasSessionId()).isFalse(); - assertThat(savedInstanceState.getScrollState()).isEqualTo(SCROLL_STATE); - } - - @Test - public void testGetSavedInstanceStateString_afterOnShow_afterSessionStart() - throws InvalidProtocolBufferException { - mBasicStream.onShow(); - - StreamSavedInstanceState savedInstanceState = StreamSavedInstanceState.parseFrom( - decodeSavedInstanceStateString(mBasicStream.getSavedInstanceStateString())); - assertThat(savedInstanceState.getSessionId()).isEqualTo(SESSION_ID); - assertThat(savedInstanceState.getScrollState()).isEqualTo(SCROLL_STATE); - } - - @Test - public void testGetSavedInstanceStateString_noScrollRestoreBundle() - throws InvalidProtocolBufferException { - mBasicStream.onShow(); - - when(mScrollRestorer.getScrollStateForScrollRestore(ADAPTER_HEADER_COUNT)).thenReturn(null); - StreamSavedInstanceState savedInstanceState = StreamSavedInstanceState.parseFrom( - decodeSavedInstanceStateString(mBasicStream.getSavedInstanceStateString())); - assertThat(savedInstanceState.hasScrollState()).isFalse(); - } - - @Test - public void testRestore() { - mBasicStream.onShow(); - - String savedInstanceState = mBasicStream.getSavedInstanceStateString(); - - mBasicStream.onHide(); - mBasicStream.onDestroy(); - - when(mModelProviderFactory.create(SESSION_ID, UiContext.getDefaultInstance())) - .thenReturn(mRestoredModelProvider); - - mBasicStream = createBasicStream(new LinearLayoutManagerWithFakePositioning(mContext)); - mBasicStream.onCreate(savedInstanceState); - - mBasicStream.onShow(); - - verify(mRestoredModelProvider).registerObserver(mBasicStream); - } - - @Test - public void testRestore_withStringSavedState() { - mBasicStream.onShow(); - - String savedInstanceState = mBasicStream.getSavedInstanceStateString(); - - mBasicStream.onHide(); - mBasicStream.onDestroy(); - - when(mModelProviderFactory.create(SESSION_ID, UiContext.getDefaultInstance())) - .thenReturn(mRestoredModelProvider); - - mBasicStream = createBasicStream(new LinearLayoutManagerWithFakePositioning(mContext)); - mBasicStream.onCreate(savedInstanceState); - - mBasicStream.onShow(); - - verify(mRestoredModelProvider).registerObserver(mBasicStream); - } - - @Test - public void testRestore_doesNotShowZeroState() { - mBasicStream.onShow(); - - String savedInstanceState = mBasicStream.getSavedInstanceStateString(); - - mBasicStream.onHide(); - mBasicStream.onDestroy(); - - when(mModelProviderFactory.create(SESSION_ID, UiContext.getDefaultInstance())) - .thenReturn(mRestoredModelProvider); - - reset(mStreamDriver); - mBasicStream = createBasicStream(new LinearLayoutManagerWithFakePositioning(mContext)); - mBasicStream.onCreate(savedInstanceState); - - mBasicStream.onShow(); - - verify(mStreamDriver, never()).showZeroState(/* zeroStateShowReason= */ anyInt()); - verify(mStreamDriver, never()).showSpinner(); - } - - @Test - public void testRestore_showsZeroStateIfNoSessionToRestore() { - mBasicStream = createBasicStream(new LinearLayoutManagerWithFakePositioning(mContext)); - mBasicStream.onCreate(""); - - mBasicStream.onShow(); - - verify(mStreamDriver, never()).showSpinner(); - - mClock.advance(SPINNER_DELAY_MS); - - verify(mStreamDriver).showSpinner(); - } - - @Test - public void testRestore_invalidSession() { - mBasicStream.onShow(); - - String savedInstanceState = mBasicStream.getSavedInstanceStateString(); - - mBasicStream.onHide(); - mBasicStream.onDestroy(); - - mBasicStream = createBasicStream(new LinearLayoutManagerWithFakePositioning(mContext)); - mBasicStream.onCreate(savedInstanceState); - mBasicStream.onShow(); - - verify(mModelProvider).registerObserver(mBasicStream); - } - - @Test - public void testRestore_invalidBase64Encoding() { - mBasicStream.onShow(); - - mBasicStream.onHide(); - mBasicStream.onDestroy(); - - mBasicStream = createBasicStream(new LinearLayoutManagerWithFakePositioning(mContext)); - assertThatRunnable(() -> mBasicStream.onCreate("=invalid")) - .throwsAnExceptionOfType(RuntimeException.class); - } - - @Test - public void testRestore_invalidProtocolBuffer() { - mBasicStream.onShow(); - - mBasicStream.onHide(); - mBasicStream.onDestroy(); - - mBasicStream = createBasicStream(new LinearLayoutManagerWithFakePositioning(mContext)); - assertThatRunnable(() - -> mBasicStream.onCreate(Base64.encodeToString( - "invalid".getBytes(UTF_8), Base64.DEFAULT))) - .throwsAnExceptionOfType(RuntimeException.class); - } - - @Test - public void testRestore_createsStreamDriver() { - mBasicStream.onShow(); - - String savedInstanceState = mBasicStream.getSavedInstanceStateString(); - - mBasicStream.onHide(); - mBasicStream.onDestroy(); - - when(mModelProviderFactory.create(SESSION_ID, UiContext.getDefaultInstance())) - .thenReturn(mRestoredModelProvider); - - mBasicStream = createBasicStream(new LinearLayoutManagerWithFakePositioning(mContext)); - mBasicStream.onCreate(savedInstanceState); - - mBasicStream.onShow(); - - assertThat(mBasicStream.mStreamDriverRestoring).isTrue(); - } - - @Test - public void testRestore_createsStreamDriver_afterFailure() { - mBasicStream.onShow(); - - String savedInstanceState = mBasicStream.getSavedInstanceStateString(); - - mBasicStream.onHide(); - mBasicStream.onDestroy(); - - when(mModelProviderFactory.create(SESSION_ID, UiContext.getDefaultInstance())) - .thenReturn(mRestoredModelProvider); - - mBasicStream = createBasicStream(new LinearLayoutManagerWithFakePositioning(mContext)); - mBasicStream.onCreate(savedInstanceState); - - // onSessionFinish indicates the restore has failed. - mBasicStream.onSessionFinished(UiContext.getDefaultInstance()); - - mBasicStream.onShow(); - - assertThat(mBasicStream.mStreamDriverRestoring).isFalse(); - } - - @Test - public void testTrim() { - ShadowRecycledViewPool viewPool = - Shadow.extract(getStreamRecyclerView().getRecycledViewPool()); - - // RecyclerView ends up clearing the pool initially when the adapter is set on the - // RecyclerView. Verify that has happened before anything else - assertThat(viewPool.getClearCallCount()).isEqualTo(1); - - mBasicStream.trim(); - - verify(mPietManager).purgeRecyclerPools(); - - // We expect the clear() call to be 2 as RecyclerView ends up clearing the pool initially - // when the adapter is set on the RecyclerView. So one call for that and one call for - // trim() call on stream. - assertThat(viewPool.getClearCallCount()).isEqualTo(2); - } - - @Test - public void testLayoutChanges() { - // initial layout from 0, 0 will not rebind. - getStreamRecyclerView().layout(0, 0, 100, 300); - verify(mAdapter, never()).rebind(); - // change the width / height to simulate device rotation - getStreamRecyclerView().layout(0, 0, 300, 100); - verify(mAdapter).rebind(); - } - - @Test - public void testAddScrollListener() { - ScrollListener scrollListener = mock(ScrollListener.class); - mBasicStream.addScrollListener(scrollListener); - verify(mScrollListenerNotifier).addScrollListener(scrollListener); - } - - @Test - public void testRemoveScrollListener() { - ScrollListener scrollListener = mock(ScrollListener.class); - mBasicStream.removeScrollListener(scrollListener); - verify(mScrollListenerNotifier).removeScrollListener(scrollListener); - } - - @Test - public void testIsChildAtPositionVisible() { - mLayoutManager.mFirstVisiblePosition = 0; - mLayoutManager.mLastVisiblePosition = 1; - assertThat(mBasicStream.isChildAtPositionVisible(-2)).isFalse(); - assertThat(mBasicStream.isChildAtPositionVisible(-1)).isFalse(); - assertThat(mBasicStream.isChildAtPositionVisible(0)).isTrue(); - assertThat(mBasicStream.isChildAtPositionVisible(1)).isTrue(); - assertThat(mBasicStream.isChildAtPositionVisible(2)).isFalse(); - } - - @Test - public void testIsChildAtPositionVisible_nothingVisible() { - assertThat(mBasicStream.isChildAtPositionVisible(0)).isFalse(); - } - - @Test - public void testIsChildAtPositionVisible_validTop() { - mLayoutManager.mFirstVisiblePosition = 0; - assertThat(mBasicStream.isChildAtPositionVisible(0)).isFalse(); - } - - @Test - public void testIsChildAtPositionVisible_validBottom() { - mLayoutManager.mLastVisiblePosition = 1; - assertThat(mBasicStream.isChildAtPositionVisible(0)).isFalse(); - } - - @Test - public void testGetChildTopAt_noVisibleChild() { - assertThat(mBasicStream.getChildTopAt(0)).isEqualTo(POSITION_NOT_KNOWN); - } - - @Test - public void testGetChildTopAt_noChild() { - mLayoutManager.mFirstVisiblePosition = 0; - mLayoutManager.mLastVisiblePosition = 1; - assertThat(mBasicStream.getChildTopAt(0)).isEqualTo(POSITION_NOT_KNOWN); - } - - @Test - public void testGetChildTopAt() { - mLayoutManager.mFirstVisiblePosition = 0; - mLayoutManager.mLastVisiblePosition = 1; - View view = new FrameLayout(mContext); - mLayoutManager.addChildToPosition(0, view); - - assertThat(mBasicStream.getChildTopAt(0)).isEqualTo(view.getTop()); - } - - @Test - public void testStreamContentVisible() { - mBasicStream.setStreamContentVisibility(false); - verify(mAdapter).setStreamContentVisible(false); - - reset(mAdapter); - mBasicStream.setStreamContentVisibility(true); - verify(mAdapter).setStreamContentVisible(true); - } - - @Test - public void testStreamContentVisible_notifiesItemAnimator_notVisible() { - mBasicStream.setStreamContentVisibility(false); - - assertThat(((StreamItemAnimator) getStreamRecyclerView().getItemAnimator()) - .getStreamContentVisibility()) - .isFalse(); - } - - @Test - public void testStreamContentVisible_notifiesItemAnimator_visible() { - mBasicStream.setStreamContentVisibility(true); - - assertThat(((StreamItemAnimator) getStreamRecyclerView().getItemAnimator()) - .getStreamContentVisibility()) - .isTrue(); - } - - @Test - public void testSetStreamContentVisibility_createsModelProvider_ifContentNotVisible() { - mBasicStream.setStreamContentVisibility(false); - mBasicStream.onShow(); - - verifyNoMoreInteractions(mModelProvider); - - mBasicStream.setStreamContentVisibility(true); - - verify(mModelProviderFactory).createNew(any(ViewDepthProvider.class), any(UiContext.class)); - } - - @Test - public void testSetStreamContentVisibility_resetsViewLogging() { - mBasicStream.setStreamContentVisibility(false); - mBasicStream.onShow(); - - mBasicStream.setStreamContentVisibility(true); - - verify(mViewLoggingUpdater).resetViewTracking(); - } - - @Test - public void testSetStreamContentVisibility_trueMultipleTimes_doesNotResetViewLogging() { - mBasicStream.setStreamContentVisibility(true); - mBasicStream.onShow(); - - mBasicStream.setStreamContentVisibility(true); - - verify(mViewLoggingUpdater, never()).resetViewTracking(); - } - - @Test - public void testTriggerRefresh() { - mBasicStream.onShow(); - - reset(mAdapter, mStreamDriver); - - mBasicStream.triggerRefresh(); - - verify(mInitialModelProvider).triggerRefresh(RequestReason.HOST_REQUESTED); - verify(mStreamDriver).showSpinner(); - } - - @Test - public void testTriggerRefresh_beforeOnShow() { - mBasicStream.triggerRefresh(); - - verify(mInitialModelProvider, never()).triggerRefresh(anyInt()); - verify(mStreamDriver, never()).showSpinner(); - } - - @Test - public void testAddOnContentChangedListener() { - ContentChangedListener contentChangedListener = mock(ContentChangedListener.class); - - mBasicStream.addOnContentChangedListener(contentChangedListener); - mBasicStream.mContentChangedListener.onContentChanged(); - - verify(contentChangedListener).onContentChanged(); - } - - @Test - public void testRemoveOnContentChangedListener() { - ContentChangedListener contentChangedListener = mock(ContentChangedListener.class); - - mBasicStream.addOnContentChangedListener(contentChangedListener); - mBasicStream.removeOnContentChangedListener(contentChangedListener); - - mBasicStream.mContentChangedListener.onContentChanged(); - - verify(contentChangedListener, never()).onContentChanged(); - } - - @Test - public void testOnShow_nonRestoringRestorer() { - mBasicStream.onShow(); - - assertThat(mBasicStream.mStreamDriverScrollRestorer).isEqualTo(mNonRestoringScrollRestorer); - } - - @Test - public void testOnShow_restoringScrollRestorer() { - when(mInitialModelProvider.getCurrentState()).thenReturn(State.READY); - mBasicStream.onShow(); - - assertThat(mBasicStream.mStreamDriverScrollRestorer).isEqualTo(mScrollRestorer); - } - - @Test - public void testOnShow_setShown() { - mBasicStream.onShow(); - - verify(mAdapter).setShown(true); - } - - @Test - public void testOnShow_doesNotCreateModelProvider_ifStreamContentNotVisible() { - mBasicStream.setStreamContentVisibility(false); - - mBasicStream.onShow(); - - verifyNoMoreInteractions(mModelProviderFactory); - verify(mAdapter, never()).setDriver(any(StreamDriver.class)); - } - - @Test - public void testOnShow_restoresScrollPosition_ifStreamContentNotVisible() { - mBasicStream.setStreamContentVisibility(false); - - mBasicStream.onShow(); - - verify(mScrollRestorer).maybeRestoreScroll(); - } - - @Test - public void testOnSessionStart_showsContentImmediately_ifNotInitialLoad() { - mBasicStream.onShow(); - mBasicStream.onSessionStart(UiContext.getDefaultInstance()); - reset(mAdapter); - - mBasicStream.onSessionStart(UiContext.getDefaultInstance()); - verify(mAdapter).setDriver(mStreamDriver); - } - - @Test - public void testOnSessionStart_showsContentImmediately_ifSpinnerTimeElapsed() { - mBasicStream.onShow(); - reset(mAdapter); - - // Advance so the spinner is shown. - mClock.advance(SPINNER_DELAY_MS); - - // Advance so that it has shown long enough - mClock.advance(SPINNER_MINIMUM_SHOW_TIME_MS); - - mBasicStream.onSessionStart(UiContext.getDefaultInstance()); - - // The adapter should be immediately set in onSesssionStart - verify(mAdapter).setDriver(mStreamDriver); - } - - @Test - public void testOnSessionStart_showsContentWithDelay_ifSpinnerTimeNotElapsed() { - mBasicStream.onShow(); - - // Advance so the spinner is shown. - mClock.advance(SPINNER_DELAY_MS); - - reset(mAdapter); - - mBasicStream.onSessionStart(UiContext.getDefaultInstance()); - verify(mAdapter, never()).setDriver(any(StreamDriver.class)); - - // Advance so that it has shown long enough. - mClock.advance(SPINNER_MINIMUM_SHOW_TIME_MS); - - verify(mAdapter).setDriver(mStreamDriver); - } - - @Test - public void testOnSessionStart_doesNotShowContent_ifSessionFinishesBeforeSpinnerTimeElapsed() { - mClock.set(10); - - mBasicStream.onShow(); - - reset(mAdapter); - - // Advance so the spinner is shown. - mClock.advance(SPINNER_DELAY_MS); - - mBasicStream.onSessionStart(UiContext.getDefaultInstance()); - mBasicStream.onSessionFinished(UiContext.getDefaultInstance()); - - // Advance so that it has shown long enough. - mClock.advance(SPINNER_MINIMUM_SHOW_TIME_MS); - - verify(mAdapter, never()).setDriver(mStreamDriver); - } - - @Test - public void testOnSessionStart_showsZeroState_ifFeatureDriversEmpty() { - mBasicStream.onShow(); - - mBasicStream.onSessionStart(UiContext.getDefaultInstance()); - - verify(mStreamDriver).showZeroState(ZeroStateShowReason.NO_CONTENT); - } - - @Test - public void testOnShow_delaysShowingZeroState_onInitialLoad() { - mBasicStream.onShow(); - - verify(mStreamDriver, never()).showZeroState(/* zeroStateShowReason= */ anyInt()); - verify(mStreamDriver, never()).showSpinner(); - - // Advance so the spinner is shown. - mClock.advance(SPINNER_DELAY_MS); - - verify(mStreamDriver).showSpinner(); - } - - @Test - public void testOnShow_delaysShowingZeroState_configured_delay_time() { - mBasicStream.onShow(); - - verify(mStreamDriver, never()).showZeroState(/* zeroStateShowReason= */ anyInt()); - verify(mStreamDriver, never()).showSpinner(); - - // Advance so the spinner is shown. - mClock.advance(SPINNER_DELAY_MS); - - verify(mStreamDriver).showSpinner(); - } - - @Test - public void testOnHide_setShown() { - mBasicStream.onShow(); - reset(mAdapter); - - mBasicStream.onHide(); - - verify(mAdapter).setShown(false); - } - - @Test - public void testOnShow_signalsViewActionManager() { - mBasicStream.onShow(); - verify(mActionManager).onShow(); - } - - @Test - public void testOnHide_signalsViewActionManager() { - mBasicStream.onHide(); - verify(mActionManager).onHide(); - } - - @Test - public void testOnHide_dismissesPopup() { - mBasicStream.onHide(); - verify(mContextMenuManager).dismissPopup(); - } - - @Test - public void onSessionFinished_afterOnDestroy_unregistersOnce() { - mBasicStream.onShow(); - - mBasicStream.onDestroy(); - mBasicStream.onSessionFinished(UiContext.getDefaultInstance()); - - // Should only occur once between onDestroy() and onSessionFinished() - verify(mInitialModelProvider).unregisterObserver(mBasicStream); - } - - @Test - public void onDestroyTwice_unregistersOnce() { - mBasicStream.onShow(); - - mBasicStream.onDestroy(); - mBasicStream.onDestroy(); - - // Should only occur once between multiple onDestroy() calls - verify(mInitialModelProvider).unregisterObserver(mBasicStream); - } - - @Test - public void onSessionStart_propagatesUiContext() { - mBasicStream.onShow(); - - UiRefreshReason uiRefreshReason = - UiRefreshReason.newBuilder().setReason(Reason.ZERO_STATE).build(); - mBasicStream.onSessionStart(UiContext.getDefaultInstance()); - mBasicStream.onSessionFinished( - UiContext.newBuilder() - .setExtension(UiRefreshReason.uiRefreshReasonExtension, uiRefreshReason) - .build()); - mBasicStream.onSessionStart(UiContext.getDefaultInstance()); - - assertThat(mBasicStream.mStreamDriverUiRefreshReason).isEqualTo(uiRefreshReason); - } - - @Test - public void onShow_whileStreamContentNotVisible_logsOpenedWithNoContent() { - mBasicStream.setStreamContentVisibility(false); - - mBasicStream.onShow(); - - verify(mBasicLoggingApi).onOpenedWithNoContent(); - } - - @Test - public void onShow_whileStreamContentNotVisible_twice_logsOpenedWithNoContentOnce() { - mBasicStream.setStreamContentVisibility(false); - - mBasicStream.onShow(); - mBasicStream.onHide(); - mBasicStream.onShow(); - - verify(mBasicLoggingApi).onOpenedWithNoContent(); - } - - @Test - public void failToRestoreSession_doesntShowSpinnerImmediately() { - mBasicStream.onShow(); - - mBasicStream.onSessionFinished(UiContext.getDefaultInstance()); - - verify(mStreamDriver, never()).showSpinner(); - } - - @Test - public void failToRestoreSession_showsSpinnerAfterDelay() { - mBasicStream.onShow(); - - mBasicStream.onSessionFinished(UiContext.getDefaultInstance()); - - mClock.advance(SPINNER_DELAY_MS); - - verify(mStreamDriver).showSpinner(); - } - - @Test - public void startSession_quicklyFinish_doesntShowInitialSpinner() { - mBasicStream.onShow(); - - // Advance, but not enough so that the spinner shows. - mClock.advance(SPINNER_DELAY_MS / 2); - - // Start the session. At this point, the spinner enqueued by onShow() should never be shown. - mBasicStream.onSessionStart(UiContext.getDefaultInstance()); - - // Finish the session immediately. As we had started a session and the user had presumably - // seen content, we shouldn't trigger the spinner enqueued by onShow(). - mBasicStream.onSessionFinished(UiContext.getDefaultInstance()); - - // It has now been long enough since onShow that the spinner would show if onSessionStart() - // hadn't been called first. - mClock.advance(SPINNER_DELAY_MS / 2 + 1); - - verify(mStreamDriver, never()).showSpinner(); - } - - @Test - public void startSession_thenFinish_showsSpinnerAfterDelay() { - mBasicStream.onShow(); - - mBasicStream.onSessionStart(UiContext.getDefaultInstance()); - mBasicStream.onSessionFinished(UiContext.getDefaultInstance()); - - verify(mStreamDriver, never()).showSpinner(); - - mClock.advance(SPINNER_DELAY_MS); - - verify(mStreamDriver).showSpinner(); - } - - private byte[] decodeSavedInstanceStateString(String savedInstanceState) { - return Base64.decode(savedInstanceState, Base64.DEFAULT); - } - - private RecyclerView getStreamRecyclerView() { - return (RecyclerView) mBasicStream.getView(); - } - - private BasicStreamForTest createBasicStream(LinearLayoutManager layoutManager) { - return new BasicStreamForTest(mContext, mStreamConfiguration, mock(CardConfiguration.class), - mock(ImageLoaderApi.class), mock(ActionParserFactory.class), mock(ActionApi.class), - mock(CustomElementProvider.class), DebugBehavior.VERBOSE, new ThreadUtils(), - mHeaders, mClock, mModelProviderFactory, new HostBindingProvider(), mActionManager, - CONFIGURATION, layoutManager, mock(OfflineIndicatorApi.class), mStreamDriver); - } - - private class BasicStreamForTest extends BasicStream { - private final LinearLayoutManager mLayoutManager; - private StreamDriver mStreamDriver; - private boolean mStreamDriverRestoring; - - private ScrollRestorer mStreamDriverScrollRestorer; - private StreamContentChangedListener mContentChangedListener; - private UiRefreshReason mStreamDriverUiRefreshReason; - - public BasicStreamForTest(Context context, StreamConfiguration streamConfiguration, - CardConfiguration cardConfiguration, ImageLoaderApi imageLoaderApi, - ActionParserFactory actionParserFactory, ActionApi actionApi, - /*@Nullable*/ CustomElementProvider customElementProvider, - DebugBehavior debugBehavior, ThreadUtils threadUtils, List<Header> headers, - Clock clock, ModelProviderFactory modelProviderFactory, - /*@Nullable*/ HostBindingProvider hostBindingProvider, ActionManager actionManager, - Configuration configuration, LinearLayoutManager layoutManager, - OfflineIndicatorApi offlineIndicatorApi, StreamDriver streamDriver) { - super(context, streamConfiguration, cardConfiguration, imageLoaderApi, - actionParserFactory, actionApi, customElementProvider, debugBehavior, - threadUtils, headers, clock, modelProviderFactory, hostBindingProvider, - actionManager, configuration, mSnackbarApi, mBasicLoggingApi, - offlineIndicatorApi, - - mMainThreadRunner, mFakeFeedKnownContent, mTooltipApi, - /* isBackgroundDark= */ false, /* isPlaceholderShown= */ false); - this.mLayoutManager = layoutManager; - this.mStreamDriver = streamDriver; - } - - @Override - PietManager createPietManager(Context context, CardConfiguration cardConfiguration, - ImageLoaderApi imageLoaderApi, - /*@Nullable*/ CustomElementProvider customElementProvider, - DebugBehavior debugBehavior, Clock clock, - /*@Nullable*/ HostBindingProvider hostBindingProvider, - StreamOfflineMonitor streamOfflineMonitor, Configuration config, - boolean isBackgroundDark) { - return mPietManager; - } - - @Override - StreamDriver createStreamDriver(ActionApi actionApi, ActionManager actionManager, - ActionParserFactory actionParserFactory, ModelProvider modelProvider, - ThreadUtils threadUtils, Clock clock, Configuration configuration, Context context, - SnackbarApi snackbarApi, ContentChangedListener contentChangedListener, - ScrollRestorer scrollRestorer, BasicLoggingApi basicLoggingApi, - StreamOfflineMonitor streamOfflineMonitor, FeedKnownContent feedKnownContent, - ContextMenuManager contextMenuManager, boolean restoring, boolean isInitialLoad, - MainThreadRunner mainThreadRunner, TooltipApi tooltipApi, - UiRefreshReason uiRefreshReason, ScrollListenerNotifier scrollListenerNotifier) { - mStreamDriverScrollRestorer = scrollRestorer; - mStreamDriverRestoring = restoring; - this.mStreamDriverUiRefreshReason = uiRefreshReason; - return mStreamDriver; - } - - @Override - StreamContentChangedListener createStreamContentChangedListener() { - mContentChangedListener = new StreamContentChangedListener(); - return mContentChangedListener; - } - - @Override - StreamRecyclerViewAdapter createRecyclerViewAdapter(Context context, - CardConfiguration cardConfiguration, PietManager pietManager, - DeepestContentTracker deepestContentTracker, - StreamContentChangedListener streamContentChangedListener, - ScrollObservable scrollObservable, Configuration configuration, - PietEventLogger pietEventLogger) { - return mAdapter; - } - - @Override - ScrollListenerNotifier createScrollListenerNotifier( - ContentChangedListener contentChangedListener, - BasicStreamScrollMonitor scrollMonitor, MainThreadRunner mainThreadRunner) { - return mScrollListenerNotifier; - } - - @Override - LinearLayoutManager createRecyclerViewLayoutManager(Context context) { - return mLayoutManager; - } - - @Override - ScrollRestorer createScrollRestorer(Configuration configuration, RecyclerView recyclerView, - ScrollListenerNotifier scrollListenerNotifier, - /*@Nullable*/ ScrollState scrollState) { - return mScrollRestorer; - } - - @Override - ScrollRestorer createNonRestoringScrollRestorer(Configuration configuration, - RecyclerView recyclerView, ScrollListenerNotifier scrollListenerNotifier) { - return mNonRestoringScrollRestorer; - } - - @Override - ContextMenuManagerImpl createContextMenuManager( - RecyclerView recyclerView, MenuMeasurer menuMeasurer) { - return mContextMenuManager; - } - - @Override - ViewLoggingUpdater createViewLoggingUpdater() { - return mViewLoggingUpdater; - } - } - - private class LinearLayoutManagerWithFakePositioning extends LinearLayoutManager { - private final List<View> mChildMap; - private int mFirstVisiblePosition = RecyclerView.NO_POSITION; - private int mLastVisiblePosition = RecyclerView.NO_POSITION; - - public LinearLayoutManagerWithFakePositioning(Context context) { - super(context); - mChildMap = new ArrayList<>(); - } - - @Override - public int findFirstVisibleItemPosition() { - return mFirstVisiblePosition; - } - - @Override - public int findLastVisibleItemPosition() { - return mLastVisiblePosition; - } - - @Override - public View findViewByPosition(int i) { - if (i < 0 || i >= mChildMap.size()) { - return null; - } - return mChildMap.get(i); - } - - private void addChildToPosition(int position, View child) { - mChildMap.add(position, child); - } - } - - private static class FakeFeedKnownContent implements FeedKnownContent { - private final Set<KnownContent.Listener> mListeners = new HashSet<>(); - - @Override - public void getKnownContent(Consumer<List<ContentMetadata>> knownContentConsumer) {} - - @Override - public void addListener(KnownContent.Listener listener) { - mListeners.add(listener); - } - - @Override - public void removeListener(KnownContent.Listener listener) { - mListeners.remove(listener); - } - - @Override - public Listener getKnownContentHostNotifier() { - return null; - } - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/StreamItemAnimatorTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/StreamItemAnimatorTest.java deleted file mode 100644 index 020bf63..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/StreamItemAnimatorTest.java +++ /dev/null
@@ -1,79 +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. - -package org.chromium.chrome.browser.feed.library.basicstream.internal; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.internal.actionmanager.ViewActionManager; -import org.chromium.chrome.browser.feed.library.basicstream.internal.viewholders.FeedViewHolder; -import org.chromium.chrome.browser.feed.shared.stream.Stream.ContentChangedListener; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link StreamItemAnimator}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class StreamItemAnimatorTest { - @Mock - private ContentChangedListener mContentChangedListener; - @Mock - private ViewActionManager mViewActionManager; - @Mock - private FeedViewHolder mFeedViewHolder; - - private StreamItemAnimatorForTest mStreamItemAnimator; - - @Before - public void setup() { - initMocks(this); - mStreamItemAnimator = - new StreamItemAnimatorForTest(mContentChangedListener, mViewActionManager); - } - - @Test - public void testOnAnimationFinished() { - mStreamItemAnimator.onAnimationFinished(mFeedViewHolder); - verify(mContentChangedListener).onContentChanged(); - verify(mViewActionManager, never()).onAnimationFinished(); - } - - @Test - public void testOnAnimationFinished_visible() { - mStreamItemAnimator.setStreamVisibility(true); - mStreamItemAnimator.onAnimationFinished(mFeedViewHolder); - verify(mContentChangedListener).onContentChanged(); - verify(mViewActionManager).onAnimationFinished(); - } - - @Test - public void setStreamVisibility_toVisible_endsAnimations() { - mStreamItemAnimator.setStreamVisibility(true); - assertThat(mStreamItemAnimator.mAnimationsEnded).isTrue(); - } - - private static class StreamItemAnimatorForTest extends StreamItemAnimator { - private boolean mAnimationsEnded; - - StreamItemAnimatorForTest( - ContentChangedListener contentChangedListener, ViewActionManager actionManager) { - super(contentChangedListener, actionManager, null); - } - - @Override - public void endAnimations() { - super.endAnimations(); - mAnimationsEnded = true; - } - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/StreamItemTouchCallbacksTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/StreamItemTouchCallbacksTest.java deleted file mode 100644 index c8a1f93..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/StreamItemTouchCallbacksTest.java +++ /dev/null
@@ -1,133 +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. - -package org.chromium.chrome.browser.feed.library.basicstream.internal; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.mock; - -import android.app.Activity; -import android.content.Context; -import android.graphics.Canvas; -import android.view.View; -import android.view.View.MeasureSpec; -import android.widget.FrameLayout; - -import androidx.recyclerview.widget.ItemTouchHelper; -import androidx.recyclerview.widget.RecyclerView; -import androidx.recyclerview.widget.RecyclerView.ViewHolder; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.basicstream.internal.viewholders.SwipeableViewHolder; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link StreamItemTouchCallbacks}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public final class StreamItemTouchCallbacksTest { - private final int mNoMovementFlag = 0; - - private DismissibleViewHolder mDismissibleViewHolder; - - private StreamItemTouchCallbacks mCallbacks; - private FrameLayout mFrameLayout; - private RecyclerView mRecyclerView; - - @Before - public void setUp() { - mCallbacks = new StreamItemTouchCallbacks(); - Context context = Robolectric.buildActivity(Activity.class).get(); - mRecyclerView = new RecyclerView(context); - mFrameLayout = new FrameLayout(context); - mDismissibleViewHolder = - new DismissibleViewHolder(mFrameLayout, /* isDismissible= */ false); - } - - @Test - public void testGetMovementFlags_nonSwipeableViewHolderType() { - ViewHolder nonPietViewHolder = mock(ViewHolder.class); - - int movementFlags = mCallbacks.getMovementFlags(mRecyclerView, nonPietViewHolder); - - assertThat(movementFlags).isEqualTo(mNoMovementFlag); - } - - @Test - public void testGetMovementFlags_notDismissibleSwipeableViewholder() { - mDismissibleViewHolder = - new DismissibleViewHolder(mFrameLayout, /* isDismissible= */ false); - - int movementFlags = mCallbacks.getMovementFlags(mRecyclerView, mDismissibleViewHolder); - - assertThat(movementFlags).isEqualTo(mNoMovementFlag); - } - - @Test - public void testGetMovementFlags_swipeablePiet() { - mDismissibleViewHolder = new DismissibleViewHolder(mFrameLayout, /* isDismissible= */ true); - - int movementFlags = mCallbacks.getMovementFlags(mRecyclerView, mDismissibleViewHolder); - - assertThat(movementFlags) - .isEqualTo(ItemTouchHelper.Callback.makeMovementFlags( - 0, ItemTouchHelper.START | ItemTouchHelper.END)); - } - - @Test - public void testOnSwiped() { - mDismissibleViewHolder = new DismissibleViewHolder(mFrameLayout, /* isDismissible= */ true); - assertThat(mDismissibleViewHolder.isOnSwipedCalled()).isFalse(); - - mCallbacks.onSwiped(mDismissibleViewHolder, 0); - - assertThat(mDismissibleViewHolder.isOnSwipedCalled()).isTrue(); - } - - @Test - public void testOnChildDraw() { - float translationX = 65; - mFrameLayout.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(200, MeasureSpec.EXACTLY)); - mDismissibleViewHolder = - new DismissibleViewHolder(mFrameLayout, /* isDismissible= */ false); - - mCallbacks.onChildDraw(new Canvas(), mRecyclerView, mDismissibleViewHolder, translationX, - /* dY= */ 0, - /* i= */ 1, - /* isCurrentlyActive= */ true); - - assertThat(mDismissibleViewHolder.itemView.getTranslationX()).isEqualTo(translationX); - assertThat(mDismissibleViewHolder.itemView.getAlpha()).isEqualTo(.5f); - } - - private static class DismissibleViewHolder extends ViewHolder implements SwipeableViewHolder { - private final boolean mIsDismissible; - private boolean mOnSwipedCalled; - - DismissibleViewHolder(View view, boolean isDismissible) { - super(view); - this.mIsDismissible = isDismissible; - } - - @Override - public boolean canSwipe() { - return mIsDismissible; - } - - @Override - public void onSwiped() { - mOnSwipedCalled = true; - } - - boolean isOnSwipedCalled() { - return mOnSwipedCalled; - } - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/StreamRecyclerViewAdapterTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/StreamRecyclerViewAdapterTest.java deleted file mode 100644 index ee1cab06..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/StreamRecyclerViewAdapterTest.java +++ /dev/null
@@ -1,560 +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. - -package org.chromium.chrome.browser.feed.library.basicstream.internal; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import android.app.Activity; -import android.content.Context; -import android.view.ViewGroup; -import android.widget.FrameLayout; -import android.widget.FrameLayout.LayoutParams; -import android.widget.LinearLayout; - -import androidx.recyclerview.widget.RecyclerView; -import androidx.recyclerview.widget.RecyclerView.ViewHolder; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentMatchers; -import org.mockito.InOrder; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.base.supplier.Supplier; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration; -import org.chromium.chrome.browser.feed.library.api.host.stream.CardConfiguration; -import org.chromium.chrome.browser.feed.library.basicstream.internal.drivers.ContentDriver; -import org.chromium.chrome.browser.feed.library.basicstream.internal.drivers.HeaderDriver; -import org.chromium.chrome.browser.feed.library.basicstream.internal.drivers.LeafFeatureDriver; -import org.chromium.chrome.browser.feed.library.basicstream.internal.drivers.StreamDriver; -import org.chromium.chrome.browser.feed.library.basicstream.internal.viewholders.ContinuationViewHolder; -import org.chromium.chrome.browser.feed.library.basicstream.internal.viewholders.FeedViewHolder; -import org.chromium.chrome.browser.feed.library.basicstream.internal.viewholders.NoContentViewHolder; -import org.chromium.chrome.browser.feed.library.basicstream.internal.viewholders.PietViewHolder; -import org.chromium.chrome.browser.feed.library.basicstream.internal.viewholders.ViewHolderType; -import org.chromium.chrome.browser.feed.library.basicstream.internal.viewholders.ZeroStateViewHolder; -import org.chromium.chrome.browser.feed.library.piet.FrameAdapter; -import org.chromium.chrome.browser.feed.library.piet.PietManager; -import org.chromium.chrome.browser.feed.library.piet.host.ActionHandler; -import org.chromium.chrome.browser.feed.library.piet.host.EventLogger; -import org.chromium.chrome.browser.feed.library.sharedstream.deepestcontenttracker.DeepestContentTracker; -import org.chromium.chrome.browser.feed.library.sharedstream.piet.PietEventLogger; -import org.chromium.chrome.browser.feed.library.sharedstream.publicapi.scroll.ScrollObservable; -import org.chromium.chrome.browser.feed.shared.stream.Header; -import org.chromium.chrome.browser.feed.shared.stream.Stream.ContentChangedListener; -import org.chromium.chrome.R; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.Collections; -import java.util.List; - -/** Tests for {@link StreamRecyclerViewAdapter}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class StreamRecyclerViewAdapterTest { - private static final int HEADER_COUNT = 2; - private static final long FEATURE_DRIVER_1_ID = 123; - private static final long FEATURE_DRIVER_2_ID = 321; - private static final String INITIAL_CONTENT_ID = "INITIAL_CONTENT_ID"; - private static final String FEATURE_DRIVER_1_CONTENT_ID = "FEATURE_DRIVER_1_CONTENT_ID"; - private static final String FEATURE_DRIVER_2_CONTENT_ID = "FEATURE_DRIVER_2_CONTENT_ID"; - private static final Configuration CONFIGURATION = new Configuration.Builder().build(); - - @Mock - private CardConfiguration mCardConfiguration; - @Mock - private ContentChangedListener mContentChangedListener; - @Mock - private PietManager mPietManager; - @Mock - private FrameAdapter mFrameAdapter; - @Mock - private StreamDriver mDriver; - @Mock - private ContentDriver mInitialFeatureDriver; - @Mock - private ContentDriver mFeatureDriver1; - @Mock - private ContentDriver mFeatureDriver2; - @Mock - private HeaderDriver mHeaderDriver1; - @Mock - private HeaderDriver mHeaderDriver2; - @Mock - private DeepestContentTracker mDeepestContentTracker; - @Mock - private Header mHeader1; - @Mock - private Header mHeader2; - @Mock - private ScrollObservable mScrollObservable; - @Mock - private PietEventLogger mPietEventLogger; - - private Context mContext; - private LinearLayout mFrameContainer; - private StreamRecyclerViewAdapter mStreamRecyclerViewAdapter; - private List<Header> mHeaders; - private StreamAdapterObserver mStreamAdapterObserver; - - @Before - public void setUp() { - initMocks(this); - - mContext = Robolectric.buildActivity(Activity.class).get(); - mContext.setTheme(R.style.Light); - mFrameContainer = new LinearLayout(mContext); - - when(mPietManager.createPietFrameAdapter(ArgumentMatchers.<Supplier<ViewGroup>>any(), - any(ActionHandler.class), any(EventLogger.class), eq(mContext))) - .thenReturn(mFrameAdapter); - when(mFrameAdapter.getFrameContainer()).thenReturn(mFrameContainer); - - when(mFeatureDriver1.itemId()).thenReturn(FEATURE_DRIVER_1_ID); - when(mFeatureDriver2.itemId()).thenReturn(FEATURE_DRIVER_2_ID); - when(mInitialFeatureDriver.getContentId()).thenReturn(INITIAL_CONTENT_ID); - - mHeaders = ImmutableList.of(mHeader1, mHeader2); - - when(mFeatureDriver1.getContentId()).thenReturn(FEATURE_DRIVER_1_CONTENT_ID); - when(mFeatureDriver2.getContentId()).thenReturn(FEATURE_DRIVER_2_CONTENT_ID); - when(mHeaderDriver1.getHeader()).thenReturn(mHeader1); - when(mHeaderDriver2.getHeader()).thenReturn(mHeader2); - - mStreamRecyclerViewAdapter = new StreamRecyclerViewAdapter(mContext, - new RecyclerView(mContext), mCardConfiguration, mPietManager, - mDeepestContentTracker, mContentChangedListener, mScrollObservable, CONFIGURATION, - mPietEventLogger); - mStreamRecyclerViewAdapter.setHeaders(mHeaders); - - when(mDriver.getLeafFeatureDrivers()).thenReturn(Lists.newArrayList(mInitialFeatureDriver)); - mStreamRecyclerViewAdapter.setDriver(mDriver); - - mStreamAdapterObserver = new StreamAdapterObserver(); - mStreamRecyclerViewAdapter.registerAdapterDataObserver(mStreamAdapterObserver); - } - - @Test - public void testCreateViewHolderPiet() { - FrameLayout parent = new FrameLayout(mContext); - ViewHolder viewHolder = - mStreamRecyclerViewAdapter.onCreateViewHolder(parent, ViewHolderType.TYPE_CARD); - - FrameLayout cardView = getCardView(viewHolder); - assertThat(cardView.getChildAt(0)).isEqualTo(mFrameContainer); - } - - @Test - public void testCreateViewHolderContinuation() { - FrameLayout parent = new FrameLayout(mContext); - ViewHolder viewHolder = mStreamRecyclerViewAdapter.onCreateViewHolder( - parent, ViewHolderType.TYPE_CONTINUATION); - FrameLayout viewHolderFrameLayout = getCardView(viewHolder); - - assertThat(viewHolder).isInstanceOf(ContinuationViewHolder.class); - assertThat(viewHolderFrameLayout.getLayoutParams().height) - .isEqualTo(LayoutParams.WRAP_CONTENT); - assertThat(viewHolderFrameLayout.getLayoutParams().width) - .isEqualTo(LayoutParams.MATCH_PARENT); - } - - @Test - public void testCreateViewHolderNoContent() { - FrameLayout parent = new FrameLayout(mContext); - ViewHolder viewHolder = mStreamRecyclerViewAdapter.onCreateViewHolder( - parent, ViewHolderType.TYPE_NO_CONTENT); - FrameLayout viewHolderFrameLayout = getCardView(viewHolder); - - assertThat(viewHolder).isInstanceOf(NoContentViewHolder.class); - assertThat(viewHolderFrameLayout.getLayoutParams().height) - .isEqualTo(LayoutParams.WRAP_CONTENT); - assertThat(viewHolderFrameLayout.getLayoutParams().width) - .isEqualTo(LayoutParams.MATCH_PARENT); - } - - @Test - public void testCreateViewHolderZeroState() { - FrameLayout parent = new FrameLayout(mContext); - ViewHolder viewHolder = mStreamRecyclerViewAdapter.onCreateViewHolder( - parent, ViewHolderType.TYPE_ZERO_STATE); - FrameLayout viewHolderFrameLayout = getCardView(viewHolder); - - assertThat(viewHolder).isInstanceOf(ZeroStateViewHolder.class); - assertThat(viewHolderFrameLayout.getLayoutParams().height) - .isEqualTo(LayoutParams.WRAP_CONTENT); - assertThat(viewHolderFrameLayout.getLayoutParams().width) - .isEqualTo(LayoutParams.MATCH_PARENT); - } - - @Test - public void testOnBindViewHolder() { - FrameLayout parent = new FrameLayout(mContext); - FeedViewHolder viewHolder = - mStreamRecyclerViewAdapter.onCreateViewHolder(parent, ViewHolderType.TYPE_CARD); - - mStreamRecyclerViewAdapter.onBindViewHolder(viewHolder, getContentBindingIndex(0)); - - verify(mInitialFeatureDriver).bind(viewHolder); - } - - @Test - public void testOnViewRecycled() { - PietViewHolder viewHolder = mock(PietViewHolder.class); - - mStreamRecyclerViewAdapter.onBindViewHolder(viewHolder, getContentBindingIndex(0)); - - // Make sure the content model is bound - verify(mInitialFeatureDriver).bind(viewHolder); - - mStreamRecyclerViewAdapter.onViewRecycled(viewHolder); - - verify(mInitialFeatureDriver).unbind(); - } - - @Test - public void testSetDriver_initialContentModels() { - // streamRecyclerViewAdapter.setDriver(driver) is called in setup() - assertThat(mStreamRecyclerViewAdapter.getLeafFeatureDrivers()) - .containsExactly(mInitialFeatureDriver); - } - - @Test - public void testSetDriver_newDriver() { - StreamDriver newDriver = mock(StreamDriver.class); - List<LeafFeatureDriver> newFeatureDrivers = - Lists.newArrayList(mFeatureDriver1, mFeatureDriver2); - - when(newDriver.getLeafFeatureDrivers()).thenReturn(newFeatureDrivers); - - mStreamRecyclerViewAdapter.setDriver(newDriver); - - verify(mDriver).setStreamContentListener(null); - assertThat(mStreamRecyclerViewAdapter.getItemId(getContentBindingIndex(0))) - .isEqualTo(FEATURE_DRIVER_1_ID); - assertThat(mStreamRecyclerViewAdapter.getItemId(getContentBindingIndex(1))) - .isEqualTo(FEATURE_DRIVER_2_ID); - - InOrder inOrder = Mockito.inOrder(newDriver); - - // getLeafFeatureDrivers() needs to be called before setting the listener, otherwise the - // adapter could be notified of a child and then given it in getLeafFeatureDrivers(). - inOrder.verify(newDriver).getLeafFeatureDrivers(); - inOrder.verify(newDriver).setStreamContentListener(mStreamRecyclerViewAdapter); - inOrder.verify(newDriver).maybeRestoreScroll(); - } - - @Test - public void testNotifyContentsAdded_endOfList() { - mStreamRecyclerViewAdapter.notifyContentsAdded( - 1, Lists.newArrayList(mFeatureDriver1, mFeatureDriver2)); - assertThat(mStreamRecyclerViewAdapter.getLeafFeatureDrivers()) - .containsAtLeast(mInitialFeatureDriver, mFeatureDriver1, mFeatureDriver2); - } - - @Test - public void testNotifyContentsAdded_startOfList() { - mStreamRecyclerViewAdapter.notifyContentsAdded( - 0, Lists.newArrayList(mFeatureDriver1, mFeatureDriver2)); - assertThat(mStreamRecyclerViewAdapter.getLeafFeatureDrivers()) - .containsAtLeast(mFeatureDriver1, mFeatureDriver2, mInitialFeatureDriver); - } - - @Test - public void testNotifyContentsRemoved() { - mStreamRecyclerViewAdapter.notifyContentRemoved(0); - assertThat(mStreamRecyclerViewAdapter.getLeafFeatureDrivers()).isEmpty(); - verify(mDeepestContentTracker).removeContentId(0); - } - - @Test - public void testNotifyContentsAdded_notifiesListener() { - mStreamRecyclerViewAdapter.setShown(false); - mStreamRecyclerViewAdapter.notifyContentsAdded( - 0, Lists.newArrayList(mFeatureDriver1, mFeatureDriver2)); - - assertThat(mStreamAdapterObserver.mInsertedStart).isEqualTo(mHeaders.size()); - assertThat(mStreamAdapterObserver.mInsertedCount).isEqualTo(2); - verify(mContentChangedListener).onContentChanged(); - } - - @Test - public void testNotifyContentsAdded_doesNotNotifiesContentChangedListener_ifShownTrue() { - mStreamRecyclerViewAdapter.setShown(true); - mStreamRecyclerViewAdapter.notifyContentsAdded( - 0, Lists.newArrayList(mFeatureDriver1, mFeatureDriver2)); - - verify(mContentChangedListener, never()).onContentChanged(); - } - - @Test - public void testNotifyContentsAdded_streamVisibleFalse() { - mStreamRecyclerViewAdapter.setStreamContentVisible(false); - mStreamAdapterObserver.reset(); - - mStreamRecyclerViewAdapter.notifyContentsAdded( - 0, Lists.newArrayList(mFeatureDriver1, mFeatureDriver2)); - assertThat(mStreamAdapterObserver.mInsertedStart).isEqualTo(0); - assertThat(mStreamAdapterObserver.mInsertedCount).isEqualTo(0); - } - - @Test - public void testNotifyContentsRemoved_notifiesListener() { - mStreamRecyclerViewAdapter.setShown(false); - mStreamRecyclerViewAdapter.notifyContentRemoved(0); - - assertThat(mStreamAdapterObserver.mRemovedStart).isEqualTo(mHeaders.size()); - assertThat(mStreamAdapterObserver.mRemovedCount).isEqualTo(1); - verify(mContentChangedListener).onContentChanged(); - } - - @Test - public void testNotifyContentsRemoved_doesNotNotifiesContentChangedListener_ifShownTrue() { - mStreamRecyclerViewAdapter.setShown(true); - mStreamRecyclerViewAdapter.notifyContentRemoved(0); - - verify(mContentChangedListener, never()).onContentChanged(); - } - - @Test - public void testNotifyContentsRemoved_streamVisibleFalse() { - mStreamRecyclerViewAdapter.setStreamContentVisible(false); - mStreamAdapterObserver.reset(); - - mStreamRecyclerViewAdapter.notifyContentRemoved(0); - assertThat(mStreamAdapterObserver.mRemovedStart).isEqualTo(0); - assertThat(mStreamAdapterObserver.mRemovedCount).isEqualTo(0); - } - - @Test - public void testNotifyContentsCleared_notifiesListener() { - mStreamRecyclerViewAdapter.setShown(false); - mStreamRecyclerViewAdapter.notifyContentsCleared(); - - assertThat(mStreamAdapterObserver.mRemovedStart).isEqualTo(mHeaders.size()); - assertThat(mStreamAdapterObserver.mRemovedCount).isEqualTo(1); - verify(mContentChangedListener).onContentChanged(); - } - - @Test - public void testNotifyContentsCleared_doesNotNotifiesContentChangedListener_ifShownTrue() { - mStreamRecyclerViewAdapter.setShown(true); - mStreamRecyclerViewAdapter.notifyContentsCleared(); - - verify(mContentChangedListener, never()).onContentChanged(); - } - - @Test - public void testNotifyContentsCleared_streamVisibleFalse() { - mStreamRecyclerViewAdapter.setStreamContentVisible(false); - mStreamAdapterObserver.reset(); - - mStreamRecyclerViewAdapter.notifyContentsCleared(); - assertThat(mStreamAdapterObserver.mRemovedStart).isEqualTo(0); - assertThat(mStreamAdapterObserver.mRemovedCount).isEqualTo(0); - } - - @Test - public void testOnDestroy() { - mStreamRecyclerViewAdapter = new StreamRecyclerViewAdapter(mContext, - new RecyclerView(mContext), mCardConfiguration, mPietManager, - mDeepestContentTracker, mContentChangedListener, mScrollObservable, CONFIGURATION, - mPietEventLogger) { - @Override - HeaderDriver createHeaderDriver(Header header) { - if (header == mHeaders.get(0)) { - return mHeaderDriver1; - } - return mHeaderDriver2; - } - }; - mStreamRecyclerViewAdapter.setHeaders(mHeaders); - mStreamRecyclerViewAdapter.onDestroy(); - - verify(mHeaderDriver1).unbind(); - verify(mHeaderDriver1).onDestroy(); - verify(mHeaderDriver2).unbind(); - verify(mHeaderDriver2).onDestroy(); - } - - @Test - public void testSetHeaders_destroysPreviousHeaderDrivers() { - mStreamRecyclerViewAdapter = new StreamRecyclerViewAdapter(mContext, - new RecyclerView(mContext), mCardConfiguration, mPietManager, - mDeepestContentTracker, mContentChangedListener, mScrollObservable, CONFIGURATION, - mPietEventLogger) { - @Override - HeaderDriver createHeaderDriver(Header header) { - if (header == mHeaders.get(0)) { - return mHeaderDriver1; - } - return mHeaderDriver2; - } - }; - mStreamRecyclerViewAdapter.setHeaders(mHeaders); - - mStreamRecyclerViewAdapter.setHeaders(Collections.emptyList()); - - verify(mHeaderDriver1).onDestroy(); - verify(mHeaderDriver2).onDestroy(); - } - - @Test - public void testGetItemCount() { - assertThat(mStreamRecyclerViewAdapter.getItemCount()).isEqualTo(mHeaders.size() + 1); - } - - @Test - public void testGetItemCount_streamVisibleFalse() { - mStreamRecyclerViewAdapter.setStreamContentVisible(false); - assertThat(mStreamRecyclerViewAdapter.getItemCount()).isEqualTo(mHeaders.size()); - } - - @Test - public void setStreamContentVisible_hidesContent() { - mStreamRecyclerViewAdapter.setStreamContentVisible(false); - assertThat(mStreamAdapterObserver.mRemovedStart).isEqualTo(mHeaders.size()); - assertThat(mStreamAdapterObserver.mRemovedCount).isEqualTo(1); - } - - @Test - public void setStreamContentVisible_hidesContent_doubleCall() { - mStreamRecyclerViewAdapter.setStreamContentVisible(false); - - mStreamAdapterObserver.reset(); - mStreamRecyclerViewAdapter.setStreamContentVisible(false); - - // Nothing additional should get called - assertThat(mStreamAdapterObserver.mRemovedStart).isEqualTo(0); - assertThat(mStreamAdapterObserver.mRemovedCount).isEqualTo(0); - } - - @Test - public void setStreamContentVisible_showsContent() { - mStreamRecyclerViewAdapter.setStreamContentVisible(false); - mStreamAdapterObserver.reset(); - - mStreamRecyclerViewAdapter.setStreamContentVisible(true); - assertThat(mStreamAdapterObserver.mInsertedStart).isEqualTo(mHeaders.size()); - assertThat(mStreamAdapterObserver.mInsertedCount).isEqualTo(1); - } - - @Test - public void setStreamContentVisible_showsContent_doubleCall() { - mStreamRecyclerViewAdapter.setStreamContentVisible(false); - mStreamAdapterObserver.reset(); - - mStreamRecyclerViewAdapter.setStreamContentVisible(true); - - mStreamAdapterObserver.reset(); - mStreamRecyclerViewAdapter.setStreamContentVisible(true); - - // Nothing additional should get called - assertThat(mStreamAdapterObserver.mInsertedStart).isEqualTo(0); - assertThat(mStreamAdapterObserver.mInsertedCount).isEqualTo(0); - } - - @Test - public void testOnBindViewHolder_updatesDeepestViewedContent() { - PietViewHolder viewHolder = mock(PietViewHolder.class); - - mStreamRecyclerViewAdapter.onBindViewHolder(viewHolder, getContentBindingIndex(0)); - - verify(mDeepestContentTracker).updateDeepestContentTracker(0, INITIAL_CONTENT_ID); - } - - @Test - public void testDismissHeader() { - mStreamRecyclerViewAdapter = new StreamRecyclerViewAdapter(mContext, - new RecyclerView(mContext), mCardConfiguration, mPietManager, - mDeepestContentTracker, mContentChangedListener, mScrollObservable, CONFIGURATION, - mPietEventLogger) { - @Override - HeaderDriver createHeaderDriver(Header header) { - if (header == mHeaders.get(0)) { - return mHeaderDriver1; - } - return mHeaderDriver2; - } - }; - mStreamRecyclerViewAdapter.setHeaders(mHeaders); - assertThat(mStreamRecyclerViewAdapter.getItemCount()).isEqualTo(2); - - mStreamRecyclerViewAdapter.dismissHeader(mHeader1); - - assertThat(mStreamRecyclerViewAdapter.getItemCount()).isEqualTo(1); - verify(mHeader1).onDismissed(); - verify(mHeaderDriver1).onDestroy(); - } - - @Test - public void testDismissHeader_whenNoHeaders() { - mStreamRecyclerViewAdapter.setHeaders(Collections.emptyList()); - reset(mHeader1); - assertThat(mStreamRecyclerViewAdapter.getItemCount()).isEqualTo(1); - - mStreamRecyclerViewAdapter.dismissHeader(mHeader1); - - assertThat(mStreamRecyclerViewAdapter.getItemCount()).isEqualTo(1); - verify(mHeader1, never()).onDismissed(); - } - - @Test - public void testRebind() { - PietViewHolder viewHolder = mock(PietViewHolder.class); - mStreamRecyclerViewAdapter.onBindViewHolder(viewHolder, getContentBindingIndex(0)); - mStreamRecyclerViewAdapter.rebind(); - verify(mInitialFeatureDriver).maybeRebind(); - } - - private FrameLayout getCardView(ViewHolder viewHolder) { - return (FrameLayout) viewHolder.itemView; - } - - private int getContentBindingIndex(int index) { - return HEADER_COUNT + index; - } - - private class StreamAdapterObserver extends RecyclerView.AdapterDataObserver { - private int mInsertedStart; - private int mInsertedCount; - private int mRemovedStart; - private int mRemovedCount; - - @Override - public void onItemRangeInserted(int positionStart, int itemCount) { - mInsertedStart = positionStart; - mInsertedCount = itemCount; - } - - @Override - public void onItemRangeRemoved(int positionStart, int itemCount) { - mRemovedStart = positionStart; - mRemovedCount = itemCount; - } - - public void reset() { - mInsertedStart = 0; - mInsertedCount = 0; - mRemovedStart = 0; - mRemovedCount = 0; - } - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/actions/StreamActionApiImplTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/actions/StreamActionApiImplTest.java deleted file mode 100644 index 732f444b..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/actions/StreamActionApiImplTest.java +++ /dev/null
@@ -1,729 +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. - -package org.chromium.chrome.browser.feed.library.basicstream.internal.actions; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import android.app.Activity; -import android.content.Context; -import android.view.View; - -import com.google.common.collect.ImmutableList; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestRule; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.InOrder; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.base.Consumer; -import org.chromium.chrome.browser.feed.library.api.client.knowncontent.ContentMetadata; -import org.chromium.chrome.browser.feed.library.api.host.action.ActionApi; -import org.chromium.chrome.browser.feed.library.api.host.logging.ActionType; -import org.chromium.chrome.browser.feed.library.api.host.logging.BasicLoggingApi; -import org.chromium.chrome.browser.feed.library.api.host.logging.ContentLoggingData; -import org.chromium.chrome.browser.feed.library.api.host.stream.TooltipApi; -import org.chromium.chrome.browser.feed.library.api.host.stream.TooltipCallbackApi; -import org.chromium.chrome.browser.feed.library.api.host.stream.TooltipCallbackApi.TooltipDismissType; -import org.chromium.chrome.browser.feed.library.api.host.stream.TooltipInfo; -import org.chromium.chrome.browser.feed.library.api.internal.actionmanager.ActionManager; -import org.chromium.chrome.browser.feed.library.api.internal.actionparser.ActionParser; -import org.chromium.chrome.browser.feed.library.api.internal.actionparser.ActionSource; -import org.chromium.chrome.browser.feed.library.basicstream.internal.pendingdismiss.ClusterPendingDismissHelper; -import org.chromium.chrome.browser.feed.library.sharedstream.logging.StreamContentLoggingData; -import org.chromium.chrome.browser.feed.library.sharedstream.pendingdismiss.PendingDismissCallback; -import org.chromium.chrome.browser.feed.library.testing.sharedstream.contextmenumanager.FakeContextMenuManager; -import org.chromium.chrome.browser.flags.ChromeFeatureList; -import org.chromium.chrome.test.util.browser.Features; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamDataOperation; -import org.chromium.components.feed.core.proto.ui.action.FeedActionPayloadProto.FeedActionPayload; -import org.chromium.components.feed.core.proto.ui.action.FeedActionProto.FeedAction; -import org.chromium.components.feed.core.proto.ui.action.FeedActionProto.FeedActionMetadata; -import org.chromium.components.feed.core.proto.ui.action.FeedActionProto.FeedActionMetadata.ElementType; -import org.chromium.components.feed.core.proto.ui.action.FeedActionProto.FeedActionMetadata.Type; -import org.chromium.components.feed.core.proto.ui.action.FeedActionProto.LabelledFeedActionData; -import org.chromium.components.feed.core.proto.ui.action.FeedActionProto.OpenContextMenuData; -import org.chromium.components.feed.core.proto.ui.action.FeedActionProto.OpenUrlData; -import org.chromium.components.feed.core.proto.ui.action.FeedActionProto.UndoAction; -import org.chromium.components.feed.core.proto.ui.stream.StreamStructureProto.BasicLoggingMetadata; -import org.chromium.components.feed.core.proto.ui.stream.StreamStructureProto.RepresentationData; -import org.chromium.components.feed.core.proto.wire.ActionPayloadProto.ActionPayload; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -/** Tests for {@link StreamActionApiImpl}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -@Features.DisableFeatures(ChromeFeatureList.INTEREST_FEED_V2) -@Features.EnableFeatures(ChromeFeatureList.INTEREST_FEED_CONTENT_SUGGESTIONS) -public class StreamActionApiImplTest { - private static final String URL = "www.google.com"; - private static final String OPEN_LABEL = "Open"; - private static final String OPEN_IN_NEW_WINDOW_LABEL = "Open in new window"; - private static final String PARAM = "param"; - private static final String NEW_URL = "ooh.shiny.com"; - private static final int INTEREST_TYPE = 2; - private static final ActionPayload ACTION_PAYLOAD = ActionPayload.getDefaultInstance(); - private static final LabelledFeedActionData OPEN_IN_NEW_WINDOW = - LabelledFeedActionData.newBuilder() - .setLabel(OPEN_IN_NEW_WINDOW_LABEL) - .setFeedActionPayload(FeedActionPayload.newBuilder().setExtension( - FeedAction.feedActionExtension, - FeedAction.newBuilder() - .setMetadata( - FeedActionMetadata.newBuilder() - .setType(Type.OPEN_URL_NEW_WINDOW) - .setOpenUrlData( - OpenUrlData.newBuilder().setUrl(URL))) - .build())) - .build(); - - private static final String OPEN_IN_INCOGNITO_MODE_LABEL = "Open in incognito mode"; - - private static final LabelledFeedActionData OPEN_IN_INCOGNITO_MODE = - LabelledFeedActionData.newBuilder() - .setLabel(OPEN_IN_INCOGNITO_MODE_LABEL) - .setFeedActionPayload(FeedActionPayload.newBuilder().setExtension( - FeedAction.feedActionExtension, - FeedAction.newBuilder() - .setMetadata( - FeedActionMetadata.newBuilder() - .setType(Type.OPEN_URL_INCOGNITO) - .setOpenUrlData( - OpenUrlData.newBuilder().setUrl(URL))) - .build())) - .build(); - - private static final LabelledFeedActionData NORMAL_OPEN_URL = - LabelledFeedActionData.newBuilder() - .setLabel(OPEN_LABEL) - .setFeedActionPayload(FeedActionPayload.newBuilder().setExtension( - FeedAction.feedActionExtension, - FeedAction.newBuilder() - .setMetadata( - FeedActionMetadata.newBuilder() - .setType(Type.OPEN_URL) - .setOpenUrlData( - OpenUrlData.newBuilder().setUrl(URL))) - .build())) - .build(); - private static final String SESSION_ID = "SESSION_ID"; - private static final String CONTENT_ID = "CONTENT_ID"; - private static final ContentMetadata CONTENT_METADATA = new ContentMetadata(URL, "title", - /* timePublished= */ -1, - /* imageUrl= */ null, - /* publisher= */ null, - /* faviconUrl= */ null, - /* snippet=*/null); - - @Mock - private ActionApi mActionApi; - @Mock - private ActionParser mActionParser; - @Mock - private ActionManager mActionManager; - @Mock - private BasicLoggingApi mBasicLoggingApi; - @Mock - private ClusterPendingDismissHelper mClusterPendingDismissHelper; - @Mock - private ViewElementActionHandler mViewElementActionHandler; - @Mock - private TooltipApi mTooltipApi; - - @Captor - private ArgumentCaptor<Consumer<String>> mConsumerCaptor; - private ContentLoggingData mContentLoggingData; - private FakeContextMenuManager mContextMenuManager; - private StreamActionApiImpl mStreamActionApi; - private View mView; - - @Rule - public TestRule mFeaturesProcessorRule = new Features.JUnitProcessor(); - - @Before - public void setup() { - initMocks(this); - - Context context = Robolectric.buildActivity(Activity.class).get(); - mContentLoggingData = new StreamContentLoggingData(0, - BasicLoggingMetadata.getDefaultInstance(), RepresentationData.getDefaultInstance(), - /* availableOffline= */ false); - mView = new View(context); - mContextMenuManager = new FakeContextMenuManager(); - mStreamActionApi = - new StreamActionApiImpl(mActionApi, mActionParser, mActionManager, mBasicLoggingApi, - () - -> mContentLoggingData, - mContextMenuManager, SESSION_ID, mClusterPendingDismissHelper, - mViewElementActionHandler, CONTENT_ID, mTooltipApi); - } - - @Test - public void testCanDismiss() { - assertThat(mStreamActionApi.canDismiss()).isTrue(); - } - - @Test - public void testDismiss() { - String contentId = "contentId"; - List<StreamDataOperation> streamDataOperations = - Collections.singletonList(StreamDataOperation.getDefaultInstance()); - mStreamActionApi.dismiss( - contentId, streamDataOperations, UndoAction.getDefaultInstance(), ACTION_PAYLOAD); - - verify(mActionManager) - .dismissLocal(ImmutableList.of(contentId), streamDataOperations, SESSION_ID); - verify(mBasicLoggingApi).onContentDismissed(mContentLoggingData, /*wasCommitted =*/true); - } - - @Test - public void testDismiss_withSnackbar_onCommitted() { - testCommittedDismissWithSnackbar(Type.DISMISS); - } - - @Test - public void testDismiss_withSnackbar_onReverted() { - testRevertedDismissWithSnackbar(Type.DISMISS); - } - - @Test - public void testDismiss_noSnackbar() { - testDismissNoSnackbar(Type.DISMISS); - } - - @Test - public void testDismissWithSnackbar_dismissLocal_onCommitted() { - testCommittedDismissWithSnackbar(Type.DISMISS_LOCAL); - } - - @Test - public void testDismissWithSnackbar_dismissLocal_onReverted() { - testRevertedDismissWithSnackbar(Type.DISMISS_LOCAL); - } - - @Test - public void testDismissNoSnackbar_dismissLocal_onReverted() { - testDismissNoSnackbar(Type.DISMISS_LOCAL); - } - - @Test - public void testHandleNotInterestedInTopic_onCommitted() { - testCommittedDismissWithSnackbar(Type.NOT_INTERESTED_IN); - } - - @Test - public void testHandleNotInterestedInTopic_onReverted() { - testRevertedDismissWithSnackbar(Type.NOT_INTERESTED_IN); - } - - @Test - public void testHandleNotInterestedInTopic_noSnackbar() { - testDismissNoSnackbar(Type.NOT_INTERESTED_IN); - } - - @Test - public void testHandleBlockContent() { - List<StreamDataOperation> streamDataOperations = - Collections.singletonList(StreamDataOperation.getDefaultInstance()); - mStreamActionApi.handleBlockContent(streamDataOperations, ACTION_PAYLOAD); - - verify(mActionManager).dismiss(streamDataOperations, SESSION_ID); - verify(mActionManager) - .createAndUploadAction( - CONTENT_ID, ACTION_PAYLOAD, ActionManager.UploadActionType.MISC); - } - - @Test - public void testOnClientAction() { - mStreamActionApi.onClientAction(ActionType.OPEN_URL); - - verify(mBasicLoggingApi).onClientAction(mContentLoggingData, ActionType.OPEN_URL); - } - - @Test - public void testOnElementClick_logsElementClicked() { - mStreamActionApi.onElementClick(ElementType.INTEREST_HEADER.getNumber()); - - verify(mBasicLoggingApi) - .onVisualElementClicked( - mContentLoggingData, ElementType.INTEREST_HEADER.getNumber()); - } - - @Test - public void testOnElementClick_logsElementClicked_retrievesLoggingDataLazily() { - mContentLoggingData = new StreamContentLoggingData(1, - BasicLoggingMetadata.getDefaultInstance(), RepresentationData.getDefaultInstance(), - /* availableOffline= */ true); - - mStreamActionApi.onElementClick(ElementType.INTEREST_HEADER.getNumber()); - - // Should use the new ContentLoggingData defined, not the old one. - verify(mBasicLoggingApi) - .onVisualElementClicked( - mContentLoggingData, ElementType.INTEREST_HEADER.getNumber()); - } - - @Test - public void testOnElementView() { - mStreamActionApi.onElementView(ElementType.INTEREST_HEADER.getNumber()); - - verify(mViewElementActionHandler).onElementView(ElementType.INTEREST_HEADER.getNumber()); - } - - @Test - @Features.EnableFeatures(ChromeFeatureList.REPORT_FEED_USER_ACTIONS) - public void testReportClickAction_withFeature() { - String contentId = "contentId"; - mStreamActionApi.reportClickAction(contentId, ACTION_PAYLOAD); - - verify(mActionManager) - .createAndUploadAction( - contentId, ACTION_PAYLOAD, ActionManager.UploadActionType.CLICK); - } - - @Test - @Features.DisableFeatures(ChromeFeatureList.REPORT_FEED_USER_ACTIONS) - public void testNoReportClickAction_withoutFeature() { - mStreamActionApi.reportClickAction("contentId", ACTION_PAYLOAD); - - verify(mActionManager, never()) - .createAndUploadAction(anyString(), any(ActionPayload.class), - any(ActionManager.UploadActionType.class)); - } - - @Test - @Features.EnableFeatures(ChromeFeatureList.REPORT_FEED_USER_ACTIONS) - public void testReportViewVisible_withFeature() { - String contentId = "contentId"; - mStreamActionApi.reportViewVisible(mView, contentId, ACTION_PAYLOAD); - - verify(mActionManager).onViewVisible(mView, contentId, ACTION_PAYLOAD); - } - - @Test - @Features.DisableFeatures(ChromeFeatureList.REPORT_FEED_USER_ACTIONS) - public void testReportViewVisible_withoutFeature() { - mStreamActionApi.reportViewHidden(mView, "contentId"); - - verify(mActionManager, never()) - .onViewVisible(any(View.class), anyString(), any(ActionPayload.class)); - } - - @Test - @Features.EnableFeatures(ChromeFeatureList.REPORT_FEED_USER_ACTIONS) - public void testReportViewHidden_withFeature() { - String contentId = "contentId"; - mStreamActionApi.reportViewHidden(mView, contentId); - - verify(mActionManager).onViewHidden(mView, contentId); - } - - @Test - @Features.DisableFeatures(ChromeFeatureList.REPORT_FEED_USER_ACTIONS) - public void testReportViewHidden_withoutFeature() { - mStreamActionApi.reportViewHidden(mView, "contentId"); - - verify(mActionManager, never()).onViewHidden(any(View.class), anyString()); - } - - @Test - public void testOnElementHide() { - mStreamActionApi.onElementHide(ElementType.INTEREST_HEADER.getNumber()); - - verify(mViewElementActionHandler).onElementHide(ElementType.INTEREST_HEADER.getNumber()); - } - - @Test - public void testOpenUrl() { - mStreamActionApi.openUrlInNewWindow(URL); - verify(mActionApi).openUrlInNewWindow(URL); - } - - @Test - public void testOpenUrl_withParam() { - mStreamActionApi.openUrl(URL, PARAM); - - verify(mActionManager) - .uploadAllActionsAndUpdateUrl(eq(URL), eq(PARAM), mConsumerCaptor.capture()); - mConsumerCaptor.getValue().accept(NEW_URL); - verify(mActionApi).openUrl(NEW_URL); - } - - @Test - public void testCanOpenUrl() { - when(mActionApi.canOpenUrl()).thenReturn(true); - assertThat(mStreamActionApi.canOpenUrl()).isTrue(); - - when(mActionApi.canOpenUrl()).thenReturn(false); - assertThat(mStreamActionApi.canOpenUrl()).isFalse(); - } - - @Test - public void testCanOpenUrlInIncognitoMode() { - when(mActionApi.canOpenUrlInIncognitoMode()).thenReturn(true); - assertThat(mStreamActionApi.canOpenUrlInIncognitoMode()).isTrue(); - - when(mActionApi.canOpenUrlInIncognitoMode()).thenReturn(false); - assertThat(mStreamActionApi.canOpenUrlInIncognitoMode()).isFalse(); - } - - @Test - public void testOpenUrlInIncognitoMode_withParam() { - mStreamActionApi.openUrlInIncognitoMode(URL, PARAM); - - verify(mActionManager) - .uploadAllActionsAndUpdateUrl(eq(URL), eq(PARAM), mConsumerCaptor.capture()); - mConsumerCaptor.getValue().accept(NEW_URL); - verify(mActionApi).openUrlInIncognitoMode(NEW_URL); - } - - @Test - public void testOpenUrlInNewTab() { - mStreamActionApi.openUrlInNewTab(URL); - verify(mActionApi).openUrlInNewTab(URL); - } - - @Test - public void testOpenUrlInNewTab_withParam() { - mStreamActionApi.openUrlInNewTab(URL, PARAM); - - verify(mActionManager) - .uploadAllActionsAndUpdateUrl(eq(URL), eq(PARAM), mConsumerCaptor.capture()); - mConsumerCaptor.getValue().accept(NEW_URL); - verify(mActionApi).openUrlInNewTab(NEW_URL); - } - - @Test - public void testCanOpenUrlInNewTab() { - when(mActionApi.canOpenUrlInNewTab()).thenReturn(true); - assertThat(mStreamActionApi.canOpenUrlInNewTab()).isTrue(); - - when(mActionApi.canOpenUrlInNewTab()).thenReturn(false); - assertThat(mStreamActionApi.canOpenUrlInNewTab()).isFalse(); - } - - @Test - public void testDownloadUrl() { - mStreamActionApi.downloadUrl(CONTENT_METADATA); - verify(mActionApi).downloadUrl(CONTENT_METADATA); - } - - @Test - public void testCanDownloadUrl() { - when(mActionApi.canDownloadUrl()).thenReturn(true); - assertThat(mStreamActionApi.canDownloadUrl()).isTrue(); - - when(mActionApi.canDownloadUrl()).thenReturn(false); - assertThat(mStreamActionApi.canDownloadUrl()).isFalse(); - } - - @Test - public void testLearnMore() { - mStreamActionApi.learnMore(); - verify(mActionApi).learnMore(); - } - - @Test - public void testCanLearnMore() { - when(mActionApi.canLearnMore()).thenReturn(true); - assertThat(mStreamActionApi.canLearnMore()).isTrue(); - - when(mActionApi.canLearnMore()).thenReturn(false); - assertThat(mStreamActionApi.canLearnMore()).isFalse(); - } - - @Test - public void openContextMenuTest() { - when(mActionParser.canPerformAction(any(FeedActionPayload.class), eq(mStreamActionApi))) - .thenReturn(true); - - List<LabelledFeedActionData> labelledFeedActionDataList = new ArrayList<>(); - labelledFeedActionDataList.add(NORMAL_OPEN_URL); - labelledFeedActionDataList.add(OPEN_IN_NEW_WINDOW); - labelledFeedActionDataList.add(OPEN_IN_INCOGNITO_MODE); - - mStreamActionApi.openContextMenu(OpenContextMenuData.newBuilder() - .addAllContextMenuData(labelledFeedActionDataList) - .build(), - mView); - - mContextMenuManager.performClick(0); - mContextMenuManager.performClick(1); - mContextMenuManager.performClick(2); - - InOrder inOrder = Mockito.inOrder(mActionParser); - - inOrder.verify(mActionParser) - .parseFeedActionPayload(NORMAL_OPEN_URL.getFeedActionPayload(), mStreamActionApi, - mView, ActionSource.CONTEXT_MENU); - inOrder.verify(mActionParser) - .parseFeedActionPayload(OPEN_IN_NEW_WINDOW.getFeedActionPayload(), mStreamActionApi, - mView, ActionSource.CONTEXT_MENU); - inOrder.verify(mActionParser) - .parseFeedActionPayload(OPEN_IN_INCOGNITO_MODE.getFeedActionPayload(), - mStreamActionApi, mView, ActionSource.CONTEXT_MENU); - } - - @Test - public void openContextMenuTest_noNewWindow() { - when(mActionParser.canPerformAction( - NORMAL_OPEN_URL.getFeedActionPayload(), mStreamActionApi)) - .thenReturn(true); - when(mActionParser.canPerformAction( - OPEN_IN_INCOGNITO_MODE.getFeedActionPayload(), mStreamActionApi)) - .thenReturn(true); - when(mActionParser.canPerformAction( - OPEN_IN_NEW_WINDOW.getFeedActionPayload(), mStreamActionApi)) - .thenReturn(false); - - List<LabelledFeedActionData> labelledFeedActionDataList = new ArrayList<>(); - labelledFeedActionDataList.add(NORMAL_OPEN_URL); - labelledFeedActionDataList.add(OPEN_IN_NEW_WINDOW); - labelledFeedActionDataList.add(OPEN_IN_INCOGNITO_MODE); - - mStreamActionApi.openContextMenu(OpenContextMenuData.newBuilder() - .addAllContextMenuData(labelledFeedActionDataList) - .build(), - mView); - - assertThat(mContextMenuManager.getMenuOptions()) - .isEqualTo(Arrays.asList(OPEN_LABEL, OPEN_IN_INCOGNITO_MODE_LABEL)); - } - - @Test - public void openContextMenuTest_noIncognitoWindow() { - when(mActionParser.canPerformAction( - NORMAL_OPEN_URL.getFeedActionPayload(), mStreamActionApi)) - .thenReturn(true); - when(mActionParser.canPerformAction( - OPEN_IN_NEW_WINDOW.getFeedActionPayload(), mStreamActionApi)) - .thenReturn(true); - when(mActionParser.canPerformAction( - OPEN_IN_INCOGNITO_MODE.getFeedActionPayload(), mStreamActionApi)) - .thenReturn(false); - - List<LabelledFeedActionData> labelledFeedActionDataList = new ArrayList<>(); - labelledFeedActionDataList.add(NORMAL_OPEN_URL); - labelledFeedActionDataList.add(OPEN_IN_NEW_WINDOW); - labelledFeedActionDataList.add(OPEN_IN_INCOGNITO_MODE); - - mStreamActionApi.openContextMenu(OpenContextMenuData.newBuilder() - .addAllContextMenuData(labelledFeedActionDataList) - .build(), - mView); - - assertThat(mContextMenuManager.getMenuOptions()) - .isEqualTo(Arrays.asList(OPEN_LABEL, OPEN_IN_NEW_WINDOW_LABEL)); - } - - @Test - public void openContextMenuTest_logsContentContextMenuOpened() { - when(mActionParser.canPerformAction(any(FeedActionPayload.class), eq(mStreamActionApi))) - .thenReturn(true); - - mStreamActionApi.openContextMenu( - OpenContextMenuData.newBuilder() - .addAllContextMenuData(Collections.singletonList(NORMAL_OPEN_URL)) - .build(), - mView); - - // First context menu succeeds in opening and is logged. - verify(mBasicLoggingApi).onContentContextMenuOpened(mContentLoggingData); - - reset(mBasicLoggingApi); - - mStreamActionApi.openContextMenu( - OpenContextMenuData.newBuilder() - .addAllContextMenuData(Collections.singletonList(NORMAL_OPEN_URL)) - .build(), - mView); - - // Second context menu fails in opening and is not logged. - verifyZeroInteractions(mBasicLoggingApi); - } - - @Test - public void testMaybeShowTooltip() { - TooltipInfo info = mock(TooltipInfo.class); - ArgumentCaptor<TooltipCallbackApi> callbackCaptor = - ArgumentCaptor.forClass(TooltipCallbackApi.class); - - mStreamActionApi.maybeShowTooltip(info, mView); - - verify(mTooltipApi).maybeShowHelpUi(eq(info), eq(mView), callbackCaptor.capture()); - - callbackCaptor.getValue().onShow(); - verify(mViewElementActionHandler).onElementView(ElementType.TOOLTIP.getNumber()); - - callbackCaptor.getValue().onHide(TooltipDismissType.TIMEOUT); - verify(mViewElementActionHandler).onElementHide(ElementType.TOOLTIP.getNumber()); - } - - private void testCommittedDismissWithSnackbar(Type actionType) { - ArgumentCaptor<PendingDismissCallback> pendingDismissCallback = - ArgumentCaptor.forClass(PendingDismissCallback.class); - List<StreamDataOperation> streamDataOperations = - Collections.singletonList(StreamDataOperation.getDefaultInstance()); - UndoAction undoAction = - UndoAction.newBuilder().setConfirmationLabel("confirmation").build(); - switch (actionType) { - case DISMISS: - case DISMISS_LOCAL: - mStreamActionApi.dismiss( - CONTENT_ID, streamDataOperations, undoAction, ACTION_PAYLOAD); - break; - case NOT_INTERESTED_IN: - mStreamActionApi.handleNotInterestedIn( - streamDataOperations, undoAction, ACTION_PAYLOAD, INTEREST_TYPE); - break; - default: - break; - } - - verify(mClusterPendingDismissHelper) - .triggerPendingDismissForCluster(eq(undoAction), pendingDismissCallback.capture()); - - pendingDismissCallback.getValue().onDismissCommitted(); - switch (actionType) { - case DISMISS: - verify(mActionManager) - .dismissLocal( - ImmutableList.of(CONTENT_ID), streamDataOperations, SESSION_ID); - verify(mBasicLoggingApi) - .onContentDismissed(mContentLoggingData, /*wasCommitted =*/true); - verify(mActionManager) - .createAndUploadAction( - CONTENT_ID, ACTION_PAYLOAD, ActionManager.UploadActionType.MISC); - break; - case DISMISS_LOCAL: - verify(mActionManager) - .dismissLocal( - ImmutableList.of(CONTENT_ID), streamDataOperations, SESSION_ID); - verify(mBasicLoggingApi) - .onContentDismissed(mContentLoggingData, /*wasCommitted =*/true); - break; - case NOT_INTERESTED_IN: - verify(mActionManager).dismiss(streamDataOperations, SESSION_ID); - verify(mBasicLoggingApi) - .onNotInterestedIn( - INTEREST_TYPE, mContentLoggingData, /*wasCommitted =*/true); - verify(mActionManager) - .createAndUploadAction( - CONTENT_ID, ACTION_PAYLOAD, ActionManager.UploadActionType.MISC); - break; - default: - break; - } - } - - private void testRevertedDismissWithSnackbar(Type actionType) { - ArgumentCaptor<PendingDismissCallback> pendingDismissCallback = - ArgumentCaptor.forClass(PendingDismissCallback.class); - String contentId = "contentId"; - List<StreamDataOperation> streamDataOperations = - Collections.singletonList(StreamDataOperation.getDefaultInstance()); - UndoAction undoAction = - UndoAction.newBuilder().setConfirmationLabel("confirmation").build(); - switch (actionType) { - case DISMISS: - case DISMISS_LOCAL: - mStreamActionApi.dismiss( - contentId, streamDataOperations, undoAction, ACTION_PAYLOAD); - break; - case NOT_INTERESTED_IN: - mStreamActionApi.handleNotInterestedIn( - streamDataOperations, undoAction, ACTION_PAYLOAD, INTEREST_TYPE); - break; - default: - break; - } - - verify(mClusterPendingDismissHelper) - .triggerPendingDismissForCluster(eq(undoAction), pendingDismissCallback.capture()); - - pendingDismissCallback.getValue().onDismissReverted(); - - verify(mActionManager, never()) - .dismissLocal(ImmutableList.of(contentId), streamDataOperations, SESSION_ID); - switch (actionType) { - case DISMISS: - case DISMISS_LOCAL: - verify(mBasicLoggingApi) - .onContentDismissed(mContentLoggingData, /*wasCommitted =*/false); - break; - case NOT_INTERESTED_IN: - verify(mBasicLoggingApi) - .onNotInterestedIn( - INTEREST_TYPE, mContentLoggingData, /*wasCommitted =*/false); - break; - default: - break; - } - } - - private void testDismissNoSnackbar(Type actionType) { - String contentId = "contentId"; - List<StreamDataOperation> streamDataOperations = - Collections.singletonList(StreamDataOperation.getDefaultInstance()); - UndoAction undoAction = UndoAction.getDefaultInstance(); - switch (actionType) { - case DISMISS: - case DISMISS_LOCAL: - mStreamActionApi.dismiss( - contentId, streamDataOperations, undoAction, ACTION_PAYLOAD); - break; - case NOT_INTERESTED_IN: - mStreamActionApi.handleNotInterestedIn( - streamDataOperations, undoAction, ACTION_PAYLOAD, INTEREST_TYPE); - break; - default: - break; - } - - verify(mClusterPendingDismissHelper, never()).triggerPendingDismissForCluster(any(), any()); - - switch (actionType) { - case DISMISS: - case DISMISS_LOCAL: - verify(mActionManager) - .dismissLocal( - ImmutableList.of(contentId), streamDataOperations, SESSION_ID); - verify(mBasicLoggingApi) - .onContentDismissed(mContentLoggingData, /*wasCommitted =*/true); - break; - case NOT_INTERESTED_IN: - verify(mActionManager).dismiss(streamDataOperations, SESSION_ID); - verify(mBasicLoggingApi) - .onNotInterestedIn( - INTEREST_TYPE, mContentLoggingData, /*wasCommitted =*/true); - break; - default: - break; - } - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/drivers/CardDriverTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/drivers/CardDriverTest.java deleted file mode 100644 index 3b6a0e2e..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/drivers/CardDriverTest.java +++ /dev/null
@@ -1,215 +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. - -package org.chromium.chrome.browser.feed.library.basicstream.internal.drivers; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import com.google.common.collect.Lists; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.action.ActionApi; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration; -import org.chromium.chrome.browser.feed.library.api.host.logging.BasicLoggingApi; -import org.chromium.chrome.browser.feed.library.api.host.logging.InternalFeedError; -import org.chromium.chrome.browser.feed.library.api.host.stream.TooltipApi; -import org.chromium.chrome.browser.feed.library.api.internal.actionmanager.ActionManager; -import org.chromium.chrome.browser.feed.library.api.internal.actionparser.ActionParserFactory; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelChild; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelChild.Type; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelFeature; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider; -import org.chromium.chrome.browser.feed.library.basicstream.internal.pendingdismiss.ClusterPendingDismissHelper; -import org.chromium.chrome.browser.feed.library.basicstream.internal.viewloggingupdater.ViewLoggingUpdater; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeMainThreadRunner; -import org.chromium.chrome.browser.feed.library.sharedstream.contextmenumanager.ContextMenuManager; -import org.chromium.chrome.browser.feed.library.sharedstream.offlinemonitor.StreamOfflineMonitor; -import org.chromium.chrome.browser.feed.library.testing.modelprovider.FakeModelCursor; -import org.chromium.chrome.browser.feed.shared.stream.Stream.ContentChangedListener; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamFeature; -import org.chromium.components.feed.core.proto.ui.action.FeedActionPayloadProto.FeedActionPayload; -import org.chromium.components.feed.core.proto.ui.action.FeedActionProto.DismissData; -import org.chromium.components.feed.core.proto.ui.action.FeedActionProto.FeedAction; -import org.chromium.components.feed.core.proto.ui.action.FeedActionProto.FeedActionMetadata; -import org.chromium.components.feed.core.proto.ui.stream.StreamStructureProto.Card; -import org.chromium.components.feed.core.proto.ui.stream.StreamStructureProto.Content; -import org.chromium.components.feed.core.proto.ui.stream.StreamSwipeExtensionProto.SwipeActionExtension; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link CardDriver}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class CardDriverTest { - private static final StreamFeature STREAM_FEATURE = - StreamFeature.newBuilder().setContent(Content.getDefaultInstance()).build(); - - private static final FeedActionPayload SWIPE_ACTION = - FeedActionPayload.newBuilder() - .setExtension(FeedAction.feedActionExtension, - FeedAction.newBuilder() - .setMetadata(FeedActionMetadata.newBuilder().setDismissData( - DismissData.getDefaultInstance())) - .build()) - .build(); - - private static final Card CARD_WITH_SWIPE_ACTION = - Card.newBuilder() - .setExtension(SwipeActionExtension.swipeActionExtension, - SwipeActionExtension.newBuilder().setSwipeAction(SWIPE_ACTION).build()) - .build(); - - private static final int POSITION = 0; - - @Mock - private ContentDriver mContentDriverChild; - @Mock - private ModelFeature mCardModelFeature; - @Mock - private LeafFeatureDriver mLeafFeatureDriver; - @Mock - private ContentChangedListener mContentChangedListener; - @Mock - private ClusterPendingDismissHelper mClusterPendingDismissHelper; - @Mock - private BasicLoggingApi mBasicLoggingApi; - @Mock - private TooltipApi mTooltipApi; - - private final Configuration mConfiguration = new Configuration.Builder().build(); - private final FakeMainThreadRunner mMainThreadRunner = FakeMainThreadRunner.queueAllTasks(); - private CardDriverForTest mCardDriver; - private FakeModelCursor mCardCursor; - - @Before - public void setup() { - initMocks(this); - - // Represents payload of the child of the card. - ModelFeature childModelFeature = mock(ModelFeature.class); - when(childModelFeature.getStreamFeature()).thenReturn(STREAM_FEATURE); - - // ModelChild containing content. - ModelChild pietModelChild = mock(ModelChild.class); - when(pietModelChild.getModelFeature()).thenReturn(childModelFeature); - when(pietModelChild.getType()).thenReturn(Type.FEATURE); - - // Cursor to transverse the content of a card. - mCardCursor = new FakeModelCursor(Lists.newArrayList(pietModelChild)); - - // A ModelFeature representing a card. - when(mCardModelFeature.getCursor()).thenReturn(mCardCursor); - when(mCardModelFeature.getStreamFeature()) - .thenReturn(StreamFeature.newBuilder().setCard(Card.getDefaultInstance()).build()); - when(mContentDriverChild.getLeafFeatureDriver()).thenReturn(mLeafFeatureDriver); - - mCardDriver = new CardDriverForTest(mock(ActionApi.class), mock(ActionManager.class), - mock(ActionParserFactory.class), mBasicLoggingApi, mCardModelFeature, - mock(ModelProvider.class), POSITION, mContentDriverChild, - mock(StreamOfflineMonitor.class), mock(ContextMenuManager.class), - mock(ViewLoggingUpdater.class)); - } - - @Test - public void testGetLeafFeatureDriver() { - assertThat((mCardDriver.getLeafFeatureDriver())).isEqualTo(mLeafFeatureDriver); - } - - @Test - public void testGetLeafFeatureDriver_reusesPreviousLeafFeatureDriver() { - mCardDriver.getLeafFeatureDriver(); - - verify(mCardModelFeature).getCursor(); - - reset(mCardModelFeature); - - mCardDriver.getLeafFeatureDriver(); - - verify(mCardModelFeature, never()).getCursor(); - } - - @Test - public void testGetLeafFeatureDriver_notSwipeable() { - when(mCardModelFeature.getStreamFeature()) - .thenReturn(StreamFeature.newBuilder().setCard(Card.getDefaultInstance()).build()); - - mCardDriver.getLeafFeatureDriver(); - - assertThat(mCardDriver.mSwipeActionArg).isEqualTo(FeedActionPayload.getDefaultInstance()); - } - - @Test - public void testGetLeafFeatureDriver_swipeable() { - when(mCardModelFeature.getStreamFeature()) - .thenReturn(StreamFeature.newBuilder().setCard(CARD_WITH_SWIPE_ACTION).build()); - - mCardDriver.getLeafFeatureDriver(); - - assertThat(mCardDriver.mSwipeActionArg).isEqualTo(SWIPE_ACTION); - } - - @Test - public void testOnDestroy() { - mCardDriver.getLeafFeatureDriver(); - mCardDriver.onDestroy(); - - verify(mContentDriverChild).onDestroy(); - } - - @Test - public void testUnboundChild() { - ModelChild pietModelChild = mock(ModelChild.class); - when(pietModelChild.getType()).thenReturn(Type.UNBOUND); - - // Override setup with an unbound child in the cursor - mCardCursor.setModelChildren(Lists.newArrayList(pietModelChild)); - - assertThat(mCardDriver.getLeafFeatureDriver()).isNull(); - } - - @Test - public void getLeafFeatureDrivers_childNotAFeature_logsInternalError() { - mCardCursor = FakeModelCursor.newBuilder().addUnboundChild().build(); - when(mCardModelFeature.getCursor()).thenReturn(mCardCursor); - - mCardDriver.getLeafFeatureDriver(); - - verify(mBasicLoggingApi).onInternalError(InternalFeedError.CARD_CHILD_MISSING_FEATURE); - } - - public class CardDriverForTest extends CardDriver { - private final ContentDriver mChild; - private FeedActionPayload mSwipeActionArg; - - CardDriverForTest(ActionApi actionApi, ActionManager actionManager, - ActionParserFactory actionParserFactory, BasicLoggingApi basicLoggingApi, - ModelFeature cardModel, ModelProvider modelProvider, int position, - ContentDriver childContentDriver, StreamOfflineMonitor streamOfflineMonitor, - ContextMenuManager contextMenuManager, ViewLoggingUpdater viewLoggingUpdater) { - super(actionApi, actionManager, actionParserFactory, basicLoggingApi, cardModel, - modelProvider, position, mClusterPendingDismissHelper, streamOfflineMonitor, - mContentChangedListener, contextMenuManager, mMainThreadRunner, mConfiguration, - viewLoggingUpdater, mTooltipApi); - this.mChild = childContentDriver; - } - - @Override - ContentDriver createContentDriver( - ModelFeature contentModel, FeedActionPayload swipeAction) { - this.mSwipeActionArg = swipeAction; - return mChild; - } - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/drivers/ClusterDriverTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/drivers/ClusterDriverTest.java deleted file mode 100644 index fece673e..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/drivers/ClusterDriverTest.java +++ /dev/null
@@ -1,176 +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. - -package org.chromium.chrome.browser.feed.library.basicstream.internal.drivers; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import com.google.common.collect.Lists; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.action.ActionApi; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration; -import org.chromium.chrome.browser.feed.library.api.host.logging.BasicLoggingApi; -import org.chromium.chrome.browser.feed.library.api.host.logging.InternalFeedError; -import org.chromium.chrome.browser.feed.library.api.host.stream.TooltipApi; -import org.chromium.chrome.browser.feed.library.api.internal.actionmanager.ActionManager; -import org.chromium.chrome.browser.feed.library.api.internal.actionparser.ActionParserFactory; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelChild; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelChild.Type; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelFeature; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider; -import org.chromium.chrome.browser.feed.library.basicstream.internal.pendingdismiss.PendingDismissHandler; -import org.chromium.chrome.browser.feed.library.basicstream.internal.viewloggingupdater.ViewLoggingUpdater; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeMainThreadRunner; -import org.chromium.chrome.browser.feed.library.sharedstream.contextmenumanager.ContextMenuManager; -import org.chromium.chrome.browser.feed.library.sharedstream.offlinemonitor.StreamOfflineMonitor; -import org.chromium.chrome.browser.feed.library.sharedstream.pendingdismiss.PendingDismissCallback; -import org.chromium.chrome.browser.feed.library.testing.modelprovider.FakeModelCursor; -import org.chromium.chrome.browser.feed.shared.stream.Stream.ContentChangedListener; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamFeature; -import org.chromium.components.feed.core.proto.ui.action.FeedActionProto.UndoAction; -import org.chromium.components.feed.core.proto.ui.stream.StreamStructureProto.Card; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link ClusterDriver}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ClusterDriverTest { - private static final StreamFeature CARD_STREAM_FEATURE = - StreamFeature.newBuilder().setCard(Card.getDefaultInstance()).build(); - - @Mock - private CardDriver mCardDriver; - @Mock - private LeafFeatureDriver mLeafFeatureDriver; - @Mock - private ModelFeature mClusterModelFeature; - @Mock - private ContentChangedListener mContentChangedListener; - @Mock - private PendingDismissHandler mPendingDismissHandler; - @Mock - private BasicLoggingApi mBasicLoggingApi; - @Mock - private TooltipApi mTooltipApi; - - private final Configuration mConfiguration = new Configuration.Builder().build(); - private final FakeMainThreadRunner mMainThreadRunner = FakeMainThreadRunner.queueAllTasks(); - private ClusterDriverForTest mClusterDriver; - - @Before - public void setup() { - initMocks(this); - - // Child produced by Cursor representing a card. - ModelChild cardChild = mock(ModelChild.class); - when(cardChild.getType()).thenReturn(Type.FEATURE); - - // ModelFeature representing a card. - ModelFeature cardModelFeature = mock(ModelFeature.class); - when(cardModelFeature.getStreamFeature()).thenReturn(CARD_STREAM_FEATURE); - when(cardChild.getModelFeature()).thenReturn(cardModelFeature); - - // Cursor representing the content of the cluster, which is one card. - FakeModelCursor clusterCursor = new FakeModelCursor(Lists.newArrayList(cardChild)); - when(mClusterModelFeature.getCursor()).thenReturn(clusterCursor); - - when(mCardDriver.getLeafFeatureDriver()).thenReturn(mLeafFeatureDriver); - - mClusterDriver = new ClusterDriverForTest(mock(ActionApi.class), mock(ActionManager.class), - mock(ActionParserFactory.class), mBasicLoggingApi, mClusterModelFeature, - mock(ModelProvider.class), - /* position= */ 0, mCardDriver, mock(StreamOfflineMonitor.class), - mock(ContextMenuManager.class), mock(ViewLoggingUpdater.class)); - } - - @Test - public void testGetContentModel() { - assertThat(mClusterDriver.getLeafFeatureDriver()).isEqualTo(mLeafFeatureDriver); - } - - @Test - public void testGetContentModel_reusesPreviousContentModel() { - mClusterDriver.getLeafFeatureDriver(); - - verify(mClusterModelFeature).getCursor(); - - mClusterDriver.getLeafFeatureDriver(); - - verifyNoMoreInteractions(mClusterModelFeature); - } - - @Test - public void testOnDestroy() { - mClusterDriver.getLeafFeatureDriver(); - mClusterDriver.onDestroy(); - - verify(mCardDriver).onDestroy(); - } - - @Test - public void testTriggerPendingDismiss() { - StreamFeature streamFeature = StreamFeature.newBuilder().setContentId("contentId").build(); - when(mClusterModelFeature.getStreamFeature()).thenReturn(streamFeature); - PendingDismissCallback pendingDismissCallback = Mockito.mock(PendingDismissCallback.class); - mClusterDriver.triggerPendingDismissForCluster( - UndoAction.getDefaultInstance(), pendingDismissCallback); - verify(mPendingDismissHandler) - .triggerPendingDismiss(mClusterModelFeature.getStreamFeature().getContentId(), - UndoAction.getDefaultInstance(), pendingDismissCallback); - } - - @Test - public void getLeafFeatureDrivers_childNotAFeature_logsInternalError() { - FakeModelCursor clusterCursor = FakeModelCursor.newBuilder().addUnboundChild().build(); - when(mClusterModelFeature.getCursor()).thenReturn(clusterCursor); - - mClusterDriver.getLeafFeatureDriver(); - - verify(mBasicLoggingApi).onInternalError(InternalFeedError.CLUSTER_CHILD_MISSING_FEATURE); - } - - @Test - public void getLeafFeatureDrivers_childNotACard_logsInternalError() { - FakeModelCursor clusterCursor = FakeModelCursor.newBuilder().addCluster().build(); - when(mClusterModelFeature.getCursor()).thenReturn(clusterCursor); - - mClusterDriver.getLeafFeatureDriver(); - - verify(mBasicLoggingApi).onInternalError(InternalFeedError.CLUSTER_CHILD_NOT_CARD); - } - - class ClusterDriverForTest extends ClusterDriver { - private final CardDriver mCardDriver; - - ClusterDriverForTest(ActionApi actionApi, ActionManager actionManager, - ActionParserFactory actionParserFactory, BasicLoggingApi basicLoggingApi, - ModelFeature clusterModel, ModelProvider modelProvider, int position, - CardDriver cardDriver, StreamOfflineMonitor streamOfflineMonitor, - ContextMenuManager contextMenuManager, ViewLoggingUpdater viewLoggingUpdater) { - super(actionApi, actionManager, actionParserFactory, basicLoggingApi, clusterModel, - modelProvider, position, mPendingDismissHandler, streamOfflineMonitor, - mContentChangedListener, contextMenuManager, mMainThreadRunner, mConfiguration, - viewLoggingUpdater, mTooltipApi); - this.mCardDriver = cardDriver; - } - - @Override - CardDriver createCardDriver(ModelFeature content) { - return mCardDriver; - } - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/drivers/ContentDriverTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/drivers/ContentDriverTest.java deleted file mode 100644 index e1646ca3..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/drivers/ContentDriverTest.java +++ /dev/null
@@ -1,597 +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. - -package org.chromium.chrome.browser.feed.library.basicstream.internal.drivers; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyListOf; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import androidx.recyclerview.widget.RecyclerView; - -import com.google.common.collect.ImmutableList; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.ArgumentMatchers; -import org.mockito.InOrder; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.robolectric.annotation.Config; - -import org.chromium.base.supplier.Supplier; -import org.chromium.chrome.browser.feed.library.api.client.knowncontent.ContentMetadata; -import org.chromium.chrome.browser.feed.library.api.host.action.ActionApi; -import org.chromium.chrome.browser.feed.library.api.host.action.StreamActionApi; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration.ConfigKey; -import org.chromium.chrome.browser.feed.library.api.host.logging.BasicLoggingApi; -import org.chromium.chrome.browser.feed.library.api.host.logging.ContentLoggingData; -import org.chromium.chrome.browser.feed.library.api.host.logging.InternalFeedError; -import org.chromium.chrome.browser.feed.library.api.host.stream.TooltipApi; -import org.chromium.chrome.browser.feed.library.api.internal.actionmanager.ActionManager; -import org.chromium.chrome.browser.feed.library.api.internal.actionparser.ActionParser; -import org.chromium.chrome.browser.feed.library.api.internal.actionparser.ActionParserFactory; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelFeature; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider; -import org.chromium.chrome.browser.feed.library.basicstream.internal.actions.StreamActionApiImpl; -import org.chromium.chrome.browser.feed.library.basicstream.internal.actions.ViewElementActionHandler; -import org.chromium.chrome.browser.feed.library.basicstream.internal.pendingdismiss.ClusterPendingDismissHelper; -import org.chromium.chrome.browser.feed.library.basicstream.internal.viewholders.PietViewHolder; -import org.chromium.chrome.browser.feed.library.basicstream.internal.viewloggingupdater.ViewLoggingUpdater; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeMainThreadRunner; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.sharedstream.contextmenumanager.ContextMenuManager; -import org.chromium.chrome.browser.feed.library.sharedstream.logging.LoggingListener; -import org.chromium.chrome.browser.feed.library.sharedstream.logging.StreamContentLoggingData; -import org.chromium.chrome.browser.feed.library.testing.sharedstream.offlinemonitor.FakeStreamOfflineMonitor; -import org.chromium.chrome.browser.feed.shared.stream.Stream.ContentChangedListener; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamFeature; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamSharedState; -import org.chromium.components.feed.core.proto.ui.action.FeedActionPayloadProto.FeedActionPayload; -import org.chromium.components.feed.core.proto.ui.action.FeedActionProto.FeedAction; -import org.chromium.components.feed.core.proto.ui.action.FeedActionProto.FeedActionMetadata.ElementType; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.Frame; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.PietSharedState; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.Template; -import org.chromium.components.feed.core.proto.ui.stream.StreamStructureProto.BasicLoggingMetadata; -import org.chromium.components.feed.core.proto.ui.stream.StreamStructureProto.Content; -import org.chromium.components.feed.core.proto.ui.stream.StreamStructureProto.Content.Type; -import org.chromium.components.feed.core.proto.ui.stream.StreamStructureProto.OfflineMetadata; -import org.chromium.components.feed.core.proto.ui.stream.StreamStructureProto.PietContent; -import org.chromium.components.feed.core.proto.ui.stream.StreamStructureProto.RepresentationData; -import org.chromium.components.feed.core.proto.wire.ContentIdProto.ContentId; -import org.chromium.components.feed.core.proto.wire.PietSharedStateItemProto.PietSharedStateItem; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.ArrayList; -import java.util.List; - -/** Tests for {@link ContentDriver}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ContentDriverTest { - private static final long VIEW_MIN_TIME_MS = 200; - private static final int POSITION = 1; - private static final String CONTENT_URL = "google.com"; - private static final String CONTENT_TITLE = "title"; - - private static final BasicLoggingMetadata BASIC_LOGGING_METADATA = - BasicLoggingMetadata.newBuilder().setScore(40).build(); - private static final RepresentationData REPRESENTATION_DATA = - RepresentationData.newBuilder().setUri(CONTENT_URL).setPublishedTimeSeconds(10).build(); - private static final StreamContentLoggingData CONTENT_LOGGING_DATA = - new StreamContentLoggingData(POSITION, BASIC_LOGGING_METADATA, REPRESENTATION_DATA, - /*availableOffline= */ false); - private static final OfflineMetadata OFFLINE_METADATA = - OfflineMetadata.newBuilder().setTitle(CONTENT_TITLE).build(); - - private static final ContentId CONTENT_ID_1 = ContentId.newBuilder() - .setContentDomain("piet-shared-state") - .setId(2) - .setTable("piet-shared-state") - .build(); - private static final ContentId CONTENT_ID_2 = ContentId.newBuilder() - .setContentDomain("piet-shared-state") - .setId(3) - .setTable("piet-shared-state") - .build(); - private static final PietContent PIET_CONTENT = - PietContent.newBuilder() - .setFrame(Frame.newBuilder().setStylesheetId("id")) - .addPietSharedStates(CONTENT_ID_1) - .addPietSharedStates(CONTENT_ID_2) - .build(); - private static final Content CONTENT_NO_OFFLINE_METADATA = - Content.newBuilder() - .setBasicLoggingMetadata(BASIC_LOGGING_METADATA) - .setRepresentationData(REPRESENTATION_DATA) - .setType(Type.PIET) - .setExtension(PietContent.pietContentExtension, PIET_CONTENT) - .build(); - private static final Content CONTENT = - CONTENT_NO_OFFLINE_METADATA.toBuilder().setOfflineMetadata(OFFLINE_METADATA).build(); - - private static final PietSharedState PIET_SHARED_STATE_1 = - PietSharedState.newBuilder() - .addTemplates(Template.newBuilder().setTemplateId("1")) - .build(); - private static final PietSharedState PIET_SHARED_STATE_2 = - PietSharedState.newBuilder() - .addTemplates(Template.newBuilder().setTemplateId("2")) - .build(); - private static final ImmutableList<PietSharedState> PIET_SHARED_STATES = - ImmutableList.of(PIET_SHARED_STATE_1, PIET_SHARED_STATE_2); - - private static final StreamSharedState STREAM_SHARED_STATE_1 = - StreamSharedState.newBuilder() - .setPietSharedStateItem(PietSharedStateItem.newBuilder() - .setContentId(CONTENT_ID_1) - .setPietSharedState(PIET_SHARED_STATE_1)) - .build(); - private static final StreamSharedState STREAM_SHARED_STATE_2 = - StreamSharedState.newBuilder() - .setPietSharedStateItem(PietSharedStateItem.newBuilder() - .setContentId(CONTENT_ID_2) - .setPietSharedState(PIET_SHARED_STATE_2)) - .build(); - - @Mock - private ActionApi mActionApi; - @Mock - private ActionManager mActionManager; - @Mock - private ActionParserFactory mActionParserFactory; - @Mock - private BasicLoggingApi mBasicLoggingApi; - @Mock - private ModelFeature mModelFeature; - @Mock - private ModelProvider mModelProvider; - @Mock - private ClusterPendingDismissHelper mClusterPendingDismissHelper; - @Mock - private PietViewHolder mPietViewHolder; - @Mock - private StreamActionApiImpl mStreamActionApi; - @Mock - private ContentChangedListener mContentChangedListener; - @Mock - private ActionParser mActionParser; - @Mock - private ContextMenuManager mContextMenuManager; - @Mock - private TooltipApi mTooltipApi; - - private FakeStreamOfflineMonitor mFakeStreamOfflineMonitor; - private ContentDriver mContentDriver; - private final FakeClock mFakeClock = new FakeClock(); - private final FakeMainThreadRunner mFakeMainThreadRunner = - FakeMainThreadRunner.create(mFakeClock); - private final Configuration mConfiguration = - new Configuration.Builder().put(ConfigKey.VIEW_MIN_TIME_MS, VIEW_MIN_TIME_MS).build(); - private ViewLoggingUpdater mViewLoggingUpdater; - - @Before - public void setup() { - initMocks(this); - - when(mModelFeature.getStreamFeature()) - .thenReturn(StreamFeature.newBuilder().setContent(CONTENT).build()); - when(mModelProvider.getSharedState(CONTENT_ID_1)).thenReturn(STREAM_SHARED_STATE_1); - when(mModelProvider.getSharedState(CONTENT_ID_2)).thenReturn(STREAM_SHARED_STATE_2); - when(mActionParserFactory.build(ArgumentMatchers.<Supplier<ContentMetadata>>any())) - .thenReturn(mActionParser); - mViewLoggingUpdater = new ViewLoggingUpdater(); - mFakeStreamOfflineMonitor = FakeStreamOfflineMonitor.create(); - mContentDriver = new ContentDriver(mActionApi, mActionManager, mActionParserFactory, - mBasicLoggingApi, mModelFeature, mModelProvider, POSITION, - FeedActionPayload.getDefaultInstance(), mClusterPendingDismissHelper, - mFakeStreamOfflineMonitor, mContentChangedListener, mContextMenuManager, - mFakeMainThreadRunner, mConfiguration, mViewLoggingUpdater, mTooltipApi) { - @Override - StreamActionApiImpl createStreamActionApi(ActionApi actionApi, - ActionParser actionParser, ActionManager actionManager, - BasicLoggingApi basicLoggingApi, - Supplier<ContentLoggingData> contentLoggingData, String sessionId, - ContextMenuManager contextMenuManager, - ClusterPendingDismissHelper clusterPendingDismissHelper, - ViewElementActionHandler handler, String contentId, TooltipApi tooltipApi) { - return mStreamActionApi; - } - }; - } - - @Test - public void testBind() { - mContentDriver.bind(mPietViewHolder); - - verify(mPietViewHolder) - .bind(eq(PIET_CONTENT.getFrame()), eq(PIET_SHARED_STATES), eq(mStreamActionApi), - eq(FeedActionPayload.getDefaultInstance()), any(LoggingListener.class), - eq(mActionParser)); - } - - @Test - public void testMaybeRebind() { - mContentDriver.bind(mPietViewHolder); - mContentDriver.maybeRebind(); - verify(mPietViewHolder, times(2)) - .bind(eq(PIET_CONTENT.getFrame()), eq(PIET_SHARED_STATES), eq(mStreamActionApi), - eq(FeedActionPayload.getDefaultInstance()), any(LoggingListener.class), - eq(mActionParser)); - verify(mPietViewHolder).unbind(); - } - - @Test - public void testMaybeRebind_nullViewHolder() { - // bind/unbind to associated the pietViewHolder with the contentDriver - mContentDriver.bind(mPietViewHolder); - mContentDriver.unbind(); - reset(mPietViewHolder); - - mContentDriver.maybeRebind(); - verify(mPietViewHolder, never()) - .bind(any(Frame.class), ArgumentMatchers.<List<PietSharedState>>any(), - any(StreamActionApi.class), any(FeedActionPayload.class), - any(LoggingListener.class), any(ActionParser.class)); - verify(mPietViewHolder, never()).unbind(); - } - - @Test - public void testOnViewVisible_visibilityListenerLogsContentViewed() { - mContentDriver.bind(mPietViewHolder); - - ArgumentCaptor<LoggingListener> visibilityListenerCaptor = - ArgumentCaptor.forClass(LoggingListener.class); - - verify(mPietViewHolder) - .bind(any(Frame.class), anyListOf(PietSharedState.class), - any(StreamActionApi.class), any(FeedActionPayload.class), - visibilityListenerCaptor.capture(), any(ActionParser.class)); - LoggingListener listener = visibilityListenerCaptor.getValue(); - listener.onViewVisible(); - - verify(mBasicLoggingApi).onContentViewed(CONTENT_LOGGING_DATA); - } - - @Test - public void testOnViewVisible_resetVisibility_logsTwice() { - mContentDriver.bind(mPietViewHolder); - - ArgumentCaptor<LoggingListener> visibilityListenerCaptor = - ArgumentCaptor.forClass(LoggingListener.class); - - verify(mPietViewHolder) - .bind(any(Frame.class), anyListOf(PietSharedState.class), - any(StreamActionApi.class), any(FeedActionPayload.class), - visibilityListenerCaptor.capture(), any(ActionParser.class)); - LoggingListener listener = visibilityListenerCaptor.getValue(); - listener.onViewVisible(); - mViewLoggingUpdater.resetViewTracking(); - listener.onViewVisible(); - - verify(mBasicLoggingApi, times(2)).onContentViewed(CONTENT_LOGGING_DATA); - } - - @Test - public void - testOnContentClicked_offlineStatusChanges_logsContentClicked_withNewOfflineStatus() { - mContentDriver.bind(mPietViewHolder); - - ArgumentCaptor<LoggingListener> visibilityListenerCaptor = - ArgumentCaptor.forClass(LoggingListener.class); - - verify(mPietViewHolder) - .bind(any(Frame.class), anyListOf(PietSharedState.class), - any(StreamActionApi.class), any(FeedActionPayload.class), - visibilityListenerCaptor.capture(), any(ActionParser.class)); - LoggingListener listener = visibilityListenerCaptor.getValue(); - - mFakeStreamOfflineMonitor.setOfflineStatus(CONTENT_URL, true); - - listener.onContentClicked(); - - verify(mBasicLoggingApi) - .onContentClicked(CONTENT_LOGGING_DATA.createWithOfflineStatus(true)); - } - - @Test - public void testOnContentClicked_visibilityListenerLogsContentClicked() { - mContentDriver.bind(mPietViewHolder); - - ArgumentCaptor<LoggingListener> visibilityListenerCaptor = - ArgumentCaptor.forClass(LoggingListener.class); - - verify(mPietViewHolder) - .bind(any(Frame.class), anyListOf(PietSharedState.class), - any(StreamActionApi.class), any(FeedActionPayload.class), - visibilityListenerCaptor.capture(), any(ActionParser.class)); - LoggingListener listener = visibilityListenerCaptor.getValue(); - listener.onContentClicked(); - - verify(mBasicLoggingApi).onContentClicked(CONTENT_LOGGING_DATA); - } - - @Test - public void testOnContentSwipe_visibilityListenerLogsContentSwiped() { - mContentDriver.bind(mPietViewHolder); - - ArgumentCaptor<LoggingListener> visibilityListenerCaptor = - ArgumentCaptor.forClass(LoggingListener.class); - - verify(mPietViewHolder) - .bind(any(Frame.class), anyListOf(PietSharedState.class), - any(StreamActionApi.class), any(FeedActionPayload.class), - visibilityListenerCaptor.capture(), any(ActionParser.class)); - LoggingListener listener = visibilityListenerCaptor.getValue(); - listener.onContentSwiped(); - - verify(mBasicLoggingApi).onContentSwiped(CONTENT_LOGGING_DATA); - } - - @Test - public void testBind_nullSharedStates() { - reset(mModelProvider); - when(mModelProvider.getSharedState(CONTENT_ID_1)).thenReturn(null); - - mContentDriver = new ContentDriver(mActionApi, mActionManager, mActionParserFactory, - mBasicLoggingApi, mModelFeature, mModelProvider, POSITION, - FeedActionPayload.getDefaultInstance(), mClusterPendingDismissHelper, - mFakeStreamOfflineMonitor, mContentChangedListener, mContextMenuManager, - mFakeMainThreadRunner, mConfiguration, mViewLoggingUpdater, mTooltipApi); - - mContentDriver.bind(mPietViewHolder); - - verify(mPietViewHolder) - .bind(eq(PIET_CONTENT.getFrame()), - /* pietSharedStates= */ eq(new ArrayList<>()), any(StreamActionApi.class), - eq(FeedActionPayload.getDefaultInstance()), any(LoggingListener.class), - any(ActionParser.class)); - verify(mModelProvider).getSharedState(CONTENT_ID_1); - verify(mBasicLoggingApi).onInternalError(InternalFeedError.NULL_SHARED_STATES); - } - - @Test - public void testBind_swipeableWithNonDefaultFeedActionPayload() { - FeedActionPayload payload = FeedActionPayload.newBuilder() - .setExtension(FeedAction.feedActionExtension, - FeedAction.getDefaultInstance()) - .build(); - mContentDriver = new ContentDriver(mActionApi, mActionManager, mActionParserFactory, - mBasicLoggingApi, mModelFeature, mModelProvider, POSITION, payload, - mClusterPendingDismissHelper, mFakeStreamOfflineMonitor, mContentChangedListener, - mContextMenuManager, mFakeMainThreadRunner, mConfiguration, mViewLoggingUpdater, - mTooltipApi); - - mContentDriver.bind(mPietViewHolder); - - verify(mPietViewHolder) - .bind(eq(PIET_CONTENT.getFrame()), eq(PIET_SHARED_STATES), - any(StreamActionApi.class), eq(payload), any(LoggingListener.class), - any(ActionParser.class)); - } - - @Test - public void testOfflineStatusChange() { - mContentDriver = new ContentDriver(mActionApi, mActionManager, mActionParserFactory, - mBasicLoggingApi, mModelFeature, mModelProvider, POSITION, - FeedActionPayload.getDefaultInstance(), mClusterPendingDismissHelper, - mFakeStreamOfflineMonitor, mContentChangedListener, mContextMenuManager, - mFakeMainThreadRunner, mConfiguration, mViewLoggingUpdater, mTooltipApi); - - mContentDriver.bind(mPietViewHolder); - - reset(mPietViewHolder); - - mFakeStreamOfflineMonitor.setOfflineStatus(CONTENT_URL, true); - - verify(mContentChangedListener).onContentChanged(); - InOrder inOrder = Mockito.inOrder(mPietViewHolder); - inOrder.verify(mPietViewHolder).unbind(); - inOrder.verify(mPietViewHolder) - .bind(eq(PIET_CONTENT.getFrame()), eq(PIET_SHARED_STATES), - any(StreamActionApi.class), eq(FeedActionPayload.getDefaultInstance()), - any(LoggingListener.class), any(ActionParser.class)); - } - - @Test - public void testOfflineStatusChange_noOpWithoutUpdate() { - mFakeStreamOfflineMonitor = FakeStreamOfflineMonitor.create(); - - mContentDriver = new ContentDriver(mActionApi, mActionManager, mActionParserFactory, - mBasicLoggingApi, mModelFeature, mModelProvider, POSITION, - FeedActionPayload.getDefaultInstance(), mClusterPendingDismissHelper, - mFakeStreamOfflineMonitor, mContentChangedListener, mContextMenuManager, - mFakeMainThreadRunner, mConfiguration, mViewLoggingUpdater, mTooltipApi); - - mFakeStreamOfflineMonitor.setOfflineStatus(CONTENT_URL, true); - mContentDriver.bind(mPietViewHolder); - - reset(mPietViewHolder); - - mFakeStreamOfflineMonitor.setOfflineStatus(CONTENT_URL, true); - - verifyNoMoreInteractions(mPietViewHolder, mContentChangedListener); - } - - @Test - public void testNotEnoughInformationForContentMetadata() { - assertThat(getContentMetadataFor(CONTENT_NO_OFFLINE_METADATA)).isNull(); - } - - @Test - public void testContentMetadataProvider() { - ContentMetadata contentMetadata = getContentMetadataFor(CONTENT); - - assertThat(contentMetadata).isNotNull(); - assertThat(contentMetadata.getTitle()).isEqualTo(CONTENT_TITLE); - assertThat(contentMetadata.getUrl()).isEqualTo(CONTENT_URL); - } - - @Test - public void testUnbind() { - mContentDriver.bind(mPietViewHolder); - - mContentDriver.unbind(); - - verify(mPietViewHolder).unbind(); - assertThat(mContentDriver.isBound()).isFalse(); - } - - @Test - public void testOnElementView_logsElementViewed() { - mContentDriver.onElementView(ElementType.INTEREST_HEADER.getNumber()); - mFakeClock.advance(VIEW_MIN_TIME_MS); - - verify(mBasicLoggingApi) - .onVisualElementViewed( - any(ContentLoggingData.class), eq(ElementType.INTEREST_HEADER.getNumber())); - } - - @Test - public void testOnElementView_logsElementViewed_usingOfflineStatusWhenLogging() { - mContentDriver.onElementView(ElementType.INTEREST_HEADER.getNumber()); - - // When the view first happens, the offline status is false. - mFakeClock.advance(VIEW_MIN_TIME_MS / 2); - - // When waiting to log the view, the offline status switches to true - mFakeStreamOfflineMonitor.setOfflineStatus(CONTENT_URL, true); - - // Advance so that the event is logged - mFakeClock.advance(VIEW_MIN_TIME_MS / 2); - - // Should be logged with offline status true. - verify(mBasicLoggingApi) - .onVisualElementViewed(eq(CONTENT_LOGGING_DATA.createWithOfflineStatus(true)), - eq(ElementType.INTEREST_HEADER.getNumber())); - } - - @Test - public void testOnElementView_logsElementViewed_beforeTimeout() { - mContentDriver.onElementView(ElementType.INTEREST_HEADER.getNumber()); - mFakeClock.advance(VIEW_MIN_TIME_MS - 1); - - verify(mBasicLoggingApi, never()) - .onVisualElementViewed( - any(ContentLoggingData.class), eq(ElementType.INTEREST_HEADER.getNumber())); - } - - @Test - public void testOnElementView_logsElementViewedThenHidden() { - mContentDriver.onElementView(ElementType.INTEREST_HEADER.getNumber()); - mContentDriver.onElementHide(ElementType.INTEREST_HEADER.getNumber()); - mFakeClock.advance(VIEW_MIN_TIME_MS); - - verify(mBasicLoggingApi, never()) - .onVisualElementViewed( - any(ContentLoggingData.class), eq(ElementType.INTEREST_HEADER.getNumber())); - } - - @Test - public void testOnElementView_logsElementViewedThenHiddenThenViewed() { - mContentDriver.onElementView(ElementType.INTEREST_HEADER.getNumber()); - mContentDriver.onElementHide(ElementType.INTEREST_HEADER.getNumber()); - mFakeClock.advance(VIEW_MIN_TIME_MS - 1); - mContentDriver.onElementView(ElementType.INTEREST_HEADER.getNumber()); - mFakeClock.advance(VIEW_MIN_TIME_MS); - // Check that it only gets recorded once. - verify(mBasicLoggingApi) - .onVisualElementViewed( - any(ContentLoggingData.class), eq(ElementType.INTEREST_HEADER.getNumber())); - } - - @Test - public void testOnElementView_logsElementViewedMultiple_differentTypes() { - mContentDriver.onElementView(ElementType.INTEREST_HEADER.getNumber()); - mContentDriver.onElementView(ElementType.CARD_LARGE_IMAGE.getNumber()); - mFakeClock.advance(VIEW_MIN_TIME_MS); - - verify(mBasicLoggingApi) - .onVisualElementViewed( - any(ContentLoggingData.class), eq(ElementType.INTEREST_HEADER.getNumber())); - verify(mBasicLoggingApi) - .onVisualElementViewed(any(ContentLoggingData.class), - eq(ElementType.CARD_LARGE_IMAGE.getNumber())); - } - - @Test - public void testOnElementView_logsElementViewedMultiple_sameTypes() { - mContentDriver.onElementView(ElementType.INTEREST_HEADER.getNumber()); - mContentDriver.onElementView(ElementType.INTEREST_HEADER.getNumber()); - mFakeClock.advance(VIEW_MIN_TIME_MS); - - // Make sure it only logs one view. - verify(mBasicLoggingApi) - .onVisualElementViewed( - any(ContentLoggingData.class), eq(ElementType.INTEREST_HEADER.getNumber())); - } - - @Test - public void testOnScrollStateChanged() { - mContentDriver.onElementView(ElementType.INTEREST_HEADER.getNumber()); - mContentDriver.onScrollStateChanged(RecyclerView.SCROLL_STATE_DRAGGING); - mFakeClock.advance(VIEW_MIN_TIME_MS); - verify(mBasicLoggingApi, never()) - .onVisualElementViewed( - any(ContentLoggingData.class), eq(ElementType.INTEREST_HEADER.getNumber())); - } - - @Test - public void testOnScrollStateChanged_idle() { - mContentDriver.onElementView(ElementType.INTEREST_HEADER.getNumber()); - mContentDriver.onScrollStateChanged(RecyclerView.SCROLL_STATE_IDLE); - mFakeClock.advance(VIEW_MIN_TIME_MS); - verify(mBasicLoggingApi) - .onVisualElementViewed( - any(ContentLoggingData.class), eq(ElementType.INTEREST_HEADER.getNumber())); - } - - @Test - public void testOnDestroy_cancelsTasks() { - mContentDriver.onElementView(ElementType.INTEREST_HEADER.getNumber()); - mContentDriver.onDestroy(); - mFakeClock.advance(VIEW_MIN_TIME_MS); - verify(mBasicLoggingApi, never()) - .onVisualElementViewed( - any(ContentLoggingData.class), eq(ElementType.INTEREST_HEADER.getNumber())); - } - - /** For Captor of generic. */ - @SuppressWarnings("unchecked") - /*@Nullable*/ - private ContentMetadata getContentMetadataFor(Content content) { - when(mModelFeature.getStreamFeature()) - .thenReturn(StreamFeature.newBuilder().setContent(content).build()); - - reset(mActionParserFactory); - when(mActionParserFactory.build(ArgumentMatchers.<Supplier<ContentMetadata>>any())) - .thenReturn(mActionParser); - - mContentDriver = new ContentDriver(mActionApi, mActionManager, mActionParserFactory, - mBasicLoggingApi, mModelFeature, mModelProvider, POSITION, - FeedActionPayload.getDefaultInstance(), mClusterPendingDismissHelper, - mFakeStreamOfflineMonitor, mContentChangedListener, mContextMenuManager, - mFakeMainThreadRunner, mConfiguration, mViewLoggingUpdater, mTooltipApi); - - ArgumentCaptor<Supplier<ContentMetadata>> contentMetadataSupplierCaptor = - ArgumentCaptor.forClass((Class<Supplier<ContentMetadata>>) (Class) Supplier.class); - - verify(mActionParserFactory).build(contentMetadataSupplierCaptor.capture()); - - return contentMetadataSupplierCaptor.getValue().get(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/drivers/ContinuationDriverTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/drivers/ContinuationDriverTest.java deleted file mode 100644 index 1df6789..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/drivers/ContinuationDriverTest.java +++ /dev/null
@@ -1,720 +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. - -package org.chromium.chrome.browser.feed.library.basicstream.internal.drivers; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import static org.chromium.chrome.browser.feed.library.common.testing.RunnableSubject.assertThatRunnable; - -import android.app.Activity; -import android.content.Context; -import android.view.View; -import android.view.View.OnClickListener; - -import com.google.common.collect.ImmutableList; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.ArgumentMatchers; -import org.mockito.InOrder; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.R; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration.ConfigKey; -import org.chromium.chrome.browser.feed.library.api.host.logging.BasicLoggingApi; -import org.chromium.chrome.browser.feed.library.api.host.logging.InternalFeedError; -import org.chromium.chrome.browser.feed.library.api.host.logging.SpinnerType; -import org.chromium.chrome.browser.feed.library.api.host.stream.SnackbarApi; -import org.chromium.chrome.browser.feed.library.api.internal.common.ThreadUtils; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelChild; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelError; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelError.ErrorType; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelToken; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.TokenCompleted; -import org.chromium.chrome.browser.feed.library.basicstream.internal.drivers.ContinuationDriver.CursorChangedListener; -import org.chromium.chrome.browser.feed.library.basicstream.internal.viewholders.ContinuationViewHolder; -import org.chromium.chrome.browser.feed.library.common.time.Clock; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.sharedstream.logging.LoggingListener; -import org.chromium.chrome.browser.feed.library.sharedstream.logging.SpinnerLogger; -import org.chromium.chrome.browser.feed.library.testing.modelprovider.FakeModelCursor; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.List; - -/** Tests for {@link ContinuationDriver}.j */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ContinuationDriverTest { - private static final int POSITION = 1; - public static final TokenCompleted EMPTY_TOKEN_COMPLETED = - new TokenCompleted(FakeModelCursor.newBuilder().build()); - - @Mock - private BasicLoggingApi mBasicLoggingApi; - @Mock - private ModelChild mModelChild; - @Mock - private ModelProvider mModelProvider; - @Mock - private ModelToken mModelToken; - @Mock - private SnackbarApi mSnackbarApi; - @Mock - private ThreadUtils mThreadUtils; - @Mock - private CursorChangedListener mCursorChangedListener; - @Mock - private ContinuationViewHolder mContinuationViewHolder; - - private SpinnerLogger mSpinnerLogger; - private Clock mClock; - private Context mContext; - private ContinuationDriver mContinuationDriver; - private Configuration mConfiguration = new Configuration.Builder().build(); - private View mView; - - @Before - public void setup() { - initMocks(this); - mClock = new FakeClock(); - mContext = Robolectric.buildActivity(Activity.class).get(); - mView = new View(mContext); - when(mModelProvider.handleToken(any(ModelToken.class))).thenReturn(true); - when(mModelChild.getModelToken()).thenReturn(mModelToken); - mSpinnerLogger = new SpinnerLogger(mBasicLoggingApi, mClock); - - mContinuationDriver = new ContinuationDriverForTest(mBasicLoggingApi, mClock, - mConfiguration, mContext, mCursorChangedListener, mModelChild, mModelProvider, - POSITION, mSnackbarApi, mThreadUtils, - /* restoring= */ false); - mContinuationDriver.initialize(); - } - - @Test - public void testHasTokenBeenHandled_returnsTrue_ifSyntheticTokenConsumedImmediately() { - when(mModelToken.isSynthetic()).thenReturn(true); - mContinuationDriver = new ContinuationDriverForTest(mBasicLoggingApi, mClock, - new Configuration.Builder().put(ConfigKey.CONSUME_SYNTHETIC_TOKENS, true).build(), - mContext, mCursorChangedListener, mModelChild, mModelProvider, POSITION, - mSnackbarApi, mThreadUtils, - /* restoring= */ false); - mContinuationDriver.initialize(); - - assertThat(mContinuationDriver.hasTokenBeenHandled()).isTrue(); - } - - @Test - public void testHasTokenBeenHandled_returnsFalse_ifSyntheticTokenNotConsumedImmediately() { - when(mModelToken.isSynthetic()).thenReturn(true); - mContinuationDriver = new ContinuationDriverForTest(mBasicLoggingApi, mClock, - mConfiguration, mContext, mCursorChangedListener, mModelChild, mModelProvider, - POSITION, mSnackbarApi, mThreadUtils, - /* restoring= */ false); - mContinuationDriver.initialize(); - - assertThat(mContinuationDriver.hasTokenBeenHandled()).isFalse(); - } - - @Test - public void testInitialize_nonSyntheticToken() { - mContinuationDriver = new ContinuationDriverForTest(mBasicLoggingApi, mClock, - new Configuration.Builder() - .put(ConfigKey.TRIGGER_IMMEDIATE_PAGINATION, true) - .build(), - mContext, mCursorChangedListener, mModelChild, mModelProvider, POSITION, - mSnackbarApi, mThreadUtils, - /* restoring= */ false); - mContinuationDriver.initialize(); - - verify(mModelToken).registerObserver(mContinuationDriver); - verify(mModelProvider, never()).handleToken(any(ModelToken.class)); - } - - @Test - public void testInitialize_syntheticTokenConsume() { - when(mModelToken.isSynthetic()).thenReturn(true); - mContinuationDriver = new ContinuationDriverForTest(mBasicLoggingApi, mClock, - new Configuration.Builder() - .put(ConfigKey.TRIGGER_IMMEDIATE_PAGINATION, true) - .put(ConfigKey.CONSUME_SYNTHETIC_TOKENS, true) - .build(), - mContext, mCursorChangedListener, mModelChild, mModelProvider, POSITION, - mSnackbarApi, mThreadUtils, - /* restoring= */ false); - mContinuationDriver.initialize(); - - // Call initialize again to make sure it doesn't duplicate work - mContinuationDriver.initialize(); - - verify(mModelToken).registerObserver(mContinuationDriver); - verify(mModelProvider).handleToken(mModelToken); - - mContinuationDriver.bind(mContinuationViewHolder); - verify(mContinuationViewHolder) - .bind(eq(mContinuationDriver), any(LoggingListener.class), eq(true)); - } - - @Test - public void testInitialize_syntheticTokenConsume_logsErrorForUnhandledToken() { - when(mModelToken.isSynthetic()).thenReturn(true); - when(mModelProvider.handleToken(any(ModelToken.class))).thenReturn(false); - mContinuationDriver = new ContinuationDriverForTest(mBasicLoggingApi, mClock, - new Configuration.Builder() - .put(ConfigKey.TRIGGER_IMMEDIATE_PAGINATION, true) - .put(ConfigKey.CONSUME_SYNTHETIC_TOKENS, true) - .build(), - mContext, mCursorChangedListener, mModelChild, mModelProvider, POSITION, - mSnackbarApi, mThreadUtils, - /* restoring= */ false); - mContinuationDriver.initialize(); - - verify(mBasicLoggingApi).onInternalError(InternalFeedError.UNHANDLED_TOKEN); - } - - @Test - public void testInitialize_syntheticTokenNotConsumed() { - when(mModelToken.isSynthetic()).thenReturn(true); - mContinuationDriver = new ContinuationDriverForTest(mBasicLoggingApi, mClock, - new Configuration.Builder() - .put(ConfigKey.TRIGGER_IMMEDIATE_PAGINATION, true) - .put(ConfigKey.CONSUME_SYNTHETIC_TOKENS, false) - .build(), - mContext, mCursorChangedListener, mModelChild, mModelProvider, POSITION, - mSnackbarApi, mThreadUtils, - /* restoring= */ false); - mContinuationDriver.initialize(); - - // Call initialize again to make sure it doesn't duplicate work - mContinuationDriver.initialize(); - - verify(mModelToken).registerObserver(mContinuationDriver); - verify(mModelProvider, never()).handleToken(mModelToken); - - mContinuationDriver.bind(mContinuationViewHolder); - verify(mContinuationViewHolder) - .bind(eq(mContinuationDriver), any(LoggingListener.class), eq(true)); - } - - @Test - public void testInitialize_doesNotAutoConsumeSyntheticTokenOnRestore() { - when(mModelToken.isSynthetic()).thenReturn(true); - - Configuration configuration = - new Configuration.Builder() - .put(ConfigKey.TRIGGER_IMMEDIATE_PAGINATION, false) - .put(ConfigKey.CONSUME_SYNTHETIC_TOKENS, false) - .put(ConfigKey.CONSUME_SYNTHETIC_TOKENS_WHILE_RESTORING, false) - .build(); - - mContinuationDriver = new ContinuationDriverForTest(mBasicLoggingApi, mClock, configuration, - mContext, mCursorChangedListener, mModelChild, mModelProvider, POSITION, - mSnackbarApi, mThreadUtils, - /* restoring= */ true); - - mContinuationDriver.initialize(); - - verify(mModelToken).registerObserver(mContinuationDriver); - verify(mModelProvider, never()).handleToken(mModelToken); - - mContinuationDriver.bind(mContinuationViewHolder); - verify(mContinuationViewHolder) - .bind(eq(mContinuationDriver), any(LoggingListener.class), eq(false)); - } - - @Test - public void testInitialize_autoConsumeSyntheticTokenOnRestore() { - when(mModelToken.isSynthetic()).thenReturn(true); - - Configuration configuration = - new Configuration.Builder() - .put(ConfigKey.TRIGGER_IMMEDIATE_PAGINATION, false) - .put(ConfigKey.CONSUME_SYNTHETIC_TOKENS, true) - .put(ConfigKey.CONSUME_SYNTHETIC_TOKENS_WHILE_RESTORING, true) - .build(); - - mContinuationDriver = new ContinuationDriverForTest(mBasicLoggingApi, mClock, configuration, - mContext, mCursorChangedListener, mModelChild, mModelProvider, POSITION, - mSnackbarApi, mThreadUtils, - /* restoring= */ true); - - mContinuationDriver.initialize(); - - // Token should be immediately handled as we create the ContinuationDriver with - // forceAutoConsumeSyntheticTokens = true. - verify(mModelProvider).handleToken(mModelToken); - - mContinuationDriver.onTokenCompleted( - new TokenCompleted(FakeModelCursor.newBuilder().addCard().build())); - - // The listener should be notified that the token was automatically consumed as it was a - // synthetic token. - verify(mCursorChangedListener) - .onNewChildren(any(ModelChild.class), ArgumentMatchers.<List<ModelChild>>any(), - /* wasSynthetic= */ eq(true)); - } - - @Test - public void testBind_immediatePaginationOn() { - mContinuationDriver = new ContinuationDriverForTest(mBasicLoggingApi, mClock, - new Configuration.Builder() - .put(ConfigKey.TRIGGER_IMMEDIATE_PAGINATION, true) - .build(), - mContext, mCursorChangedListener, mModelChild, mModelProvider, POSITION, - mSnackbarApi, mThreadUtils, - /* restoring= */ false); - - mContinuationDriver.initialize(); - mContinuationDriver.bind(mContinuationViewHolder); - verify(mContinuationViewHolder) - .bind(eq(mContinuationDriver), any(LoggingListener.class), - /* showSpinner= */ eq(true)); - } - - @Test - public void testBind_immediatePaginationOff() { - mContinuationDriver = new ContinuationDriverForTest(mBasicLoggingApi, mClock, - new Configuration.Builder() - .put(ConfigKey.TRIGGER_IMMEDIATE_PAGINATION, false) - .build(), - mContext, mCursorChangedListener, mModelChild, mModelProvider, POSITION, - mSnackbarApi, mThreadUtils, - /* restoring= */ false); - - mContinuationDriver.initialize(); - mContinuationDriver.bind(mContinuationViewHolder); - verify(mContinuationViewHolder) - .bind(eq(mContinuationDriver), any(LoggingListener.class), - /* showSpinner= */ eq(false)); - } - - @Test - public void testBind_noInitialization() { - mContinuationDriver = new ContinuationDriverForTest(mBasicLoggingApi, mClock, - new Configuration.Builder() - .put(ConfigKey.TRIGGER_IMMEDIATE_PAGINATION, false) - .build(), - mContext, mCursorChangedListener, mModelChild, mModelProvider, POSITION, - mSnackbarApi, mThreadUtils, - /* restoring= */ false); - - assertThatRunnable(() -> mContinuationDriver.bind(mContinuationViewHolder)) - .throwsAnExceptionOfType(IllegalStateException.class); - } - - @Test - public void testShowsSpinnerAfterClick() { - mContinuationDriver.bind(mContinuationViewHolder); - - mContinuationDriver.onClick(mView); - - mContinuationDriver.unbind(); - - mContinuationDriver.bind(mContinuationViewHolder); - - verify(mContinuationViewHolder) - .bind(eq(mContinuationDriver), any(LoggingListener.class), - /* showSpinner= */ eq(true)); - } - - @Test - public void testOnDestroy_doesNotUnregisterTokenObserver_ifNotInitialized() { - mContinuationDriver = new ContinuationDriverForTest(mBasicLoggingApi, mClock, - mConfiguration, mContext, mCursorChangedListener, mModelChild, mModelProvider, - POSITION, mSnackbarApi, mThreadUtils, - /* restoring= */ false); - - mContinuationDriver.onDestroy(); - - verify(mModelToken, never()).unregisterObserver(any()); - } - - @Test - public void testOnDestroy_unregistersTokenObserver_ifAlreadyInitialized() { - mContinuationDriver.onDestroy(); - - verify(mModelToken).unregisterObserver(mContinuationDriver); - } - - @Test - public void testOnClick() { - mContinuationDriver.bind(mContinuationViewHolder); - mContinuationDriver.onClick(mView); - - verify(mContinuationViewHolder).setShowSpinner(true); - verify(mModelProvider).handleToken(mModelToken); - } - - @Test - public void testBind_listenerLogsMoreButtonClicked() { - ArgumentCaptor<LoggingListener> captor = ArgumentCaptor.forClass(LoggingListener.class); - mContinuationDriver.bind(mContinuationViewHolder); - - verify(mContinuationViewHolder) - .bind(eq(mContinuationDriver), captor.capture(), anyBoolean()); - captor.getValue().onContentClicked(); - - verify(mBasicLoggingApi).onMoreButtonClicked(POSITION); - } - - @Test - public void testBind_listenerLogsMoreButtonViewed() { - ArgumentCaptor<LoggingListener> captor = ArgumentCaptor.forClass(LoggingListener.class); - mContinuationDriver.bind(mContinuationViewHolder); - - verify(mContinuationViewHolder) - .bind(eq(mContinuationDriver), captor.capture(), anyBoolean()); - captor.getValue().onViewVisible(); - - verify(mBasicLoggingApi).onMoreButtonViewed(POSITION); - } - - @Test - public void testBind_listenerDoesNotLogViewTwice() { - ArgumentCaptor<LoggingListener> captor = ArgumentCaptor.forClass(LoggingListener.class); - mContinuationDriver.bind(mContinuationViewHolder); - - verify(mContinuationViewHolder) - .bind(eq(mContinuationDriver), captor.capture(), anyBoolean()); - captor.getValue().onViewVisible(); - reset(mBasicLoggingApi); - captor.getValue().onViewVisible(); - - verify(mBasicLoggingApi, never()).onMoreButtonViewed(anyInt()); - } - - @Test - public void testBind_listenerDoesNotLogViewIfSpinnerShown() { - ArgumentCaptor<LoggingListener> captor = ArgumentCaptor.forClass(LoggingListener.class); - mContinuationDriver = new ContinuationDriverForTest(mBasicLoggingApi, mClock, - new Configuration.Builder() - .put(ConfigKey.TRIGGER_IMMEDIATE_PAGINATION, true) - .build(), - mContext, mCursorChangedListener, mModelChild, mModelProvider, POSITION, - mSnackbarApi, mThreadUtils, - /* restoring= */ false); - mContinuationDriver.initialize(); - mContinuationDriver.bind(mContinuationViewHolder); - - verify(mContinuationViewHolder) - .bind(eq(mContinuationDriver), captor.capture(), anyBoolean()); - captor.getValue().onViewVisible(); - - verify(mBasicLoggingApi, never()).onMoreButtonViewed(anyInt()); - } - - @Test - public void testUnbind() { - mContinuationDriver.bind(mContinuationViewHolder); - assertThat(mContinuationDriver.isBound()).isTrue(); - mContinuationDriver.unbind(); - - verify(mContinuationViewHolder).unbind(); - assertThat(mContinuationDriver.isBound()).isFalse(); - } - - @Test - public void testOnTokenCompleted_checksMainThread() { - mContinuationDriver.bind(mContinuationViewHolder); - - clickWithTokenCompleted(EMPTY_TOKEN_COMPLETED); - - verify(mThreadUtils).checkMainThread(); - } - - @Test - public void testOnTokenCompleted_afterDestroy() { - mContinuationDriver.onDestroy(); - - mContinuationDriver.onTokenCompleted(EMPTY_TOKEN_COMPLETED); - - verify(mCursorChangedListener, never()) - .onNewChildren(any(ModelChild.class), ArgumentMatchers.<List<ModelChild>>any(), - /* wasSynthetic= */ eq(false)); - } - - @Test - public void testOnTokenCompleted_extractsModelChildren() { - FakeModelCursor cursor = - FakeModelCursor.newBuilder().addCard().addCluster().addToken().build(); - - mContinuationDriver.bind(mContinuationViewHolder); - clickWithTokenCompleted(new TokenCompleted(cursor)); - - verify(mCursorChangedListener) - .onNewChildren(mModelChild, cursor.getModelChildren(), /* wasSynthetic= */ false); - verifyNoMoreInteractions(mSnackbarApi); - } - - @Test - public void testOnTokenCompleted_createsSnackbar_whenCursorReturnsEmptyPage() { - mContinuationDriver.bind(mContinuationViewHolder); - - clickWithTokenCompleted(EMPTY_TOKEN_COMPLETED); - - verify(mSnackbarApi) - .show(mContext.getString(R.string.ntp_suggestions_fetch_no_new_suggestions)); - verify(mCursorChangedListener) - .onNewChildren(mModelChild, ImmutableList.of(), /* wasSynthetic= */ false); - } - - @Test - public void testOnTokenCompleted_createsSnackbar_whenCursorJustReturnsToken() { - mContinuationDriver.bind(mContinuationViewHolder); - - FakeModelCursor cursor = FakeModelCursor.newBuilder().addToken().build(); - clickWithTokenCompleted(new TokenCompleted(cursor)); - - verify(mSnackbarApi) - .show(mContext.getString(R.string.ntp_suggestions_fetch_no_new_suggestions)); - verify(mCursorChangedListener) - .onNewChildren(mModelChild, cursor.getModelChildren(), /* wasSynthetic= */ false); - } - - @Test - public void testOnTokenCompleted_logsSpinnerFinished() { - FakeModelCursor cursor = FakeModelCursor.newBuilder().addToken().build(); - - mContinuationDriver.bind(mContinuationViewHolder); - clickWithTokenCompleted(new TokenCompleted(cursor)); - - verify(mBasicLoggingApi) - .onSpinnerFinished(/* timeShownMs= */ anyInt(), /* spinnerType= */ anyInt()); - } - - @Test - public void testOnTokenCompleted_doesNotCreateSnackbar_whenTokenFromOthertab() { - FakeModelCursor cursor = FakeModelCursor.newBuilder().addToken().build(); - mContinuationDriver.onTokenCompleted(new TokenCompleted(cursor)); - - verifyNoMoreInteractions(mSnackbarApi); - verify(mCursorChangedListener) - .onNewChildren(mModelChild, cursor.getModelChildren(), /* wasSynthetic= */ false); - } - - @Test - public void testOnError() { - mContinuationDriver.bind(mContinuationViewHolder); - - clickWithError(); - - verify(mContinuationViewHolder).setShowSpinner(false); - verify(mSnackbarApi).show(mContext.getString(R.string.ntp_suggestions_fetch_failed)); - } - - @Test - public void testOnError_hidesSpinnerAfterBeingBound() { - mContinuationDriver = new ContinuationDriverForTest(mBasicLoggingApi, mClock, - new Configuration.Builder() - .put(ConfigKey.TRIGGER_IMMEDIATE_PAGINATION, true) - .build(), - mContext, mCursorChangedListener, mModelChild, mModelProvider, POSITION, - mSnackbarApi, mThreadUtils, - /* restoring= */ false); - - mContinuationDriver.initialize(); - mContinuationDriver.bind(mContinuationViewHolder); - verify(mContinuationViewHolder) - .bind(eq(mContinuationDriver), any(LoggingListener.class), eq(true)); - - mContinuationDriver.unbind(); - mContinuationDriver.onError(new ModelError(ErrorType.PAGINATION_ERROR, null)); - mContinuationDriver.bind(mContinuationViewHolder); - - verify(mContinuationViewHolder) - .bind(eq(mContinuationDriver), any(LoggingListener.class), eq(false)); - verify(mContinuationViewHolder, never()).setShowSpinner(anyBoolean()); - } - - @Test - public void testBind_logsSpinnerStarted_afterInitializeWithSyntheticToken() { - when(mModelToken.isSynthetic()).thenReturn(true); - mContinuationDriver = new ContinuationDriverForTest(mBasicLoggingApi, mClock, - new Configuration.Builder().put(ConfigKey.CONSUME_SYNTHETIC_TOKENS, true).build(), - mContext, mCursorChangedListener, mModelChild, mModelProvider, POSITION, - mSnackbarApi, mThreadUtils, - /* restoring= */ true); - mContinuationDriver.initialize(); - - mContinuationDriver.bind(mContinuationViewHolder); - - assertThat(mSpinnerLogger.getSpinnerType()).isEqualTo(SpinnerType.SYNTHETIC_TOKEN); - } - - @Test - public void testBind_logsSpinnerStarted_ifTriggerImmediatePaginationEnabled() { - mContinuationDriver = new ContinuationDriverForTest(mBasicLoggingApi, mClock, - new Configuration.Builder() - .put(ConfigKey.TRIGGER_IMMEDIATE_PAGINATION, true) - .build(), - mContext, mCursorChangedListener, mModelChild, mModelProvider, POSITION, - mSnackbarApi, mThreadUtils, - /* restoring= */ true); - mContinuationDriver.initialize(); - - mContinuationDriver.bind(mContinuationViewHolder); - - assertThat(mSpinnerLogger.getSpinnerType()).isEqualTo(SpinnerType.INFINITE_FEED); - } - - @Test - public void testOnClick_logsSpinnerStarted() { - mContinuationDriver.bind(mContinuationViewHolder); - - mContinuationDriver.onClick(mView); - - assertThat(mSpinnerLogger.getSpinnerType()).isEqualTo(SpinnerType.MORE_BUTTON); - } - - @Test - public void testOnClick_logsErrorForUnhandledToken() { - when(mModelProvider.handleToken(any(ModelToken.class))).thenReturn(false); - mContinuationDriver.bind(mContinuationViewHolder); - - mContinuationDriver.onClick(mView); - - verify(mBasicLoggingApi).onInternalError(InternalFeedError.UNHANDLED_TOKEN); - verify(mContinuationViewHolder).setShowSpinner(false); - verify(mSnackbarApi).show(mContext.getString(R.string.ntp_suggestions_fetch_failed)); - } - - @Test - public void testOnError_logsSpinnerFinished() { - mContinuationDriver.bind(mContinuationViewHolder); - - clickWithError(); - - verify(mBasicLoggingApi) - .onSpinnerFinished(/* timeShownMs= */ anyInt(), /* spinnerType= */ anyInt()); - } - - @Test - public void testOnError_logsTokenError() { - mContinuationDriver.bind(mContinuationViewHolder); - - clickWithError(); - - verify(mBasicLoggingApi) - .onTokenFailedToComplete(/* wasSynthetic= */ false, /*failureCount=*/1); - } - - @Test - public void testOnError_logsTokenError_incrementsFailureCount() { - mContinuationDriver.bind(mContinuationViewHolder); - - clickWithError(); - clickWithError(); - clickWithError(); - - InOrder inOrder = Mockito.inOrder(mBasicLoggingApi); - inOrder.verify(mBasicLoggingApi).onTokenFailedToComplete(/* wasSynthetic= */ false, 1); - inOrder.verify(mBasicLoggingApi).onTokenFailedToComplete(/* wasSynthetic= */ false, 2); - inOrder.verify(mBasicLoggingApi).onTokenFailedToComplete(/* wasSynthetic= */ false, 3); - } - - @Test - public void testOnError_syntheticToken_logsTokenError() { - when(mModelToken.isSynthetic()).thenReturn(true); - - mContinuationDriver.bind(mContinuationViewHolder); - - clickWithError(); - - verify(mBasicLoggingApi) - .onTokenFailedToComplete(/* wasSynthetic= */ true, /* failureCount= */ 1); - } - - @Test - public void testOnDestroy_logsSpinnerFinished_ifSpinnerActive() { - mContinuationDriver.bind(mContinuationViewHolder); - - mContinuationDriver.onClick(mView); - mContinuationDriver.onDestroy(); - - verify(mBasicLoggingApi) - .onSpinnerDestroyedWithoutCompleting( - /* timeShownMs= */ anyInt(), /* spinnerType= */ anyInt()); - } - - @Test - public void testOnDestroy_doesNotLogSpinnerFinished_ifSpinnerNotActive() { - when(mSpinnerLogger.isSpinnerActive()).thenReturn(false); - mContinuationDriver.bind(mContinuationViewHolder); - - mContinuationDriver.onDestroy(); - - verify(mBasicLoggingApi, never()) - .onSpinnerDestroyedWithoutCompleting( - /* timeShownMs= */ anyInt(), /* spinnerType= */ anyInt()); - } - - @Test - public void testMaybeRebind() { - mContinuationDriver.bind(mContinuationViewHolder); - mContinuationDriver.maybeRebind(); - verify(mContinuationViewHolder, times(2)) - .bind(eq(mContinuationDriver), any(LoggingListener.class), eq(false)); - verify(mContinuationViewHolder).unbind(); - } - - @Test - public void testMaybeRebind_nullViewHolder() { - // bind/unbind continuationViewHolder so we can then test the driver (and assume the view - // holder is null) - mContinuationDriver.bind(mContinuationViewHolder); - mContinuationDriver.unbind(); - reset(mContinuationViewHolder); - - mContinuationDriver.maybeRebind(); - verify(mContinuationViewHolder, never()).unbind(); - verify(mContinuationViewHolder, never()) - .bind(any(OnClickListener.class), any(LoggingListener.class), anyBoolean()); - } - - private void clickWithError() { - mContinuationDriver.onClick(mView); - mContinuationDriver.onError(new ModelError(ErrorType.PAGINATION_ERROR, null)); - } - - private void clickWithTokenCompleted(TokenCompleted tokenCompleted) { - mContinuationDriver.onClick(mView); - mContinuationDriver.onTokenCompleted(tokenCompleted); - } - - private final class ContinuationDriverForTest extends ContinuationDriver { - ContinuationDriverForTest(BasicLoggingApi basicLoggingApi, Clock clock, - Configuration configuration, Context context, - CursorChangedListener cursorChangedListener, ModelChild modelChild, - ModelProvider modelProvider, int position, SnackbarApi snackbarApi, - ThreadUtils threadUtils, boolean restoring) { - super(basicLoggingApi, clock, configuration, context, cursorChangedListener, modelChild, - modelProvider, position, snackbarApi, threadUtils, restoring); - } - - @Override - SpinnerLogger createSpinnerLogger(BasicLoggingApi basicLoggingApi, Clock clock) { - return mSpinnerLogger; - } - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/drivers/HeaderDriverTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/drivers/HeaderDriverTest.java deleted file mode 100644 index 2a0614e..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/drivers/HeaderDriverTest.java +++ /dev/null
@@ -1,117 +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. - -package org.chromium.chrome.browser.feed.library.basicstream.internal.drivers; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.basicstream.internal.viewholders.HeaderViewHolder; -import org.chromium.chrome.browser.feed.library.basicstream.internal.viewholders.SwipeNotifier; -import org.chromium.chrome.browser.feed.shared.stream.Header; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link HeaderDriver}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class HeaderDriverTest { - @Mock - private Header mHeader; - @Mock - private HeaderViewHolder mHeaderViewHolder; - @Mock - private SwipeNotifier mSwipeNotifier; - - private HeaderDriver mHeaderDriver; - - @Before - public void setup() { - initMocks(this); - mHeaderDriver = new HeaderDriver(mHeader, mSwipeNotifier); - } - - @Test - public void testBind() { - assertThat(mHeaderDriver.isBound()).isFalse(); - - mHeaderDriver.bind(mHeaderViewHolder); - - assertThat(mHeaderDriver.isBound()).isTrue(); - verify(mHeaderViewHolder).bind(mHeader, mSwipeNotifier); - } - - @Test - public void testUnbind() { - mHeaderDriver.bind(mHeaderViewHolder); - assertThat(mHeaderDriver.isBound()).isTrue(); - - mHeaderDriver.unbind(); - - assertThat(mHeaderDriver.isBound()).isFalse(); - verify(mHeaderViewHolder).unbind(); - } - - @Test - public void testUnbind_doesNotCallUnbindIfNotBound() { - assertThat(mHeaderDriver.isBound()).isFalse(); - - mHeaderDriver.unbind(); - verifyNoMoreInteractions(mHeaderViewHolder); - } - - @Test - public void testMaybeRebind() { - mHeaderDriver.bind(mHeaderViewHolder); - mHeaderDriver.maybeRebind(); - verify(mHeaderViewHolder, times(2)).bind(mHeader, mSwipeNotifier); - verify(mHeaderViewHolder).unbind(); - } - - @Test - public void testMaybeRebind_nullViewHolder() { - mHeaderDriver.bind(mHeaderViewHolder); - mHeaderDriver.unbind(); - reset(mHeaderViewHolder); - - mHeaderDriver.maybeRebind(); - verify(mHeaderViewHolder, never()).bind(mHeader, mSwipeNotifier); - verify(mHeaderViewHolder, never()).unbind(); - } - - @Test - public void testBind_rebindToSameViewHolder_bindsOnlyOnce() { - // Bind twice to the same viewholder. - mHeaderDriver.bind(mHeaderViewHolder); - mHeaderDriver.bind(mHeaderViewHolder); - - // Only binds to the viewholder once, ignoring the second bind. - verify(mHeaderViewHolder).bind(mHeader, mSwipeNotifier); - } - - @Test - public void testBind_bindWhileBoundToOtherViewHolder_unbindsOldViewHolderBindsNew() { - HeaderViewHolder initialViewHolder = mock(HeaderViewHolder.class); - - // Bind to one ViewHolder then another. - mHeaderDriver.bind(initialViewHolder); - - mHeaderDriver.bind(mHeaderViewHolder); - - verify(initialViewHolder).unbind(); - verify(mHeaderViewHolder).bind(mHeader, mSwipeNotifier); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/drivers/NoContentDriverTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/drivers/NoContentDriverTest.java deleted file mode 100644 index 06b39a23..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/drivers/NoContentDriverTest.java +++ /dev/null
@@ -1,92 +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. - -package org.chromium.chrome.browser.feed.library.basicstream.internal.drivers; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.basicstream.internal.viewholders.NoContentViewHolder; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link NoContentDriver}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class NoContentDriverTest { - @Mock - private NoContentViewHolder mNoContentViewHolder; - - private NoContentDriver mNoContentDriver; - - @Before - public void setup() { - initMocks(this); - mNoContentDriver = new NoContentDriver(); - } - - @Test - public void testBind() { - assertThat(mNoContentDriver.isBound()).isFalse(); - - mNoContentDriver.bind(mNoContentViewHolder); - - assertThat(mNoContentDriver.isBound()).isTrue(); - verify(mNoContentViewHolder).bind(); - } - - @Test - public void testUnbind() { - mNoContentDriver.bind(mNoContentViewHolder); - assertThat(mNoContentDriver.isBound()).isTrue(); - - mNoContentDriver.unbind(); - - assertThat(mNoContentDriver.isBound()).isFalse(); - verify(mNoContentViewHolder).unbind(); - } - - @Test - public void testUnbind_doesNotCallUnbindIfNotBound() { - assertThat(mNoContentDriver.isBound()).isFalse(); - - mNoContentDriver.unbind(); - verifyNoMoreInteractions(mNoContentViewHolder); - } - - @Test - public void testMaybeRebind() { - mNoContentDriver.bind(mNoContentViewHolder); - assertThat(mNoContentDriver.isBound()).isTrue(); - - mNoContentDriver.maybeRebind(); - assertThat(mNoContentDriver.isBound()).isTrue(); - verify(mNoContentViewHolder, times(2)).bind(); - verify(mNoContentViewHolder).unbind(); - } - - @Test - public void testMaybeRebind_nullViewHolder() { - // bind/unbind to associate the noContentViewHolder with the driver - mNoContentDriver.bind(mNoContentViewHolder); - mNoContentDriver.unbind(); - reset(mNoContentViewHolder); - - mNoContentDriver.maybeRebind(); - assertThat(mNoContentDriver.isBound()).isFalse(); - verify(mNoContentViewHolder, never()).bind(); - verify(mNoContentViewHolder, never()).unbind(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/drivers/StreamDriverTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/drivers/StreamDriverTest.java deleted file mode 100644 index 1a43f78..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/drivers/StreamDriverTest.java +++ /dev/null
@@ -1,1084 +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. - -package org.chromium.chrome.browser.feed.library.basicstream.internal.drivers; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import static org.chromium.chrome.browser.feed.library.common.testing.RunnableSubject.assertThatRunnable; -import static org.chromium.chrome.browser.feed.library.testing.modelprovider.FakeModelCursor.getCardModelFeatureWithCursor; - -import android.app.Activity; -import android.content.Context; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.InOrder; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.R; -import org.chromium.chrome.browser.feed.library.api.host.action.ActionApi; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration; -import org.chromium.chrome.browser.feed.library.api.host.logging.BasicLoggingApi; -import org.chromium.chrome.browser.feed.library.api.host.logging.InternalFeedError; -import org.chromium.chrome.browser.feed.library.api.host.logging.ZeroStateShowReason; -import org.chromium.chrome.browser.feed.library.api.host.stream.SnackbarApi; -import org.chromium.chrome.browser.feed.library.api.host.stream.SnackbarCallbackApi; -import org.chromium.chrome.browser.feed.library.api.host.stream.TooltipApi; -import org.chromium.chrome.browser.feed.library.api.internal.actionmanager.ActionManager; -import org.chromium.chrome.browser.feed.library.api.internal.actionparser.ActionParserFactory; -import org.chromium.chrome.browser.feed.library.api.internal.common.ThreadUtils; -import org.chromium.chrome.browser.feed.library.api.internal.knowncontent.FeedKnownContent; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelChild; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelChild.Type; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelFeature; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider.RemoveTrackingFactory; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider.State; -import org.chromium.chrome.browser.feed.library.basicstream.internal.drivers.StreamDriver.StreamContentListener; -import org.chromium.chrome.browser.feed.library.basicstream.internal.drivers.testing.FakeFeatureDriver; -import org.chromium.chrome.browser.feed.library.basicstream.internal.drivers.testing.FakeLeafFeatureDriver; -import org.chromium.chrome.browser.feed.library.basicstream.internal.scroll.BasicStreamScrollMonitor; -import org.chromium.chrome.browser.feed.library.basicstream.internal.scroll.ScrollRestorer; -import org.chromium.chrome.browser.feed.library.basicstream.internal.viewloggingupdater.ViewLoggingUpdater; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeMainThreadRunner; -import org.chromium.chrome.browser.feed.library.common.time.Clock; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.sharedstream.contextmenumanager.ContextMenuManager; -import org.chromium.chrome.browser.feed.library.sharedstream.offlinemonitor.StreamOfflineMonitor; -import org.chromium.chrome.browser.feed.library.sharedstream.pendingdismiss.PendingDismissCallback; -import org.chromium.chrome.browser.feed.library.sharedstream.removetrackingfactory.StreamRemoveTrackingFactory; -import org.chromium.chrome.browser.feed.library.testing.modelprovider.FakeModelChild; -import org.chromium.chrome.browser.feed.library.testing.modelprovider.FakeModelCursor; -import org.chromium.chrome.browser.feed.library.testing.modelprovider.FakeModelFeature; -import org.chromium.chrome.browser.feed.library.testing.modelprovider.FeatureChangeBuilder; -import org.chromium.chrome.browser.feed.shared.stream.Stream.ContentChangedListener; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamFeature; -import org.chromium.components.feed.core.proto.libraries.sharedstream.UiRefreshReasonProto.UiRefreshReason; -import org.chromium.components.feed.core.proto.libraries.sharedstream.UiRefreshReasonProto.UiRefreshReason.Reason; -import org.chromium.components.feed.core.proto.ui.action.FeedActionProto.UndoAction; -import org.chromium.components.feed.core.proto.ui.stream.StreamStructureProto.Card; -import org.chromium.components.feed.core.proto.ui.stream.StreamStructureProto.Cluster; -import org.chromium.components.feed.core.proto.ui.stream.StreamStructureProto.Content; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.ArrayList; -import java.util.List; - -/** Tests for {@link StreamDriver}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class StreamDriverTest { - private static final String CONTENT_ID = "contentID"; - private FakeModelCursor mCursorWithInvalidChildren; - - private static final FakeModelCursor EMPTY_MODEL_CURSOR = FakeModelCursor.newBuilder().build(); - - private static final ModelFeature UNBOUND_CARD = - FakeModelFeature.newBuilder() - .setStreamFeature( - StreamFeature.newBuilder().setCard(Card.getDefaultInstance()).build()) - .build(); - - @Mock - private ActionApi mActionApi; - @Mock - private ActionManager mActionManager; - @Mock - private ActionParserFactory mActionParserFactory; - @Mock - private ModelFeature mStreamFeature; - @Mock - private ModelProvider mModelProvider; - @Mock - private ContinuationDriver mContinuationDriver; - @Mock - private NoContentDriver mNoContentDriver; - @Mock - private ZeroStateDriver mZeroStateDriver; - @Mock - private StreamContentListener mContentlistener; - @Mock - private ContentChangedListener mContentChangedListener; - @Mock - private SnackbarApi mSnackbarApi; - @Mock - private ScrollRestorer mScrollRestorer; - @Mock - private BasicLoggingApi mBasicLoggingApi; - @Mock - private FeedKnownContent mFeedKnownContent; - @Mock - private StreamOfflineMonitor mStreamOfflineMonitor; - @Mock - private PendingDismissCallback mPendingDismissCallback; - @Mock - private TooltipApi mTooltipApi; - @Mock - private BasicStreamScrollMonitor mScrollmonitor; - - @Captor - private ArgumentCaptor<List<LeafFeatureDriver>> mFeatureDriversCaptor; - - private StreamDriverForTest mStreamDriver; - private Configuration mConfiguration = new Configuration.Builder().build(); - private Context mContext; - private Clock mClock; - private ThreadUtils mThreadUtils; - private final FakeMainThreadRunner mMainThreadRunner = FakeMainThreadRunner.queueAllTasks(); - private final ViewLoggingUpdater mViewLoggingUpdater = new ViewLoggingUpdater(); - - private static FakeModelChild createFakeClusterModelChild() { - return FakeModelChild.newBuilder() - .setModelFeature( - FakeModelFeature.newBuilder() - .setStreamFeature(StreamFeature.newBuilder() - .setCluster(Cluster.getDefaultInstance()) - .build()) - .build()) - .build(); - } - - @Before - public void setup() { - FakeModelFeature feature = - FakeModelFeature.newBuilder() - .setStreamFeature(StreamFeature.newBuilder() - .setContent(Content.getDefaultInstance()) - .build()) - .build(); - mCursorWithInvalidChildren = - FakeModelCursor.newBuilder() - .addChild(FakeModelChild.newBuilder().setModelFeature(feature).build()) - .build(); - - initMocks(this); - mContext = Robolectric.buildActivity(Activity.class).get(); - mClock = new FakeClock(); - - when(mContinuationDriver.getLeafFeatureDriver()).thenReturn(mContinuationDriver); - when(mNoContentDriver.getLeafFeatureDriver()).thenReturn(mNoContentDriver); - when(mZeroStateDriver.getLeafFeatureDriver()).thenReturn(mZeroStateDriver); - when(mZeroStateDriver.isSpinnerShowing()).thenReturn(false); - - when(mModelProvider.getRootFeature()).thenReturn(mStreamFeature); - when(mModelProvider.getCurrentState()).thenReturn(State.READY); - mThreadUtils = new ThreadUtils(); - - mStreamDriver = createNonRestoringStreamDriver(); - - mStreamDriver.setStreamContentListener(mContentlistener); - } - - @Test - public void testConstruction() { - ArgumentCaptor<RemoveTrackingFactory> removeTrackingFactoryArgumentCaptor = - ArgumentCaptor.forClass(RemoveTrackingFactory.class); - - verify(mModelProvider).enableRemoveTracking(removeTrackingFactoryArgumentCaptor.capture()); - - assertThat(removeTrackingFactoryArgumentCaptor.getValue()) - .isInstanceOf(StreamRemoveTrackingFactory.class); - } - - @Test - public void testBuildChildren() { - when(mStreamFeature.getCursor()) - .thenReturn(FakeModelCursor.newBuilder().addCard().addCluster().addToken().build()); - - // Causes StreamDriver to build a list of children based on the children from the cursor. - List<LeafFeatureDriver> leafFeatureDrivers = mStreamDriver.getLeafFeatureDrivers(); - - assertThat(leafFeatureDrivers).hasSize(3); - - assertThat(leafFeatureDrivers.get(0)).isEqualTo(getLeafFeatureDriverFromCard(0)); - assertThat(leafFeatureDrivers.get(1)).isEqualTo(getLeafFeatureDriverFromCluster(1)); - assertThat(leafFeatureDrivers.get(2)).isEqualTo(mContinuationDriver); - - verify(mContinuationDriver).initialize(); - verify(mStreamOfflineMonitor).requestOfflineStatusForNewContent(); - } - - @Test - public void testBuildChildren_unboundContent() { - when(mStreamFeature.getCursor()) - .thenReturn(FakeModelCursor.newBuilder().addChild(UNBOUND_CARD).addCard().build()); - - // Causes StreamDriver to build a list of children based on the children from the cursor. - List<LeafFeatureDriver> leafFeatureDrivers = mStreamDriver.getLeafFeatureDrivers(); - - assertThat(leafFeatureDrivers).hasSize(1); - assertThat(leafFeatureDrivers.get(0)).isEqualTo(getLeafFeatureDriverFromCard(1)); - verify(mBasicLoggingApi).onInternalError(InternalFeedError.FAILED_TO_CREATE_LEAF); - } - - @Test - public void testBuildChildren_unboundChild_logsInternalError() { - when(mStreamFeature.getCursor()) - .thenReturn(FakeModelCursor.newBuilder().addUnboundChild().build()); - - mStreamDriver.getLeafFeatureDrivers(); - - verify(mBasicLoggingApi).onInternalError(InternalFeedError.TOP_LEVEL_UNBOUND_CHILD); - } - - @Test - public void testBuildChildren_initializing() { - when(mModelProvider.getRootFeature()).thenReturn(null); - when(mModelProvider.getCurrentState()).thenReturn(State.INITIALIZING); - List<LeafFeatureDriver> leafFeatureDrivers = mStreamDriver.getLeafFeatureDrivers(); - assertThat(leafFeatureDrivers).hasSize(1); - assertThat(mStreamDriver.getLeafFeatureDrivers().get(0)) - .isInstanceOf(ZeroStateDriver.class); - } - - @Test - public void testBuildChildren_nullRootFeature_logsInternalError() { - when(mModelProvider.getRootFeature()).thenReturn(null); - - mStreamDriver.getLeafFeatureDrivers(); - - verify(mBasicLoggingApi).onInternalError(InternalFeedError.NO_ROOT_FEATURE); - } - - @Test - public void testCreateChildren_invalidFeatureType_logsInternalError() { - when(mStreamFeature.getCursor()).thenReturn(mCursorWithInvalidChildren); - - mStreamDriver.getLeafFeatureDrivers(); - - verify(mBasicLoggingApi).onInternalError(InternalFeedError.TOP_LEVEL_INVALID_FEATURE_TYPE); - } - - @Test - public void testMaybeRestoreScroll() { - mStreamDriver = createRestoringStreamDriver(); - - when(mStreamFeature.getCursor()).thenReturn(FakeModelCursor.newBuilder().addCard().build()); - - mStreamDriver.getLeafFeatureDrivers(); - - mStreamDriver.maybeRestoreScroll(); - - verify(mScrollRestorer).maybeRestoreScroll(); - } - - @Test - public void testMaybeRestoreScroll_withToken() { - mStreamDriver = createRestoringStreamDriver(); - - when(mStreamFeature.getCursor()) - .thenReturn(FakeModelCursor.newBuilder().addCard().addCluster().addToken().build()); - - mStreamDriver.getLeafFeatureDrivers(); - - mStreamDriver.maybeRestoreScroll(); - - // Should restore scroll if a non-synthetic token is last - verify(mScrollRestorer).maybeRestoreScroll(); - } - - @Test - public void testMaybeRestoreScroll_withSyntheticToken() { - mStreamDriver = createRestoringStreamDriver(); - - when(mStreamFeature.getCursor()) - .thenReturn(FakeModelCursor.newBuilder() - .addCard() - .addCluster() - .addSyntheticToken() - .build()); - when(mContinuationDriver.hasTokenBeenHandled()).thenReturn(true); - - mStreamDriver.getLeafFeatureDrivers(); - - mStreamDriver.maybeRestoreScroll(); - - // Should never restore scroll if a synthetic token is last - verify(mScrollRestorer, never()).maybeRestoreScroll(); - } - - @Test - public void testMaybeRestoreScroll_notRestoring_doesNotScroll() { - mStreamDriver = createNonRestoringStreamDriver(); - - when(mStreamFeature.getCursor()) - .thenReturn(FakeModelCursor.newBuilder() - .addCard() - .addCluster() - .addSyntheticToken() - .build()); - - mStreamDriver.getLeafFeatureDrivers(); - - mStreamDriver.maybeRestoreScroll(); - - // Should never restore scroll if created in a non-restoring state. - verify(mScrollRestorer, never()).maybeRestoreScroll(); - } - - @Test - public void testContinuationToken_createsContinuationContentModel() { - when(mStreamFeature.getCursor()) - .thenReturn(FakeModelCursor.newBuilder().addToken().build()); - - List<LeafFeatureDriver> leafFeatureDrivers = mStreamDriver.getLeafFeatureDrivers(); - assertThat(leafFeatureDrivers).hasSize(2); - assertThat(leafFeatureDrivers.get(0)).isEqualTo(mNoContentDriver); - assertThat(leafFeatureDrivers.get(1)).isEqualTo(mContinuationDriver); - } - - @Test - public void testContinuationToken_tokenHandling() { - mStreamDriver = createStreamDriver(/* restoring= */ true, /* isInitialLoad= */ false); - - FakeModelCursor initialCursor = FakeModelCursor.newBuilder().addToken().build(); - FakeModelCursor newCursor = FakeModelCursor.newBuilder().addCluster().build(); - when(mStreamFeature.getCursor()).thenReturn(initialCursor); - - // Causes StreamDriver to build a list of children based on the children from the cursor. - List<LeafFeatureDriver> leafFeatureDrivers = mStreamDriver.getLeafFeatureDrivers(); - assertThat(leafFeatureDrivers).hasSize(2); - assertThat(leafFeatureDrivers.get(0)).isEqualTo(mNoContentDriver); - assertThat(leafFeatureDrivers.get(1)).isEqualTo(mContinuationDriver); - - mStreamDriver.onNewChildren(initialCursor.getChildAt(0), newCursor.getModelChildren(), - /* wasSynthetic = */ false); - leafFeatureDrivers = mStreamDriver.getLeafFeatureDrivers(); - assertThat(mStreamDriver.getLeafFeatureDrivers()).hasSize(1); - assertThat(leafFeatureDrivers.get(0)).isEqualTo(getLeafFeatureDriverFromCluster(1)); - - // If the above two assertions pass, this is also guaranteed to pass. This is just to - // explicitly check that the ContinuationDriver has been removed. - assertThat(leafFeatureDrivers).doesNotContain(mContinuationDriver); - - verify(mScrollRestorer).maybeRestoreScroll(); - } - - @Test - public void testContinuationToken_tokenHandling_newSyntheticToken() { - FakeModelCursor initialCursor = FakeModelCursor.newBuilder().addSyntheticToken().build(); - FakeModelCursor newCursor = - FakeModelCursor.newBuilder().addCluster().addSyntheticToken().build(); - when(mStreamFeature.getCursor()).thenReturn(initialCursor); - when(mContinuationDriver.hasTokenBeenHandled()).thenReturn(true); - - // Causes StreamDriver to build a list of children based on the children from the cursor. - List<LeafFeatureDriver> leafFeatureDrivers = mStreamDriver.getLeafFeatureDrivers(); - assertThat(leafFeatureDrivers).hasSize(2); - assertThat(leafFeatureDrivers.get(0)).isEqualTo(mNoContentDriver); - assertThat(leafFeatureDrivers.get(1)).isEqualTo(mContinuationDriver); - - mStreamDriver.onNewChildren(initialCursor.getChildAt(0), newCursor.getModelChildren(), - /* wasSynthetic = */ true); - leafFeatureDrivers = mStreamDriver.getLeafFeatureDrivers(); - assertThat(mStreamDriver.getLeafFeatureDrivers()).hasSize(2); - assertThat(leafFeatureDrivers.get(0)).isEqualTo(getLeafFeatureDriverFromCluster(1)); - assertThat(leafFeatureDrivers.get(1)).isEqualTo(mContinuationDriver); - - verify(mScrollRestorer, never()).maybeRestoreScroll(); - } - - @Test - public void testContinuationToken_tokenHandling_notifiesObservers() { - FakeModelCursor initialCursor = FakeModelCursor.newBuilder().addCard().addToken().build(); - FakeModelCursor newCursor = FakeModelCursor.newBuilder().addCluster().build(); - when(mStreamFeature.getCursor()).thenReturn(initialCursor); - - mStreamDriver.getLeafFeatureDrivers(); - - mStreamDriver.onNewChildren(initialCursor.getChildAt(1), newCursor.getModelChildren(), - /* wasSynthetic = */ false); - - verify(mContentlistener).notifyContentRemoved(1); - verify(mContentlistener) - .notifyContentsAdded(1, Lists.newArrayList(getLeafFeatureDriverFromCluster(2))); - verify(mStreamOfflineMonitor, times(2)).requestOfflineStatusForNewContent(); - } - - @Test - public void testContinuationToken_tokenChildrenAddedAtTokenPosition() { - FakeModelCursor initialCursor = - FakeModelCursor.newBuilder().addCluster().addToken().build(); - FakeModelCursor newCursor = FakeModelCursor.newBuilder().addCluster().addToken().build(); - when(mStreamFeature.getCursor()).thenReturn(initialCursor); - - mStreamDriver.getLeafFeatureDrivers(); - mStreamDriver.onNewChildren(initialCursor.getChildAt(1), newCursor.getModelChildren(), - /* wasSynthetic = */ false); - - List<LeafFeatureDriver> leafFeatureDrivers = mStreamDriver.getLeafFeatureDrivers(); - assertThat(leafFeatureDrivers).hasSize(3); - assertThat(leafFeatureDrivers) - .containsExactly(getLeafFeatureDriverFromCluster(0), - getLeafFeatureDriverFromCluster(2), mContinuationDriver); - } - - @Test - public void testContinuationToken_tokenChildrenAddedAtTokenPosition_tokenNotAtEnd() { - FakeModelCursor initialCursor = - FakeModelCursor.newBuilder().addCluster().addToken().addCluster().build(); - FakeModelCursor newCursor = - FakeModelCursor.newBuilder().addCluster().addCard().addCluster().build(); - when(mStreamFeature.getCursor()).thenReturn(initialCursor); - - mStreamDriver.getLeafFeatureDrivers(); - mStreamDriver.onNewChildren(initialCursor.getChildAt(1), newCursor.getModelChildren(), - /* wasSynthetic = */ false); - - List<LeafFeatureDriver> leafFeatureDrivers = mStreamDriver.getLeafFeatureDrivers(); - assertThat(leafFeatureDrivers).hasSize(5); - assertThat(leafFeatureDrivers) - .containsExactly(getLeafFeatureDriverFromCluster(0), - getLeafFeatureDriverFromCluster(2), getLeafFeatureDriverFromCluster(3), - getLeafFeatureDriverFromCard(4), getLeafFeatureDriverFromCluster(5)); - } - - @Test - public void testContinuationToken_tokenNotFound() { - FakeModelCursor initialCursor = - FakeModelCursor.newBuilder().addCluster().addToken().addCluster().build(); - FakeModelCursor badCursor = FakeModelCursor.newBuilder().addCard().build(); - when(mStreamFeature.getCursor()).thenReturn(initialCursor); - - mStreamDriver.getLeafFeatureDrivers(); - assertThatRunnable(() - -> mStreamDriver.onNewChildren(badCursor.getChildAt(0), - badCursor.getModelChildren(), - /* wasSynthetic = */ false)) - .throwsAnExceptionOfType(RuntimeException.class); - } - - @Test - public void testOnChange_remove() { - FakeModelCursor fakeModelCursor = - FakeModelCursor.newBuilder().addCard().addCard().addCard().addCard().build(); - - when(mStreamFeature.getCursor()).thenReturn(fakeModelCursor); - - List<LeafFeatureDriver> leafFeatureDrivers = mStreamDriver.getLeafFeatureDrivers(); - - assertThat(leafFeatureDrivers).hasSize(4); - - mStreamDriver.onChange(new FeatureChangeBuilder() - .addChildForRemoval(fakeModelCursor.getChildAt(1)) - .addChildForRemoval(fakeModelCursor.getChildAt(2)) - .build()); - - assertThat(mStreamDriver.getLeafFeatureDrivers()) - .containsExactly(leafFeatureDrivers.get(0), leafFeatureDrivers.get(3)); - } - - @Test - public void testOnChange_addsZeroState_whenFeatureDriversEmpty() { - FakeModelCursor fakeModelCursor = FakeModelCursor.newBuilder().addCard().build(); - - initializeStreamDriverAndDismissAllFeatureChildren(fakeModelCursor); - - assertThat(mStreamDriver.getLeafFeatureDrivers()).hasSize(1); - assertThat(mStreamDriver.getLeafFeatureDrivers().get(0)) - .isInstanceOf(ZeroStateDriver.class); - } - - @Test - public void testOnChange_dismissesLastDriver_logsContentDismissed() { - FakeModelCursor fakeModelCursor = FakeModelCursor.newBuilder().addCard().build(); - - initializeStreamDriverAndDismissAllFeatureChildren(fakeModelCursor); - - verify(mBasicLoggingApi).onZeroStateShown(ZeroStateShowReason.CONTENT_DISMISSED); - } - - @Test - public void testGetLeafFeatureDrivers_addsZeroState_withNoModelChildren() { - when(mStreamFeature.getCursor()).thenReturn(EMPTY_MODEL_CURSOR); - - List<LeafFeatureDriver> leafFeatureDrivers = mStreamDriver.getLeafFeatureDrivers(); - - assertThat(leafFeatureDrivers).hasSize(1); - assertThat(leafFeatureDrivers.get(0)).isInstanceOf(ZeroStateDriver.class); - } - - @Test - public void testGetLeafFeatureDrivers_noContent_logsNoContent() { - when(mStreamFeature.getCursor()).thenReturn(EMPTY_MODEL_CURSOR); - - mStreamDriver.getLeafFeatureDrivers(); - - verify(mBasicLoggingApi).onZeroStateShown(ZeroStateShowReason.NO_CONTENT); - } - - @Test - public void testGetLeafFeatureDrivers_doesNotAddZeroState_ifInitialLoad() { - mStreamDriver = createStreamDriver(/* restoring= */ false, /* isInitialLoad= */ true); - - when(mStreamFeature.getCursor()).thenReturn(EMPTY_MODEL_CURSOR); - - List<LeafFeatureDriver> leafFeatureDrivers = mStreamDriver.getLeafFeatureDrivers(); - - assertThat(leafFeatureDrivers).isEmpty(); - } - - @Test - public void testGetLeafFeatureDrivers_doesNotAddZeroState_ifRestoring() { - mStreamDriver = createStreamDriver(/* restoring= */ true, /* isInitialLoad= */ false); - - when(mStreamFeature.getCursor()).thenReturn(EMPTY_MODEL_CURSOR); - - List<LeafFeatureDriver> leafFeatureDrivers = mStreamDriver.getLeafFeatureDrivers(); - - assertThat(leafFeatureDrivers).isEmpty(); - } - - @Test - public void testShowZeroState_createsZeroState() { - FakeModelCursor fakeModelCursor = FakeModelCursor.newBuilder().addCard().addCard().build(); - - when(mStreamFeature.getCursor()).thenReturn(fakeModelCursor); - assertThat(mStreamDriver.getLeafFeatureDrivers()).hasSize(2); - - mStreamDriver.showZeroState(ZeroStateShowReason.ERROR); - - List<LeafFeatureDriver> leafFeatureDrivers = mStreamDriver.getLeafFeatureDrivers(); - - assertThat(leafFeatureDrivers).hasSize(1); - assertThat(leafFeatureDrivers.get(0)).isInstanceOf(ZeroStateDriver.class); - } - - @Test - public void testShowZeroState_logsZeroStateReason() { - FakeModelCursor fakeModelCursor = FakeModelCursor.newBuilder().addCard().addCard().build(); - when(mStreamFeature.getCursor()).thenReturn(fakeModelCursor); - - mStreamDriver.getLeafFeatureDrivers(); - mStreamDriver.showZeroState(ZeroStateShowReason.ERROR); - - verify(mBasicLoggingApi).onZeroStateShown(ZeroStateShowReason.ERROR); - } - - @Test - public void testShowZeroState_notifiesContentsCleared() { - FakeModelCursor fakeModelCursor = FakeModelCursor.newBuilder().addCard().addCard().build(); - - when(mStreamFeature.getCursor()).thenReturn(fakeModelCursor); - - mStreamDriver.showSpinner(); - - verify(mContentlistener).notifyContentsCleared(); - } - - @Test - public void testShowZeroState_destroysFeatureDrivers() { - FakeModelCursor fakeModelCursor = FakeModelCursor.newBuilder().addToken().build(); - - when(mStreamFeature.getCursor()).thenReturn(fakeModelCursor); - mStreamDriver.getLeafFeatureDrivers(); - - mStreamDriver.showSpinner(); - - verify(mContinuationDriver).onDestroy(); - } - - @Test - public void testOnChange_addsNoContentCard_withJustContinuationDriver() { - FakeModelCursor fakeModelCursor = FakeModelCursor.newBuilder().addCard().addToken().build(); - - initializeStreamDriverAndDismissAllFeatureChildren(fakeModelCursor); - - assertThat(mStreamDriver.getLeafFeatureDrivers()).hasSize(2); - assertThat(mStreamDriver.getLeafFeatureDrivers().get(0)) - .isInstanceOf(NoContentDriver.class); - } - - @Test - public void testContinuationToken_removesNoContentCard() { - FakeModelCursor fakeModelCursor = FakeModelCursor.newBuilder().addCard().addToken().build(); - - initializeStreamDriverAndDismissAllFeatureChildren(fakeModelCursor); - - assertThat(mStreamDriver.getLeafFeatureDrivers()).hasSize(2); - assertThat(mStreamDriver.getLeafFeatureDrivers().get(0)) - .isInstanceOf(NoContentDriver.class); - - FakeModelCursor newCursor = FakeModelCursor.newBuilder().addCard().build(); - mStreamDriver.onNewChildren(fakeModelCursor.getChildAt(1), newCursor.getModelChildren(), - /* wasSynthetic = */ false); - - assertThat(mStreamDriver.getLeafFeatureDrivers()).hasSize(1); - assertThat(mStreamDriver.getLeafFeatureDrivers().get(0)) - .isInstanceOf(FakeLeafFeatureDriver.class); - } - - @Test - public void testContinuationToken_replacesNoContentCardWithZeroState() { - FakeModelCursor initialCursor = FakeModelCursor.newBuilder().addCard().addToken().build(); - initializeStreamDriverAndDismissAllFeatureChildren(initialCursor); - mStreamDriver.onNewChildren( - initialCursor.getChildAt(1), ImmutableList.of(), /* wasSynthetic = */ false); - - verify(mNoContentDriver).onDestroy(); - assertThat(mStreamDriver.getLeafFeatureDrivers()).hasSize(1); - assertThat(mStreamDriver.getLeafFeatureDrivers().get(0)) - .isInstanceOf(ZeroStateDriver.class); - } - - @Test - public void testContinuationToken_logsContinuationTokenPayload() { - FakeModelCursor initialCursor = FakeModelCursor.newBuilder().addCard().addToken().build(); - when(mStreamFeature.getCursor()).thenReturn(initialCursor); - - mStreamDriver.getLeafFeatureDrivers(); - mStreamDriver.onNewChildren(initialCursor.getChildAt(1), - FakeModelCursor.newBuilder() - .addCluster() - .addCard() - .addCard() - .addToken() - .build() - .getModelChildren(), - true); - - verify(mBasicLoggingApi) - .onTokenCompleted( - /* wasSynthetic= */ true, /* contentCount= */ 3, /* tokenCount= */ 1); - } - - @Test - public void testOnChange_remove_notifiesListener() { - FakeModelCursor fakeModelCursor = FakeModelCursor.newBuilder().addCard().addCard().build(); - - when(mStreamFeature.getCursor()).thenReturn(fakeModelCursor); - - mStreamDriver.getLeafFeatureDrivers(); - - mStreamDriver.onChange(new FeatureChangeBuilder() - .addChildForRemoval(fakeModelCursor.getChildAt(0)) - .build()); - - verify(mContentlistener).notifyContentRemoved(0); - verifyNoMoreInteractions(mContentlistener); - } - - @Test - public void testOnChange_addAndRemoveContent() { - FakeModelCursor fakeModelCursor = FakeModelCursor.newBuilder().addCard().addCard().build(); - - when(mStreamFeature.getCursor()).thenReturn(fakeModelCursor); - - // Causes StreamDriver to build a list of children based on the children from the cursor. - mStreamDriver.getLeafFeatureDrivers(); - - mStreamDriver.onChange(new FeatureChangeBuilder() - .addChildForRemoval(fakeModelCursor.getChildAt(0)) - .addChildForAppending(createFakeClusterModelChild()) - .build()); - - InOrder inOrder = Mockito.inOrder(mContentlistener); - - inOrder.verify(mContentlistener).notifyContentRemoved(0); - inOrder.verify(mContentlistener) - .notifyContentsAdded(eq(1), mFeatureDriversCaptor.capture()); - inOrder.verifyNoMoreInteractions(); - - assertThat(mFeatureDriversCaptor.getValue()).hasSize(1); - assertThat(mFeatureDriversCaptor.getValue().get(0)) - .isEqualTo(getLeafFeatureDriverFromCluster(2)); - } - - @Test - public void testOnChange_addContent() { - FakeModelCursor fakeModelCursor = FakeModelCursor.newBuilder().addCard().addCard().build(); - - when(mStreamFeature.getCursor()).thenReturn(fakeModelCursor); - - // Causes StreamDriver to build a list of children based on the children from the cursor. - mStreamDriver.getLeafFeatureDrivers(); - - reset(mContentlistener); - - mStreamDriver.onChange(new FeatureChangeBuilder() - .addChildForAppending(createFakeClusterModelChild()) - .build()); - - InOrder inOrder = Mockito.inOrder(mContentlistener); - - inOrder.verify(mContentlistener) - .notifyContentsAdded(eq(2), mFeatureDriversCaptor.capture()); - inOrder.verifyNoMoreInteractions(); - - assertThat(mFeatureDriversCaptor.getValue()).hasSize(1); - assertThat(mFeatureDriversCaptor.getValue().get(0)) - .isEqualTo(getLeafFeatureDriverFromCluster(2)); - verify(mStreamOfflineMonitor, times(2)).requestOfflineStatusForNewContent(); - } - - @Test - public void testOnDestroy() { - FakeModelCursor cursor = FakeModelCursor.newBuilder().addCard().addToken().build(); - initializeStreamDriverAndDismissAllFeatureChildren(cursor); - - assertThat(mStreamDriver.getLeafFeatureDrivers()) - .containsExactly(mNoContentDriver, mContinuationDriver); - mStreamDriver.onDestroy(); - - verify(mNoContentDriver).onDestroy(); - verify(mContinuationDriver).onDestroy(); - verify(mStreamFeature).unregisterObserver(mStreamDriver); - } - - @Test - public void testOnDestroy_clearsFeatureDrivers() { - mStreamDriver = createStreamDriver(false, true); - when(mStreamFeature.getCursor()).thenReturn(FakeModelCursor.newBuilder().addCard().build()); - - assertThat(mStreamDriver.getLeafFeatureDrivers()).hasSize(1); - mStreamDriver.onDestroy(); - - assertThat(mStreamDriver.getLeafFeatureDrivers()).isEmpty(); - } - - @Test - public void testHasContent_returnsTrue() { - FakeModelCursor cursor = FakeModelCursor.newBuilder().addCard().addToken().build(); - when(mStreamFeature.getCursor()).thenReturn(cursor); - mStreamDriver.getLeafFeatureDrivers(); - - assertThat(mStreamDriver.hasContent()).isTrue(); - } - - @Test - public void testHasContent_returnsFalse_withNoContentCard() { - FakeModelCursor cursor = FakeModelCursor.newBuilder().addCard().addToken().build(); - initializeStreamDriverAndDismissAllFeatureChildren(cursor); - - assertThat(mStreamDriver.hasContent()).isFalse(); - } - - @Test - public void testHasContent_returnsFalse_withZeroState() { - when(mStreamFeature.getCursor()).thenReturn(EMPTY_MODEL_CURSOR); - - mStreamDriver.getLeafFeatureDrivers(); - - assertThat(mStreamDriver.hasContent()).isFalse(); - } - - @Test - public void testAutoConsumeSyntheticTokensOnRestore() { - FakeModelCursor initialCursor = FakeModelCursor.newBuilder().addCard().addToken().build(); - FakeModelCursor newCursor = FakeModelCursor.newBuilder().addToken().build(); - - when(mStreamFeature.getCursor()).thenReturn(initialCursor); - - mStreamDriver = createStreamDriver(/* restoring= */ true, /* isInitialLoad= */ false); - - mStreamDriver.getLeafFeatureDrivers(); - - assertThat(mStreamDriver.mWasRestoringDuringLastContinuationDriver).isTrue(); - - // Restoring scroll indicates that restore is over, and further continuation drivers will - // not be forced to consume synthetic tokens. - mStreamDriver.maybeRestoreScroll(); - - mStreamDriver.onNewChildren(initialCursor.getChildAt(1), newCursor.getModelChildren(), - /* wasSynthetic = */ false); - - assertThat(mStreamDriver.mWasRestoringDuringLastContinuationDriver).isFalse(); - } - - @Test - public void testTriggerPendingDismiss_noAction() { - setCards(CONTENT_ID); - SnackbarCallbackApi snackbarCallbackApi = triggerPendingDismiss( - UndoAction.newBuilder().setConfirmationLabel("confirmation").build(), CONTENT_ID); - - assertThat(mStreamDriver.isZeroStateBeingShown()).isTrue(); - - snackbarCallbackApi.onDismissNoAction(); - - verify(mPendingDismissCallback).onDismissCommitted(); - assertThat(mStreamDriver.isZeroStateBeingShown()).isTrue(); - } - - @Test - public void testTriggerPendingDismiss_actionTaken_lastCard() { - setCards(CONTENT_ID); - SnackbarCallbackApi snackbarCallbackApi = triggerPendingDismiss( - UndoAction.newBuilder().setConfirmationLabel("confirmation").build(), CONTENT_ID); - - List<LeafFeatureDriver> leafFeatureDrivers = mStreamDriver.getLeafFeatureDrivers(); - assertThat(leafFeatureDrivers).hasSize(1); - assertThat(mStreamDriver.isZeroStateBeingShown()).isTrue(); - - snackbarCallbackApi.onDismissedWithAction(); - - verify(mPendingDismissCallback).onDismissReverted(); - leafFeatureDrivers = mStreamDriver.getLeafFeatureDrivers(); - assertThat(leafFeatureDrivers).hasSize(1); - assertThat(mStreamDriver.isZeroStateBeingShown()).isFalse(); - } - - @Test - public void testTriggerPendingDismiss_actionTaken_multipleCards() { - setCards(CONTENT_ID, CONTENT_ID + "1"); - SnackbarCallbackApi snackbarCallbackApi = triggerPendingDismiss( - UndoAction.newBuilder().setConfirmationLabel("confirmation").build(), CONTENT_ID); - - List<LeafFeatureDriver> leafFeatureDrivers = mStreamDriver.getLeafFeatureDrivers(); - assertThat(leafFeatureDrivers).hasSize(1); - assertThat(mStreamDriver.isZeroStateBeingShown()).isFalse(); - - snackbarCallbackApi.onDismissedWithAction(); - - verify(mPendingDismissCallback).onDismissReverted(); - leafFeatureDrivers = mStreamDriver.getLeafFeatureDrivers(); - assertThat(leafFeatureDrivers).hasSize(2); - assertThat(mStreamDriver.isZeroStateBeingShown()).isFalse(); - } - - @Test - public void testTriggerPendingDismiss_actionStringSent() { - setCards(CONTENT_ID); - triggerPendingDismiss(UndoAction.newBuilder() - .setConfirmationLabel("conf") - .setUndoLabel("undo label") - .build(), - CONTENT_ID); - } - - @Test - public void testIsZeroStateBeingShown_returnsTrue_ifZeroState() { - when(mStreamFeature.getCursor()).thenReturn(EMPTY_MODEL_CURSOR); - mStreamDriver.getLeafFeatureDrivers(); - - assertThat(mStreamDriver.isZeroStateBeingShown()).isTrue(); - } - - @Test - public void testIsZeroStateBeingShown_returnsFalse_whenNoContentCardShowing() { - FakeModelCursor cursor = FakeModelCursor.newBuilder().addCard().addToken().build(); - - // Dismisses all features, but not the token, so the no-content state will be showing. - initializeStreamDriverAndDismissAllFeatureChildren(cursor); - - assertThat(mStreamDriver.isZeroStateBeingShown()).isFalse(); - } - - @Test - public void testIsZeroStateBeingShown_returnsFalse_ifZeroStateIsSpinner() { - when(mStreamFeature.getCursor()) - .thenReturn(FakeModelCursor.newBuilder().addCard().addToken().build()); - - mStreamDriver.getLeafFeatureDrivers(); - - mStreamDriver.showSpinner(); - - assertThat(mStreamDriver.isZeroStateBeingShown()).isFalse(); - } - - @Test - public void testSetModelProvider_setsModelProviderOnTheZeroState() { - when(mStreamFeature.getCursor()).thenReturn(EMPTY_MODEL_CURSOR); - mStreamDriver.getLeafFeatureDrivers(); - - mStreamDriver.setModelProviderForZeroState(mModelProvider); - - verify(mZeroStateDriver).setModelProvider(mModelProvider); - } - - @Test - public void testRefreshFromZeroState_resultsInZeroState_logsNoNewContent() { - mStreamDriver = createStreamDriverFromZeroStateRefresh(); - - when(mStreamFeature.getCursor()).thenReturn(EMPTY_MODEL_CURSOR); - mStreamDriver.getLeafFeatureDrivers(); - - verify(mBasicLoggingApi) - .onZeroStateRefreshCompleted(/* newContentCount= */ 0, /* newTokenCount= */ 0); - } - - @Test - public void testRefreshFromZeroState_addsContent_logsContent() { - mStreamDriver = createStreamDriverFromZeroStateRefresh(); - - when(mStreamFeature.getCursor()) - .thenReturn(FakeModelCursor.newBuilder().addClusters(10).addToken().build()); - mStreamDriver.getLeafFeatureDrivers(); - - verify(mBasicLoggingApi) - .onZeroStateRefreshCompleted(/* newContentCount= */ 10, /* newTokenCount= */ 1); - } - - private void initializeStreamDriverAndDismissAllFeatureChildren( - FakeModelCursor fakeModelCursor) { - when(mStreamFeature.getCursor()).thenReturn(fakeModelCursor); - - mStreamDriver.getLeafFeatureDrivers(); - - FeatureChangeBuilder dismissAllChildrenBuilder = new FeatureChangeBuilder(); - - for (ModelChild child : fakeModelCursor.getModelChildren()) { - if (child.getType() == Type.FEATURE) { - dismissAllChildrenBuilder.addChildForRemoval(child); - } - } - - mStreamDriver.onChange(dismissAllChildrenBuilder.build()); - } - - private StreamDriverForTest createNonRestoringStreamDriver() { - return createStreamDriver(/* restoring= */ false, /* isInitialLoad= */ false); - } - - private StreamDriverForTest createRestoringStreamDriver() { - return createStreamDriver(/* restoring= */ true, /* isInitialLoad= */ true); - } - - private StreamDriverForTest createStreamDriverFromZeroStateRefresh() { - return createStreamDriver( - /* restoring= */ false, - /* isInitialLoad= */ false, - UiRefreshReason.newBuilder().setReason(Reason.ZERO_STATE).build()); - } - - private StreamDriverForTest createStreamDriver( - boolean restoring, boolean isInitialLoad, UiRefreshReason uiRefreshReason) { - return new StreamDriverForTest( - mModelProvider, mThreadUtils, restoring, isInitialLoad, uiRefreshReason); - } - - private StreamDriverForTest createStreamDriver(boolean restoring, boolean isInitialLoad) { - return new StreamDriverForTest(mModelProvider, mThreadUtils, restoring, isInitialLoad, - UiRefreshReason.getDefaultInstance()); - } - - // TODO: Instead of just checking that the ModelFeature is of the correct type, check - // that it is the one created by the FakeModelCursor.Builder. - private LeafFeatureDriver getLeafFeatureDriverFromCard(int i) { - FakeFeatureDriver featureDriver = (FakeFeatureDriver) mStreamDriver.mChildrenCreated.get(i); - assertThat(featureDriver.getModelFeature().getStreamFeature().hasCard()).isTrue(); - return mStreamDriver.mChildrenCreated.get(i).getLeafFeatureDriver(); - } - - // TODO: Instead of just checking that the ModelFeature is of the correct type, check - // that it is the one created by the FakeModelCursor.Builder. - private LeafFeatureDriver getLeafFeatureDriverFromCluster(int i) { - FakeFeatureDriver featureDriver = (FakeFeatureDriver) mStreamDriver.mChildrenCreated.get(i); - assertThat(featureDriver.getModelFeature().getStreamFeature().hasCluster()).isTrue(); - return mStreamDriver.mChildrenCreated.get(i).getLeafFeatureDriver(); - } - - private void setCards(String... contentId) { - FakeModelCursor.Builder cursor = FakeModelCursor.newBuilder(); - for (String id : contentId) { - cursor.addChild( - FakeModelChild.newBuilder() - .setModelFeature(getCardModelFeatureWithCursor(EMPTY_MODEL_CURSOR)) - .setContentId(id) - .build()); - } - when(mStreamFeature.getCursor()).thenReturn(cursor.build()); - } - - private SnackbarCallbackApi triggerPendingDismiss(UndoAction undoAction, String contentId) { - ArgumentCaptor<SnackbarCallbackApi> snackbarCallbackApi = - ArgumentCaptor.forClass(SnackbarCallbackApi.class); - - // Causes StreamDriver to build a list of children based on the children from the cursor. - mStreamDriver.getLeafFeatureDrivers(); - - mStreamDriver.triggerPendingDismiss(contentId, undoAction, mPendingDismissCallback); - - verify(mContentlistener).notifyContentRemoved(0); - verify(mSnackbarApi) - .show(eq(undoAction.getConfirmationLabel()), - undoAction.hasUndoLabel() - ? eq(undoAction.getUndoLabel()) - : eq(mContext.getResources().getString(R.string.undo)), - snackbarCallbackApi.capture()); - - return snackbarCallbackApi.getValue(); - } - - private class StreamDriverForTest extends StreamDriver { - // TODO: create a fake for ContinuationDriver so that this can be - // List<FakeFeatureDriver> - private List<FeatureDriver> mChildrenCreated; - private boolean mWasRestoringDuringLastContinuationDriver; - - StreamDriverForTest(ModelProvider modelProvider, ThreadUtils threadUtils, boolean restoring, - boolean isInitialLoad, UiRefreshReason uiRefreshReason) { - super(mActionApi, mActionManager, mActionParserFactory, modelProvider, threadUtils, - mClock, mConfiguration, mContext, mSnackbarApi, mContentChangedListener, - mScrollRestorer, mBasicLoggingApi, mStreamOfflineMonitor, mFeedKnownContent, - mock(ContextMenuManager.class), restoring, isInitialLoad, mMainThreadRunner, - mViewLoggingUpdater, mTooltipApi, uiRefreshReason, mScrollmonitor); - mChildrenCreated = new ArrayList<>(); - } - - @Override - ContinuationDriver createContinuationDriver(BasicLoggingApi basicLoggingApi, Clock clock, - Configuration configuration, Context context, ModelChild modelChild, - ModelProvider modelProvider, int position, SnackbarApi snackbarApi, - boolean restoring) { - this.mWasRestoringDuringLastContinuationDriver = restoring; - mChildrenCreated.add(mContinuationDriver); - return mContinuationDriver; - } - - @Override - FeatureDriver createClusterDriver(ModelFeature modelFeature, int position) { - FeatureDriver featureDriver = - new FakeFeatureDriver.Builder().setModelFeature(modelFeature).build(); - mChildrenCreated.add(featureDriver); - return featureDriver; - } - - @Override - FeatureDriver createCardDriver(ModelFeature modelFeature, int position) { - if (modelFeature != UNBOUND_CARD) { - FeatureDriver featureDriver = - new FakeFeatureDriver.Builder().setModelFeature(modelFeature).build(); - mChildrenCreated.add(featureDriver); - return featureDriver; - } else { - FeatureDriver featureDriver = new FakeFeatureDriver.Builder() - .setModelFeature(modelFeature) - .setLeafFeatureDriver(null) - .build(); - mChildrenCreated.add(featureDriver); - return featureDriver; - } - } - - @Override - NoContentDriver createNoContentDriver() { - return mNoContentDriver; - } - - @Override - ZeroStateDriver createZeroStateDriver() { - return mZeroStateDriver; - } - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/drivers/ZeroStateDriverTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/drivers/ZeroStateDriverTest.java deleted file mode 100644 index 0053e5d..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/drivers/ZeroStateDriverTest.java +++ /dev/null
@@ -1,272 +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. - -package org.chromium.chrome.browser.feed.library.basicstream.internal.drivers; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import static org.chromium.chrome.browser.feed.library.common.testing.RunnableSubject.assertThatRunnable; - -import android.app.Activity; -import android.content.Context; -import android.view.View.OnClickListener; -import android.widget.FrameLayout; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.InOrder; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.logging.BasicLoggingApi; -import org.chromium.chrome.browser.feed.library.api.host.logging.RequestReason; -import org.chromium.chrome.browser.feed.library.api.host.logging.SpinnerType; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider; -import org.chromium.chrome.browser.feed.library.basicstream.internal.viewholders.ZeroStateViewHolder; -import org.chromium.chrome.browser.feed.library.common.time.Clock; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.sharedstream.logging.SpinnerLogger; -import org.chromium.chrome.browser.feed.shared.stream.Stream.ContentChangedListener; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.UiContext; -import org.chromium.components.feed.core.proto.libraries.sharedstream.UiRefreshReasonProto.UiRefreshReason; -import org.chromium.components.feed.core.proto.libraries.sharedstream.UiRefreshReasonProto.UiRefreshReason.Reason; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link ZeroStateDriver}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ZeroStateDriverTest { - private static final UiContext ZERO_STATE_UI_CONTEXT = - UiContext.newBuilder() - .setExtension(UiRefreshReason.uiRefreshReasonExtension, - UiRefreshReason.newBuilder().setReason(Reason.ZERO_STATE).build()) - .build(); - - @Mock - private BasicLoggingApi mBasicLoggingApi; - @Mock - private ContentChangedListener mContentChangedListener; - @Mock - private ModelProvider mModelProvider; - @Mock - private SpinnerLogger mSpinnerLogger; - @Mock - private ZeroStateViewHolder mZeroStateViewHolder; - - private ZeroStateDriver mZeroStateDriver; - private Clock mClock; - private Context mContext; - - @Before - public void setup() { - initMocks(this); - mClock = new FakeClock(); - mContext = Robolectric.buildActivity(Activity.class).get(); - - mZeroStateDriver = new ZeroStateDriverForTest(mBasicLoggingApi, mClock, mModelProvider, - mContentChangedListener, - /* spinnerShown= */ false); - } - - @Test - public void testBind() { - assertThat(mZeroStateDriver.isBound()).isFalse(); - - mZeroStateDriver.bind(mZeroStateViewHolder); - - assertThat(mZeroStateDriver.isBound()).isTrue(); - verify(mZeroStateViewHolder).bind(mZeroStateDriver, /* showSpinner= */ false); - } - - @Test - public void testBind_whenSpinnerShownTrue() { - mZeroStateDriver = new ZeroStateDriverForTest(mBasicLoggingApi, mClock, mModelProvider, - mContentChangedListener, - /* spinnerShown= */ true); - - mZeroStateDriver.bind(mZeroStateViewHolder); - verify(mZeroStateViewHolder).bind(mZeroStateDriver, /* showSpinner= */ true); - } - - @Test - public void testBindAfterOnClick_bindsViewholderWithSpinnerShown() { - InOrder inOrder = Mockito.inOrder(mZeroStateViewHolder); - mZeroStateDriver.bind(mZeroStateViewHolder); - inOrder.verify(mZeroStateViewHolder).bind(mZeroStateDriver, /* showSpinner= */ false); - - mZeroStateDriver.onClick(new FrameLayout(mContext)); - mZeroStateDriver.unbind(); - - mZeroStateDriver.bind(mZeroStateViewHolder); - - inOrder.verify(mZeroStateViewHolder).bind(mZeroStateDriver, /* showSpinner= */ true); - } - - @Test - public void testBind_startsRecordingSpinner_ifSpinnerIsShownAndNotLogged() { - when(mSpinnerLogger.isSpinnerActive()).thenReturn(false); - mZeroStateDriver = new ZeroStateDriverForTest(mBasicLoggingApi, mClock, mModelProvider, - mContentChangedListener, - /* spinnerShown= */ true); - mZeroStateDriver.bind(mZeroStateViewHolder); - - verify(mSpinnerLogger).spinnerStarted(SpinnerType.INITIAL_LOAD); - } - - @Test - public void testBind_doesNotStartRecordingSpinner_ifSpinnerIsNotShownAndNotLogged() { - when(mSpinnerLogger.isSpinnerActive()).thenReturn(false); - mZeroStateDriver.bind(mZeroStateViewHolder); - - verifyNoMoreInteractions(mSpinnerLogger); - } - - @Test - public void testBind_doesNotStartRecordingSpinner_ifSpinnerIsShownAndAlreadyLogged() { - when(mSpinnerLogger.isSpinnerActive()).thenReturn(true); - mZeroStateDriver = new ZeroStateDriverForTest(mBasicLoggingApi, mClock, mModelProvider, - mContentChangedListener, - /* spinnerShown= */ true); - mZeroStateDriver.bind(mZeroStateViewHolder); - - verify(mSpinnerLogger, never()).spinnerStarted(anyInt()); - } - - @Test - public void testUnbind() { - mZeroStateDriver.bind(mZeroStateViewHolder); - assertThat(mZeroStateDriver.isBound()).isTrue(); - - mZeroStateDriver.unbind(); - - assertThat(mZeroStateDriver.isBound()).isFalse(); - verify(mZeroStateViewHolder).unbind(); - } - - @Test - public void testUnbind_doesNotCallUnbindIfNotBound() { - assertThat(mZeroStateDriver.isBound()).isFalse(); - - mZeroStateDriver.unbind(); - verifyNoMoreInteractions(mZeroStateViewHolder); - } - - @Test - public void testOnClick() { - mZeroStateDriver.bind(mZeroStateViewHolder); - - mZeroStateDriver.onClick(new FrameLayout(mContext)); - - verify(mZeroStateViewHolder).showSpinner(true); - verify(mContentChangedListener).onContentChanged(); - verify(mModelProvider).triggerRefresh(RequestReason.ZERO_STATE, ZERO_STATE_UI_CONTEXT); - } - - @Test - public void testOnClick_usesNewModelProvider_afterSettingNewModelProvider() { - ModelProvider newModelProvider = mock(ModelProvider.class); - mZeroStateDriver.setModelProvider(newModelProvider); - mZeroStateDriver.bind(mZeroStateViewHolder); - - mZeroStateDriver.onClick(new FrameLayout(mContext)); - - verify(newModelProvider).triggerRefresh(RequestReason.ZERO_STATE, ZERO_STATE_UI_CONTEXT); - } - - @Test - public void testOnClick_startsRecordingSpinner_ifSpinnerNotActive() { - when(mSpinnerLogger.isSpinnerActive()).thenReturn(false); - mZeroStateDriver.bind(mZeroStateViewHolder); - - mZeroStateDriver.onClick(new FrameLayout(mContext)); - - verify(mSpinnerLogger).spinnerStarted(SpinnerType.ZERO_STATE_REFRESH); - } - - @Test - public void testOnClick_throwsRuntimeException_ifSpinnerActive() { - when(mSpinnerLogger.isSpinnerActive()).thenReturn(true); - mZeroStateDriver = new ZeroStateDriverForTest(mBasicLoggingApi, mClock, mModelProvider, - mContentChangedListener, - /* spinnerShown= */ true); - - mZeroStateDriver.bind(mZeroStateViewHolder); - reset(mSpinnerLogger); - - assertThatRunnable(() -> mZeroStateDriver.onClick(new FrameLayout(mContext))); - } - - @Test - public void testOnDestroy_logsSpinnerFinished_ifSpinnerActive() { - when(mSpinnerLogger.isSpinnerActive()).thenReturn(true); - mZeroStateDriver = new ZeroStateDriverForTest(mBasicLoggingApi, mClock, mModelProvider, - mContentChangedListener, - /* spinnerShown= */ true); - mZeroStateDriver.bind(mZeroStateViewHolder); - - mZeroStateDriver.onDestroy(); - - verify(mSpinnerLogger).spinnerFinished(); - } - - @Test - public void testOnDestroy_doesNotLogSpinnerFinished_ifSpinnerNotActive() { - when(mSpinnerLogger.isSpinnerActive()).thenReturn(false); - mZeroStateDriver.bind(mZeroStateViewHolder); - - mZeroStateDriver.onDestroy(); - verify(mSpinnerLogger, never()).spinnerFinished(); - } - - @Test - public void testMaybeRebind() { - mZeroStateDriver.bind(mZeroStateViewHolder); - assertThat(mZeroStateDriver.isBound()).isTrue(); - mZeroStateDriver.maybeRebind(); - assertThat(mZeroStateDriver.isBound()).isTrue(); - verify(mZeroStateViewHolder, times(2)).bind(mZeroStateDriver, /* showSpinner= */ false); - verify(mZeroStateViewHolder).unbind(); - } - - @Test - public void testMaybeRebind_nullViewHolder() { - mZeroStateDriver.bind(mZeroStateViewHolder); - mZeroStateDriver.unbind(); - reset(mZeroStateViewHolder); - - assertThat(mZeroStateDriver.isBound()).isFalse(); - mZeroStateDriver.maybeRebind(); - assertThat(mZeroStateDriver.isBound()).isFalse(); - verify(mZeroStateViewHolder, never()).bind(any(OnClickListener.class), anyBoolean()); - verify(mZeroStateViewHolder, never()).unbind(); - } - - private final class ZeroStateDriverForTest extends ZeroStateDriver { - ZeroStateDriverForTest(BasicLoggingApi basicLoggingApi, Clock clock, - ModelProvider modelProvider, ContentChangedListener contentChangedListener, - boolean spinnerShown) { - super(basicLoggingApi, clock, modelProvider, contentChangedListener, spinnerShown); - } - - @Override - SpinnerLogger createSpinnerLogger(BasicLoggingApi basicLoggingApi, Clock clock) { - return mSpinnerLogger; - } - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/scroll/BasicStreamScrollMonitorTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/scroll/BasicStreamScrollMonitorTest.java deleted file mode 100644 index e6ded422..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/scroll/BasicStreamScrollMonitorTest.java +++ /dev/null
@@ -1,137 +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. - -package org.chromium.chrome.browser.feed.library.basicstream.internal.scroll; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.MockitoAnnotations.initMocks; - -import android.app.Activity; -import android.view.View; - -import androidx.recyclerview.widget.RecyclerView; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.InOrder; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.sharedstream.publicapi.scroll.ScrollObserver; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link BasicStreamScrollMonitor}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public final class BasicStreamScrollMonitorTest { - private static final String FEATURE_ID = ""; - private static final long TIMESTAMP = 150000L; - - @Mock - private ScrollObserver mScrollObserver1; - @Mock - private ScrollObserver mScrollObserver2; - - private RecyclerView mView; - private FakeClock mClock; - private BasicStreamScrollMonitor mScrollMonitor; - - @Before - public void setUp() { - initMocks(this); - mView = new RecyclerView(Robolectric.buildActivity(Activity.class).get()); - mClock = new FakeClock(); - mClock.set(TIMESTAMP); - mScrollMonitor = new BasicStreamScrollMonitor(mClock); - } - - @Test - public void testCallbacks_onScroll() { - mScrollMonitor.onScrolled(mView, 0, 0); - - mScrollMonitor.addScrollObserver(mScrollObserver1); - - mScrollMonitor.onScrolled(mView, 1, 1); - mScrollMonitor.onScrolled(mView, 2, 2); - - mScrollMonitor.addScrollObserver(mScrollObserver2); - - mScrollMonitor.onScrolled(mView, 3, 3); - mScrollMonitor.onScrolled(mView, 4, 4); - - mScrollMonitor.removeScrollObserver(mScrollObserver1); - - mScrollMonitor.onScrolled(mView, 5, 5); - mScrollMonitor.onScrolled(mView, 6, 6); - - InOrder inOrder1 = inOrder(mScrollObserver1); - inOrder1.verify(mScrollObserver1).onScroll(mView, FEATURE_ID, 1, 1); - inOrder1.verify(mScrollObserver1).onScroll(mView, FEATURE_ID, 2, 2); - inOrder1.verify(mScrollObserver1).onScroll(mView, FEATURE_ID, 3, 3); - inOrder1.verify(mScrollObserver1).onScroll(mView, FEATURE_ID, 4, 4); - - InOrder inOrder2 = inOrder(mScrollObserver2); - inOrder2.verify(mScrollObserver2).onScroll(mView, FEATURE_ID, 3, 3); - inOrder2.verify(mScrollObserver2).onScroll(mView, FEATURE_ID, 4, 4); - inOrder2.verify(mScrollObserver2).onScroll(mView, FEATURE_ID, 5, 5); - inOrder2.verify(mScrollObserver2).onScroll(mView, FEATURE_ID, 6, 6); - } - - @Test - public void testCallbacks_onScrollStateChanged() { - mScrollMonitor.onScrollStateChanged(mView, 0); - - mScrollMonitor.addScrollObserver(mScrollObserver1); - - mScrollMonitor.onScrollStateChanged(mView, 1); - - mScrollMonitor.addScrollObserver(mScrollObserver2); - - mScrollMonitor.onScrollStateChanged(mView, 2); - - mScrollMonitor.removeScrollObserver(mScrollObserver1); - - mScrollMonitor.onScrollStateChanged(mView, 1); - mScrollMonitor.onScrollStateChanged(mView, 0); - - InOrder inOrder1 = inOrder(mScrollObserver1); - inOrder1.verify(mScrollObserver1).onScrollStateChanged(mView, FEATURE_ID, 1, TIMESTAMP); - inOrder1.verify(mScrollObserver1).onScrollStateChanged(mView, FEATURE_ID, 2, TIMESTAMP); - - InOrder inOrder2 = inOrder(mScrollObserver2); - inOrder2.verify(mScrollObserver2).onScrollStateChanged(mView, FEATURE_ID, 2, TIMESTAMP); - inOrder2.verify(mScrollObserver2).onScrollStateChanged(mView, FEATURE_ID, 1, TIMESTAMP); - inOrder2.verify(mScrollObserver2).onScrollStateChanged(mView, FEATURE_ID, 0, TIMESTAMP); - } - - @Test - public void testCallbacks_afterEvent() { - mScrollMonitor.onScrolled(mView, 1, 1); - mScrollMonitor.onScrolled(mView, 2, 2); - - mScrollMonitor.addScrollObserver(mScrollObserver1); - - verify(mScrollObserver1, never()) - .onScroll(any(View.class), anyString(), anyInt(), anyInt()); - } - - @Test - public void testGetCurrentScrollState() { - assertThat(mScrollMonitor.getCurrentScrollState()) - .isEqualTo(RecyclerView.SCROLL_STATE_IDLE); - mScrollMonitor.onScrollStateChanged(mView, RecyclerView.SCROLL_STATE_DRAGGING); - assertThat(mScrollMonitor.getCurrentScrollState()) - .isEqualTo(RecyclerView.SCROLL_STATE_DRAGGING); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/scroll/BasicStreamScrollTrackerTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/scroll/BasicStreamScrollTrackerTest.java deleted file mode 100644 index 0df70b9..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/scroll/BasicStreamScrollTrackerTest.java +++ /dev/null
@@ -1,54 +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. - -package org.chromium.chrome.browser.feed.library.basicstream.internal.scroll; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.verify; -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.logging.ScrollType; -import org.chromium.chrome.browser.feed.library.sharedstream.publicapi.scroll.ScrollObservable; -import org.chromium.chrome.browser.feed.library.sharedstream.publicapi.scroll.ScrollObserver; -import org.chromium.chrome.browser.feed.library.sharedstream.scroll.ScrollLogger; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link BasicStreamScrollTracker}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class BasicStreamScrollTrackerTest { - @Mock - private ScrollLogger mLogger; - @Mock - private ScrollObservable mScrollObservable; - - private BasicStreamScrollTracker mScrollTracker; - - @Before - public void setUp() { - initMocks(this); - mScrollTracker = new BasicStreamScrollTracker(mLogger, mScrollObservable); - verify(mScrollObservable).addScrollObserver(any(ScrollObserver.class)); - } - - @Test - public void onUnbind_removedScrollListener() { - mScrollTracker.onUnbind(); - verify(mScrollObservable).removeScrollObserver(any(ScrollObserver.class)); - } - - @Test - public void onScrollEvent() { - int scrollAmount = 10; - long timestamp = 10L; - mScrollTracker.onScrollEvent(scrollAmount); - verify(mLogger).handleScroll(ScrollType.STREAM_SCROLL, scrollAmount); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/scroll/ScrollRestorerTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/scroll/ScrollRestorerTest.java deleted file mode 100644 index 486704a8..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/scroll/ScrollRestorerTest.java +++ /dev/null
@@ -1,191 +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. - -package org.chromium.chrome.browser.feed.library.basicstream.internal.scroll; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import static org.chromium.chrome.browser.feed.library.basicstream.internal.scroll.ScrollRestorer.nonRestoringRestorer; - -import android.app.Activity; -import android.content.Context; -import android.view.View; - -import androidx.recyclerview.widget.RecyclerView; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration.ConfigKey; -import org.chromium.chrome.browser.feed.library.sharedstream.scroll.ScrollListenerNotifier; -import org.chromium.chrome.browser.feed.library.testing.android.LinearLayoutManagerForTest; -import org.chromium.components.feed.core.proto.libraries.sharedstream.ScrollStateProto.ScrollState; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link ScrollRestorer}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ScrollRestorerTest { - private static final int HEADER_COUNT = 3; - private static final int TOP_POSITION = 4; - private static final int BOTTOM_POSITION = 10; - private static final int ABANDON_RESTORE_THRESHOLD = BOTTOM_POSITION; - private static final int OFFSET = -10; - private static final ScrollState SCROLL_STATE = - ScrollState.newBuilder().setPosition(TOP_POSITION).setOffset(OFFSET).build(); - - @Mock - private ScrollListenerNotifier mScrollListenerNotifier; - @Mock - private Configuration mConfiguration; - - private RecyclerView mRecyclerView; - private LinearLayoutManagerForTest mLayoutManager; - private Context mContext; - - @Before - public void setUp() { - initMocks(this); - - when(mConfiguration.getValueOrDefault( - eq(ConfigKey.ABANDON_RESTORE_BELOW_FOLD), anyBoolean())) - .thenReturn(false); - when(mConfiguration.getValueOrDefault( - eq(ConfigKey.ABANDON_RESTORE_BELOW_FOLD_THRESHOLD), anyLong())) - .thenReturn((long) ABANDON_RESTORE_THRESHOLD); - - mContext = Robolectric.buildActivity(Activity.class).get(); - - mRecyclerView = new RecyclerView(mContext); - mLayoutManager = new LinearLayoutManagerForTest(mContext); - mRecyclerView.setLayoutManager(mLayoutManager); - } - - @Test - public void testRestoreScroll() { - ScrollRestorer scrollRestorer = new ScrollRestorer( - mConfiguration, mRecyclerView, mScrollListenerNotifier, SCROLL_STATE); - scrollRestorer.maybeRestoreScroll(); - - verify(mScrollListenerNotifier).onProgrammaticScroll(mRecyclerView); - assertThat(mLayoutManager.scrolledPosition).isEqualTo(TOP_POSITION); - assertThat(mLayoutManager.scrolledOffset).isEqualTo(OFFSET); - } - - @Test - public void testRestoreScroll_repeatedCall() { - ScrollRestorer scrollRestorer = new ScrollRestorer( - mConfiguration, mRecyclerView, mScrollListenerNotifier, createScrollState(10, 20)); - scrollRestorer.maybeRestoreScroll(); - - mLayoutManager.scrollToPositionWithOffset(TOP_POSITION, OFFSET); - scrollRestorer.maybeRestoreScroll(); - - verify(mScrollListenerNotifier).onProgrammaticScroll(mRecyclerView); - assertThat(mLayoutManager.scrolledPosition).isEqualTo(TOP_POSITION); - assertThat(mLayoutManager.scrolledOffset).isEqualTo(OFFSET); - } - - @Test - public void testAbandonRestoringScroll() { - mLayoutManager.scrollToPositionWithOffset(TOP_POSITION, OFFSET); - - ScrollRestorer scrollRestorer = new ScrollRestorer( - mConfiguration, mRecyclerView, mScrollListenerNotifier, createScrollState(10, 20)); - scrollRestorer.abandonRestoringScroll(); - scrollRestorer.maybeRestoreScroll(); - - assertThat(mLayoutManager.scrolledPosition).isEqualTo(TOP_POSITION); - assertThat(mLayoutManager.scrolledOffset).isEqualTo(OFFSET); - } - - @Test - public void testGetScrollStateForScrollPosition() { - mLayoutManager.firstVisibleItemPosition = TOP_POSITION; - mLayoutManager.firstVisibleViewOffset = OFFSET; - View view = new View(mContext); - view.setTop(OFFSET); - mLayoutManager.addChildToPosition(TOP_POSITION, view); - ScrollState restorerScrollState = - nonRestoringRestorer(mConfiguration, mRecyclerView, mScrollListenerNotifier) - .getScrollStateForScrollRestore(HEADER_COUNT); - assertThat(restorerScrollState).isEqualTo(SCROLL_STATE); - } - - @Test - public void testGetBundleForScrollPosition_invalidPosition() { - assertThat(nonRestoringRestorer(mConfiguration, mRecyclerView, mScrollListenerNotifier) - .getScrollStateForScrollRestore(10)) - .isNull(); - } - - @Test - public void testGetScrollStateForScrollPosition_abandonRestoreBelowFold_properRestore() { - when(mConfiguration.getValueOrDefault( - eq(ConfigKey.ABANDON_RESTORE_BELOW_FOLD), anyBoolean())) - .thenReturn(true); - - mLayoutManager.firstVisibleItemPosition = TOP_POSITION; - mLayoutManager.firstVisibleViewOffset = OFFSET; - mLayoutManager.lastVisibleItemPosition = BOTTOM_POSITION; - View view = new View(mContext); - view.setTop(OFFSET); - mLayoutManager.addChildToPosition(TOP_POSITION, view); - ScrollState restorerScrollState = - nonRestoringRestorer(mConfiguration, mRecyclerView, mScrollListenerNotifier) - .getScrollStateForScrollRestore(HEADER_COUNT); - assertThat(restorerScrollState).isEqualTo(SCROLL_STATE); - } - - @Test - public void testGetScrollStateForScrollPosition_abandonRestoreBelowFold_badBottomPosition() { - when(mConfiguration.getValueOrDefault( - eq(ConfigKey.ABANDON_RESTORE_BELOW_FOLD), anyBoolean())) - .thenReturn(true); - - mLayoutManager.firstVisibleItemPosition = TOP_POSITION; - mLayoutManager.firstVisibleViewOffset = OFFSET; - View view = new View(mContext); - view.setTop(OFFSET); - mLayoutManager.addChildToPosition(TOP_POSITION, view); - ScrollState restorerScrollState = - nonRestoringRestorer(mConfiguration, mRecyclerView, mScrollListenerNotifier) - .getScrollStateForScrollRestore(HEADER_COUNT); - assertThat(restorerScrollState).isNull(); - } - - @Test - public void testGetScrollStateForScrollPosition_abandonRestoreBelowFold_restorePastThreshold() { - when(mConfiguration.getValueOrDefault( - eq(ConfigKey.ABANDON_RESTORE_BELOW_FOLD), anyBoolean())) - .thenReturn(true); - - mLayoutManager.firstVisibleItemPosition = TOP_POSITION; - mLayoutManager.firstVisibleViewOffset = OFFSET; - mLayoutManager.lastVisibleItemPosition = ABANDON_RESTORE_THRESHOLD + HEADER_COUNT + 1; - View view = new View(mContext); - view.setTop(OFFSET); - mLayoutManager.addChildToPosition(TOP_POSITION, view); - ScrollState restorerScrollState = - nonRestoringRestorer(mConfiguration, mRecyclerView, mScrollListenerNotifier) - .getScrollStateForScrollRestore(HEADER_COUNT); - assertThat(restorerScrollState).isNull(); - } - - private ScrollState createScrollState(int position, int offset) { - return ScrollState.newBuilder().setPosition(position).setOffset(offset).build(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/viewholders/ContinuationViewHolderTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/viewholders/ContinuationViewHolderTest.java deleted file mode 100644 index 9f5f6bcd..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/viewholders/ContinuationViewHolderTest.java +++ /dev/null
@@ -1,139 +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. - -package org.chromium.chrome.browser.feed.library.basicstream.internal.viewholders; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.verify; -import static org.mockito.MockitoAnnotations.initMocks; - -import android.app.Activity; -import android.content.Context; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup.MarginLayoutParams; -import android.widget.FrameLayout; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration; -import org.chromium.chrome.browser.feed.library.api.host.stream.CardConfiguration; -import org.chromium.chrome.browser.feed.library.sharedstream.logging.LoggingListener; -import org.chromium.chrome.browser.feed.library.sharedstream.logging.VisibilityMonitor; -import org.chromium.chrome.browser.feed.library.testing.host.stream.FakeCardConfiguration; -import org.chromium.chrome.R; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link ContinuationViewHolder}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ContinuationViewHolderTest { - private static final Configuration CONFIGURATION = new Configuration.Builder().build(); - - private ContinuationViewHolder mContinuationViewHolder; - private Context mContext; - private FrameLayout mFrameLayout; - private CardConfiguration mCardConfiguration; - - @Mock - private OnClickListener mOnClickListener; - @Mock - private LoggingListener mLoggingListener; - @Mock - private VisibilityMonitor mVisibilityMonitor; - - @Before - public void setup() { - initMocks(this); - mCardConfiguration = new FakeCardConfiguration(); - mContext = Robolectric.buildActivity(Activity.class).get(); - mContext.setTheme(R.style.Light); - mFrameLayout = new FrameLayout(mContext); - mFrameLayout.setLayoutParams(new MarginLayoutParams(100, 100)); - mContinuationViewHolder = new ContinuationViewHolder( - CONFIGURATION, mContext, mFrameLayout, mCardConfiguration) { - @Override - VisibilityMonitor createVisibilityMonitor(View view, Configuration configuration) { - return mVisibilityMonitor; - } - }; - } - - @Test - public void testConstructorInflatesView() { - assertThat((View) mFrameLayout.findViewById(R.id.more_button)).isNotNull(); - } - - @Test - public void testClick() { - mContinuationViewHolder.bind(mOnClickListener, mLoggingListener, /* showSpinner= */ false); - - View buttonView = mFrameLayout.findViewById(R.id.action_button); - buttonView.performClick(); - - verify(mOnClickListener).onClick(buttonView); - verify(mLoggingListener).onContentClicked(); - } - - @Test - public void testBind_spinnerOff() { - mContinuationViewHolder.bind(mOnClickListener, mLoggingListener, /* showSpinner= */ false); - View buttonView = mFrameLayout.findViewById(R.id.action_button); - View spinnerView = mFrameLayout.findViewById(R.id.loading_spinner); - - assertThat(buttonView.isClickable()).isTrue(); - assertThat(buttonView.getVisibility()).isEqualTo(View.VISIBLE); - - assertThat(spinnerView.getVisibility()).isEqualTo(View.GONE); - } - - @Test - public void testBind_spinnerOn() { - mContinuationViewHolder.bind(mOnClickListener, mLoggingListener, /* showSpinner= */ true); - View buttonView = mFrameLayout.findViewById(R.id.action_button); - View spinnerView = mFrameLayout.findViewById(R.id.loading_spinner); - - assertThat(buttonView.getVisibility()).isEqualTo(View.GONE); - assertThat(spinnerView.getVisibility()).isEqualTo(View.VISIBLE); - } - - @Test - public void testBind_setsListener() { - mContinuationViewHolder.bind(mOnClickListener, mLoggingListener, /* showSpinner= */ false); - - verify(mVisibilityMonitor).setListener(mLoggingListener); - } - - @Test - public void testBind_setsMargins() { - mContinuationViewHolder.bind(mOnClickListener, mLoggingListener, /* showSpinner= */ false); - - MarginLayoutParams marginLayoutParams = - (MarginLayoutParams) mContinuationViewHolder.itemView.getLayoutParams(); - assertThat(marginLayoutParams.bottomMargin) - .isEqualTo(mCardConfiguration.getCardBottomMargin()); - assertThat(marginLayoutParams.leftMargin) - .isEqualTo(mCardConfiguration.getCardStartMargin()); - assertThat(marginLayoutParams.rightMargin).isEqualTo(mCardConfiguration.getCardEndMargin()); - assertThat(marginLayoutParams.topMargin) - .isEqualTo((int) mContext.getResources().getDimension( - R.dimen.feed_more_button_container_top_margins)); - } - - @Test - public void testUnbind() { - mContinuationViewHolder.bind(mOnClickListener, mLoggingListener, /* showSpinner= */ false); - mContinuationViewHolder.unbind(); - - View view = mFrameLayout.findViewById(R.id.action_button); - assertThat(view.isClickable()).isFalse(); - verify(mVisibilityMonitor).setListener(null); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/viewholders/HeaderViewHolderTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/viewholders/HeaderViewHolderTest.java deleted file mode 100644 index 2c06ea5d..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/viewholders/HeaderViewHolderTest.java +++ /dev/null
@@ -1,105 +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. - -package org.chromium.chrome.browser.feed.library.basicstream.internal.viewholders; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import android.app.Activity; -import android.content.Context; -import android.widget.FrameLayout; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.shared.stream.Header; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link HeaderViewHolder}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class HeaderViewHolderTest { - private Context mContext; - private HeaderViewHolder mHeaderViewHolder; - private FrameLayout mFrameLayout; - private FrameLayout mHeaderView; - - @Mock - private Header mHeader; - @Mock - private SwipeNotifier mSwipeNotifier; - - @Before - public void setUp() { - initMocks(this); - mContext = Robolectric.buildActivity(Activity.class).get(); - mFrameLayout = new FrameLayout(mContext); - mHeaderView = new FrameLayout(mContext); - mHeaderViewHolder = new HeaderViewHolder(mFrameLayout); - when(mHeader.getView()).thenReturn(mHeaderView); - } - - @Test - public void testBind() { - mHeaderViewHolder.bind(mHeader, mSwipeNotifier); - - assertThat(mFrameLayout.getChildAt(0)).isSameInstanceAs(mHeaderView); - } - - @Test - public void testBind_removesHeaderFromPreviousView_ifHeaderViewAlreadyHasParent() { - FrameLayout parentView = new FrameLayout(mContext); - parentView.addView(mHeaderView); - - mHeaderViewHolder.bind(mHeader, mSwipeNotifier); - - assertThat(parentView.getChildCount()).isEqualTo(0); - assertThat(mFrameLayout.getChildAt(0)).isSameInstanceAs(mHeaderView); - } - - @Test - public void testUnbind() { - mHeaderViewHolder.bind(mHeader, mSwipeNotifier); - } - - @Test - public void testCanSwipe() { - when(mHeader.isDismissible()).thenReturn(true); - mHeaderViewHolder.bind(mHeader, mSwipeNotifier); - - assertThat(mHeaderViewHolder.canSwipe()).isTrue(); - } - - @Test - public void testCanSwipe_returnsFalse_whenViewHolderNotBound() { - when(mHeader.isDismissible()).thenReturn(true); - - assertThat(mHeaderViewHolder.canSwipe()).isFalse(); - } - - @Test - public void testOnSwiped() { - mHeaderViewHolder.bind(mHeader, mSwipeNotifier); - - mHeaderViewHolder.onSwiped(); - - verify(mSwipeNotifier).onSwiped(); - } - - @Test - public void testOnSwiped_doesNotCallOnSwiped_whenViewHolderNotBound() { - mHeaderViewHolder.onSwiped(); - - verify(mSwipeNotifier, never()).onSwiped(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/viewholders/NoContentViewHolderTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/viewholders/NoContentViewHolderTest.java deleted file mode 100644 index b73c054f..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/viewholders/NoContentViewHolderTest.java +++ /dev/null
@@ -1,80 +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. - -package org.chromium.chrome.browser.feed.library.basicstream.internal.viewholders; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import android.app.Activity; -import android.content.Context; -import android.graphics.Color; -import android.graphics.drawable.ColorDrawable; -import android.view.View; -import android.view.ViewGroup.MarginLayoutParams; -import android.widget.FrameLayout; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.stream.CardConfiguration; -import org.chromium.chrome.R; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link NoContentViewHolder}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class NoContentViewHolderTest { - private NoContentViewHolder mNoContentViewHolder; - private FrameLayout mFrameLayout; - - ColorDrawable mRedBackground = new ColorDrawable(Color.RED); - - @Mock - private CardConfiguration mCardConfiguration; - - @Before - public void setup() { - initMocks(this); - Context context = Robolectric.buildActivity(Activity.class).get(); - context.setTheme(R.style.Light); - mFrameLayout = new FrameLayout(context); - mFrameLayout.setLayoutParams(new MarginLayoutParams(100, 100)); - mNoContentViewHolder = new NoContentViewHolder(mCardConfiguration, context, mFrameLayout); - when(mCardConfiguration.getCardBackground()).thenReturn(mRedBackground); - } - - @Test - public void testNoContentViewInflated() { - View view = mFrameLayout.findViewById(R.id.no_content); - assertThat(view).isNotNull(); - assertThat(view.getVisibility()).isEqualTo(View.VISIBLE); - } - - @Test - public void testBind_setsBackground() { - mNoContentViewHolder.bind(); - - assertThat(mFrameLayout.getBackground()).isEqualTo(mRedBackground); - } - - @Test - public void testBind_setsMargins() { - mNoContentViewHolder.bind(); - - MarginLayoutParams marginLayoutParams = - (MarginLayoutParams) mNoContentViewHolder.itemView.getLayoutParams(); - assertThat(marginLayoutParams.bottomMargin) - .isEqualTo(mCardConfiguration.getCardBottomMargin()); - assertThat(marginLayoutParams.leftMargin) - .isEqualTo(mCardConfiguration.getCardStartMargin()); - assertThat(marginLayoutParams.rightMargin).isEqualTo(mCardConfiguration.getCardEndMargin()); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/viewholders/PietViewHolderTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/viewholders/PietViewHolderTest.java deleted file mode 100644 index e4a7776a..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/viewholders/PietViewHolderTest.java +++ /dev/null
@@ -1,357 +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. - -package org.chromium.chrome.browser.feed.library.basicstream.internal.viewholders; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import android.app.Activity; -import android.content.Context; -import android.graphics.drawable.ColorDrawable; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewGroup.MarginLayoutParams; -import android.widget.FrameLayout; -import android.widget.TextView; - -import androidx.recyclerview.widget.RecyclerView; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.ArgumentMatchers; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.base.supplier.Supplier; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration; -import org.chromium.chrome.browser.feed.library.api.host.logging.BasicLoggingApi; -import org.chromium.chrome.browser.feed.library.api.host.stream.CardConfiguration; -import org.chromium.chrome.browser.feed.library.api.internal.actionparser.ActionParser; -import org.chromium.chrome.browser.feed.library.api.internal.actionparser.ActionSource; -import org.chromium.chrome.browser.feed.library.api.internal.actionparser.ActionSourceConverter; -import org.chromium.chrome.browser.feed.library.basicstream.internal.actions.StreamActionApiImpl; -import org.chromium.chrome.browser.feed.library.basicstream.internal.scroll.BasicStreamScrollMonitor; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.piet.PietManager; -import org.chromium.chrome.browser.feed.library.piet.host.ActionHandler; -import org.chromium.chrome.browser.feed.library.piet.host.ActionHandler.ActionType; -import org.chromium.chrome.browser.feed.library.piet.host.EventLogger; -import org.chromium.chrome.browser.feed.library.piet.testing.FakeFrameAdapter; -import org.chromium.chrome.browser.feed.library.sharedstream.logging.LoggingListener; -import org.chromium.chrome.browser.feed.library.sharedstream.logging.VisibilityMonitor; -import org.chromium.chrome.browser.feed.library.sharedstream.piet.PietEventLogger; -import org.chromium.chrome.browser.feed.library.testing.host.stream.FakeCardConfiguration; -import org.chromium.chrome.R; -import org.chromium.components.feed.core.proto.ui.action.FeedActionPayloadProto.FeedActionPayload; -import org.chromium.components.feed.core.proto.ui.action.FeedActionProto.FeedAction; -import org.chromium.components.feed.core.proto.ui.piet.ActionsProto.Action; -import org.chromium.components.feed.core.proto.ui.piet.ErrorsProto.ErrorCode; -import org.chromium.components.feed.core.proto.ui.piet.LogDataProto.LogData; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.Frame; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.PietSharedState; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** Tests for {@link PietViewHolder}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class PietViewHolderTest { - private static final Action ACTION = Action.getDefaultInstance(); - private static final Frame FRAME = Frame.newBuilder().build(); - private static final FeedActionPayload SWIPE_ACTION = - FeedActionPayload.newBuilder() - .setExtension(FeedAction.feedActionExtension, FeedAction.getDefaultInstance()) - .build(); - private static final LogData VE_LOGGING_INFO = LogData.getDefaultInstance(); - - private CardConfiguration mCardConfiguration; - @Mock - private ActionParser mActionParser; - @Mock - private PietManager mPietManager; - @Mock - private StreamActionApiImpl mStreamActionApi; - @Mock - private LoggingListener mLoggingListener; - @Mock - private VisibilityMonitor mVisibilityMonitor; - @Mock - private BasicLoggingApi mBasicLoggingApi; - - private BasicStreamScrollMonitor mStreamScrollMonitor; - private FakeFrameAdapter mFrameAdapter; - private ActionHandler mActionHandler; - private Configuration mConfiguration; - private PietViewHolder mPietViewHolder; - private FrameLayout mFrameLayout; - private View mView; - private View mViewport; - private final List<PietSharedState> mPietSharedStates = new ArrayList<>(); - private Context mContext; - - @Before - public void setUp() { - initMocks(this); - mStreamScrollMonitor = new BasicStreamScrollMonitor(new FakeClock()); - mCardConfiguration = new FakeCardConfiguration(); - mContext = Robolectric.buildActivity(Activity.class).get(); - mFrameLayout = new FrameLayout(mContext); - mFrameLayout.setLayoutParams(new MarginLayoutParams(100, 100)); - mView = new TextView(mContext); - mViewport = new FrameLayout(mContext); - - // TODO: Use FakePietManager once it is implemented. - when(mPietManager.createPietFrameAdapter(ArgumentMatchers.<Supplier<ViewGroup>>any(), - any(ActionHandler.class), any(EventLogger.class), eq(mContext))) - .thenAnswer(invocation -> { - mFrameAdapter = - FakeFrameAdapter.builder(mContext) - .setActionHandler((ActionHandler) invocation.getArguments()[1]) - .addViewAction(Action.getDefaultInstance()) - .addHideAction(Action.getDefaultInstance()) - .build(); - return mFrameAdapter; - }); - - mConfiguration = new Configuration.Builder().build(); - mPietViewHolder = new PietViewHolder(mCardConfiguration, mFrameLayout, mPietManager, - mStreamScrollMonitor, mViewport, mContext, mConfiguration, - new PietEventLogger(mBasicLoggingApi)) { - @Override - VisibilityMonitor createVisibilityMonitor(View view, Configuration configuration) { - return mVisibilityMonitor; - } - }; - - ArgumentCaptor<ActionHandler> captor = ArgumentCaptor.forClass(ActionHandler.class); - verify(mPietManager) - .createPietFrameAdapter(ArgumentMatchers.<Supplier<ViewGroup>>any(), - captor.capture(), any(EventLogger.class), any(Context.class)); - mActionHandler = captor.getValue(); - } - - @Test - public void testCardViewSetup() { - assertThat(mFrameLayout.getId()).isEqualTo(R.id.feed_content_card); - } - - @Test - public void testBind_clearsPadding() { - mFrameLayout.setPadding(1, 2, 3, 4); - - mPietViewHolder.bind(Frame.getDefaultInstance(), mPietSharedStates, mStreamActionApi, - FeedActionPayload.getDefaultInstance(), mLoggingListener, mActionParser); - - assertThat(mFrameLayout.getPaddingLeft()).isEqualTo(0); - assertThat(mFrameLayout.getPaddingRight()).isEqualTo(0); - assertThat(mFrameLayout.getPaddingTop()).isEqualTo(0); - assertThat(mFrameLayout.getPaddingBottom()).isEqualTo(0); - } - - @Test - public void testBind_setsBackground() { - mPietViewHolder.bind(Frame.getDefaultInstance(), mPietSharedStates, mStreamActionApi, - FeedActionPayload.getDefaultInstance(), mLoggingListener, mActionParser); - - assertThat(((ColorDrawable) mFrameLayout.getBackground()).getColor()) - .isEqualTo(((ColorDrawable) mCardConfiguration.getCardBackground()).getColor()); - } - - @Test - public void testBind_setsMargins() { - mPietViewHolder.bind(Frame.getDefaultInstance(), mPietSharedStates, mStreamActionApi, - FeedActionPayload.getDefaultInstance(), mLoggingListener, mActionParser); - - MarginLayoutParams marginLayoutParams = - (MarginLayoutParams) mPietViewHolder.itemView.getLayoutParams(); - assertThat(marginLayoutParams.bottomMargin) - .isEqualTo(mCardConfiguration.getCardBottomMargin()); - assertThat(marginLayoutParams.leftMargin) - .isEqualTo(mCardConfiguration.getCardStartMargin()); - assertThat(marginLayoutParams.rightMargin).isEqualTo(mCardConfiguration.getCardEndMargin()); - } - - @Test - public void testBind_bindsModel() { - mPietViewHolder.bind(Frame.getDefaultInstance(), mPietSharedStates, mStreamActionApi, - FeedActionPayload.getDefaultInstance(), mLoggingListener, mActionParser); - - assertThat(mFrameAdapter.isBound()).isTrue(); - } - - @Test - public void testBind_onlyBindsOnce() { - mPietViewHolder.bind(Frame.getDefaultInstance(), mPietSharedStates, mStreamActionApi, - FeedActionPayload.getDefaultInstance(), mLoggingListener, mActionParser); - - mPietViewHolder.bind(Frame.getDefaultInstance(), mPietSharedStates, mStreamActionApi, - FeedActionPayload.getDefaultInstance(), mLoggingListener, mActionParser); - - // Should not crash. - } - - @Test - public void testBind_setsListener() { - mPietViewHolder.bind(Frame.getDefaultInstance(), mPietSharedStates, mStreamActionApi, - FeedActionPayload.getDefaultInstance(), mLoggingListener, mActionParser); - - verify(mVisibilityMonitor).setListener(mLoggingListener); - } - - @Test - public void testBind_setsScrollListener() { - mPietViewHolder.bind(Frame.getDefaultInstance(), mPietSharedStates, mStreamActionApi, - FeedActionPayload.getDefaultInstance(), mLoggingListener, mActionParser); - - assertThat(mStreamScrollMonitor.getObserverCount()).isEqualTo(1); - } - - @Test - public void testUnbind() { - mPietViewHolder.bind(Frame.getDefaultInstance(), mPietSharedStates, mStreamActionApi, - FeedActionPayload.getDefaultInstance(), mLoggingListener, mActionParser); - - mPietViewHolder.unbind(); - - assertThat(mFrameAdapter.isBound()).isFalse(); - } - - @Test - public void testUnbind_setsListenerToNull() { - mPietViewHolder.bind(Frame.getDefaultInstance(), mPietSharedStates, mStreamActionApi, - FeedActionPayload.getDefaultInstance(), mLoggingListener, mActionParser); - - mPietViewHolder.unbind(); - - verify(mVisibilityMonitor).setListener(null); - } - - @Test - public void testUnbind_unsetsScrollListener() { - mPietViewHolder.bind(Frame.getDefaultInstance(), mPietSharedStates, mStreamActionApi, - FeedActionPayload.getDefaultInstance(), mLoggingListener, mActionParser); - - mPietViewHolder.unbind(); - - assertThat(mStreamScrollMonitor.getObserverCount()).isEqualTo(0); - } - - @Test - public void testSwipe_cantSwipeWithDefaultInstance() { - mPietViewHolder.bind(Frame.getDefaultInstance(), mPietSharedStates, mStreamActionApi, - FeedActionPayload.getDefaultInstance(), mLoggingListener, mActionParser); - - assertThat(mPietViewHolder.canSwipe()).isFalse(); - } - - @Test - public void testSwipe_canSwipeWithNonDefaultInstance() { - mPietViewHolder.bind(Frame.getDefaultInstance(), mPietSharedStates, mStreamActionApi, - SWIPE_ACTION, mLoggingListener, mActionParser); - - assertThat(mPietViewHolder.canSwipe()).isTrue(); - } - - @Test - public void testSwipeToDismissPerformed() { - mPietViewHolder.bind(Frame.getDefaultInstance(), mPietSharedStates, mStreamActionApi, - SWIPE_ACTION, mLoggingListener, mActionParser); - - mPietViewHolder.onSwiped(); - - verify(mLoggingListener).onContentSwiped(); - verify(mActionParser) - .parseFeedActionPayload(SWIPE_ACTION, mStreamActionApi, mPietViewHolder.itemView, - ActionSource.SWIPE); - } - - @Test - public void testActionHandler_logsClickOnClickAction() { - mPietViewHolder.bind(Frame.getDefaultInstance(), mPietSharedStates, mStreamActionApi, - FeedActionPayload.getDefaultInstance(), mLoggingListener, mActionParser); - - mActionHandler.handleAction(ACTION, ActionType.CLICK, FRAME, mView, VE_LOGGING_INFO); - - verify(mLoggingListener).onContentClicked(); - verify(mActionParser) - .parseAction(ACTION, mStreamActionApi, mView, VE_LOGGING_INFO, ActionSource.CLICK); - } - - @Test - public void testActionHandler_doesNotLogClickOnLongClickAction() { - mPietViewHolder.bind(Frame.getDefaultInstance(), mPietSharedStates, mStreamActionApi, - FeedActionPayload.getDefaultInstance(), mLoggingListener, mActionParser); - - mActionHandler.handleAction(ACTION, ActionType.LONG_CLICK, FRAME, mView, VE_LOGGING_INFO); - - verify(mLoggingListener, never()).onContentClicked(); - verify(mActionParser) - .parseAction( - ACTION, mStreamActionApi, mView, VE_LOGGING_INFO, ActionSource.LONG_CLICK); - } - - @Test - public void testActionHandler_doesNotLogClickOnViewAction() { - mPietViewHolder.bind(Frame.getDefaultInstance(), mPietSharedStates, mStreamActionApi, - FeedActionPayload.getDefaultInstance(), mLoggingListener, mActionParser); - - mActionHandler.handleAction(ACTION, ActionType.VIEW, FRAME, mView, VE_LOGGING_INFO); - - verify(mLoggingListener, never()).onContentClicked(); - verify(mActionParser) - .parseAction(ACTION, mStreamActionApi, mView, VE_LOGGING_INFO, ActionSource.VIEW); - } - - @Test - public void testHideActionsOnUnbind() { - mPietViewHolder.bind(Frame.getDefaultInstance(), mPietSharedStates, mStreamActionApi, - FeedActionPayload.getDefaultInstance(), mLoggingListener, mActionParser); - - // Triggers view actions. - mStreamScrollMonitor.onScrollStateChanged( - new RecyclerView(mContext), RecyclerView.SCROLL_STATE_IDLE); - - // Triggers hide actions associated with those views - mPietViewHolder.unbind(); - - // TODO: Instead of using the default instance twice, create an extension for test - // proto. - // Once on the view, once on the hide. - verify(mActionParser, times(2)) - .parseAction(Action.getDefaultInstance(), mStreamActionApi, - mFrameAdapter.getFrameContainer(), LogData.getDefaultInstance(), - ActionSourceConverter.convertPietAction(ActionType.VIEW)); - } - - @Test - public void testPietError_loggedToHost() { - ArgumentCaptor<EventLogger> pietEventLoggerCaptor = - ArgumentCaptor.forClass(EventLogger.class); - - verify(mPietManager) - .createPietFrameAdapter(ArgumentMatchers.<Supplier<ViewGroup>>any(), - eq(mActionHandler), pietEventLoggerCaptor.capture(), eq(mContext)); - - pietEventLoggerCaptor.getValue().logEvents( - Collections.singletonList(ErrorCode.ERR_MISSING_BINDING_VALUE)); - - verify(mBasicLoggingApi) - .onPietFrameRenderingEvent( - Collections.singletonList(ErrorCode.ERR_MISSING_BINDING_VALUE.getNumber())); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/viewholders/ZeroStateViewHolderTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/viewholders/ZeroStateViewHolderTest.java deleted file mode 100644 index 139374db..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/viewholders/ZeroStateViewHolderTest.java +++ /dev/null
@@ -1,149 +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. - -package org.chromium.chrome.browser.feed.library.basicstream.internal.viewholders; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.verify; -import static org.mockito.MockitoAnnotations.initMocks; - -import android.app.Activity; -import android.content.Context; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup.MarginLayoutParams; -import android.widget.FrameLayout; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.stream.CardConfiguration; -import org.chromium.chrome.browser.feed.library.testing.host.stream.FakeCardConfiguration; -import org.chromium.chrome.R; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link ZeroStateViewHolder}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ZeroStateViewHolderTest { - @Mock - private OnClickListener mOnClickListener; - - private CardConfiguration mCardConfiguration; - private FrameLayout mFrameLayout; - private ZeroStateViewHolder mZeroStateViewHolder; - - @Before - public void setup() { - initMocks(this); - mCardConfiguration = new FakeCardConfiguration(); - Context context = Robolectric.buildActivity(Activity.class).get(); - context.setTheme(R.style.Light); - mFrameLayout = new FrameLayout(context); - mFrameLayout.setLayoutParams(new MarginLayoutParams(100, 100)); - mZeroStateViewHolder = new ZeroStateViewHolder(context, mFrameLayout, mCardConfiguration); - } - - @Test - public void testZeroStateViewInflated() { - View view = mFrameLayout.findViewById(R.id.zero_state); - assertThat(view).isNotNull(); - assertThat(view.getVisibility()).isEqualTo(View.VISIBLE); - } - - @Test - public void testBind_setsOnClickListener() { - mZeroStateViewHolder.bind(mOnClickListener, /* showSpinner= */ false); - - View actionButton = mFrameLayout.findViewById(R.id.action_button); - actionButton.performClick(); - - verify(mOnClickListener).onClick(actionButton); - } - - @Test - public void testBind_showsLoadingSpinner_whenInitializingFalse() { - mZeroStateViewHolder.bind(mOnClickListener, /* showSpinner= */ false); - - View spinner = mFrameLayout.findViewById(R.id.loading_spinner); - View zeroState = mFrameLayout.findViewById(R.id.zero_state); - - assertThat(spinner.getVisibility()).isEqualTo(View.GONE); - assertThat(zeroState.getVisibility()).isEqualTo(View.VISIBLE); - } - - @Test - public void testBind_hidesSpinner() { - View spinner = mFrameLayout.findViewById(R.id.loading_spinner); - View zeroState = mFrameLayout.findViewById(R.id.zero_state); - mZeroStateViewHolder.showSpinner(true); - - assertThat(spinner.getVisibility()).isEqualTo(View.VISIBLE); - assertThat(zeroState.getVisibility()).isEqualTo(View.GONE); - - mZeroStateViewHolder.bind(mOnClickListener, /* showSpinner= */ false); - - assertThat(spinner.getVisibility()).isEqualTo(View.GONE); - assertThat(zeroState.getVisibility()).isEqualTo(View.VISIBLE); - } - - @Test - public void testBind_setsMargins() { - mZeroStateViewHolder.bind(mOnClickListener, /* showSpinner= */ false); - - View zeroStateView = mZeroStateViewHolder.itemView.findViewById(R.id.no_content_container); - MarginLayoutParams marginLayoutParams = - (MarginLayoutParams) zeroStateView.getLayoutParams(); - assertThat(marginLayoutParams.bottomMargin) - .isEqualTo(mCardConfiguration.getCardBottomMargin()); - assertThat(marginLayoutParams.leftMargin) - .isEqualTo(mCardConfiguration.getCardStartMargin()); - assertThat(marginLayoutParams.rightMargin).isEqualTo(mCardConfiguration.getCardEndMargin()); - } - - @Test - public void testUnbind() { - mZeroStateViewHolder.bind(mOnClickListener, /* showSpinner= */ false); - - View actionButton = mFrameLayout.findViewById(R.id.action_button); - assertThat(actionButton.hasOnClickListeners()).isTrue(); - assertThat(actionButton.isClickable()).isTrue(); - - mZeroStateViewHolder.unbind(); - - assertThat(actionButton.hasOnClickListeners()).isFalse(); - assertThat(actionButton.isClickable()).isFalse(); - } - - @Test - public void testShowSpinner_showsSpinner() { - View spinner = mFrameLayout.findViewById(R.id.loading_spinner); - View zeroState = mFrameLayout.findViewById(R.id.zero_state); - - mZeroStateViewHolder.showSpinner(true); - - assertThat(spinner.getVisibility()).isEqualTo(View.VISIBLE); - assertThat(zeroState.getVisibility()).isEqualTo(View.GONE); - } - - @Test - public void testShowSpinner_hidesSpinner() { - View spinner = mFrameLayout.findViewById(R.id.loading_spinner); - View zeroState = mFrameLayout.findViewById(R.id.zero_state); - mZeroStateViewHolder.showSpinner(true); - - assertThat(spinner.getVisibility()).isEqualTo(View.VISIBLE); - assertThat(zeroState.getVisibility()).isEqualTo(View.GONE); - - mZeroStateViewHolder.showSpinner(false); - - assertThat(spinner.getVisibility()).isEqualTo(View.GONE); - assertThat(zeroState.getVisibility()).isEqualTo(View.VISIBLE); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/viewloggingupdater/ResettableOneShotVisibilityLoggingListenerTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/viewloggingupdater/ResettableOneShotVisibilityLoggingListenerTest.java deleted file mode 100644 index 919337f..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/viewloggingupdater/ResettableOneShotVisibilityLoggingListenerTest.java +++ /dev/null
@@ -1,34 +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. - -package org.chromium.chrome.browser.feed.library.basicstream.internal.viewloggingupdater; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.sharedstream.logging.LoggingListener; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link ResettableOneShotVisibilityLoggingListener}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ResettableOneShotVisibilityLoggingListenerTest { - @Test - public void testReset_logsTwice() { - LoggingListener loggingListener = mock(LoggingListener.class); - ResettableOneShotVisibilityLoggingListener resettableLoggingListener = - new ResettableOneShotVisibilityLoggingListener(loggingListener); - resettableLoggingListener.onViewVisible(); - resettableLoggingListener.reset(); - resettableLoggingListener.onViewVisible(); - resettableLoggingListener.onViewVisible(); - - verify(loggingListener, times(2)).onViewVisible(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/viewloggingupdater/ViewLoggingUpdaterTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/viewloggingupdater/ViewLoggingUpdaterTest.java deleted file mode 100644 index 2d6646cf..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/basicstream/internal/viewloggingupdater/ViewLoggingUpdaterTest.java +++ /dev/null
@@ -1,37 +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. - -package org.chromium.chrome.browser.feed.library.basicstream.internal.viewloggingupdater; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link ViewLoggingUpdater}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ViewLoggingUpdaterTest { - @Test - public void testResetViewTracking_resetsListeners() { - ResettableOneShotVisibilityLoggingListener listerner1 = - mock(ResettableOneShotVisibilityLoggingListener.class); - ResettableOneShotVisibilityLoggingListener listerner2 = - mock(ResettableOneShotVisibilityLoggingListener.class); - - ViewLoggingUpdater viewLoggingUpdater = new ViewLoggingUpdater(); - - viewLoggingUpdater.registerObserver(listerner1); - viewLoggingUpdater.registerObserver(listerner2); - - viewLoggingUpdater.resetViewTracking(); - - verify(listerner1).reset(); - verify(listerner2).reset(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/ResultTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/ResultTest.java deleted file mode 100644 index 25e308c60..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/ResultTest.java +++ /dev/null
@@ -1,43 +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. - -package org.chromium.chrome.browser.feed.library.common; - -import static com.google.common.truth.Truth.assertThat; - -import static org.chromium.chrome.browser.feed.library.common.testing.RunnableSubject.assertThatRunnable; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Test class for {@link Result} */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ResultTest { - private static final String HELLO_WORLD = "Hello World"; - - @Test - public void success() throws Exception { - Result<String> result = Result.success(HELLO_WORLD); - assertThat(result.isSuccessful()).isTrue(); - assertThat(result.getValue()).isEqualTo(HELLO_WORLD); - } - - @Test - public void success_nullValue() throws Exception { - Result<String> result = Result.success(null); - assertThat(result.isSuccessful()).isTrue(); - assertThatRunnable(result::getValue).throwsAnExceptionOfType(NullPointerException.class); - } - - @Test - public void error() throws Exception { - Result<String> result = Result.failure(); - assertThat(result.isSuccessful()).isFalse(); - assertThatRunnable(result::getValue).throwsAnExceptionOfType(IllegalStateException.class); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/ValidatorsTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/ValidatorsTest.java deleted file mode 100644 index 3dd2012..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/ValidatorsTest.java +++ /dev/null
@@ -1,66 +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. - -package org.chromium.chrome.browser.feed.library.common; - -import static com.google.common.truth.Truth.assertThat; - -import static org.chromium.chrome.browser.feed.library.common.testing.RunnableSubject.assertThatRunnable; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests of the {@link Validators} class. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ValidatorsTest { - @Test - public void testCheckNotNull_null() { - assertThatRunnable(() -> Validators.checkNotNull(null)) - .throwsAnExceptionOfType(NullPointerException.class); - } - - @Test - public void testCheckNotNull_debugString() { - String debugString = "Debug-String"; - assertThatRunnable(() -> Validators.checkNotNull(null, debugString)) - .throwsAnExceptionOfType(NullPointerException.class) - .that() - .hasMessageThat() - .contains(debugString); - } - - @Test - public void testCheckNotNull_notNull() { - String test = "test"; - assertThat(Validators.checkNotNull(test)).isEqualTo(test); - } - - @Test - public void testCheckState_trueWithMessagel() { - // no exception expected - Validators.checkState(true, "format-string"); - } - - @Test - public void testCheckState_True() { - // no exception expected - Validators.checkState(true); - } - - @Test - public void testCheckState_falseWithMessage() { - assertThatRunnable(() -> Validators.checkState(false, "format-string")) - .throwsAnExceptionOfType(IllegalStateException.class); - } - - @Test - public void testCheckState_false() { - assertThatRunnable(() -> Validators.checkState(false)) - .throwsAnExceptionOfType(IllegalStateException.class); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/concurrent/CancelableRunnableTaskTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/concurrent/CancelableRunnableTaskTest.java deleted file mode 100644 index 390212a..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/concurrent/CancelableRunnableTaskTest.java +++ /dev/null
@@ -1,42 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.feed.library.common.concurrent; - -import static com.google.common.truth.Truth.assertThat; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests of the {@link TaskQueue} class. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class CancelableRunnableTaskTest { - private boolean mWasRun; - private CancelableRunnableTask mCancelable; - - @Before - public void setUp() { - mCancelable = new CancelableRunnableTask(() -> { mWasRun = true; }); - } - - @Test - public void testRunnableCanceled_notCanceled() { - mCancelable.run(); - - assertThat(mWasRun).isTrue(); - } - - @Test - public void testRunnableCanceled_canceled() { - mCancelable.cancel(); - mCancelable.run(); - - assertThat(mWasRun).isFalse(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/concurrent/SimpleSettableFutureTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/concurrent/SimpleSettableFutureTest.java deleted file mode 100644 index 7a6c7bb7..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/concurrent/SimpleSettableFutureTest.java +++ /dev/null
@@ -1,174 +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. - -package org.chromium.chrome.browser.feed.library.common.concurrent; - -import static com.google.common.truth.Truth.assertThat; - -import static org.chromium.chrome.browser.feed.library.common.testing.RunnableSubject.assertThatRunnable; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.concurrent.CancellationException; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -/** Tests for {@link SimpleSettableFuture} */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class SimpleSettableFutureTest { - @Test - public void testCancel() throws Exception { - SimpleSettableFuture<Boolean> future = new SimpleSettableFuture<>(); - boolean cancelled = future.cancel(false); - assertThat(cancelled).isTrue(); - assertThatRunnable(future::get) - .throwsAnExceptionOfType(ExecutionException.class) - .causedByAnExceptionOfType(CancellationException.class); - assertThat(future.isCancelled()).isTrue(); - assertThat(future.isDone()).isTrue(); - } - - @Test - public void testCancel_multipleCalls() throws Exception { - SimpleSettableFuture<Boolean> future = new SimpleSettableFuture<>(); - boolean cancelled = future.cancel(false); - cancelled = future.cancel(false); - assertThat(cancelled).isTrue(); - assertThatRunnable(future::get) - .throwsAnExceptionOfType(ExecutionException.class) - .causedByAnExceptionOfType(CancellationException.class); - assertThat(future.isCancelled()).isTrue(); - assertThat(future.isDone()).isTrue(); - } - - @Test - public void testCancel_alreadyFinished() throws Exception { - SimpleSettableFuture<Boolean> future = new SimpleSettableFuture<>(); - future.put(Boolean.TRUE); - boolean cancelled = future.cancel(false); - assertThat(cancelled).isFalse(); - } - - @Test - public void testPut() throws Exception { - SimpleSettableFuture<Boolean> future = new SimpleSettableFuture<>(); - future.put(Boolean.TRUE); - Boolean futureResult = future.get(); - assertThat(futureResult).isEqualTo(Boolean.TRUE); - assertThat(future.isDone()).isTrue(); - } - - @Test - public void testPut_onlyOnce() throws Exception { - SimpleSettableFuture<Boolean> future = new SimpleSettableFuture<>(); - future.put(Boolean.TRUE); - future.put(Boolean.FALSE); - Boolean futureResult = future.get(); - assertThat(futureResult).isEqualTo(Boolean.TRUE); - assertThat(future.isDone()).isTrue(); - } - - @Test - public void testPut_onlyOnce_andException() throws Exception { - SimpleSettableFuture<Boolean> future = new SimpleSettableFuture<>(); - future.put(Boolean.TRUE); - future.putException(new RuntimeException()); - Boolean futureResult = future.get(); - assertThat(futureResult).isEqualTo(Boolean.TRUE); - assertThat(future.isDone()).isTrue(); - } - - @Test - public void testPut_alreadyCancelled() throws Exception { - SimpleSettableFuture<Boolean> future = new SimpleSettableFuture<>(); - boolean cancelled = future.cancel(false); - future.put(Boolean.TRUE); - assertThatRunnable(future::get) - .throwsAnExceptionOfType(ExecutionException.class) - .causedByAnExceptionOfType(CancellationException.class); - assertThat(future.isCancelled()).isTrue(); - assertThat(future.isDone()).isTrue(); - } - - @Test - public void testPutException() throws Exception { - SimpleSettableFuture<Boolean> future = new SimpleSettableFuture<>(); - future.putException(new RuntimeException()); - assertThatRunnable(future::get) - .throwsAnExceptionOfType(ExecutionException.class) - .causedByAnExceptionOfType(RuntimeException.class); - } - - @Test - public void testPutException_onlyOnce() throws Exception { - SimpleSettableFuture<Boolean> future = new SimpleSettableFuture<>(); - future.putException(new RuntimeException()); - future.putException(new IllegalAccessException()); - assertThatRunnable(future::get) - .throwsAnExceptionOfType(ExecutionException.class) - .causedByAnExceptionOfType(RuntimeException.class); - } - - @Test - public void testPutException_onlyOnce_andValue() throws Exception { - SimpleSettableFuture<Boolean> future = new SimpleSettableFuture<>(); - future.putException(new RuntimeException()); - future.put(Boolean.TRUE); - assertThatRunnable(future::get) - .throwsAnExceptionOfType(ExecutionException.class) - .causedByAnExceptionOfType(RuntimeException.class); - } - - @Test - public void testPutException_alreadyCancelled() throws Exception { - SimpleSettableFuture<Boolean> future = new SimpleSettableFuture<>(); - boolean cancelled = future.cancel(false); - future.putException(new RuntimeException()); - assertThatRunnable(future::get) - .throwsAnExceptionOfType(ExecutionException.class) - .causedByAnExceptionOfType(CancellationException.class); - assertThat(future.isCancelled()).isTrue(); - assertThat(future.isDone()).isTrue(); - } - - @Test - public void testGetTimeout() throws Exception { - SimpleSettableFuture<Boolean> future = new SimpleSettableFuture<>(); - assertThatRunnable(() -> future.get(1, TimeUnit.MILLISECONDS)) - .throwsAnExceptionOfType(TimeoutException.class); - } - - @Test - public void testGetTimeout_success() throws Exception { - SimpleSettableFuture<Boolean> future = new SimpleSettableFuture<>(); - future.put(Boolean.TRUE); - Boolean futureResult = future.get(1, TimeUnit.MILLISECONDS); - assertThat(futureResult).isEqualTo(Boolean.TRUE); - assertThat(future.isDone()).isTrue(); - } - - @Test - public void testGetTimeout_cancelled() throws Exception { - SimpleSettableFuture<Boolean> future = new SimpleSettableFuture<>(); - future.cancel(false); - assertThatRunnable(() -> future.get(1, TimeUnit.MILLISECONDS)) - .throwsAnExceptionOfType(ExecutionException.class) - .causedByAnExceptionOfType(CancellationException.class); - } - - @Test - public void testGetTimeout_putException() throws Exception { - SimpleSettableFuture<Boolean> future = new SimpleSettableFuture<>(); - future.putException(new RuntimeException()); - assertThatRunnable(() -> future.get(1, TimeUnit.MILLISECONDS)) - .throwsAnExceptionOfType(ExecutionException.class) - .causedByAnExceptionOfType(RuntimeException.class); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/concurrent/TaskQueueTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/concurrent/TaskQueueTest.java deleted file mode 100644 index 12b722f..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/concurrent/TaskQueueTest.java +++ /dev/null
@@ -1,328 +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. - -package org.chromium.chrome.browser.feed.library.common.concurrent; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.MockitoAnnotations.initMocks; - -import com.google.common.util.concurrent.MoreExecutors; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.logging.InternalFeedError; -import org.chromium.chrome.browser.feed.library.api.host.logging.Task; -import org.chromium.chrome.browser.feed.library.common.concurrent.TaskQueue.TaskType; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeMainThreadRunner; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.testing.host.logging.FakeBasicLoggingApi; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.ArrayList; -import java.util.List; - -/** Tests of the {@link TaskQueue} class. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class TaskQueueTest { - private static final long LONG_RUNNING_TASK_TIME = 123456L; - private final FakeBasicLoggingApi mFakeBasicLoggingApi = new FakeBasicLoggingApi(); - private final FakeClock mFakeClock = new FakeClock(); - private final List<Integer> mCallOrder = new ArrayList<>(); - private final FakeMainThreadRunner mFakeMainThreadRunner = - FakeMainThreadRunner.create(mFakeClock); - private final TaskQueue mTaskQueue = new TaskQueue(mFakeBasicLoggingApi, - MoreExecutors.directExecutor(), mFakeMainThreadRunner, mFakeClock); - - private boolean mDelayedTaskHasRun; - private boolean mDelayedTaskHasTimedOut; - - @Before - public void setUp() { - initMocks(this); - mCallOrder.clear(); - } - - @Test - public void testInitialization() { - assertThat(mTaskQueue.isDelayed()).isTrue(); - mTaskQueue.initialize(this::noOp); - assertThat(mTaskQueue.isDelayed()).isFalse(); - } - - @Test - public void testInitializationCallOrder() { - Runnable background = () -> runnable(1); - Runnable userFacing = () -> runnable(2); - Runnable postInit = () -> runnable(3); - Runnable init = () -> runnable(4); - - mTaskQueue.execute(Task.UNKNOWN, TaskType.BACKGROUND, background); - mTaskQueue.execute(Task.UNKNOWN, TaskType.USER_FACING, userFacing); - mTaskQueue.execute(Task.UNKNOWN, TaskType.IMMEDIATE, postInit); - assertThat(mTaskQueue.hasBacklog()).isTrue(); - mTaskQueue.initialize(init); - - assertThat(mTaskQueue.hasBacklog()).isFalse(); - assertOrder(4, 3, 2, 1); - } - - @Test - public void testPostInit() { - mTaskQueue.initialize(this::noOp); - - Runnable invalidate = () -> runnable(1); - Runnable postInit = () -> runnable(2); - Runnable userFacing = () -> runnable(3); - Runnable reset = () -> runnable(4); - - mTaskQueue.execute(Task.UNKNOWN, TaskType.HEAD_INVALIDATE, invalidate); - mTaskQueue.execute(Task.UNKNOWN, TaskType.IMMEDIATE, postInit); - mTaskQueue.execute(Task.UNKNOWN, TaskType.USER_FACING, userFacing); - mTaskQueue.execute(Task.UNKNOWN, TaskType.HEAD_RESET, reset); - - assertThat(mTaskQueue.hasBacklog()).isFalse(); - assertOrder(1, 2, 4, 3); - } - - @Test - public void testHeadInvalidateReset() { - mTaskQueue.initialize(this::noOp); - assertThat(mTaskQueue.isDelayed()).isFalse(); - - mTaskQueue.execute(Task.UNKNOWN, TaskType.HEAD_INVALIDATE, this::noOp); - mTaskQueue.execute(Task.UNKNOWN, TaskType.BACKGROUND, this::delayedTask); - - assertThat(mTaskQueue.isDelayed()).isTrue(); - assertThat(mDelayedTaskHasRun).isFalse(); - assertThat(mTaskQueue.hasPendingStarvationCheck()).isTrue(); - - mTaskQueue.execute(Task.UNKNOWN, TaskType.HEAD_RESET, this::noOp); - - assertThat(mTaskQueue.isDelayed()).isFalse(); - assertThat(mDelayedTaskHasRun).isTrue(); - assertThat(mTaskQueue.hasPendingStarvationCheck()).isFalse(); - } - - @Test - public void testHeadInvalidateDropMultiple() { - Runnable invalidate = () -> runnable(1); - Runnable invalidateNotRun = () -> runnable(2); - Runnable init = () -> runnable(3); - - mTaskQueue.execute(Task.UNKNOWN, TaskType.HEAD_INVALIDATE, invalidate); - mTaskQueue.execute(Task.UNKNOWN, TaskType.HEAD_INVALIDATE, invalidateNotRun); - assertThat(mTaskQueue.hasBacklog()).isTrue(); - mTaskQueue.initialize(init); - - assertThat(mTaskQueue.hasBacklog()).isFalse(); - assertOrder(3, 1); - } - - @Test - public void testHeadInvalidateCallOrder() { - mTaskQueue.initialize(this::noOp); - assertThat(mTaskQueue.isDelayed()).isFalse(); - - Runnable headInvalidate = () -> runnable(1); - Runnable background = () -> runnable(2); - Runnable userFacing = () -> runnable(3); - Runnable postInit = () -> runnable(4); - Runnable headReset = () -> runnable(5); - - mTaskQueue.execute(Task.UNKNOWN, TaskType.HEAD_INVALIDATE, headInvalidate); - mTaskQueue.execute(Task.UNKNOWN, TaskType.BACKGROUND, background); - mTaskQueue.execute(Task.UNKNOWN, TaskType.USER_FACING, userFacing); - mTaskQueue.execute(Task.UNKNOWN, TaskType.IMMEDIATE, postInit); // run immediately - assertThat(mTaskQueue.hasBacklog()).isTrue(); - mTaskQueue.execute(Task.UNKNOWN, TaskType.HEAD_RESET, headReset); - - assertThat(mTaskQueue.hasBacklog()).isFalse(); - assertOrder(1, 4, 5, 3, 2); - } - - @Test - public void testResetTaskQueue_immediate() { - mTaskQueue.initialize(this::noOp); - assertThat(mTaskQueue.isDelayed()).isFalse(); - - mTaskQueue.reset(); - assertThat(mTaskQueue.isDelayed()).isTrue(); - mTaskQueue.initialize(this::noOp); - assertThat(mTaskQueue.isDelayed()).isFalse(); - } - - @Test - public void testResetQueue_withDelay() { - mTaskQueue.initialize(this::noOp); - assertThat(mTaskQueue.isDelayed()).isFalse(); - - Runnable headInvalidate = () -> runnable(1); - Runnable background = () -> runnable(2); - Runnable userFacing = () -> runnable(3); - Runnable postInit = () -> runnable(4); - - mTaskQueue.execute(Task.UNKNOWN, TaskType.HEAD_INVALIDATE, headInvalidate); - mTaskQueue.execute(Task.UNKNOWN, TaskType.BACKGROUND, background); - mTaskQueue.execute(Task.UNKNOWN, TaskType.USER_FACING, userFacing); - mTaskQueue.execute(Task.UNKNOWN, TaskType.IMMEDIATE, postInit); - assertThat(mTaskQueue.hasBacklog()).isTrue(); - - mTaskQueue.reset(); - assertThat(mTaskQueue.isDelayed()).isTrue(); - assertThat(mTaskQueue.hasBacklog()).isFalse(); - mTaskQueue.initialize(this::noOp); - assertThat(mTaskQueue.isDelayed()).isFalse(); - } - - @Test - public void testStarvation_initialization() { - mTaskQueue.initialize(this::noOp); - mTaskQueue.execute(Task.UNKNOWN, TaskType.BACKGROUND, this::delayedTask); - - assertThat(mDelayedTaskHasRun).isTrue(); - assertThat(mTaskQueue.isDelayed()).isFalse(); - } - - @Test - public void testStarvation_headInvalidate() { - mTaskQueue.initialize(this::noOp); - mTaskQueue.execute(Task.UNKNOWN, TaskType.HEAD_INVALIDATE, this::noOp); - mTaskQueue.execute(Task.UNKNOWN, TaskType.BACKGROUND, this::delayedTask); - - assertThat(mFakeMainThreadRunner.getCompletedTaskCount()).isEqualTo(0); - assertThat(mDelayedTaskHasRun).isFalse(); - assertThat(mTaskQueue.isDelayed()).isTrue(); - - runAndAssertStarvationChecks(); - assertThat(mDelayedTaskHasRun).isTrue(); - assertThat(mTaskQueue.isDelayed()).isFalse(); - assertThat(mFakeBasicLoggingApi.lastInternalError) - .isEqualTo(InternalFeedError.TASK_QUEUE_STARVATION); - } - - @Test - public void testStarvation_reset() { - mTaskQueue.initialize(this::noOp); - mTaskQueue.reset(); - mTaskQueue.execute(Task.UNKNOWN, TaskType.BACKGROUND, this::delayedTask); - - assertThat(mDelayedTaskHasRun).isFalse(); - assertThat(mTaskQueue.isDelayed()).isTrue(); - - runAndAssertStarvationChecks(); - assertThat(mDelayedTaskHasRun).isTrue(); - assertThat(mTaskQueue.isDelayed()).isFalse(); - } - - @Test - public void testTaskTiming_immediatelyRunTask_logsTaskFinished() { - mTaskQueue.initialize(this::noOp); - - mTaskQueue.execute(Task.CLEAR_ALL, TaskType.IMMEDIATE, this::noOp); - - assertThat(mFakeBasicLoggingApi.lastTaskDelay).isEqualTo(0); - assertThat(mFakeBasicLoggingApi.lastTaskTime).isEqualTo(0); - assertThat(mFakeBasicLoggingApi.lastTaskLogged).isEqualTo(Task.CLEAR_ALL); - } - - @Test - public void testTaskTiming_longTask_logsTaskFinished() { - mTaskQueue.initialize(this::noOp); - - mTaskQueue.execute(Task.UNKNOWN, TaskType.IMMEDIATE, this::longRunningTask); - - assertThat(mFakeBasicLoggingApi.lastTaskTime).isEqualTo(LONG_RUNNING_TASK_TIME); - } - - @Test - public void testTaskTiming_delayedTask_logsTaskFinished() { - // Queue task before initialization, causing it to be delayed - mTaskQueue.execute(Task.UNKNOWN, TaskType.HEAD_INVALIDATE, this::delayedTask); - long delayTime = 123L; - mFakeClock.advance(delayTime); - - // Initialize, allowing the delayed task to be run - mTaskQueue.initialize(this::noOp); - - assertThat(mFakeBasicLoggingApi.lastTaskDelay).isEqualTo(delayTime); - } - - @Test - public void testTimeout_withoutTimeout() { - // Put the TaskQueue into a delaying state and schedule a task with a timeout. - mTaskQueue.initialize(this::noOp); - mTaskQueue.execute(Task.UNKNOWN, TaskType.HEAD_INVALIDATE, this::noOp); - mTaskQueue.execute(Task.UNKNOWN, TaskType.BACKGROUND, this::delayedTask, - this::delayedTaskTimeout, - /*timeoutMillis= */ 10L); - - mFakeClock.advance(9L); - mTaskQueue.execute(Task.UNKNOWN, TaskType.HEAD_RESET, this::noOp); - assertThat(mDelayedTaskHasRun).isTrue(); - assertThat(mDelayedTaskHasTimedOut).isFalse(); - - mFakeClock.tick(); - assertThat(mDelayedTaskHasTimedOut).isFalse(); - } - - @Test - public void testTimeout_withTimeout() { - // Put the TaskQueue into a delaying state and schedule a task with a timeout. - mTaskQueue.initialize(this::noOp); - mTaskQueue.execute(Task.UNKNOWN, TaskType.HEAD_INVALIDATE, this::noOp); - mTaskQueue.execute(Task.UNKNOWN, TaskType.BACKGROUND, this::delayedTask, - this::delayedTaskTimeout, - /*timeoutMillis= */ 10L); - - mFakeClock.advance(10L); - assertThat(mDelayedTaskHasRun).isFalse(); - assertThat(mDelayedTaskHasTimedOut).isTrue(); - - mTaskQueue.execute(Task.UNKNOWN, TaskType.HEAD_RESET, this::noOp); - assertThat(mDelayedTaskHasRun).isFalse(); - } - - private void runAndAssertStarvationChecks() { - int starvationTaskCount = 0; - long startTimeMillis = mFakeClock.currentTimeMillis(); - while (mFakeClock.currentTimeMillis() - startTimeMillis < TaskQueue.STARVATION_TIMEOUT_MS) { - assertThat(mTaskQueue.hasPendingStarvationCheck()).isTrue(); - mFakeClock.advance(TaskQueue.STARVATION_CHECK_MS); - starvationTaskCount++; - assertThat(mFakeMainThreadRunner.getCompletedTaskCount()) - .isEqualTo(starvationTaskCount); - } - assertThat(mTaskQueue.hasPendingStarvationCheck()).isFalse(); - } - - private void assertOrder(Integer... args) { - assertThat(mCallOrder.size()).isEqualTo(args.length); - for (int i = 0; i < args.length; i++) { - assertThat(mCallOrder.get(i)).isEqualTo(args[i]); - } - } - - private void runnable(int taskId) { - mCallOrder.add(taskId); - } - - private void noOp() {} - - private void delayedTask() { - mDelayedTaskHasRun = true; - } - - private void delayedTaskTimeout() { - mDelayedTaskHasTimedOut = true; - } - - private void longRunningTask() { - mFakeClock.advance(LONG_RUNNING_TASK_TIME); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/feedobservable/FeedObservableTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/feedobservable/FeedObservableTest.java deleted file mode 100644 index 4d6de17..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/feedobservable/FeedObservableTest.java +++ /dev/null
@@ -1,95 +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. - -package org.chromium.chrome.browser.feed.library.common.feedobservable; - -import static com.google.common.truth.Truth.assertThat; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** - * Tests for {@link org.chromium.chrome.browser.feed.library.common.feedobservable.FeedObservable}. - */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class FeedObservableTest { - private FeedObservableForTest mObservable; - - @Before - public void setup() { - mObservable = new FeedObservableForTest(); - } - - @Test - public void updateObservers_updatesRegisteredObservers() { - Observer observer = new Observer(); - mObservable.registerObserver(observer); - - mObservable.updateObservers(); - - assertThat(observer.mUpdateCount).isEqualTo(1); - } - - @Test - public void updateObservers_doesntUpdateUnregisteredObservers() { - Observer observer = new Observer(); - mObservable.registerObserver(observer); - mObservable.unregisterObserver(observer); - - mObservable.updateObservers(); - - assertThat(observer.mUpdateCount).isEqualTo(0); - } - - @Test - public void updateObservers_multipleObservers_updatesAll() { - Observer observer1 = new Observer(); - Observer observer2 = new Observer(); - mObservable.registerObserver(observer1); - mObservable.registerObserver(observer2); - - mObservable.updateObservers(); - - assertThat(observer1.mUpdateCount).isEqualTo(1); - assertThat(observer2.mUpdateCount).isEqualTo(1); - } - - @Test - public void updateObservers_doubleRegister_updatesOnce() { - Observer observer = new Observer(); - mObservable.registerObserver(observer); - mObservable.registerObserver(observer); - - mObservable.updateObservers(); - - assertThat(observer.mUpdateCount).isEqualTo(1); - } - - @Test - public void unRegisterObserver_nonRegisteredObserver_doesntCrash() { - // Should not crash. - mObservable.unregisterObserver(new Observer()); - } - - private static class FeedObservableForTest extends FeedObservable<Observer> { - void updateObservers() { - for (Observer observer : mObservers) { - observer.update(); - } - } - } - - private static class Observer { - private int mUpdateCount; - - void update() { - mUpdateCount++; - } - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/intern/HashPoolInternerTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/intern/HashPoolInternerTest.java deleted file mode 100644 index 0518318..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/intern/HashPoolInternerTest.java +++ /dev/null
@@ -1,98 +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. - -package org.chromium.chrome.browser.feed.library.common.intern; - -import static com.google.common.truth.Truth.assertThat; - -import static org.junit.Assert.fail; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.components.feed.core.proto.ui.piet.PietProto.PietSharedState; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.Stylesheet; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.Stylesheets; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.Template; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests of the {@link HashPoolInterner} class. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class HashPoolInternerTest { - private final HashPoolInterner<PietSharedStateWrapper> mInterner = new HashPoolInterner<>(); - - @Before - public void setUp() throws Exception {} - - @Test - public void testBasic() { - PietSharedStateWrapper first = new PietSharedStateWrapper( - PietSharedState.newBuilder() - .addTemplates(Template.newBuilder().setTemplateId("foo").setStylesheets( - Stylesheets.newBuilder().addStylesheetIds("bar"))) - .addStylesheets(Stylesheet.newBuilder().setStylesheetId("baz")) - .build()); - PietSharedStateWrapper second = new PietSharedStateWrapper( - PietSharedState.newBuilder() - .addTemplates(Template.newBuilder().setTemplateId("foo").setStylesheets( - Stylesheets.newBuilder().addStylesheetIds("bar"))) - .addStylesheets(Stylesheet.newBuilder().setStylesheetId("baz")) - .build()); - PietSharedStateWrapper third = new PietSharedStateWrapper( - PietSharedState.newBuilder() - .addTemplates(Template.newBuilder().setTemplateId("foo").setStylesheets( - Stylesheets.newBuilder().addStylesheetIds("bar"))) - .addStylesheets(Stylesheet.newBuilder().setStylesheetId("bay")) - .build()); - assertThat(first).isNotSameInstanceAs(second); - assertThat(first).isNotSameInstanceAs(third); - assertThat(second).isNotSameInstanceAs(third); - - // Pool is empty so first is added/returned. - PietSharedStateWrapper internedFirst = mInterner.intern(first); - assertThat(mInterner.size()).isEqualTo(1); - assertThat(internedFirst).isSameInstanceAs(first); - - // Pool already has an identical proto, which is returned. - PietSharedStateWrapper internSecond = mInterner.intern(second); - assertThat(mInterner.size()).isEqualTo(1); - assertThat(internSecond).isSameInstanceAs(first); - - // Third is a new object (not equal with any previous) so it is added to the pool. - PietSharedStateWrapper internedThird = mInterner.intern(third); - assertThat(mInterner.size()).isEqualTo(2); - assertThat(internedThird).isSameInstanceAs(third); - - mInterner.clear(); - assertThat(mInterner.size()).isEqualTo(0); - - // Pool is empty so second is added/returned. - internSecond = mInterner.intern(second); - assertThat(mInterner.size()).isEqualTo(1); - assertThat(internSecond).isSameInstanceAs(second); - } - - private static class PietSharedStateWrapper { - private final PietSharedState mPietSharedState; - - private PietSharedStateWrapper(PietSharedState pietSharedState) { - this.mPietSharedState = pietSharedState; - } - - @Override - public int hashCode() { - return mPietSharedState.hashCode(); - } - - @Override - public boolean equals(Object obj) { - // Equals should never be called with HashPoolInterner, it may be very expensive. - fail(); - return super.equals(obj); - } - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/intern/InternedMapTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/intern/InternedMapTest.java deleted file mode 100644 index 8351a79..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/intern/InternedMapTest.java +++ /dev/null
@@ -1,69 +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. - -package org.chromium.chrome.browser.feed.library.common.intern; - -import static com.google.common.truth.Truth.assertThat; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamStructure; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamStructure.Operation; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.HashMap; - -/** Tests of the {@link InternedMap} class. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class InternedMapTest { - private final InternedMap<String, StreamStructure> mMap = - new InternedMap<>(new HashMap<>(), new WeakPoolInterner<>()); - - @Before - public void setUp() throws Exception {} - - @Test - public void testBasic() { - StreamStructure first = StreamStructure.newBuilder() - .setContentId("foo") - .setParentContentId("bar") - .setOperation(Operation.UPDATE_OR_APPEND) - .build(); - StreamStructure second = StreamStructure.newBuilder() - .setContentId("foo") - .setParentContentId("bar") - .setOperation(Operation.UPDATE_OR_APPEND) - .build(); - StreamStructure third = StreamStructure.newBuilder() - .setContentId("foo") - .setParentContentId("baz") - .setOperation(Operation.UPDATE_OR_APPEND) - .build(); - assertThat(first).isNotSameInstanceAs(second); - assertThat(first).isEqualTo(second); - assertThat(first).isNotEqualTo(third); - - // Initially the interner pool is empty so first is added as value. - mMap.put("first", first); - assertThat(mMap.get("first")).isSameInstanceAs(first); - - // The interner pool already has an identical value object so second is not added, first is - // used instead. - mMap.put("second", second); - assertThat(mMap.get("second")).isSameInstanceAs(first); - - // Third is a new object (not equal with any previous) so it is added to the pool. - mMap.put("third", third); - assertThat(mMap.get("third")).isSameInstanceAs(third); - - // Since the pool is empty, seconds is added to the pool this time. - mMap.clear(); - mMap.put("second", second); - assertThat(mMap.get("second")).isSameInstanceAs(second); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/intern/InternerWithStatsTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/intern/InternerWithStatsTest.java deleted file mode 100644 index fa2f14ca..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/intern/InternerWithStatsTest.java +++ /dev/null
@@ -1,68 +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. - -package org.chromium.chrome.browser.feed.library.common.intern; - -import static com.google.common.truth.Truth.assertThat; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamStructure; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamStructure.Operation; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests of the {@link InternerWithStats} class. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class InternerWithStatsTest { - private final InternerWithStats<StreamStructure> mInterner = - new InternerWithStats<>(new WeakPoolInterner<>()); - - @Before - public void setUp() throws Exception {} - - @Test - public void testBasic() { - StreamStructure first = StreamStructure.newBuilder() - .setContentId("foo") - .setParentContentId("bar") - .setOperation(Operation.UPDATE_OR_APPEND) - .build(); - StreamStructure second = StreamStructure.newBuilder() - .setContentId("foo") - .setParentContentId("bar") - .setOperation(Operation.UPDATE_OR_APPEND) - .build(); - StreamStructure third = StreamStructure.newBuilder() - .setContentId("foo") - .setParentContentId("baz") - .setOperation(Operation.UPDATE_OR_APPEND) - .build(); - assertThat(first).isNotSameInstanceAs(second); - assertThat(first).isEqualTo(second); - assertThat(first).isNotEqualTo(third); - - // Pool is empty so first is added/returned. - StreamStructure internedFirst = mInterner.intern(first); - assertThat(internedFirst).isSameInstanceAs(first); - assertThat(mInterner.getStats()).isEqualTo("Cache Hit Ratio: 0/1 (0.00)"); - - // Pool already has an identical proto, which is returned. - StreamStructure internedSecond = mInterner.intern(second); - assertThat(internedSecond).isSameInstanceAs(first); - assertThat(mInterner.getStats()).isEqualTo("Cache Hit Ratio: 1/2 (0.50)"); - - // Third is a new object (not equal with any previous) so it is added to the pool. - StreamStructure internedThird = mInterner.intern(third); - assertThat(internedThird).isSameInstanceAs(third); - assertThat(mInterner.getStats()).isEqualTo("Cache Hit Ratio: 1/3 (0.33)"); - - mInterner.clear(); - assertThat(mInterner.size()).isEqualTo(0); - assertThat(mInterner.getStats()).isEqualTo("Cache Hit Ratio: 0/0 (1.00)"); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/intern/WeakPoolInternerTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/intern/WeakPoolInternerTest.java deleted file mode 100644 index b7ba026f..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/intern/WeakPoolInternerTest.java +++ /dev/null
@@ -1,67 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.feed.library.common.intern; - -import static com.google.common.truth.Truth.assertThat; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamStructure; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamStructure.Operation; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests of the {@link WeakPoolInterner} class. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class WeakPoolInternerTest { - private final WeakPoolInterner<StreamStructure> mInterner = new WeakPoolInterner<>(); - - @Test - public void testBasic() { - StreamStructure first = StreamStructure.newBuilder() - .setContentId("foo") - .setParentContentId("bar") - .setOperation(Operation.UPDATE_OR_APPEND) - .build(); - StreamStructure second = StreamStructure.newBuilder() - .setContentId("foo") - .setParentContentId("bar") - .setOperation(Operation.UPDATE_OR_APPEND) - .build(); - StreamStructure third = StreamStructure.newBuilder() - .setContentId("foo") - .setParentContentId("baz") - .setOperation(Operation.UPDATE_OR_APPEND) - .build(); - assertThat(first).isNotSameInstanceAs(second); - assertThat(first).isEqualTo(second); - assertThat(first).isNotEqualTo(third); - - // Pool is empty so first is added/returned. - StreamStructure internedFirst = mInterner.intern(first); - assertThat(mInterner.size()).isEqualTo(1); - assertThat(internedFirst).isSameInstanceAs(first); - - // Pool already has an identical proto, which is returned. - StreamStructure internedSecond = mInterner.intern(second); - assertThat(mInterner.size()).isEqualTo(1); - assertThat(internedSecond).isSameInstanceAs(first); - - // Third is a new object (not equal with any previous) so it is added to the pool. - StreamStructure internedThird = mInterner.intern(third); - assertThat(mInterner.size()).isEqualTo(2); - assertThat(internedThird).isSameInstanceAs(third); - - mInterner.clear(); - assertThat(mInterner.size()).isEqualTo(0); - - // Pool is empty so second is added/returned. - internedSecond = mInterner.intern(second); - assertThat(mInterner.size()).isEqualTo(1); - assertThat(internedSecond).isSameInstanceAs(second); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/locale/LocaleUtilsTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/locale/LocaleUtilsTest.java deleted file mode 100644 index c6b04c2..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/locale/LocaleUtilsTest.java +++ /dev/null
@@ -1,51 +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. - -package org.chromium.chrome.browser.feed.library.common.locale; - -import static com.google.common.truth.Truth.assertThat; - -import android.app.Activity; -import android.content.Context; -import android.os.Build.VERSION_CODES; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.Locale; - -/** Tests of the {@link LocaleUtils} class. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class LocaleUtilsTest { - private Context mContext; - - @Before - public void setUp() { - mContext = Robolectric.buildActivity(Activity.class).get(); - } - - @Test - @Config(qualifiers = "fr-rCA", sdk = VERSION_CODES.O /*N is not available*/) - public void getLocale_byContext_postN() { - assertThat(LocaleUtils.getLocale(mContext)).isEqualTo(Locale.CANADA_FRENCH); - } - - @Test - @Config(qualifiers = "fr-rCA", sdk = VERSION_CODES.LOLLIPOP) - public void getLoca_byContext_preN() { - assertThat(LocaleUtils.getLocale(mContext)).isEqualTo(Locale.CANADA_FRENCH); - } - - @Test - @Config(qualifiers = "fr-rCA") - public void getLanguageTag() { - assertThat(LocaleUtils.getLanguageTag(mContext)).isEqualTo("fr-CA"); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/logging/DumperTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/logging/DumperTest.java deleted file mode 100644 index c8094bf..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/logging/DumperTest.java +++ /dev/null
@@ -1,175 +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. - -package org.chromium.chrome.browser.feed.library.common.logging; - -import static com.google.common.truth.Truth.assertThat; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.common.logging.Dumper.DumperValue; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.io.StringWriter; - -/** Tests of the {@link Dumper}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class DumperTest { - private static final String KEY1 = "keyOne"; - private static final String KEY2 = "keyTwo"; - private static final String KEY3 = "keyThree"; - private static final String VALUE1 = "valueOne"; - private static final String VALUE2 = "valueTwo"; - - @Test - public void testBaseDumper() { - Dumper dumper = Dumper.newDefaultDumper(); - dumper.forKey(KEY1).value(13); - assertThat(dumper.mValues).hasSize(1); - DumperValue dumperValue = dumper.mValues.get(0); - assertThat(dumperValue).isNotNull(); - assertThat(dumperValue.mName).isEqualTo(KEY1); - assertThat(dumperValue.mContent.toString()).isEqualTo(Integer.toString(13)); - assertThat(dumperValue.mIndentLevel).isEqualTo(1); - } - - @Test - public void testBaseDumper_childDumper() { - Dumper dumper = Dumper.newDefaultDumper(); - dumper.forKey(KEY1).value(13); - assertThat(dumper.mValues).hasSize(1); - - Dumper childDumper = dumper.getChildDumper(); - childDumper.forKey(KEY2).value(17); - - assertThat(childDumper.mValues).isEqualTo(dumper.mValues); - assertThat(childDumper.mValues).hasSize(2); - - DumperValue dumperValue = dumper.mValues.get(1); - assertThat(dumperValue).isNotNull(); - assertThat(dumperValue.mName).isEqualTo(KEY2); - assertThat(dumperValue.mContent.toString()).isEqualTo(Integer.toString(17)); - assertThat(dumperValue.mIndentLevel).isEqualTo(2); - } - - @Test - public void testDumpable() { - Dumper dumper = Dumper.newDefaultDumper(); - TestDumpable testDumpable = new TestDumpable(KEY1); - dumper.dump(testDumpable); - testDumpable.assertValue(dumper.mValues.get(0)); - } - - @Test - public void testDumpable_nested() { - Dumper dumper = Dumper.newDefaultDumper(); - TestDumpable dumpableChild = new TestDumpable(KEY1); - TestDumpable dumpable = new TestDumpable(dumpableChild, KEY2); - dumper.dump(dumpable); - - assertThat(dumper.mValues).hasSize(2); - dumpable.assertValue(dumper.mValues.get(0)); - dumpableChild.assertValue(dumper.mValues.get(1)); - } - - @Test - public void testDumpable_cycle() { - Dumper dumper = Dumper.newDefaultDumper(); - TestDumpable dumpableChild = new TestDumpable(KEY1); - TestDumpable dumpable = new TestDumpable(dumpableChild, KEY2); - dumpableChild.setDumpable(dumpable); - - dumper.dump(dumpable); - - // Two dumpables + the a message that statesa cycle was detected - assertThat(dumper.mValues).hasSize(3); - dumpable.assertValue(dumper.mValues.get(0)); - dumpableChild.assertValue(dumper.mValues.get(1)); - } - - @Test - public void testDumpable_threeChildCycle() { - Dumper dumper = Dumper.newDefaultDumper(); - TestDumpable dumpableThree = new TestDumpable(KEY1); - TestDumpable dumpableTwo = new TestDumpable(dumpableThree, KEY2); - TestDumpable dumpableOne = new TestDumpable(dumpableTwo, KEY3); - dumpableThree.setDumpable(dumpableOne); - - dumper.dump(dumpableOne); - - // 3 dumpables + the a message that states cycle was detected - assertThat(dumper.mValues).hasSize(4); - } - - @Test - public void testWrite() throws Exception { - Dumper dumper = Dumper.newDefaultDumper(); - TestDumpable testDumpable = new TestDumpable(KEY1); - dumper.dump(testDumpable); - StringWriter stringWriter = new StringWriter(); - dumper.write(stringWriter); - String dump = stringWriter.toString(); - assertThat(dump).contains(KEY1); - assertThat(dump).contains("13"); - } - - @Test - public void testWrite_compact() throws Exception { - Dumper dumper = Dumper.newDefaultDumper(); - dumper.forKey(KEY1).value(VALUE1); - dumper.forKey(KEY2).value(VALUE2).compactPrevious(); - StringWriter stringWriter = new StringWriter(); - dumper.write(stringWriter); - String dump = stringWriter.toString(); - assertThat(dump).contains(" | "); - assertThat(dump).contains(VALUE1); - assertThat(dump).contains(VALUE2); - } - - @Test - public void testRedacted() throws Exception { - Dumper dumper = Dumper.newRedactedDumper(); - dumper.forKey(KEY1).value(VALUE1).sensitive(); - dumper.forKey(KEY2).value(VALUE2).compactPrevious(); - StringWriter stringWriter = new StringWriter(); - dumper.write(stringWriter); - String dump = stringWriter.toString(); - assertThat(dump).contains(" | "); - assertThat(dump).contains(DumperValue.REDACTED); - assertThat(dump).doesNotContain(VALUE1); - assertThat(dump).contains(VALUE2); - } - - private static class TestDumpable implements Dumpable { - /*@Nullable*/ private Dumpable mChild; - private final String mKey; - - TestDumpable(String key) { - this(null, key); - } - - TestDumpable(/*@Nullable*/ Dumpable child, String key) { - this.mChild = child; - this.mKey = key; - } - - void setDumpable(Dumpable child) { - this.mChild = child; - } - - @Override - public void dump(Dumper dumper) { - dumper.forKey(mKey).value(13); - dumper.dump(mChild); - } - - void assertValue(DumperValue value) { - assertThat(value.mName).isEqualTo(mKey); - assertThat(value.mContent.toString()).isEqualTo(Integer.toString(13)); - } - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/logging/LoggerTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/logging/LoggerTest.java deleted file mode 100644 index cc48e5e..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/logging/LoggerTest.java +++ /dev/null
@@ -1,102 +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. - -package org.chromium.chrome.browser.feed.library.common.logging; - -import static com.google.common.truth.Truth.assertThat; - -import static org.junit.Assert.assertEquals; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link Logger}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class LoggerTest { - private static final Object[] EMPTY_ARRAY = {}; - - @Test - public void testBuildMessage_emptyString() { - assertThat(Logger.buildMessage("", EMPTY_ARRAY)).isEmpty(); - } - - @Test - public void testBuildMessage_nullString() { - assertEquals("null", Logger.buildMessage(null, EMPTY_ARRAY)); - } - - @Test - public void testBuildMessage_nullStringWithArgs() { - // Test that any args are ignored - assertEquals("null", Logger.buildMessage(null, new Object[] {"A", "B", 2})); - } - - @Test - public void testBuildMessage_noArgs() { - assertEquals("hello", Logger.buildMessage("hello", EMPTY_ARRAY)); - } - - @Test - public void testBuildMessage_formatString() { - String format = "%s scolded %s %d times? %b/%b"; - assertEquals("A scolded B 2 times? true/false", - Logger.buildMessage(format, new Object[] {"A", "B", 2, true, false})); - } - - @Test - public void testBuildMessage_formatStringForceArgsToString() { - String format = "%s scolded %s %s times? %s/%s"; - assertEquals("A scolded B 2 times? true/false", - Logger.buildMessage(format, new Object[] {"A", "B", 2, true, false})); - } - - @Test - public void testBuildMessage_formatStringNullArgs() { - String format = "%s scolded %s %d times? %b/%b"; - assertEquals("null scolded null null times? false/false", - Logger.buildMessage(format, new Object[] {null, null, null, null, null})); - } - - @Test - public void testBuildMessage_noFormat() { - String format = "Hello"; - // Test that args are safely ignored - assertEquals("Hello", Logger.buildMessage(format, new Object[] {"A", "B", 2})); - } - - @Test - public void testBuildMessage_illegalFormat() { - String format = "Hello %d"; - // Test that args are concatenated when using a string for %d. - assertEquals("Hello %d[A]", Logger.buildMessage(format, new Object[] {"A"})); - } - - @Test - public void testBuildMessage_arrayArgs() { - String format = "%s %s"; - int[] a = {1, 2, 3}; - Object[] b = {"a", new String[] {"b", "c"}}; - assertEquals("[1, 2, 3] [a, [b, c]]", Logger.buildMessage(format, new Object[] {a, b})); - } - - @Test - public void testBuildMessage_arrayArgsWithNull() { - String format = "%s"; - Object a = new String[] {"a", null}; - assertEquals("[a, null]", Logger.buildMessage(format, new Object[] {a})); - } - - @Test - public void testBuildMessage_arrayArgsWithCycle() { - String format = "%s %s"; - Object[] a = new Object[1]; - Object[] b = {a}; - a[0] = b; - assertEquals("[[[...]]] [[[...]]]", Logger.buildMessage(format, new Object[] {a, b})); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/testing/RequiredConsumerTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/testing/RequiredConsumerTest.java deleted file mode 100644 index 3bf9814..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/testing/RequiredConsumerTest.java +++ /dev/null
@@ -1,33 +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. - -package org.chromium.chrome.browser.feed.library.common.testing; - -import static com.google.common.truth.Truth.assertThat; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -import java.util.concurrent.CountDownLatch; - -/** Test class for {@link RequiredConsumer} */ -@RunWith(JUnit4.class) -public class RequiredConsumerTest { - @Test - public void testConsumer() throws Exception { - CountDownLatch latch = new CountDownLatch(1); - Boolean callValue = Boolean.TRUE; - - RequiredConsumer<Boolean> consumer = new RequiredConsumer<>(input -> { - assertThat(input).isEqualTo(callValue); - latch.countDown(); - }); - - consumer.accept(callValue); - - assertThat(latch.getCount()).isEqualTo(0); - assertThat(consumer.isCalled()).isTrue(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/testing/RunnableSubjectTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/testing/RunnableSubjectTest.java deleted file mode 100644 index 105d97f2..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/testing/RunnableSubjectTest.java +++ /dev/null
@@ -1,228 +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. - -package org.chromium.chrome.browser.feed.library.common.testing; - -import static com.google.common.truth.ExpectFailure.assertThat; -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; - -import static org.chromium.chrome.browser.feed.library.common.testing.RunnableSubject.assertThatRunnable; -import static org.chromium.chrome.browser.feed.library.common.testing.RunnableSubject.runnables; - -import com.google.common.truth.ExpectFailure; -import com.google.common.truth.Truth; - -import org.junit.ComparisonFailure; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -import org.chromium.chrome.browser.feed.library.common.testing.RunnableSubject.ThrowingRunnable; - -import java.io.IOException; -import java.util.concurrent.ExecutionException; - -/** Unit tests for {@link RunnableSubject}. */ -@RunWith(JUnit4.class) -public class RunnableSubjectTest { - @Rule - public final ExpectFailure expectFailure = new ExpectFailure(); - - @Test - public void runToCompletion() throws Throwable { - ThrowingRunnable run = mock(ThrowingRunnable.class); - - expectFailure.whenTesting() - .about(runnables()) - .that(run) - .throwsAnExceptionOfType(RuntimeException.class); - - verify(run).run(); - AssertionError failure = expectFailure.getFailure(); - assertThat(failure).factValue("expected to throw").isEqualTo("java.lang.RuntimeException"); - assertThat(failure).factKeys().contains("but ran to completion"); - verifyNoMoreInteractions(run); - } - - @Test - public void nullSubjectFailsEvenWhenExpectingNullRefException() { - expectFailure.whenTesting() - .about(runnables()) - .that(null) - .throwsAnExceptionOfType(NullPointerException.class); - - AssertionError failure = expectFailure.getFailure(); - assertThat(failure) - .factValue("expected to throw") - .isEqualTo("java.lang.NullPointerException"); - assertThat(failure).factKeys().contains("but didn't run because it's null"); - } - - @Test - public void wrongException() { - expectFailure.whenTesting() - .about(runnables()) - .that(() -> { throw new IllegalArgumentException("a"); }) - .throwsAnExceptionOfType(NullPointerException.class); - - AssertionError failure = expectFailure.getFailure(); - assertThat(failure).factValue("value of").isEqualTo("runnable.thrownException()"); - assertThat(failure) - .factValue("expected instance of") - .isEqualTo("java.lang.NullPointerException"); - assertThat(failure) - .factValue("but was instance of") - .isEqualTo("java.lang.IllegalArgumentException"); - assertThat(failure) - .factValue("with value") - .isEqualTo("java.lang.IllegalArgumentException: a"); - } - - @Test - public void correctException() { - IllegalArgumentException ex = new IllegalArgumentException("b"); - - Truth.assertAbout(runnables()) - .that(() -> { throw ex; }) - .throwsAnExceptionOfType(IllegalArgumentException.class) - .that() - .isSameInstanceAs(ex); - } - - @Test - public void wrongMessage() { - expectFailure.whenTesting() - .about(runnables()) - .that(() -> { throw new IOException("Wrong message!"); }) - .throwsAnExceptionOfType(IOException.class) - .that() - .hasMessageThat() - .isEqualTo("Expected message."); - - ComparisonFailure failure = (ComparisonFailure) expectFailure.getFailure(); - assertThat(failure.getExpected()).isEqualTo("Expected message."); - assertThat(failure.getActual()).isEqualTo("Wrong message!"); - } - - @Test - public void correctMessage() { - String expectedMessage = "Expected message."; - - Truth.assertAbout(runnables()) - .that(() -> { throw new IOException(expectedMessage); }) - .throwsAnExceptionOfType(IOException.class) - .that() - .hasMessageThat() - .isEqualTo(expectedMessage); - } - - @Test - public void getCaught() { - IllegalArgumentException cause = new IllegalArgumentException("boo"); - IOException ex = new IOException(cause); - - IOException caught = RunnableSubject.assertThat(() -> { throw ex; }) - .throwsAnExceptionOfType(IOException.class) - .getCaught(); - assertThat(caught).isSameInstanceAs(ex); - } - - @Test - public void wrongCauseType() { - IllegalArgumentException cause = new IllegalArgumentException("boo"); - IOException ex = new IOException(cause); - expectFailure.whenTesting() - .about(runnables()) - .that(() -> { throw ex; }) - .throwsAnExceptionOfType(IOException.class) - .causedByAnExceptionOfType(ExecutionException.class); - AssertionError failure = expectFailure.getFailure(); - assertThat(failure) - .factValue("value of") - .isEqualTo("runnable.thrownException().getCause()"); - assertThat(failure) - .factValue("expected instance of") - .isEqualTo("java.util.concurrent.ExecutionException"); - assertThat(failure) - .factValue("but was instance of") - .isEqualTo("java.lang.IllegalArgumentException"); - assertThat(failure) - .factValue("with value") - .isEqualTo("java.lang.IllegalArgumentException: boo"); - } - - @Test - public void correctCauseType() { - IllegalArgumentException cause = new IllegalArgumentException("boo"); - IOException ex = new IOException(cause); - - Truth.assertAbout(runnables()) - .that(() -> { throw ex; }) - .throwsAnExceptionOfType(IOException.class) - .causedByAnExceptionOfType(IllegalArgumentException.class) - .that() - .hasMessageThat() - .isEqualTo("boo"); - } - - @Test - public void causedByCorrect() { - IOException cause = new IOException(); - IllegalArgumentException ex = new IllegalArgumentException(cause); - - Truth.assertAbout(runnables()) - .that(() -> { throw ex; }) - .throwsAnExceptionOfType(IllegalArgumentException.class) - .causedBy(cause); - } - - @Test - public void causedByWrong() { - IOException cause = new IOException(); - IllegalArgumentException ex = new IllegalArgumentException(cause); - - expectFailure.whenTesting() - .about(runnables()) - .that(() -> { throw ex; }) - .throwsAnExceptionOfType(IllegalArgumentException.class) - .causedBy(new IOException()); - } - - @Test - public void exampleUsage() { - assertThatRunnable(() -> { throw new IOException("boo!"); }) - .throwsAnExceptionOfType(IOException.class) - .that() - .hasMessageThat() - .isEqualTo("boo!"); - - RunnableSubject.assertThat(() -> { throw new IllegalArgumentException("oh no"); }) - .throwsAnExceptionOfType(IllegalArgumentException.class) - .that() - .hasMessageThat() - .isEqualTo("oh no"); - - RunnableSubject - .assertThat(() -> { - throw new IllegalArgumentException(new RuntimeException("glitch")); - }) - .throwsAnExceptionOfType(IllegalArgumentException.class) - .causedByAnExceptionOfType(RuntimeException.class) - .that() - .hasMessageThat() - .isEqualTo("glitch"); - - // Recursive self-verification. - RunnableSubject - .assertThat(() - -> RunnableSubject.assertThat(() -> {}).throwsAnExceptionOfType( - RuntimeException.class)) - .throwsAnExceptionOfType(AssertionError.class); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/ui/LayoutUtilsTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/ui/LayoutUtilsTest.java deleted file mode 100644 index 931503b..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/common/ui/LayoutUtilsTest.java +++ /dev/null
@@ -1,65 +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. - -package org.chromium.chrome.browser.feed.library.common.ui; - -import static com.google.common.truth.Truth.assertThat; - -import android.content.Context; -import android.widget.LinearLayout; - -import androidx.test.core.app.ApplicationProvider; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link LayoutUtils}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class LayoutUtilsTest { - private static final int START = 1; - private static final int TOP = 2; - private static final int END = 3; - private static final int BOTTOM = 4; - - private final Context mContext = ApplicationProvider.getApplicationContext(); - - @Test - public void testSetMarginsRelative() { - LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( - LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); - LayoutUtils.setMarginsRelative(lp, START, TOP, END, BOTTOM); - assertThat(lp.leftMargin).isEqualTo(START); - assertThat(lp.rightMargin).isEqualTo(END); - assertThat(lp.topMargin).isEqualTo(TOP); - assertThat(lp.bottomMargin).isEqualTo(BOTTOM); - } - - @Test - public void testDpToPx() { - // TODO: Switch this to using @Config to set density to something different than 1. - assertThat(LayoutUtils.dpToPx(1000.0f, mContext)).isWithin(1.0e-04f).of(1000.0f); - } - - @Test - public void testPxToDp() { - // TODO: Switch this to using @Config to set density to something different than 1. - assertThat(LayoutUtils.pxToDp(1000.0f, mContext)).isWithin(1.0e-04f).of(1000.0f); - } - - @Test - public void testSpToPx() { - mContext.getResources().getDisplayMetrics().scaledDensity = 3.0f; - assertThat(LayoutUtils.spToPx(1000.0f, mContext)).isWithin(1.0e-03f).of(3000.0f); - } - - @Test - public void testPxToSp() { - mContext.getResources().getDisplayMetrics().scaledDensity = 3.0f; - assertThat(LayoutUtils.pxToSp(3000.0f, mContext)).isWithin(1.0e-04f).of(1000.0f); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedactionmanager/FeedActionManagerImplTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedactionmanager/FeedActionManagerImplTest.java deleted file mode 100644 index d230c48..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedactionmanager/FeedActionManagerImplTest.java +++ /dev/null
@@ -1,766 +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. -package org.chromium.chrome.browser.feed.library.feedactionmanager; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import android.app.Activity; -import android.graphics.Rect; -import android.view.View; - -import com.google.protobuf.ByteString; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestRule; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.base.Consumer; -import org.chromium.base.test.util.JniMocker; -import org.chromium.chrome.browser.feed.library.api.common.MutationContext; -import org.chromium.chrome.browser.feed.library.api.internal.actionmanager.ActionManager; -import org.chromium.chrome.browser.feed.library.api.internal.common.Model; -import org.chromium.chrome.browser.feed.library.api.internal.sessionmanager.FeedSessionManager; -import org.chromium.chrome.browser.feed.library.api.internal.store.LocalActionMutation; -import org.chromium.chrome.browser.feed.library.api.internal.store.LocalActionMutation.ActionType; -import org.chromium.chrome.browser.feed.library.api.internal.store.Store; -import org.chromium.chrome.browser.feed.library.api.internal.store.UploadableActionMutation; -import org.chromium.chrome.browser.feed.library.common.Result; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeMainThreadRunner; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeTaskQueue; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeThreadUtils; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.v1.FeedLoggingBridge; -import org.chromium.chrome.browser.flags.ChromeFeatureList; -import org.chromium.chrome.browser.preferences.Pref; -import org.chromium.chrome.browser.profiles.Profile; -import org.chromium.chrome.test.util.browser.Features; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamDataOperation; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamStructure; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamStructure.Operation; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamUploadableAction; -import org.chromium.components.feed.core.proto.wire.ActionPayloadProto.ActionPayload; -import org.chromium.components.feed.core.proto.wire.ConsistencyTokenProto.ConsistencyToken; -import org.chromium.components.prefs.PrefService; -import org.chromium.components.user_prefs.UserPrefs; -import org.chromium.components.user_prefs.UserPrefsJni; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.time.Duration; -import java.util.Arrays; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; - -/** Tests of the {@link FeedActionManagerImpl} class. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -@Features.DisableFeatures({ChromeFeatureList.INTEREST_FEED_V2, - ChromeFeatureList.INTEREST_FEEDV1_CLICKS_AND_VIEWS_CONDITIONAL_UPLOAD}) -@Features.EnableFeatures({ChromeFeatureList.INTEREST_FEED_CONTENT_SUGGESTIONS, - ChromeFeatureList.REPORT_FEED_USER_ACTIONS}) -public class FeedActionManagerImplTest { - private static final String CONTENT_ID_STRING = "contentIdString"; - private static final String SESSION_ID = "session"; - private static final long DEFAULT_TIME = Duration.ofDays(42).toMillis(); - private static final long DEFAULT_TIME_SECONDS = Duration.ofDays(42).getSeconds(); - // View dimensions on screen. We satisfy or violate exposure and coverage (see - // FeedActionManagerImpl.VIEW_EXPOSURE_THRESHOLD and - // FeedActionManagerImpl.VIEWPORT_COVERAGE_THRESHOLD for definitions and values). Dimensions are - // chosen according to the default exposure and coverage thresholds, and the size of the - // viewport. - private static final Rect VIEWPORT_RECT = new Rect(0, 0, 100, 100); - private static final Rect VISIBLE_RECT = new Rect(0, 0, 100, 50); - private static final Rect INVISIBLE_RECT = new Rect(0, -50, 100, 10); - // Durations for VIEW actions. Chosen according to the default VIEW duration threshold - // FeedActionManagerImpl.VIEW_DURATION_MS_THRESHOLD_DEFAULT. - private static final long LONG_DURATION_MS = 1000; - private static final long LONG_DURATION_S = Duration.ofMillis(LONG_DURATION_MS).toSeconds(); - private static final long SHORT_DURATION_MS = 400; - private static final ActionPayload ACTION_PAYLOAD = ActionPayload.getDefaultInstance(); - - private final FakeClock mFakeClock = new FakeClock(); - private final FakeMainThreadRunner mFakeMainThreadRunner = - FakeMainThreadRunner.runTasksImmediately(); - private final FakeThreadUtils mFakeThreadUtils = FakeThreadUtils.withThreadChecks(); - - @Rule - public TestRule mFeaturesProcessorRule = new Features.JUnitProcessor(); - - @Rule - public JniMocker mocker = new JniMocker(); - - @Mock - private FeedSessionManager mFeedSessionManager; - @Mock - private Store mStore; - @Mock - private LocalActionMutation mLocalActionMutation; - @Mock - private UploadableActionMutation mUploadableActionMutation; - @Mock - private Consumer<Result<Model>> mModelConsumer; - @Mock - private FeedLoggingBridge mFeedLoggingBridge; - @Mock - private Runnable mStoreViewActionsRunnable; - @Mock - private UserPrefs.Natives mUserPrefsJniMock; - @Mock - private Profile mProfile; - @Mock - private PrefService mPrefService; - - @Captor - private ArgumentCaptor<Integer> mActionTypeCaptor; - @Captor - private ArgumentCaptor<String> mContentIdStringCaptor; - @Captor - private ArgumentCaptor<Result<Model>> mModelCaptor; - @Captor - private ArgumentCaptor<MutationContext> mMutationContextCaptor; - @Captor - private ArgumentCaptor<Consumer<Result<ConsistencyToken>>> mConsumerCaptor; - @Captor - private ArgumentCaptor<Set<StreamUploadableAction>> mActionCaptor; - @Captor - private ArgumentCaptor<StreamUploadableAction> mUploadableActionCaptor; - - private FeedActionManagerImpl mActionManager; - - private TestView mViewport; - - @Before - public void setUp() throws Exception { - initMocks(this); - - mocker.mock(UserPrefsJni.TEST_HOOKS, mUserPrefsJniMock); - Profile.setLastUsedProfileForTesting(mProfile); - when(mUserPrefsJniMock.get(mProfile)).thenReturn(mPrefService); - - mActionManager = new FeedActionManagerImpl(mStore, mFakeThreadUtils, getTaskQueue(), - mFakeMainThreadRunner, new TestViewHandler(), mFakeClock, mFeedLoggingBridge); - mActionManager.initialize(mFeedSessionManager); - - when(mFeedSessionManager.getUpdateConsumer(any(MutationContext.class))) - .thenReturn(mModelConsumer); - - when(mLocalActionMutation.add(anyInt(), anyString())).thenReturn(mLocalActionMutation); - when(mStore.editLocalActions()).thenReturn(mLocalActionMutation); - - when(mUploadableActionMutation.upsert(any(StreamUploadableAction.class), anyString())) - .thenReturn(mUploadableActionMutation); - when(mStore.editUploadableActions()).thenReturn(mUploadableActionMutation); - - mFakeClock.set(DEFAULT_TIME); - mViewport = new TestView(); - mViewport.setRectOnScreen(VIEWPORT_RECT); - mActionManager.setViewport(mViewport); - mActionManager.setCanUploadClicksAndViewsWhenNoticeCardIsPresent(false); - } - - @Test - public void dismissLocal() throws Exception { - StreamDataOperation dataOperation = buildBasicDismissOperation(); - - mActionManager.dismissLocal(Collections.singletonList(CONTENT_ID_STRING), - Collections.singletonList(dataOperation), null); - - verify(mLocalActionMutation) - .add(mActionTypeCaptor.capture(), mContentIdStringCaptor.capture()); - assertThat(mActionTypeCaptor.getValue()).isEqualTo(ActionType.DISMISS); - assertThat(mContentIdStringCaptor.getValue()).isEqualTo(CONTENT_ID_STRING); - - verify(mLocalActionMutation).commit(); - - verify(mModelConsumer).accept(mModelCaptor.capture()); - Result<Model> result = mModelCaptor.getValue(); - assertThat(result.isSuccessful()).isTrue(); - List<StreamDataOperation> streamDataOperations = result.getValue().streamDataOperations; - assertThat(streamDataOperations).hasSize(1); - StreamDataOperation streamDataOperation = streamDataOperations.get(0); - assertThat(streamDataOperation).isEqualTo(dataOperation); - } - - @Test - public void dismissLocal_sessionIdSet() throws Exception { - StreamDataOperation dataOperation = buildBasicDismissOperation(); - - mActionManager.dismissLocal(Collections.singletonList(CONTENT_ID_STRING), - Collections.singletonList(dataOperation), SESSION_ID); - - verify(mLocalActionMutation) - .add(mActionTypeCaptor.capture(), mContentIdStringCaptor.capture()); - assertThat(mActionTypeCaptor.getValue()).isEqualTo(ActionType.DISMISS); - assertThat(mContentIdStringCaptor.getValue()).isEqualTo(CONTENT_ID_STRING); - - verify(mLocalActionMutation).commit(); - - verify(mFeedSessionManager).getUpdateConsumer(mMutationContextCaptor.capture()); - assertThat(mMutationContextCaptor.getValue().getRequestingSessionId()) - .isEqualTo(SESSION_ID); - - verify(mModelConsumer).accept(mModelCaptor.capture()); - Result<Model> result = mModelCaptor.getValue(); - assertThat(result.isSuccessful()).isTrue(); - List<StreamDataOperation> streamDataOperations = result.getValue().streamDataOperations; - assertThat(streamDataOperations).hasSize(1); - StreamDataOperation streamDataOperation = streamDataOperations.get(0); - assertThat(streamDataOperation).isEqualTo(dataOperation); - } - - @Test - public void dismiss() throws Exception { - StreamDataOperation dataOperation = buildBasicDismissOperation(); - - mActionManager.dismiss(Collections.singletonList(dataOperation), null); - - verify(mModelConsumer).accept(mModelCaptor.capture()); - Result<Model> result = mModelCaptor.getValue(); - assertThat(result.isSuccessful()).isTrue(); - List<StreamDataOperation> streamDataOperations = result.getValue().streamDataOperations; - assertThat(streamDataOperations).hasSize(1); - StreamDataOperation streamDataOperation = streamDataOperations.get(0); - assertThat(streamDataOperation).isEqualTo(dataOperation); - } - - @Test - public void dismiss_sessionIdSet() throws Exception { - StreamDataOperation dataOperation = buildBasicDismissOperation(); - - mActionManager.dismiss(Collections.singletonList(dataOperation), SESSION_ID); - - verify(mFeedSessionManager).getUpdateConsumer(mMutationContextCaptor.capture()); - assertThat(mMutationContextCaptor.getValue().getRequestingSessionId()) - .isEqualTo(SESSION_ID); - - verify(mModelConsumer).accept(mModelCaptor.capture()); - Result<Model> result = mModelCaptor.getValue(); - assertThat(result.isSuccessful()).isTrue(); - List<StreamDataOperation> streamDataOperations = result.getValue().streamDataOperations; - assertThat(streamDataOperations).hasSize(1); - StreamDataOperation streamDataOperation = streamDataOperations.get(0); - assertThat(streamDataOperation).isEqualTo(dataOperation); - } - - @Test - @Features.EnableFeatures(ChromeFeatureList.INTEREST_FEEDV1_CLICKS_AND_VIEWS_CONDITIONAL_UPLOAD) - public void triggerCreateAndUploadAction_whenUploadDisabled_byCantUploadWithNotice() - throws Exception { - // Set things so that, when the conditional upload feature is enabled, the upload of clicks - // and views cannot take place. - mActionManager.setCanUploadClicksAndViewsWhenNoticeCardIsPresent(false); - when(mPrefService.getBoolean(Pref.LAST_FETCH_HAD_NOTICE_CARD)).thenReturn(true); - - mFakeClock.set(DEFAULT_TIME); - mActionManager.createAndUploadAction( - CONTENT_ID_STRING, ACTION_PAYLOAD, ActionManager.UploadActionType.CLICK); - verify(mFeedSessionManager, never()).triggerUploadActions(mActionCaptor.capture()); - - triggerViewActionAndVerifyUpserted(/* expectUpserted= */ false); - } - - @Test - @Features.EnableFeatures(ChromeFeatureList.INTEREST_FEEDV1_CLICKS_AND_VIEWS_CONDITIONAL_UPLOAD) - public void triggerCreateAndUploadAction_whenUploadEnabled_byCanUploadWithNotice() - throws Exception { - mActionManager.setCanUploadClicksAndViewsWhenNoticeCardIsPresent(true); - when(mPrefService.getBoolean(Pref.LAST_FETCH_HAD_NOTICE_CARD)).thenReturn(true); - - mFakeClock.set(DEFAULT_TIME); - mActionManager.createAndUploadAction( - CONTENT_ID_STRING, ACTION_PAYLOAD, ActionManager.UploadActionType.CLICK); - verify(mFeedSessionManager).triggerUploadActions(mActionCaptor.capture()); - StreamUploadableAction action = - (StreamUploadableAction) mActionCaptor.getValue().toArray()[0]; - assertThat(action.getFeatureContentId()).isEqualTo(CONTENT_ID_STRING); - assertThat(action.getTimestampSeconds()).isEqualTo(DEFAULT_TIME_SECONDS); - assertThat(action.getPayload()).isEqualTo(ACTION_PAYLOAD); - - triggerViewActionAndVerifyUpserted(/* expectUpserted= */ true); - } - - @Test - @Features.EnableFeatures(ChromeFeatureList.INTEREST_FEEDV1_CLICKS_AND_VIEWS_CONDITIONAL_UPLOAD) - public void triggerCreateAndUploadAction_whenUploadEnabled_byNoClickAction() throws Exception { - // Set things so that, when the conditional upload feature is enabled, the upload of clicks - // and views cannot take place. - mActionManager.setCanUploadClicksAndViewsWhenNoticeCardIsPresent(false); - when(mPrefService.getBoolean(Pref.LAST_FETCH_HAD_NOTICE_CARD)).thenReturn(true); - - mFakeClock.set(DEFAULT_TIME); - mActionManager.createAndUploadAction( - CONTENT_ID_STRING, ACTION_PAYLOAD, ActionManager.UploadActionType.MISC); - verify(mFeedSessionManager).triggerUploadActions(mActionCaptor.capture()); - StreamUploadableAction action = - (StreamUploadableAction) mActionCaptor.getValue().toArray()[0]; - assertThat(action.getFeatureContentId()).isEqualTo(CONTENT_ID_STRING); - assertThat(action.getTimestampSeconds()).isEqualTo(DEFAULT_TIME_SECONDS); - assertThat(action.getPayload()).isEqualTo(ACTION_PAYLOAD); - - // Try to store a view action and verify it isn't stored because, althought explicit actions - // can be uploaded, clicks and views cannot be yet uploaded. - triggerViewActionAndVerifyUpserted(/* expectUpserted= */ false); - } - - @Test - @Features.EnableFeatures(ChromeFeatureList.INTEREST_FEEDV1_CLICKS_AND_VIEWS_CONDITIONAL_UPLOAD) - public void triggerCreateAndUploadAction_whenLogEnabled_byNoNoticeCard() throws Exception { - mActionManager.setCanUploadClicksAndViewsWhenNoticeCardIsPresent(false); - when(mPrefService.getBoolean(Pref.LAST_FETCH_HAD_NOTICE_CARD)).thenReturn(false); - - mFakeClock.set(DEFAULT_TIME); - mActionManager.createAndUploadAction( - CONTENT_ID_STRING, ACTION_PAYLOAD, ActionManager.UploadActionType.MISC); - verify(mFeedSessionManager).triggerUploadActions(mActionCaptor.capture()); - StreamUploadableAction action = - (StreamUploadableAction) mActionCaptor.getValue().toArray()[0]; - assertThat(action.getFeatureContentId()).isEqualTo(CONTENT_ID_STRING); - assertThat(action.getTimestampSeconds()).isEqualTo(DEFAULT_TIME_SECONDS); - assertThat(action.getPayload()).isEqualTo(ACTION_PAYLOAD); - - triggerViewActionAndVerifyUpserted(/* expectUpserted= */ true); - } - - @Test - @Features.DisableFeatures(ChromeFeatureList.INTEREST_FEEDV1_CLICKS_AND_VIEWS_CONDITIONAL_UPLOAD) - public void triggerCreateAndUploadAction_whenLogEnabled_byCondUploadFeatureDisabled() - throws Exception { - // Set things so that, when the conditional upload feature is enabled, the upload of clicks - // and views would not take place. - mActionManager.setCanUploadClicksAndViewsWhenNoticeCardIsPresent(false); - when(mPrefService.getBoolean(Pref.LAST_FETCH_HAD_NOTICE_CARD)).thenReturn(true); - - mFakeClock.set(DEFAULT_TIME); - mActionManager.createAndUploadAction( - CONTENT_ID_STRING, ACTION_PAYLOAD, ActionManager.UploadActionType.MISC); - verify(mFeedSessionManager).triggerUploadActions(mActionCaptor.capture()); - StreamUploadableAction action = - (StreamUploadableAction) mActionCaptor.getValue().toArray()[0]; - assertThat(action.getFeatureContentId()).isEqualTo(CONTENT_ID_STRING); - assertThat(action.getTimestampSeconds()).isEqualTo(DEFAULT_TIME_SECONDS); - assertThat(action.getPayload()).isEqualTo(ACTION_PAYLOAD); - - triggerViewActionAndVerifyUpserted(/* expectUpserted= */ true); - } - - @Test - public void triggerUploadAllActions() throws Exception { - String url = "url"; - String param = "param"; - ConsistencyToken token = ConsistencyToken.newBuilder() - .setToken(ByteString.copyFrom(new byte[] {0x1, 0x2})) - .build(); - String expectedUrl = FeedActionManagerImpl.updateParam(url, param, token.toByteArray()); - Consumer<String> consumer = result -> { - assertThat(result).isEqualTo(expectedUrl); - }; - mActionManager.uploadAllActionsAndUpdateUrl(url, param, consumer); - verify(mFeedSessionManager).fetchActionsAndUpload(mConsumerCaptor.capture()); - mConsumerCaptor.getValue().accept(Result.success(token)); - } - - @Test - public void onShow_viewTracked_coverage() { - showThenHide( - // View covers >50% (FeedActionManagerImpl.VIEWPORT_COVERAGE_THRESHOLD) of viewport, - // but <50% (FeedActionManagerImpl.VIEW_EXPOSURE_THRESHOLD) of the view is visible. - new Rect(0, -1000, 100, 51), CONTENT_ID_STRING, LONG_DURATION_MS); - verifyActionUpserted(ACTION_PAYLOAD, CONTENT_ID_STRING, LONG_DURATION_S, LONG_DURATION_MS); - } - - @Test - public void onShow_viewTracked_exposure() { - showThenHide( - // >50% (FeedActionManagerImpl.VIEW_EXPOSURE_THRESHOLD) of the view is visible, but - // it covers <50% (FeedActionManagerImpl.VIEWPORT_COVERAGE_THRESHOLD) of the - // viewport. - new Rect(0, -48, 100, 49), CONTENT_ID_STRING, LONG_DURATION_MS); - verifyActionUpserted(ACTION_PAYLOAD, CONTENT_ID_STRING, LONG_DURATION_S, LONG_DURATION_MS); - } - - @Test - public void onShow_viewTracked_noExposure_noCoverage() { - showThenHide( - // <50% (FeedActionManagerImpl.VIEW_EXPOSURE_THRESHOLD) of the view is visible and - // it covers <50% (FeedActionManagerImpl.VIEWPORT_COVERAGE_THRESHOLD) of the - // viewport. - new Rect(0, -50, 100, 49), CONTENT_ID_STRING, LONG_DURATION_MS); - verifyNoActionUpserted(); - } - - @Test - public void onShow_viewTracked_visible_tooShort() { - showThenHide(VISIBLE_RECT, CONTENT_ID_STRING, SHORT_DURATION_MS); - verifyNoActionUpserted(); - } - - @Test - public void onShow_viewTracked_visible_repeated_tooShort() { - mActionManager.onShow(); - TestView view = new TestView(); - view.setRectOnScreen(VISIBLE_RECT); - mViewport.children.add(view); - mActionManager.onViewVisible(view, CONTENT_ID_STRING, ACTION_PAYLOAD); - mFakeClock.advance(SHORT_DURATION_MS); - mActionManager.onHide(); - - mFakeClock.advance(1000); - - mActionManager.onShow(); - mActionManager.onViewVisible(view, CONTENT_ID_STRING, ACTION_PAYLOAD); - mFakeClock.advance(SHORT_DURATION_MS); - mActionManager.onHide(); - - verifyNoActionUpserted(); - } - - @Test - public void onShow_viewTracked_visible_repeated() { - mActionManager.onShow(); - TestView view = new TestView(); - view.setRectOnScreen(VISIBLE_RECT); - mViewport.children.add(view); - mActionManager.onViewVisible(view, CONTENT_ID_STRING, ACTION_PAYLOAD); - mFakeClock.advance(LONG_DURATION_MS); - mActionManager.onHide(); - - mFakeClock.advance(1000); - - mActionManager.onShow(); - mActionManager.onViewVisible(view, CONTENT_ID_STRING, ACTION_PAYLOAD); - mFakeClock.advance(LONG_DURATION_MS); - mActionManager.onHide(); - - verifyActionsUpserted(StreamUploadableAction.newBuilder() - .setFeatureContentId(CONTENT_ID_STRING) - .setPayload(ACTION_PAYLOAD) - .setTimestampSeconds(DEFAULT_TIME_SECONDS + LONG_DURATION_S) - .setDurationMs(LONG_DURATION_MS) - .build(), - StreamUploadableAction.newBuilder() - .setFeatureContentId(CONTENT_ID_STRING) - .setPayload(ACTION_PAYLOAD) - .setTimestampSeconds( - DEFAULT_TIME_SECONDS + LONG_DURATION_S + 1 + LONG_DURATION_S) - .setDurationMs(LONG_DURATION_MS) - .build()); - } - - @Features.DisableFeatures(ChromeFeatureList.REPORT_FEED_USER_ACTIONS) - @Test - public void onShow_viewTrackedVisible_featureDisabled() { - showThenHide(VISIBLE_RECT, CONTENT_ID_STRING, LONG_DURATION_MS); - verifyNoActionUpserted(); - } - - @Test - public void onShow_viewNotTracked() { - mActionManager.onShow(); - TestView view = new TestView(); - view.setRectOnScreen(VISIBLE_RECT); - mViewport.children.add(view); - mFakeClock.advance(LONG_DURATION_MS); - mActionManager.onHide(); - verifyNoActionUpserted(); - } - - @Test - public void onShow_multipleViewsTracked() { - TestView view1 = new TestView(); - TestView parentview = new TestView(); - TestView view2 = new TestView(); - TestView view3 = new TestView(); - TestView view4 = new TestView(); - - mActionManager.onShow(); - - // Four views in the viewport, in vertical sequence, all visible except the last one. - view1.setRectOnScreen(new Rect(0, 0, 100, 20)); - mViewport.children.add(view1); - view2.setRectOnScreen(new Rect(0, 30, 100, 50)); - view3.setRectOnScreen(new Rect(0, 60, 100, 80)); - view4.setRectOnScreen(new Rect(0, 90, 100, 1000)); - parentview.children.add(view2); - parentview.children.add(view3); - parentview.children.add(view4); - mViewport.children.add(parentview); - - // All views tracked except the second one. - mActionManager.onViewVisible(view1, "contentId1", ACTION_PAYLOAD); - mActionManager.onViewVisible(view3, "contentId3", ACTION_PAYLOAD); - mActionManager.onViewVisible(view4, "contentId4", ACTION_PAYLOAD); - - mFakeClock.advance(LONG_DURATION_MS); - mActionManager.onHide(); - - verifyActionsUpserted(StreamUploadableAction.newBuilder() - .setFeatureContentId("contentId1") - .setPayload(ACTION_PAYLOAD) - .setTimestampSeconds(DEFAULT_TIME_SECONDS + LONG_DURATION_S) - .setDurationMs(LONG_DURATION_MS) - .build(), - StreamUploadableAction.newBuilder() - .setFeatureContentId("contentId3") - .setPayload(ACTION_PAYLOAD) - .setTimestampSeconds(DEFAULT_TIME_SECONDS + LONG_DURATION_S) - .setDurationMs(LONG_DURATION_MS) - .build()); - } - - private void showThenHide(Rect viewRect, String contentId, long preHideDurationMs) { - mActionManager.onShow(); - TestView view = new TestView(); - view.setRectOnScreen(viewRect); - mViewport.children.add(view); - mActionManager.onViewVisible(view, contentId, ACTION_PAYLOAD); - mFakeClock.advance(preHideDurationMs); - mActionManager.onHide(); - } - - @Test - public void onScroll_visible() { - mActionManager.onShow(); - TestView view = new TestView(); - view.setRectOnScreen(INVISIBLE_RECT); - mViewport.children.add(view); - mActionManager.onViewVisible(view, CONTENT_ID_STRING, ACTION_PAYLOAD); - mActionManager.onScrollStart(); - view.setRectOnScreen(VISIBLE_RECT); - mFakeClock.advance(LONG_DURATION_MS); - mActionManager.onScrollEnd(); - mFakeClock.advance(1000); - mActionManager.onHide(); - verifyActionUpserted( - ACTION_PAYLOAD, CONTENT_ID_STRING, LONG_DURATION_S + 1, LONG_DURATION_MS); - } - - @Test - public void onScroll_notVisible() { - mActionManager.onShow(); - TestView view = new TestView(); - view.setRectOnScreen(VISIBLE_RECT); - mViewport.children.add(view); - mActionManager.onViewVisible(view, CONTENT_ID_STRING, ACTION_PAYLOAD); - mActionManager.onScrollStart(); - view.setRectOnScreen(INVISIBLE_RECT); - mFakeClock.advance(LONG_DURATION_MS); - mActionManager.onScrollEnd(); - mActionManager.onHide(); - verifyNoActionUpserted(); - } - - @Test - public void onAnimationFinished_visible() { - mActionManager.onShow(); - TestView view = new TestView(); - view.setRectOnScreen(INVISIBLE_RECT); - mViewport.children.add(view); - mActionManager.onViewVisible(view, CONTENT_ID_STRING, ACTION_PAYLOAD); - view.setRectOnScreen(VISIBLE_RECT); - mActionManager.onAnimationFinished(); - mFakeClock.advance(LONG_DURATION_MS); - mActionManager.onHide(); - verifyActionUpserted(ACTION_PAYLOAD, CONTENT_ID_STRING, LONG_DURATION_S, LONG_DURATION_MS); - } - - @Test - public void onAnimationFinished_notVisible() { - mActionManager.onShow(); - TestView view = new TestView(); - view.setRectOnScreen(VISIBLE_RECT); - mViewport.children.add(view); - mActionManager.onViewVisible(view, CONTENT_ID_STRING, ACTION_PAYLOAD); - view.setRectOnScreen(INVISIBLE_RECT); - mActionManager.onAnimationFinished(); - mFakeClock.advance(LONG_DURATION_MS); - mActionManager.onHide(); - verifyNoActionUpserted(); - } - - @Test - public void onLayoutChange_visible() { - mActionManager.onShow(); - TestView view = new TestView(); - view.setRectOnScreen(INVISIBLE_RECT); - mViewport.children.add(view); - mActionManager.onViewVisible(view, CONTENT_ID_STRING, ACTION_PAYLOAD); - view.setRectOnScreen(VISIBLE_RECT); - mFakeClock.advance(LONG_DURATION_MS); - mActionManager.onLayoutChange(); - mFakeClock.advance(1000); - mActionManager.onHide(); - verifyActionUpserted( - ACTION_PAYLOAD, CONTENT_ID_STRING, LONG_DURATION_S + 1, LONG_DURATION_MS); - } - - @Test - public void onLayoutChange_notVisible() { - mActionManager.onShow(); - TestView view = new TestView(); - view.setRectOnScreen(VISIBLE_RECT); - mViewport.children.add(view); - mActionManager.onViewVisible(view, CONTENT_ID_STRING, ACTION_PAYLOAD); - view.setRectOnScreen(INVISIBLE_RECT); - mActionManager.onLayoutChange(); - mFakeClock.advance(LONG_DURATION_MS); - mActionManager.onHide(); - verifyNoActionUpserted(); - } - - @Test - public void storeViewActions() { - mActionManager.onShow(); - TestView view = new TestView(); - view.setRectOnScreen(VISIBLE_RECT); - mViewport.children.add(view); - mActionManager.onViewVisible(view, CONTENT_ID_STRING, ACTION_PAYLOAD); - mFakeClock.advance(LONG_DURATION_MS); - mActionManager.onLayoutChange(); - verifyNoActionUpserted(); - mActionManager.storeViewActions(() -> { - verifyActionUpserted( - ACTION_PAYLOAD, CONTENT_ID_STRING, LONG_DURATION_S, LONG_DURATION_MS); - mStoreViewActionsRunnable.run(); - }); - verify(mStoreViewActionsRunnable).run(); - } - - @Test - public void storeViewActions_calledbackNoActions() { - mActionManager.storeViewActions(() -> { - verifyNoActionUpserted(); - mStoreViewActionsRunnable.run(); - }); - verify(mStoreViewActionsRunnable, times(1)).run(); - } - - private void verifyActionUpserted( - ActionPayload payload, String contentId, long elapsedTimeS, long durationMs) { - verifyActionsUpserted(StreamUploadableAction.newBuilder() - .setFeatureContentId(contentId) - .setPayload(payload) - .setTimestampSeconds(DEFAULT_TIME_SECONDS + elapsedTimeS) - .setDurationMs(durationMs) - .build()); - } - - private void verifyActionsUpserted(StreamUploadableAction... actions) { - verify(mUploadableActionMutation, times(actions.length)) - .upsert(mUploadableActionCaptor.capture(), mContentIdStringCaptor.capture()); - assertThat(mUploadableActionCaptor.getAllValues()) - .containsExactlyElementsIn(Arrays.asList(actions)); - List<String> contentIds = new LinkedList<>(); - for (StreamUploadableAction action : actions) { - contentIds.add(action.getFeatureContentId()); - } - assertThat(mContentIdStringCaptor.getAllValues()).containsExactlyElementsIn(contentIds); - } - - private void verifyNoActionUpserted() { - verify(mUploadableActionMutation, never()) - .upsert(any(StreamUploadableAction.class), anyString()); - } - - private StreamDataOperation buildBasicDismissOperation() { - return StreamDataOperation.newBuilder() - .setStreamStructure(StreamStructure.newBuilder() - .setContentId(CONTENT_ID_STRING) - .setOperation(Operation.REMOVE)) - .build(); - } - - private void setUpDismissMocks() { - when(mFeedSessionManager.getUpdateConsumer(any(MutationContext.class))) - .thenReturn(mModelConsumer); - when(mLocalActionMutation.add(anyInt(), anyString())).thenReturn(mLocalActionMutation); - when(mStore.editLocalActions()).thenReturn(mLocalActionMutation); - } - - private void setupCreateAndStoreMocks() { - when(mUploadableActionMutation.upsert(any(StreamUploadableAction.class), anyString())) - .thenReturn(mUploadableActionMutation); - when(mStore.editUploadableActions()).thenReturn(mUploadableActionMutation); - } - - private FakeTaskQueue getTaskQueue() { - FakeTaskQueue fakeTaskQueue = new FakeTaskQueue(mFakeClock, mFakeThreadUtils); - fakeTaskQueue.initialize(() -> {}); - return fakeTaskQueue; - } - - private class TestView extends View { - private Rect mRectOnScreen; - public final List<View> children = new LinkedList<>(); - - public TestView() { - super(Robolectric.buildActivity(Activity.class).get()); - mRectOnScreen = new Rect(0, 0, 0, 0); - } - - public void setRectOnScreen(Rect rect) { - mRectOnScreen = new Rect(rect); - } - - public Rect getRectOnScreen() { - return new Rect(mRectOnScreen); - } - } - - private class TestViewHandler extends FeedActionManagerImpl.ViewHandler { - @Override - public int getChildCount(View view) { - return ((TestView) view).children.size(); - } - - @Override - public View getChildAt(View view, int index) { - return ((TestView) view).children.get(index); - } - - @Override - public Rect getRectOnScreen(View view) { - return ((TestView) view).getRectOnScreen(); - } - } - - private void triggerViewActionAndVerifyUpserted(boolean expectUpserted) { - mActionManager.onShow(); - TestView view = new TestView(); - view.setRectOnScreen(VISIBLE_RECT); - mViewport.children.add(view); - mActionManager.onViewVisible(view, CONTENT_ID_STRING, ACTION_PAYLOAD); - mFakeClock.advance(LONG_DURATION_MS); - mActionManager.onHide(); - - if (expectUpserted) { - verifyActionsUpserted( - StreamUploadableAction.newBuilder() - .setFeatureContentId(CONTENT_ID_STRING) - .setPayload(ACTION_PAYLOAD) - .setTimestampSeconds(DEFAULT_TIME_SECONDS + LONG_DURATION_S) - .setDurationMs(LONG_DURATION_MS) - .build()); - } else { - verify(mUploadableActionMutation, never()) - .upsert(mUploadableActionCaptor.capture(), mContentIdStringCaptor.capture()); - } - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedactionparser/FeedActionParserTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedactionparser/FeedActionParserTest.java deleted file mode 100644 index 93f22d6..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedactionparser/FeedActionParserTest.java +++ /dev/null
@@ -1,1072 +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. - -package org.chromium.chrome.browser.feed.library.feedactionparser; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import android.app.Activity; -import android.content.Context; -import android.view.View; - -import com.google.common.collect.Lists; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.ArgumentMatchers; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.client.knowncontent.ContentMetadata; -import org.chromium.chrome.browser.feed.library.api.host.action.StreamActionApi; -import org.chromium.chrome.browser.feed.library.api.host.logging.ActionType; -import org.chromium.chrome.browser.feed.library.api.host.logging.BasicLoggingApi; -import org.chromium.chrome.browser.feed.library.api.host.logging.InternalFeedError; -import org.chromium.chrome.browser.feed.library.api.host.stream.TooltipInfo; -import org.chromium.chrome.browser.feed.library.api.internal.actionparser.ActionSource; -import org.chromium.chrome.browser.feed.library.api.internal.protocoladapter.ProtocolAdapter; -import org.chromium.chrome.browser.feed.library.feedactionparser.internal.PietFeedActionPayloadRetriever; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamDataOperation; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamStructure; -import org.chromium.components.feed.core.proto.ui.action.FeedActionPayloadProto.FeedActionPayload; -import org.chromium.components.feed.core.proto.ui.action.FeedActionProto.BlockContentData; -import org.chromium.components.feed.core.proto.ui.action.FeedActionProto.DismissData; -import org.chromium.components.feed.core.proto.ui.action.FeedActionProto.FeedAction; -import org.chromium.components.feed.core.proto.ui.action.FeedActionProto.FeedActionMetadata; -import org.chromium.components.feed.core.proto.ui.action.FeedActionProto.FeedActionMetadata.ElementType; -import org.chromium.components.feed.core.proto.ui.action.FeedActionProto.FeedActionMetadata.Type; -import org.chromium.components.feed.core.proto.ui.action.FeedActionProto.Insets; -import org.chromium.components.feed.core.proto.ui.action.FeedActionProto.LabelledFeedActionData; -import org.chromium.components.feed.core.proto.ui.action.FeedActionProto.NotInterestedInData; -import org.chromium.components.feed.core.proto.ui.action.FeedActionProto.OpenContextMenuData; -import org.chromium.components.feed.core.proto.ui.action.FeedActionProto.OpenUrlData; -import org.chromium.components.feed.core.proto.ui.action.FeedActionProto.TooltipData; -import org.chromium.components.feed.core.proto.ui.action.FeedActionProto.TooltipData.FeatureName; -import org.chromium.components.feed.core.proto.ui.action.FeedActionProto.UndoAction; -import org.chromium.components.feed.core.proto.ui.action.FeedActionProto.ViewReportData; -import org.chromium.components.feed.core.proto.ui.action.PietExtensionsProto.PietFeedActionPayload; -import org.chromium.components.feed.core.proto.ui.piet.ActionsProto.Action; -import org.chromium.components.feed.core.proto.ui.piet.LogDataProto.LogData; -import org.chromium.components.feed.core.proto.wire.ActionPayloadProto.ActionPayload; -import org.chromium.components.feed.core.proto.wire.ContentIdProto.ContentId; -import org.chromium.components.feed.core.proto.wire.DataOperationProto.DataOperation; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.List; - -/** Tests for {@link FeedActionParser}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class FeedActionParserTest { - private static final String URL = "www.google.com"; - private static final String PARAM = "param"; - - // clang-format off - - private static final ContentId CONTENT_ID = ContentId.newBuilder().setId(123).build(); - - private static final String CONTENT_ID_STRING = "contentId"; - - private static final FeedActionPayload OPEN_URL_FEED_ACTION = - FeedActionPayload.newBuilder() - .setExtension(FeedAction.feedActionExtension, - FeedAction.newBuilder() - .setMetadata( - FeedActionMetadata.newBuilder() - .setType(Type.OPEN_URL) - .setOpenUrlData( - OpenUrlData.newBuilder().setUrl(URL))) - .build()) - .build(); - - private static final FeedActionPayload OPEN_URL_WITH_PARAM_FEED_ACTION = - FeedActionPayload.newBuilder() - .setExtension(FeedAction.feedActionExtension, - FeedAction.newBuilder() - .setMetadata( - FeedActionMetadata.newBuilder() - .setType(Type.OPEN_URL) - .setOpenUrlData( - OpenUrlData.newBuilder() - .setUrl(URL) - .setConsistencyTokenQueryParamName( - PARAM))) - .build()) - .build(); - - private static final FeedActionPayload OPEN_URL_WITH_CLICK_PAYLOAD_FEED_ACTION = - FeedActionPayload.newBuilder() - .setExtension(FeedAction.feedActionExtension, - FeedAction.newBuilder() - .setMetadata( - FeedActionMetadata.newBuilder() - .setType(Type.OPEN_URL) - .setOpenUrlData( - OpenUrlData.newBuilder() - .setUrl(URL) - .setContentId(CONTENT_ID) - .setPayload(ActionPayload.getDefaultInstance()))) - .build()) - .build(); - - private static final FeedActionPayload CONTEXT_MENU_FEED_ACTION = - FeedActionPayload.newBuilder() - .setExtension(FeedAction.feedActionExtension, - FeedAction.newBuilder() - .setMetadata( - FeedActionMetadata.newBuilder() - .setType(Type.OPEN_CONTEXT_MENU) - .setOpenContextMenuData( - OpenContextMenuData.newBuilder().addContextMenuData( - LabelledFeedActionData - .newBuilder() - .setLabel("Open url") - .setFeedActionPayload( - OPEN_URL_FEED_ACTION)))) - .build()) - .build(); - - private static final FeedActionPayload OPEN_URL_NEW_WINDOW_FEED_ACTION = - FeedActionPayload.newBuilder() - .setExtension(FeedAction.feedActionExtension, - FeedAction.newBuilder() - .setMetadata( - FeedActionMetadata.newBuilder() - .setType(Type.OPEN_URL_NEW_WINDOW) - .setOpenUrlData( - OpenUrlData.newBuilder().setUrl(URL))) - .build()) - .build(); - private static final FeedActionPayload OPEN_URL_NEW_WINDOW_WITH_PARAM_FEED_ACTION = - FeedActionPayload.newBuilder() - .setExtension(FeedAction.feedActionExtension, - FeedAction.newBuilder() - .setMetadata( - FeedActionMetadata.newBuilder() - .setType(Type.OPEN_URL_NEW_WINDOW) - .setOpenUrlData( - OpenUrlData.newBuilder() - .setUrl(URL) - .setConsistencyTokenQueryParamName( - PARAM))) - .build()) - .build(); - - private static final FeedActionPayload OPEN_URL_INCOGNITO_FEED_ACTION = - FeedActionPayload.newBuilder() - .setExtension(FeedAction.feedActionExtension, - FeedAction.newBuilder() - .setMetadata( - FeedActionMetadata.newBuilder() - .setType(Type.OPEN_URL_INCOGNITO) - .setOpenUrlData( - OpenUrlData.newBuilder().setUrl(URL))) - .build()) - .build(); - - private static final FeedActionPayload OPEN_URL_INCOGNITO_WITH_CLICK_PAYLOAD_FEED_ACTION = - FeedActionPayload.newBuilder() - .setExtension(FeedAction.feedActionExtension, - FeedAction.newBuilder() - .setMetadata( - FeedActionMetadata.newBuilder() - .setType(Type.OPEN_URL_INCOGNITO) - .setOpenUrlData( - OpenUrlData.newBuilder() - .setUrl(URL) - .setContentId(CONTENT_ID) - .setPayload(ActionPayload.getDefaultInstance()))) - .build()) - .build(); - - private static final FeedActionPayload OPEN_URL_INCOGNITO_WITH_PARAM_FEED_ACTION = - FeedActionPayload.newBuilder() - .setExtension(FeedAction.feedActionExtension, - FeedAction.newBuilder() - .setMetadata( - FeedActionMetadata.newBuilder() - .setType(Type.OPEN_URL_INCOGNITO) - .setOpenUrlData( - OpenUrlData.newBuilder() - .setUrl(URL) - .setConsistencyTokenQueryParamName( - PARAM))) - .build()) - .build(); - - - - private static final FeedActionPayload OPEN_URL_NEW_TAB_FEED_ACTION = - FeedActionPayload.newBuilder() - .setExtension(FeedAction.feedActionExtension, - FeedAction.newBuilder() - .setMetadata( - FeedActionMetadata.newBuilder() - .setType(Type.OPEN_URL_NEW_TAB) - .setOpenUrlData( - OpenUrlData.newBuilder().setUrl(URL))) - .build()) - .build(); - private static final FeedActionPayload OPEN_URL_NEW_TAB_WITH_PARAM_FEED_ACTION = - FeedActionPayload.newBuilder() - .setExtension(FeedAction.feedActionExtension, - FeedAction.newBuilder() - .setMetadata( - FeedActionMetadata.newBuilder() - .setType(Type.OPEN_URL_NEW_TAB) - .setOpenUrlData( - OpenUrlData.newBuilder() - .setUrl(URL) - .setConsistencyTokenQueryParamName( - PARAM))) - .build()) - .build(); - - private static final FeedActionPayload DOWNLOAD_URL_FEED_ACTION = - FeedActionPayload.newBuilder() - .setExtension(FeedAction.feedActionExtension, - FeedAction.newBuilder() - .setMetadata(FeedActionMetadata.newBuilder() - .setType(Type.DOWNLOAD) - .build()) - .build()) - .build(); - - private static final FeedActionPayload LEARN_MORE_FEED_ACTION = - FeedActionPayload.newBuilder() - .setExtension(FeedAction.feedActionExtension, - FeedAction.newBuilder() - .setMetadata(FeedActionMetadata.newBuilder().setType( - Type.LEARN_MORE)) - .build()) - .build(); - - private static final FeedActionPayload MANAGE_INTERESTS_FEED_ACTION = - FeedActionPayload.newBuilder() - .setExtension(FeedAction.feedActionExtension, - FeedAction.newBuilder() - .setMetadata( - FeedActionMetadata.newBuilder() - .setType(Type.OPEN_URL) - .setOpenUrlData( - OpenUrlData.newBuilder().setUrl( - FeedActionParser.EXPECTED_MANAGE_INTERESTS_URL))) - .build()) - .build(); - - private static final FeedActionPayload SEND_FEEDBACK_FEED_ACTION = - FeedActionPayload.newBuilder() - .setExtension(FeedAction.feedActionExtension, - FeedAction.newBuilder() - .setMetadata(FeedActionMetadata.newBuilder().setType( - Type.SEND_FEEDBACK)) - .build()) - .build(); - - private static final Action OPEN_URL_ACTION = - Action.newBuilder() - .setExtension(PietFeedActionPayload.pietFeedActionPayloadExtension, - PietFeedActionPayload.newBuilder() - .setFeedActionPayload(OPEN_URL_FEED_ACTION) - .build()) - .build(); - - private static final Action OPEN_URL_WITH_PARAM_ACTION = - Action.newBuilder() - .setExtension(PietFeedActionPayload.pietFeedActionPayloadExtension, - PietFeedActionPayload.newBuilder() - .setFeedActionPayload(OPEN_URL_WITH_PARAM_FEED_ACTION) - .build()) - .build(); - - private static final Action OPEN_URL_WITH_CLICK_PAYLOAD_ACTION = - Action.newBuilder() - .setExtension(PietFeedActionPayload.pietFeedActionPayloadExtension, - PietFeedActionPayload.newBuilder() - .setFeedActionPayload(OPEN_URL_WITH_CLICK_PAYLOAD_FEED_ACTION) - .build()) - .build(); - - private static final Action OPEN_INCOGNITO_ACTION = - Action.newBuilder() - .setExtension(PietFeedActionPayload.pietFeedActionPayloadExtension, - PietFeedActionPayload.newBuilder() - .setFeedActionPayload(OPEN_URL_INCOGNITO_FEED_ACTION) - .build()) - .build(); - - private static final Action OPEN_INCOGNITO_WITH_CLICK_PAYLOAD_ACTION = - Action.newBuilder() - .setExtension(PietFeedActionPayload.pietFeedActionPayloadExtension, - PietFeedActionPayload.newBuilder() - .setFeedActionPayload(OPEN_URL_INCOGNITO_WITH_CLICK_PAYLOAD_FEED_ACTION) - .build()) - .build(); - - private static final Action OPEN_INCOGNITO_WITH_PARAM_ACTION = - Action.newBuilder() - .setExtension(PietFeedActionPayload.pietFeedActionPayloadExtension, - PietFeedActionPayload.newBuilder() - .setFeedActionPayload(OPEN_URL_INCOGNITO_WITH_PARAM_FEED_ACTION) - .build()) - .build(); - - private static final Action OPEN_NEW_WINDOW_ACTION = - Action.newBuilder() - .setExtension(PietFeedActionPayload.pietFeedActionPayloadExtension, - PietFeedActionPayload.newBuilder() - .setFeedActionPayload(OPEN_URL_NEW_WINDOW_FEED_ACTION) - .build()) - .build(); - private static final Action OPEN_NEW_WINDOW_WITH_PARAM_ACTION = - Action.newBuilder() - .setExtension(PietFeedActionPayload.pietFeedActionPayloadExtension, - PietFeedActionPayload.newBuilder() - .setFeedActionPayload( - OPEN_URL_NEW_WINDOW_WITH_PARAM_FEED_ACTION) - .build()) - .build(); - private static final Action OPEN_NEW_TAB_ACTION = - Action.newBuilder() - .setExtension(PietFeedActionPayload.pietFeedActionPayloadExtension, - PietFeedActionPayload.newBuilder() - .setFeedActionPayload(OPEN_URL_NEW_TAB_FEED_ACTION) - .build()) - .build(); - private static final Action OPEN_NEW_TAB_WITH_PARAM_ACTION = - Action.newBuilder() - .setExtension(PietFeedActionPayload.pietFeedActionPayloadExtension, - PietFeedActionPayload.newBuilder() - .setFeedActionPayload(OPEN_URL_NEW_TAB_WITH_PARAM_FEED_ACTION) - .build()) - .build(); - - private static final Action LEARN_MORE_ACTION = - Action.newBuilder() - .setExtension(PietFeedActionPayload.pietFeedActionPayloadExtension, - PietFeedActionPayload.newBuilder() - .setFeedActionPayload(LEARN_MORE_FEED_ACTION) - .build()) - .build(); - - private static final Action MANAGE_INTERESTS_ACTION = - Action.newBuilder() - .setExtension(PietFeedActionPayload.pietFeedActionPayloadExtension, - PietFeedActionPayload.newBuilder() - .setFeedActionPayload(MANAGE_INTERESTS_FEED_ACTION) - .build()) - .build(); - - private static final Action SEND_FEEDBACK_ACTION = - Action.newBuilder() - .setExtension(PietFeedActionPayload.pietFeedActionPayloadExtension, - PietFeedActionPayload.newBuilder() - .setFeedActionPayload(SEND_FEEDBACK_FEED_ACTION) - .build()) - .build(); - - private static final UndoAction UNDO_ACTION = - UndoAction.newBuilder().setConfirmationLabel("confirmation").build(); - - private static final FeedActionPayload DISMISS_LOCAL_FEED_ACTION = - FeedActionPayload.newBuilder() - .setExtension(FeedAction.feedActionExtension, - FeedAction.newBuilder() - .setMetadata( - FeedActionMetadata.newBuilder() - .setType(Type.DISMISS_LOCAL) - .setDismissData( - DismissData.newBuilder() - .addDataOperations( - DataOperation - .getDefaultInstance()) - .setContentId( - CONTENT_ID) - .setUndoAction(UNDO_ACTION))) - .build()) - .build(); - - private static final FeedActionPayload BLOCK_CONTENT_ACTION = - FeedActionPayload.newBuilder() - .setExtension(FeedAction.feedActionExtension, - FeedAction.newBuilder() - .setMetadata( - FeedActionMetadata.newBuilder() - .setType(Type.BLOCK_CONTENT) - .setBlockContentData( - BlockContentData.newBuilder() - .addDataOperations( - DataOperation - .getDefaultInstance()) - .setPayload(ActionPayload.getDefaultInstance()) - )) - .build()) - .build(); - - private static final FeedActionPayload NOT_INTERESTED_IN = - FeedActionPayload.newBuilder() - .setExtension(FeedAction.feedActionExtension, - FeedAction.newBuilder() - .setMetadata( - FeedActionMetadata.newBuilder() - .setType(Type.NOT_INTERESTED_IN) - .setNotInterestedInData( - NotInterestedInData.newBuilder() - .addDataOperations( - DataOperation - .getDefaultInstance()) - .setInterestTypeValue( - NotInterestedInData - .RecordedInterestType - .SOURCE - .getNumber()) - .setPayload( - ActionPayload - .getDefaultInstance()) - .setUndoAction(UNDO_ACTION))) - .build()) - .build(); - - private static final FeedActionPayload VIEW_ELEMENT = - FeedActionPayload.newBuilder() - .setExtension(FeedAction.feedActionExtension, - FeedAction.newBuilder() - .setMetadata( - FeedActionMetadata.newBuilder() - .setType(Type.VIEW_ELEMENT) - .setElementTypeValue(ElementType.INTEREST_HEADER - .getNumber())) - .build()) - .build(); - - private static final FeedActionPayload HIDE_ELEMENT = - FeedActionPayload.newBuilder() - .setExtension(FeedAction.feedActionExtension, - FeedAction.newBuilder() - .setMetadata( - FeedActionMetadata.newBuilder() - .setType(Type.HIDE_ELEMENT) - .setElementTypeValue(ElementType.INTEREST_HEADER - .getNumber())) - .build()) - .build(); - - private static final FeedActionPayload CLICK_ELEMENT = - FeedActionPayload.newBuilder() - .setExtension(FeedAction.feedActionExtension, - FeedAction.newBuilder() - .setMetadata( - FeedActionMetadata.newBuilder() - .setType(Type.HIDE_ELEMENT) - .setElementTypeValue(ElementType.INTEREST_HEADER - .getNumber())) - .build()) - .build(); - - private static final FeedActionPayload DISMISS_LOCAL_FEED_ACTION_NO_CONTENT_ID = - FeedActionPayload.newBuilder() - .setExtension(FeedAction.feedActionExtension, - FeedAction.newBuilder() - .setMetadata( - FeedActionMetadata.newBuilder() - .setType(Type.DISMISS_LOCAL) - .setDismissData( - DismissData.newBuilder().addDataOperations( - DataOperation - .getDefaultInstance()))) - .build()) - .build(); - - private static final ContentMetadata CONTENT_METADATA = new ContentMetadata(URL, "title", - /* timePublished= */ -1, - /* imageUrl= */ null, - /* publisher= */ null, - /* faviconUrl= */ null, - /* snippet= */ null); - - private static final FeedActionPayload OPEN_URL_MISSING_URL = - FeedActionPayload.newBuilder() - .setExtension(FeedAction.feedActionExtension, - FeedAction.newBuilder() - .setMetadata(FeedActionMetadata.newBuilder() - .setType(Type.OPEN_URL) - .setOpenUrlData( - OpenUrlData.getDefaultInstance())) - .build()) - .build(); - - @Mock - private StreamActionApi mStreamActionApi; - @Mock - private ProtocolAdapter mProtocolAdapter; - @Mock - private BasicLoggingApi mBasicLoggingApi; - - List<StreamDataOperation> mStreamDataOperations = Lists.newArrayList( - StreamDataOperation.newBuilder() - .setStreamStructure( - StreamStructure.newBuilder().setContentId("dataOpContentId")) - .build()); - - private FeedActionParser mFeedActionParser; - - // clang-format on - - @Before - public void setup() { - initMocks(this); - when(mProtocolAdapter.getStreamContentId(CONTENT_ID)).thenReturn(CONTENT_ID_STRING); - mFeedActionParser = new FeedActionParser(mProtocolAdapter, - new PietFeedActionPayloadRetriever(), () -> CONTENT_METADATA, mBasicLoggingApi); - } - - @Test - public void testParseAction() { - when(mStreamActionApi.canOpenUrl()).thenReturn(true); - mFeedActionParser.parseAction(OPEN_URL_ACTION, mStreamActionApi, - /* view= */ null, LogData.getDefaultInstance(), ActionSource.CLICK); - - verify(mStreamActionApi).openUrl(URL); - verify(mStreamActionApi).onClientAction(ActionType.OPEN_URL); - } - - @Test - public void testParseAction_manageInterests() { - when(mStreamActionApi.canOpenUrl()).thenReturn(true); - mFeedActionParser.parseAction(MANAGE_INTERESTS_ACTION, mStreamActionApi, - /* view= */ null, LogData.getDefaultInstance(), ActionSource.CLICK); - - verify(mStreamActionApi).openUrl(FeedActionParser.EXPECTED_MANAGE_INTERESTS_URL); - verify(mStreamActionApi).onClientAction(ActionType.MANAGE_INTERESTS); - } - - @Test - public void testParseAction_openUrlWithParam() { - when(mStreamActionApi.canOpenUrl()).thenReturn(true); - mFeedActionParser.parseAction(OPEN_URL_WITH_PARAM_ACTION, mStreamActionApi, - /* view= */ null, LogData.getDefaultInstance(), ActionSource.CLICK); - - verify(mStreamActionApi).openUrl(URL, PARAM); - verify(mStreamActionApi).onClientAction(ActionType.OPEN_URL); - } - - @Test - public void testParseAction_newWindow() { - when(mStreamActionApi.canOpenUrlInNewWindow()).thenReturn(true); - mFeedActionParser.parseAction(OPEN_NEW_WINDOW_ACTION, mStreamActionApi, - /* view= */ null, LogData.getDefaultInstance(), ActionSource.CLICK); - - verify(mStreamActionApi).openUrlInNewWindow(URL); - verify(mStreamActionApi).onClientAction(ActionType.OPEN_URL_NEW_WINDOW); - } - - @Test - public void testParseAction_newWindowWithParam() { - when(mStreamActionApi.canOpenUrlInNewWindow()).thenReturn(true); - mFeedActionParser.parseAction(OPEN_NEW_WINDOW_WITH_PARAM_ACTION, mStreamActionApi, - /* view= */ null, LogData.getDefaultInstance(), ActionSource.CLICK); - - verify(mStreamActionApi).openUrlInNewWindow(URL, PARAM); - verify(mStreamActionApi).onClientAction(ActionType.OPEN_URL_NEW_WINDOW); - } - - @Test - public void testParseAction_incognito() { - when(mStreamActionApi.canOpenUrlInIncognitoMode()).thenReturn(true); - mFeedActionParser.parseAction(OPEN_INCOGNITO_ACTION, mStreamActionApi, - /* view= */ null, LogData.getDefaultInstance(), ActionSource.CLICK); - - verify(mStreamActionApi).openUrlInIncognitoMode(URL); - verify(mStreamActionApi).onClientAction(ActionType.OPEN_URL_INCOGNITO); - } - - @Test - public void testParseAction_incognitoWithParam() { - when(mStreamActionApi.canOpenUrlInIncognitoMode()).thenReturn(true); - mFeedActionParser.parseAction(OPEN_INCOGNITO_WITH_PARAM_ACTION, mStreamActionApi, - /* view= */ null, LogData.getDefaultInstance(), ActionSource.CLICK); - - verify(mStreamActionApi).openUrlInIncognitoMode(URL, PARAM); - verify(mStreamActionApi).onClientAction(ActionType.OPEN_URL_INCOGNITO); - } - - @Test - public void testParseAction_incognitoNoClickAction() { - when(mStreamActionApi.canOpenUrlInIncognitoMode()).thenReturn(true); - mFeedActionParser.parseAction(OPEN_INCOGNITO_ACTION, mStreamActionApi, - /* view= */ null, LogData.getDefaultInstance(), ActionSource.CLICK); - - verify(mStreamActionApi, never()).reportClickAction(anyString(), any(ActionPayload.class)); - - verify(mStreamActionApi).openUrlInIncognitoMode(URL); - verify(mStreamActionApi).onClientAction(ActionType.OPEN_URL_INCOGNITO); - } - - @Test - public void testParseAction_newTab() { - when(mStreamActionApi.canOpenUrlInNewTab()).thenReturn(true); - mFeedActionParser.parseAction(OPEN_NEW_TAB_ACTION, mStreamActionApi, - /* view= */ null, LogData.getDefaultInstance(), ActionSource.CLICK); - - verify(mStreamActionApi).openUrlInNewTab(URL); - verify(mStreamActionApi).onClientAction(ActionType.OPEN_URL_NEW_TAB); - } - - @Test - public void testParseAction_newTabWithParam() { - when(mStreamActionApi.canOpenUrlInNewTab()).thenReturn(true); - mFeedActionParser.parseAction(OPEN_NEW_TAB_WITH_PARAM_ACTION, mStreamActionApi, - /* view= */ null, LogData.getDefaultInstance(), ActionSource.CLICK); - - verify(mStreamActionApi).openUrlInNewTab(URL, PARAM); - verify(mStreamActionApi).onClientAction(ActionType.OPEN_URL_NEW_TAB); - } - - @Test - public void testParseAction_withClickAction() { - when(mStreamActionApi.canOpenUrl()).thenReturn(true); - mFeedActionParser.parseAction(OPEN_URL_WITH_CLICK_PAYLOAD_ACTION, mStreamActionApi, - /* view= */ null, LogData.getDefaultInstance(), ActionSource.CLICK); - - verify(mStreamActionApi) - .reportClickAction(CONTENT_ID_STRING, ActionPayload.getDefaultInstance()); - - verify(mStreamActionApi).openUrl(URL); - verify(mStreamActionApi).onClientAction(ActionType.OPEN_URL); - } - - @Test - public void testParseAction_contextMenu() { - Context context = Robolectric.buildActivity(Activity.class).get(); - View view = new View(context); - - when(mStreamActionApi.canOpenContextMenu()).thenReturn(true); - PietFeedActionPayload contextMenuPietFeedAction = - PietFeedActionPayload.newBuilder() - .setFeedActionPayload(CONTEXT_MENU_FEED_ACTION) - .build(); - - mFeedActionParser.parseAction( - Action.newBuilder() - .setExtension(PietFeedActionPayload.pietFeedActionPayloadExtension, - contextMenuPietFeedAction) - .build(), - mStreamActionApi, - /* view= */ view, LogData.getDefaultInstance(), ActionSource.CLICK); - - verify(mStreamActionApi) - .openContextMenu(contextMenuPietFeedAction.getFeedActionPayload() - .getExtension(FeedAction.feedActionExtension) - .getMetadata() - .getOpenContextMenuData(), - view); - } - - @Test - public void testParseAction_downloadUrl() { - when(mStreamActionApi.canDownloadUrl()).thenReturn(true); - mFeedActionParser.parseFeedActionPayload( - DOWNLOAD_URL_FEED_ACTION, mStreamActionApi, /* view= */ null, ActionSource.CLICK); - verify(mStreamActionApi).downloadUrl(CONTENT_METADATA); - verify(mStreamActionApi).onClientAction(ActionType.DOWNLOAD); - } - - @Test - public void testParseAction_reportViewVisible() { - FeedAction reportViewAction = - FeedAction.newBuilder() - .setMetadata( - FeedActionMetadata.newBuilder() - .setType(Type.REPORT_VIEW) - .setViewReportData( - ViewReportData.newBuilder() - .setContentId(CONTENT_ID) - .setVisibility( - ViewReportData.Visibility.SHOW) - .setPayload(ActionPayload - .getDefaultInstance()))) - .build(); - - FeedActionPayload reportViewActionPayload = - FeedActionPayload.newBuilder() - .setExtension(FeedAction.feedActionExtension, reportViewAction) - .build(); - - View view = new View(Robolectric.buildActivity(Activity.class).get()); - - mFeedActionParser.parseFeedActionPayload( - reportViewActionPayload, mStreamActionApi, view, ActionSource.VIEW); - verify(mStreamActionApi) - .reportViewVisible(view, CONTENT_ID_STRING, ActionPayload.getDefaultInstance()); - } - - @Test - public void testParseAction_reportViewHidden() { - FeedAction reportViewAction = - FeedAction.newBuilder() - .setMetadata( - FeedActionMetadata.newBuilder() - .setType(Type.REPORT_VIEW) - .setViewReportData( - ViewReportData.newBuilder() - .setContentId(CONTENT_ID) - .setVisibility( - ViewReportData.Visibility.HIDE) - .setPayload(ActionPayload - .getDefaultInstance()))) - .build(); - - FeedActionPayload reportViewActionPayload = - FeedActionPayload.newBuilder() - .setExtension(FeedAction.feedActionExtension, reportViewAction) - .build(); - - View view = new View(Robolectric.buildActivity(Activity.class).get()); - - mFeedActionParser.parseFeedActionPayload( - reportViewActionPayload, mStreamActionApi, view, ActionSource.VIEW); - verify(mStreamActionApi).reportViewHidden(view, CONTENT_ID_STRING); - } - - @Test - public void testCanPerformActionFromContextMenu_openUrl() { - when(mStreamActionApi.canOpenUrl()).thenReturn(true); - assertThat(mFeedActionParser.canPerformAction(OPEN_URL_FEED_ACTION, mStreamActionApi)) - .isTrue(); - verify(mStreamActionApi).canOpenUrl(); - verifyNoMoreInteractions(mStreamActionApi); - } - - @Test - public void testCanPerformActionFromContextMenu_newWindow() { - when(mStreamActionApi.canOpenUrlInNewWindow()).thenReturn(true); - assertThat(mFeedActionParser.canPerformAction( - OPEN_URL_NEW_WINDOW_FEED_ACTION, mStreamActionApi)) - .isTrue(); - verify(mStreamActionApi).canOpenUrlInNewWindow(); - verifyNoMoreInteractions(mStreamActionApi); - } - - @Test - public void testCanPerformActionFromContextMenu_incognito() { - when(mStreamActionApi.canOpenUrlInIncognitoMode()).thenReturn(true); - assertThat(mFeedActionParser.canPerformAction( - OPEN_URL_INCOGNITO_FEED_ACTION, mStreamActionApi)) - .isTrue(); - verify(mStreamActionApi).canOpenUrlInIncognitoMode(); - verifyNoMoreInteractions(mStreamActionApi); - } - - @Test - public void testCanPerformActionFromContextMenu_nestedContextMenu() { - when(mStreamActionApi.canOpenContextMenu()).thenReturn(true); - - assertThat(mFeedActionParser.canPerformAction(CONTEXT_MENU_FEED_ACTION, mStreamActionApi)) - .isTrue(); - verify(mStreamActionApi).canOpenContextMenu(); - verifyNoMoreInteractions(mStreamActionApi); - } - - @Test - public void testCanPerformActionFromContextMenu_downloadUrl() { - when(mStreamActionApi.canDownloadUrl()).thenReturn(true); - assertThat(mFeedActionParser.canPerformAction(DOWNLOAD_URL_FEED_ACTION, mStreamActionApi)) - .isTrue(); - verify(mStreamActionApi).canDownloadUrl(); - verifyNoMoreInteractions(mStreamActionApi); - } - - @Test - public void testCanPerformActionFromContextMenu_learnMore() { - when(mStreamActionApi.canLearnMore()).thenReturn(true); - assertThat(mFeedActionParser.canPerformAction(LEARN_MORE_FEED_ACTION, mStreamActionApi)) - .isTrue(); - verify(mStreamActionApi).canLearnMore(); - verifyNoMoreInteractions(mStreamActionApi); - } - - @Test - public void testDownloadUrl_noContentMetadata() { - mFeedActionParser = - new FeedActionParser(mProtocolAdapter, new PietFeedActionPayloadRetriever(), - /* contentMetadata= */ () -> null, mBasicLoggingApi); - when(mStreamActionApi.canDownloadUrl()).thenReturn(true); - mFeedActionParser.parseFeedActionPayload( - DOWNLOAD_URL_FEED_ACTION, mStreamActionApi, /* view= */ null, ActionSource.CLICK); - verify(mStreamActionApi, times(0)).downloadUrl(any(ContentMetadata.class)); - } - - @Test - public void testDownloadUrl_noHostSupport() { - when(mStreamActionApi.canDownloadUrl()).thenReturn(false); - mFeedActionParser.parseFeedActionPayload( - DOWNLOAD_URL_FEED_ACTION, mStreamActionApi, /* view= */ null, ActionSource.CLICK); - verify(mStreamActionApi, times(0)).downloadUrl(any(ContentMetadata.class)); - } - - @Test - public void testDismiss_noApiSupport() { - when(mStreamActionApi.canDismiss()).thenReturn(false); - when(mProtocolAdapter.createOperations( - DISMISS_LOCAL_FEED_ACTION.getExtension(FeedAction.feedActionExtension) - .getMetadata() - .getDismissData() - .getDataOperationsList())) - .thenReturn(mStreamDataOperations); - mFeedActionParser.parseFeedActionPayload( - DISMISS_LOCAL_FEED_ACTION, mStreamActionApi, /* view= */ null, ActionSource.CLICK); - verify(mStreamActionApi, never()) - .dismiss(anyString(), ArgumentMatchers.anyList(), any(UndoAction.class), - any(ActionPayload.class)); - } - - @Test - public void testBlockContent() { - when(mProtocolAdapter.createOperations( - BLOCK_CONTENT_ACTION.getExtension(FeedAction.feedActionExtension) - .getMetadata() - .getBlockContentData() - .getDataOperationsList())) - .thenReturn(mStreamDataOperations); - mFeedActionParser.parseFeedActionPayload( - BLOCK_CONTENT_ACTION, mStreamActionApi, /* view= */ null, ActionSource.CLICK); - verify(mStreamActionApi) - .handleBlockContent(mStreamDataOperations, ActionPayload.getDefaultInstance()); - verify(mStreamActionApi).onClientAction(ActionType.BLOCK_CONTENT); - } - - @Test - public void testNotInterestedIn_noApiSupport() { - when(mStreamActionApi.canHandleNotInterestedIn()).thenReturn(false); - when(mProtocolAdapter.createOperations( - NOT_INTERESTED_IN.getExtension(FeedAction.feedActionExtension) - .getMetadata() - .getNotInterestedInData() - .getDataOperationsList())) - .thenReturn(mStreamDataOperations); - mFeedActionParser.parseFeedActionPayload( - DISMISS_LOCAL_FEED_ACTION, mStreamActionApi, /* view= */ null, ActionSource.CLICK); - verify(mStreamActionApi, never()) - .handleNotInterestedIn(ArgumentMatchers.anyList(), any(UndoAction.class), - any(ActionPayload.class), anyInt()); - } - - @Test - public void testDismiss_noContentId() { - when(mStreamActionApi.canDismiss()).thenReturn(true); - when(mProtocolAdapter.createOperations( - DISMISS_LOCAL_FEED_ACTION.getExtension(FeedAction.feedActionExtension) - .getMetadata() - .getDismissData() - .getDataOperationsList())) - .thenReturn(mStreamDataOperations); - mFeedActionParser.parseFeedActionPayload(DISMISS_LOCAL_FEED_ACTION_NO_CONTENT_ID, - mStreamActionApi, - /* view= */ null, ActionSource.CLICK); - verify(mStreamActionApi, never()) - .dismiss(anyString(), ArgumentMatchers.anyList(), any(UndoAction.class), - any(ActionPayload.class)); - } - - @Test - public void testDismiss() { - when(mStreamActionApi.canDismiss()).thenReturn(true); - - when(mProtocolAdapter.createOperations( - DISMISS_LOCAL_FEED_ACTION.getExtension(FeedAction.feedActionExtension) - .getMetadata() - .getDismissData() - .getDataOperationsList())) - .thenReturn(mStreamDataOperations); - - mFeedActionParser.parseFeedActionPayload( - DISMISS_LOCAL_FEED_ACTION, mStreamActionApi, /* view= */ null, ActionSource.CLICK); - - verify(mStreamActionApi) - .dismiss(CONTENT_ID_STRING, mStreamDataOperations, UNDO_ACTION, - ActionPayload.getDefaultInstance()); - } - - @Test - public void testNotInterestedIn() { - when(mStreamActionApi.canDismiss()).thenReturn(true); - when(mStreamActionApi.canHandleNotInterestedIn()).thenReturn(true); - - when(mProtocolAdapter.createOperations( - NOT_INTERESTED_IN.getExtension(FeedAction.feedActionExtension) - .getMetadata() - .getNotInterestedInData() - .getDataOperationsList())) - .thenReturn(mStreamDataOperations); - - mFeedActionParser.parseFeedActionPayload( - NOT_INTERESTED_IN, mStreamActionApi, /* view= */ null, ActionSource.CLICK); - - verify(mStreamActionApi) - .handleNotInterestedIn(mStreamDataOperations, UNDO_ACTION, - ActionPayload.getDefaultInstance(), - NotInterestedInData.RecordedInterestType.SOURCE.getNumber()); - } - - @Test - public void testLearnMore() { - when(mStreamActionApi.canLearnMore()).thenReturn(true); - mFeedActionParser.parseAction(LEARN_MORE_ACTION, mStreamActionApi, - /* view= */ null, /* veLoggingToken- */ - null, ActionSource.CLICK); - - verify(mStreamActionApi).learnMore(); - verify(mStreamActionApi).onClientAction(ActionType.LEARN_MORE); - } - - @Test - public void testLearnMore_noApiSupport() { - when(mStreamActionApi.canLearnMore()).thenReturn(false); - mFeedActionParser.parseAction(LEARN_MORE_ACTION, mStreamActionApi, - /* view= */ null, /* veLoggingToken- */ - null, ActionSource.CLICK); - - verify(mStreamActionApi, never()).learnMore(); - } - - @Test - public void testSendFeedback() { - when(mStreamActionApi.canLearnMore()).thenReturn(true); - mFeedActionParser.parseAction(SEND_FEEDBACK_ACTION, mStreamActionApi, - /* view= */ null, /* veLoggingToken- */ - null, ActionSource.CLICK); - - // TODO(petewil): Figure out how to verify that it worked as expected. - } - - @Test - public void testOnHide() { - when(mStreamActionApi.canHandleElementHide()).thenReturn(true); - mFeedActionParser.parseFeedActionPayload( - HIDE_ELEMENT, mStreamActionApi, /* view= */ null, ActionSource.VIEW); - - verify(mStreamActionApi).onElementHide(ElementType.INTEREST_HEADER.getNumber()); - - verify(mStreamActionApi, never()).onElementClick(ElementType.INTEREST_HEADER.getNumber()); - } - - @Test - public void testOnView() { - when(mStreamActionApi.canHandleElementView()).thenReturn(true); - mFeedActionParser.parseFeedActionPayload( - VIEW_ELEMENT, mStreamActionApi, /* view= */ null, ActionSource.VIEW); - - verify(mStreamActionApi).onElementView(ElementType.INTEREST_HEADER.getNumber()); - - verify(mStreamActionApi, never()).onElementClick(ElementType.INTEREST_HEADER.getNumber()); - } - - @Test - public void testOnClick() { - when(mStreamActionApi.canHandleElementClick()).thenReturn(true); - mFeedActionParser.parseFeedActionPayload( - CLICK_ELEMENT, mStreamActionApi, /* view= */ null, ActionSource.CLICK); - - verify(mStreamActionApi).onElementClick(ElementType.INTEREST_HEADER.getNumber()); - } - - @Test - public void testOnClick_notLogClick() { - when(mStreamActionApi.canHandleElementClick()).thenReturn(true); - mFeedActionParser.parseFeedActionPayload( - VIEW_ELEMENT, mStreamActionApi, /* view= */ null, ActionSource.VIEW); - - verify(mStreamActionApi, never()).onElementClick(ElementType.INTEREST_HEADER.getNumber()); - } - - @Test - public void testOpenUrl_noUrl_logsError() { - when(mStreamActionApi.canOpenUrl()).thenReturn(true); - - mFeedActionParser.parseFeedActionPayload( - OPEN_URL_MISSING_URL, mStreamActionApi, /* view= */ null, ActionSource.CLICK); - - verify(mBasicLoggingApi).onInternalError(InternalFeedError.NO_URL_FOR_OPEN); - } - - @Test - public void testShowTooltip() { - String tooltipLabel = "tooltip"; - String accessibilityLabel = "tool"; - int topInsert = 1; - int bottomInsert = 3; - when(mStreamActionApi.canShowTooltip()).thenReturn(true); - ArgumentCaptor<TooltipInfo> tooltipInfoArgumentCaptor = - ArgumentCaptor.forClass(TooltipInfo.class); - FeedActionPayload tooltipData = - FeedActionPayload.newBuilder() - .setExtension(FeedAction.feedActionExtension, - FeedAction.newBuilder() - .setMetadata( - FeedActionMetadata.newBuilder() - .setType(Type.SHOW_TOOLTIP) - .setTooltipData( - // clang-format off - TooltipData.newBuilder() - .setLabel(tooltipLabel) - .setAccessibilityLabel( - accessibilityLabel) - .setFeatureName( - FeatureName - .CARD_MENU) - .setInsets( - Insets.newBuilder() - .setTop(topInsert) - .setBottom( - bottomInsert) - .build()) - // clang-format on - )) - .build()) - .build(); - View view = new View(Robolectric.buildActivity(Activity.class).get()); - mFeedActionParser.parseFeedActionPayload( - tooltipData, mStreamActionApi, view, ActionSource.VIEW); - verify(mStreamActionApi).maybeShowTooltip(tooltipInfoArgumentCaptor.capture(), eq(view)); - TooltipInfo tooltipInfo = tooltipInfoArgumentCaptor.getValue(); - assertThat(tooltipInfo.getLabel()).isEqualTo(tooltipLabel); - assertThat(tooltipInfo.getAccessibilityLabel()).isEqualTo(accessibilityLabel); - assertThat(tooltipInfo.getFeatureName()) - .isEqualTo(TooltipInfo.FeatureName.CARD_MENU_TOOLTIP); - assertThat(tooltipInfo.getTopInset()).isEqualTo(topInsert); - assertThat(tooltipInfo.getBottomInset()).isEqualTo(bottomInsert); - } - - @Test - public void testShowTooltip_notSupported() { - when(mStreamActionApi.canShowTooltip()).thenReturn(false); - - FeedActionPayload tooltipData = - FeedActionPayload.newBuilder() - .setExtension(FeedAction.feedActionExtension, - FeedAction.newBuilder() - .setMetadata(FeedActionMetadata.newBuilder().setType( - Type.SHOW_TOOLTIP)) - .build()) - .build(); - View view = new View(Robolectric.buildActivity(Activity.class).get()); - mFeedActionParser.parseFeedActionPayload( - tooltipData, mStreamActionApi, view, ActionSource.VIEW); - verify(mStreamActionApi, never()).maybeShowTooltip(any(TooltipInfo.class), any(View.class)); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedactionreader/FeedActionReaderTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedactionreader/FeedActionReaderTest.java deleted file mode 100644 index 809e4558..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedactionreader/FeedActionReaderTest.java +++ /dev/null
@@ -1,293 +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. -package org.chromium.chrome.browser.feed.library.feedactionreader; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.anyDouble; -import static org.mockito.ArgumentMatchers.anyList; -import static org.mockito.ArgumentMatchers.anyListOf; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration.ConfigKey; -import org.chromium.chrome.browser.feed.library.api.internal.actionmanager.ActionReader; -import org.chromium.chrome.browser.feed.library.api.internal.common.DismissActionWithSemanticProperties; -import org.chromium.chrome.browser.feed.library.api.internal.common.SemanticPropertiesWithId; -import org.chromium.chrome.browser.feed.library.api.internal.common.testing.ContentIdGenerators; -import org.chromium.chrome.browser.feed.library.api.internal.protocoladapter.ProtocolAdapter; -import org.chromium.chrome.browser.feed.library.api.internal.store.LocalActionMutation.ActionType; -import org.chromium.chrome.browser.feed.library.api.internal.store.Store; -import org.chromium.chrome.browser.feed.library.common.Result; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeTaskQueue; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeThreadUtils; -import org.chromium.chrome.browser.feed.library.common.testing.ResponseBuilder; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamLocalAction; -import org.chromium.components.feed.core.proto.wire.ContentIdProto.ContentId; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.TimeUnit; - -/** Tests of the {@link FeedActionReader} class. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class FeedActionReaderTest { - private static final ContentIdGenerators ID_GENERATOR = new ContentIdGenerators(); - - private static final ContentId CONTENT_ID = ResponseBuilder.createFeatureContentId(1); - private static final String CONTENT_ID_STRING = ID_GENERATOR.createContentId(CONTENT_ID); - private static final ContentId CONTENT_ID_2 = ResponseBuilder.createFeatureContentId(2); - private static final String CONTENT_ID_STRING_2 = ID_GENERATOR.createContentId(CONTENT_ID_2); - private static final long DEFAULT_TIME = TimeUnit.DAYS.toSeconds(42); - - private final FakeClock mFakeClock = new FakeClock(); - private final FakeThreadUtils mFakeThreadUtils = FakeThreadUtils.withThreadChecks(); - - @Mock - private Store mStore; - @Mock - private ProtocolAdapter mProtocolAdapter; - @Mock - private Configuration mConfiguration; - - private ActionReader mActionReader; - - @Before - public void setUp() throws Exception { - initMocks(this); - - when(mConfiguration.getValueOrDefault( - same(ConfigKey.DEFAULT_ACTION_TTL_SECONDS), anyLong())) - .thenReturn(TimeUnit.DAYS.toSeconds(3)); - when(mConfiguration.getValueOrDefault( - same(ConfigKey.MINIMUM_VALID_ACTION_RATIO), anyDouble())) - .thenReturn(0.9); - - when(mStore.triggerLocalActionGc( - anyListOf(StreamLocalAction.class), anyListOf(String.class))) - .thenReturn(() -> {}); - - mActionReader = new FeedActionReader( - mStore, mFakeClock, mProtocolAdapter, getTaskQueue(), mConfiguration); - - when(mProtocolAdapter.getWireContentId(CONTENT_ID_STRING)) - .thenReturn(Result.success(CONTENT_ID)); - when(mProtocolAdapter.getWireContentId(CONTENT_ID_STRING_2)) - .thenReturn(Result.success(CONTENT_ID_2)); - } - - @Test - public void getAllDismissedActions() { - mFakeClock.set(DEFAULT_TIME); - - StreamLocalAction dismissAction = buildDismissAction(CONTENT_ID_STRING); - mockStoreCalls(Collections.singletonList(dismissAction), Collections.emptyList()); - - Result<List<DismissActionWithSemanticProperties>> dismissActionsResult = - mActionReader.getDismissActionsWithSemanticProperties(); - assertThat(dismissActionsResult.isSuccessful()).isTrue(); - List<DismissActionWithSemanticProperties> dismissActions = dismissActionsResult.getValue(); - assertThat(dismissActions) - .containsExactly(new DismissActionWithSemanticProperties(CONTENT_ID, null)); - } - - @Test - public void getAllDismissedActions_empty() { - mFakeClock.set(DEFAULT_TIME); - - mockStoreCalls(Collections.emptyList(), Collections.emptyList()); - - Result<List<DismissActionWithSemanticProperties>> dismissActionsResult = - mActionReader.getDismissActionsWithSemanticProperties(); - assertThat(dismissActionsResult.isSuccessful()).isTrue(); - List<DismissActionWithSemanticProperties> dismissActions = dismissActionsResult.getValue(); - assertThat(dismissActions).hasSize(0); - verify(mStore, never()) - .triggerLocalActionGc(anyListOf(StreamLocalAction.class), anyListOf(String.class)); - } - - @Test - public void getAllDismissedActions_storeError_getAllDismissActions() { - mFakeClock.set(DEFAULT_TIME); - when(mStore.getAllDismissLocalActions()).thenReturn(Result.failure()); - - Result<List<DismissActionWithSemanticProperties>> dismissActionsResult = - mActionReader.getDismissActionsWithSemanticProperties(); - assertThat(dismissActionsResult.isSuccessful()).isFalse(); - verify(mStore, never()) - .triggerLocalActionGc(anyListOf(StreamLocalAction.class), anyListOf(String.class)); - } - - @Test - public void getAllDismissedActions_storeError_getSemanticProperties() { - mFakeClock.set(DEFAULT_TIME); - StreamLocalAction dismissAction = buildDismissAction(CONTENT_ID_STRING); - when(mStore.getAllDismissLocalActions()) - .thenReturn(Result.success(Collections.singletonList(dismissAction))); - when(mStore.getSemanticProperties(anyList())).thenReturn(Result.failure()); - - Result<List<DismissActionWithSemanticProperties>> dismissActionsResult = - mActionReader.getDismissActionsWithSemanticProperties(); - assertThat(dismissActionsResult.isSuccessful()).isFalse(); - verify(mStore, never()) - .triggerLocalActionGc(anyListOf(StreamLocalAction.class), anyListOf(String.class)); - } - - @Test - public void getAllDismissedActions_expired() { - mFakeClock.set(TimeUnit.SECONDS.toMillis(DEFAULT_TIME) + TimeUnit.DAYS.toMillis(3)); - - StreamLocalAction dismissAction = buildDismissAction(CONTENT_ID_STRING); - List<StreamLocalAction> dismissActions = Collections.singletonList(dismissAction); - mockStoreCalls(dismissActions, Collections.emptyList()); - - Result<List<DismissActionWithSemanticProperties>> dismissActionsResult = - mActionReader.getDismissActionsWithSemanticProperties(); - assertThat(dismissActionsResult.isSuccessful()).isTrue(); - assertThat(dismissActionsResult.getValue()).hasSize(0); - verify(mStore).triggerLocalActionGc(eq(dismissActions), anyListOf(String.class)); - } - - @Test - public void getAllDismissedActions_semanticProperties() { - mFakeClock.set(DEFAULT_TIME); - - StreamLocalAction dismissAction = buildDismissAction(CONTENT_ID_STRING); - byte[] semanticData = {12, 41}; - mockStoreCalls(Collections.singletonList(dismissAction), - Collections.singletonList( - new SemanticPropertiesWithId(CONTENT_ID_STRING, semanticData))); - - Result<List<DismissActionWithSemanticProperties>> dismissActionsResult = - mActionReader.getDismissActionsWithSemanticProperties(); - assertThat(dismissActionsResult.isSuccessful()).isTrue(); - List<DismissActionWithSemanticProperties> dismissActions = dismissActionsResult.getValue(); - assertThat(dismissActions) - .containsExactly(new DismissActionWithSemanticProperties(CONTENT_ID, semanticData)); - verify(mStore, never()) - .triggerLocalActionGc(anyListOf(StreamLocalAction.class), anyListOf(String.class)); - } - - @Test - public void getAllDismissedActions_multipleActions() { - mFakeClock.set(DEFAULT_TIME); - - StreamLocalAction dismissAction = buildDismissAction(CONTENT_ID_STRING); - StreamLocalAction dismissAction2 = buildDismissAction(CONTENT_ID_STRING_2); - mockStoreCalls(Arrays.asList(dismissAction, dismissAction2), Collections.emptyList()); - - Result<List<DismissActionWithSemanticProperties>> dismissActionsResult = - mActionReader.getDismissActionsWithSemanticProperties(); - assertThat(dismissActionsResult.isSuccessful()).isTrue(); - List<DismissActionWithSemanticProperties> dismissActions = dismissActionsResult.getValue(); - - assertThat(dismissActions) - .containsExactly(new DismissActionWithSemanticProperties(CONTENT_ID, null), - new DismissActionWithSemanticProperties(CONTENT_ID_2, null)); - verify(mStore, never()) - .triggerLocalActionGc(anyListOf(StreamLocalAction.class), anyListOf(String.class)); - } - - @Test - public void getAllDismissedActions_multipleActions_semanticProperties() { - mFakeClock.set(DEFAULT_TIME); - - StreamLocalAction dismissAction = buildDismissAction(CONTENT_ID_STRING); - StreamLocalAction dismissAction2 = buildDismissAction(CONTENT_ID_STRING_2); - byte[] semanticData = {12, 41}; - byte[] semanticData2 = {42, 72}; - mockStoreCalls(Arrays.asList(dismissAction, dismissAction2), - Arrays.asList(new SemanticPropertiesWithId(CONTENT_ID_STRING, semanticData), - new SemanticPropertiesWithId(CONTENT_ID_STRING_2, semanticData2))); - - Result<List<DismissActionWithSemanticProperties>> dismissActionsResult = - mActionReader.getDismissActionsWithSemanticProperties(); - assertThat(dismissActionsResult.isSuccessful()).isTrue(); - List<DismissActionWithSemanticProperties> dismissActions = dismissActionsResult.getValue(); - - assertThat(dismissActions) - .containsExactly(new DismissActionWithSemanticProperties(CONTENT_ID, semanticData), - new DismissActionWithSemanticProperties(CONTENT_ID_2, semanticData2)); - verify(mStore, never()) - .triggerLocalActionGc(anyListOf(StreamLocalAction.class), anyListOf(String.class)); - } - - @Test - public void getAllDismissedActions_multipleActions_someExpired() { - mFakeClock.set(TimeUnit.SECONDS.toMillis(DEFAULT_TIME) + TimeUnit.DAYS.toMillis(3)); - - StreamLocalAction dismissAction = buildDismissAction(CONTENT_ID_STRING); - StreamLocalAction dismissAction2 = - StreamLocalAction.newBuilder() - .setAction(ActionType.DISMISS) - .setFeatureContentId(CONTENT_ID_STRING_2) - .setTimestampSeconds(DEFAULT_TIME + TimeUnit.DAYS.toSeconds(2)) - .build(); - mockStoreCalls(Arrays.asList(dismissAction, dismissAction2), Collections.emptyList()); - - Result<List<DismissActionWithSemanticProperties>> dismissActionsResult = - mActionReader.getDismissActionsWithSemanticProperties(); - assertThat(dismissActionsResult.isSuccessful()).isTrue(); - - assertThat(dismissActionsResult.getValue()) - .containsExactly(new DismissActionWithSemanticProperties(CONTENT_ID_2, null)); - verify(mStore).triggerLocalActionGc(Arrays.asList(dismissAction, dismissAction2), - Collections.singletonList(CONTENT_ID_STRING_2)); - } - - @Test - public void getAllDismissedActions_duplicateActions() { - mFakeClock.set(DEFAULT_TIME); - - StreamLocalAction dismissAction = buildDismissAction(CONTENT_ID_STRING); - StreamLocalAction dismissAction2 = buildDismissAction(CONTENT_ID_STRING); - mockStoreCalls(Arrays.asList(dismissAction, dismissAction2), Collections.emptyList()); - - Result<List<DismissActionWithSemanticProperties>> dismissActionsResult = - mActionReader.getDismissActionsWithSemanticProperties(); - assertThat(dismissActionsResult.isSuccessful()).isTrue(); - List<DismissActionWithSemanticProperties> dismissActions = dismissActionsResult.getValue(); - - assertThat(dismissActions).hasSize(1); - assertThat(dismissActions) - .containsExactly(new DismissActionWithSemanticProperties(CONTENT_ID, null)); - } - - private StreamLocalAction buildDismissAction(String contentId) { - return StreamLocalAction.newBuilder() - .setAction(ActionType.DISMISS) - .setFeatureContentId(contentId) - .setTimestampSeconds(DEFAULT_TIME) - .build(); - } - - private void mockStoreCalls(List<StreamLocalAction> dismissActions, - List<SemanticPropertiesWithId> semanticProperties) { - when(mStore.getAllDismissLocalActions()).thenReturn(Result.success(dismissActions)); - when(mStore.getSemanticProperties(anyList())) - .thenReturn(Result.success(semanticProperties)); - } - - private FakeTaskQueue getTaskQueue() { - FakeTaskQueue fakeTaskQueue = new FakeTaskQueue(mFakeClock, mFakeThreadUtils); - fakeTaskQueue.initialize(() -> {}); - return fakeTaskQueue; - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedapplifecyclelistener/FeedAppLifecycleListenerTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedapplifecyclelistener/FeedAppLifecycleListenerTest.java deleted file mode 100644 index 9cc8ba3..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedapplifecyclelistener/FeedAppLifecycleListenerTest.java +++ /dev/null
@@ -1,78 +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. - -package org.chromium.chrome.browser.feed.library.feedapplifecyclelistener; - -import static org.mockito.Mockito.verify; -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.internal.common.ThreadUtils; -import org.chromium.chrome.browser.feed.library.feedapplifecyclelistener.FeedLifecycleListener.LifecycleEvent; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Test class for {@link FeedAppLifecycleListener} */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class FeedAppLifecycleListenerTest { - @Mock - private FeedLifecycleListener mLifecycleListener; - @Mock - private ThreadUtils mThreadUtils; - private FeedAppLifecycleListener mAppLifecycleListener; - - @Before - public void setup() { - initMocks(this); - mAppLifecycleListener = new FeedAppLifecycleListener(mThreadUtils); - mAppLifecycleListener.registerObserver(mLifecycleListener); - } - - @Test - public void onEnterForeground() { - mAppLifecycleListener.onEnterForeground(); - verify(mLifecycleListener).onLifecycleEvent(LifecycleEvent.ENTER_FOREGROUND); - } - - @Test - public void onEnterBackground() { - mAppLifecycleListener.onEnterBackground(); - verify(mLifecycleListener).onLifecycleEvent(LifecycleEvent.ENTER_BACKGROUND); - } - - @Test - public void onClearAll() { - mAppLifecycleListener.onClearAll(); - verify(mLifecycleListener).onLifecycleEvent(LifecycleEvent.CLEAR_ALL); - } - - @Test - public void onClearAllWithRefresh() { - mAppLifecycleListener.onClearAllWithRefresh(); - verify(mLifecycleListener).onLifecycleEvent(LifecycleEvent.CLEAR_ALL_WITH_REFRESH); - } - - @Test - public void onSignedIn() { - mAppLifecycleListener.onSignedIn(); - verify(mLifecycleListener).onLifecycleEvent(LifecycleEvent.SIGNED_IN); - } - - @Test - public void onSignedOut() { - mAppLifecycleListener.onSignedOut(); - verify(mLifecycleListener).onLifecycleEvent(LifecycleEvent.SIGNED_OUT); - } - - @Test - public void onInitialize() { - mAppLifecycleListener.initialize(); - verify(mLifecycleListener).onLifecycleEvent(LifecycleEvent.INITIALIZE); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedknowncontent/FeedKnownContentImplTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedknowncontent/FeedKnownContentImplTest.java deleted file mode 100644 index fe9b3db..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedknowncontent/FeedKnownContentImplTest.java +++ /dev/null
@@ -1,203 +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. - -package org.chromium.chrome.browser.feed.library.feedknowncontent; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.ArgumentMatchers; -import org.mockito.Captor; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.base.Consumer; -import org.chromium.base.Function; -import org.chromium.chrome.browser.feed.library.api.client.knowncontent.ContentMetadata; -import org.chromium.chrome.browser.feed.library.api.client.knowncontent.ContentRemoval; -import org.chromium.chrome.browser.feed.library.api.client.knowncontent.KnownContent; -import org.chromium.chrome.browser.feed.library.api.internal.common.ThreadUtils; -import org.chromium.chrome.browser.feed.library.api.internal.sessionmanager.FeedSessionManager; -import org.chromium.chrome.browser.feed.library.common.Result; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeMainThreadRunner; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamFeature; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamPayload; -import org.chromium.components.feed.core.proto.ui.stream.StreamStructureProto.Content; -import org.chromium.components.feed.core.proto.ui.stream.StreamStructureProto.OfflineMetadata; -import org.chromium.components.feed.core.proto.ui.stream.StreamStructureProto.RepresentationData; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.Collections; -import java.util.List; - -/** Tests for {@link FeedKnownContentImpl}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class FeedKnownContentImplTest { - private static final long CONTENT_CREATION_DATE_TIME_MS = 123L; - private static final List<ContentRemoval> CONTENT_REMOVED = - Collections.singletonList(new ContentRemoval("url", /* requestedByUser= */ false)); - private static final String URL = "url"; - private static final String TITLE = "title"; - - @Mock - private FeedSessionManager mFeedSessionManager; - @Mock - private KnownContent.Listener mListener1; - @Mock - private KnownContent.Listener mListener2; - @Mock - private Consumer<List<ContentMetadata>> mKnownContentConsumer; - @Mock - private ThreadUtils mThreadUtils; - - private final FakeMainThreadRunner mMainThreadRunner = - FakeMainThreadRunner.runTasksImmediately(); - - @Captor - private ArgumentCaptor<Function<StreamPayload, ContentMetadata>> mKnownContentFunctionCaptor; - - @Captor - private ArgumentCaptor<Consumer<Result<List<ContentMetadata>>>> mContentMetadataResultCaptor; - - private FeedKnownContentImpl mKnownContentApi; - - @Before - public void setUp() { - initMocks(this); - when(mThreadUtils.isMainThread()).thenReturn(true); - mKnownContentApi = - new FeedKnownContentImpl(mFeedSessionManager, mMainThreadRunner, mThreadUtils); - } - - @Test - public void testSetsListenerOnSessionManager() { - verify(mFeedSessionManager) - .setKnownContentListener(mKnownContentApi.getKnownContentHostNotifier()); - } - - @Test - public void testNotifyListeners_contentReceived() { - mKnownContentApi.addListener(mListener1); - mKnownContentApi.addListener(mListener2); - - mKnownContentApi.getKnownContentHostNotifier().onNewContentReceived( - /* isNewRefresh= */ false, CONTENT_CREATION_DATE_TIME_MS); - - verify(mListener1) - .onNewContentReceived( - /* isNewRefresh= */ false, CONTENT_CREATION_DATE_TIME_MS); - verify(mListener2) - .onNewContentReceived( - /* isNewRefresh= */ false, CONTENT_CREATION_DATE_TIME_MS); - } - - @Test - public void testNotifyListeners_contentRemoved() { - mKnownContentApi.addListener(mListener1); - mKnownContentApi.addListener(mListener2); - - mKnownContentApi.getKnownContentHostNotifier().onContentRemoved(CONTENT_REMOVED); - - verify(mListener1).onContentRemoved(CONTENT_REMOVED); - verify(mListener2).onContentRemoved(CONTENT_REMOVED); - } - - @Test - public void testRemoveListener() { - mKnownContentApi.addListener(mListener1); - mKnownContentApi.removeListener(mListener1); - - mKnownContentApi.getKnownContentHostNotifier().onContentRemoved(CONTENT_REMOVED); - mKnownContentApi.getKnownContentHostNotifier().onNewContentReceived( - /* isNewRefresh= */ true, CONTENT_CREATION_DATE_TIME_MS); - - verifyNoMoreInteractions(mListener1); - } - - @Test - public void testGetKnownContent_returnsNullForNonContent() { - mKnownContentApi.getKnownContent(mKnownContentConsumer); - - verify(mFeedSessionManager) - .getStreamFeaturesFromHead(mKnownContentFunctionCaptor.capture(), - mContentMetadataResultCaptor.capture()); - - assertThat(mKnownContentFunctionCaptor.getValue().apply(StreamPayload.getDefaultInstance())) - .isNull(); - } - - @Test - public void testGetKnownContent_returnsContentMetadataFromContent() { - mKnownContentApi.getKnownContent(mKnownContentConsumer); - - verify(mFeedSessionManager) - .getStreamFeaturesFromHead(mKnownContentFunctionCaptor.capture(), - mContentMetadataResultCaptor.capture()); - - StreamPayload streamPayload = - StreamPayload.newBuilder() - .setStreamFeature(StreamFeature.newBuilder().setContent( - Content.newBuilder() - .setOfflineMetadata( - OfflineMetadata.newBuilder().setTitle(TITLE)) - .setRepresentationData( - RepresentationData.newBuilder().setUri(URL)))) - .build(); - - ContentMetadata contentMetadata = - mKnownContentFunctionCaptor.getValue().apply(streamPayload); - - assertThat(contentMetadata.getUrl()).isEqualTo(URL); - assertThat(contentMetadata.getTitle()).isEqualTo(TITLE); - } - - @Test - public void testGetKnownContent_failure() { - mKnownContentApi.getKnownContent(mKnownContentConsumer); - - verify(mFeedSessionManager) - .getStreamFeaturesFromHead(mKnownContentFunctionCaptor.capture(), - mContentMetadataResultCaptor.capture()); - - mContentMetadataResultCaptor.getValue().accept(Result.failure()); - - verify(mKnownContentConsumer, never()) - .accept(ArgumentMatchers.<List<ContentMetadata>>any()); - } - - @Test - public void testGetKnownContent_offMainThread() { - FakeMainThreadRunner fakeMainThreadRunner = FakeMainThreadRunner.queueAllTasks(); - when(mThreadUtils.isMainThread()).thenReturn(false); - - mKnownContentApi = - new FeedKnownContentImpl(mFeedSessionManager, fakeMainThreadRunner, mThreadUtils); - - mKnownContentApi.addListener(mListener1); - - mKnownContentApi.getKnownContentHostNotifier().onNewContentReceived( - /* isNewRefresh= */ false, CONTENT_CREATION_DATE_TIME_MS); - - assertThat(fakeMainThreadRunner.hasTasks()).isTrue(); - - verifyZeroInteractions(mListener1); - - fakeMainThreadRunner.runAllTasks(); - - verify(mListener1) - .onNewContentReceived( - /* isNewRefresh= */ false, CONTENT_CREATION_DATE_TIME_MS); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedmodelprovider/FeedModelProviderFactoryTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedmodelprovider/FeedModelProviderFactoryTest.java deleted file mode 100644 index 57e02aa..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedmodelprovider/FeedModelProviderFactoryTest.java +++ /dev/null
@@ -1,66 +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. - -package org.chromium.chrome.browser.feed.library.feedmodelprovider; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration.ConfigKey; -import org.chromium.chrome.browser.feed.library.api.internal.common.ThreadUtils; -import org.chromium.chrome.browser.feed.library.api.internal.sessionmanager.FeedSessionManager; -import org.chromium.chrome.browser.feed.library.common.concurrent.MainThreadRunner; -import org.chromium.chrome.browser.feed.library.common.concurrent.TaskQueue; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeMainThreadRunner; -import org.chromium.chrome.browser.feed.library.common.time.TimingUtils; -import org.chromium.chrome.browser.feed.library.testing.host.logging.FakeBasicLoggingApi; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.UiContext; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests of the {@link FeedModelProviderFactory}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class FeedModelProviderFactoryTest { - private final FakeBasicLoggingApi mFakeBasicLoggingApi = new FakeBasicLoggingApi(); - @Mock - private ThreadUtils mThreadUtils; - @Mock - private TimingUtils mTimingUtils; - @Mock - private FeedSessionManager mFeedSessionManager; - @Mock - private Configuration mConfig; - @Mock - private TaskQueue mTaskQueue; - - private MainThreadRunner mMainThreadRunner; - - @Before - public void setUp() { - initMocks(this); - - mMainThreadRunner = FakeMainThreadRunner.queueAllTasks(); - - when(mConfig.getValueOrDefault(ConfigKey.INITIAL_NON_CACHED_PAGE_SIZE, 0L)).thenReturn(0L); - when(mConfig.getValueOrDefault(ConfigKey.NON_CACHED_PAGE_SIZE, 0L)).thenReturn(0L); - when(mConfig.getValueOrDefault(ConfigKey.NON_CACHED_MIN_PAGE_SIZE, 0L)).thenReturn(0L); - } - - @Test - public void testModelProviderFactory() { - FeedModelProviderFactory factory = - new FeedModelProviderFactory(mFeedSessionManager, mThreadUtils, mTimingUtils, - mTaskQueue, mMainThreadRunner, mConfig, mFakeBasicLoggingApi); - assertThat(factory.createNew(null, UiContext.getDefaultInstance())).isNotNull(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedmodelprovider/FeedModelProviderTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedmodelprovider/FeedModelProviderTest.java deleted file mode 100644 index fb41010..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedmodelprovider/FeedModelProviderTest.java +++ /dev/null
@@ -1,813 +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. - -package org.chromium.chrome.browser.feed.library.feedmodelprovider; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import com.google.protobuf.ByteString; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration.ConfigKey; -import org.chromium.chrome.browser.feed.library.api.host.logging.InternalFeedError; -import org.chromium.chrome.browser.feed.library.api.host.logging.RequestReason; -import org.chromium.chrome.browser.feed.library.api.internal.common.PayloadWithId; -import org.chromium.chrome.browser.feed.library.api.internal.common.ThreadUtils; -import org.chromium.chrome.browser.feed.library.api.internal.common.testing.ContentIdGenerators; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelChild; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelChild.Type; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelCursor; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelError; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelError.ErrorType; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelFeature; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelMutation; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider.State; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider.ViewDepthProvider; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProviderObserver; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelToken; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.TokenCompleted; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.TokenCompletedObserver; -import org.chromium.chrome.browser.feed.library.api.internal.sessionmanager.FeedSessionManager; -import org.chromium.chrome.browser.feed.library.common.Result; -import org.chromium.chrome.browser.feed.library.common.concurrent.TaskQueue; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeMainThreadRunner; -import org.chromium.chrome.browser.feed.library.common.time.TimingUtils; -import org.chromium.chrome.browser.feed.library.feedmodelprovider.FeedModelProvider.InitializeModel; -import org.chromium.chrome.browser.feed.library.feedmodelprovider.FeedModelProvider.TokenMutation; -import org.chromium.chrome.browser.feed.library.feedmodelprovider.FeedModelProvider.TokenTracking; -import org.chromium.chrome.browser.feed.library.feedmodelprovider.internal.UpdatableModelChild; -import org.chromium.chrome.browser.feed.library.feedmodelprovider.internal.UpdatableModelToken; -import org.chromium.chrome.browser.feed.library.testing.host.logging.FakeBasicLoggingApi; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamFeature; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamPayload; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamSharedState; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamStructure; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamStructure.Operation; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamToken; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.UiContext; -import org.chromium.components.feed.core.proto.ui.stream.StreamStructureProto.Card; -import org.chromium.components.feed.core.proto.wire.ContentIdProto.ContentId; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -/** Tests of the {@link FeedModelProvider}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class FeedModelProviderTest { - private static final String SESSION_ID = "session"; - - private final ContentIdGenerators mIdGenerators = new ContentIdGenerators(); - private final String mRootContentId = mIdGenerators.createRootContentId(0); - private final FakeBasicLoggingApi mFakeBasicLoggingApi = new FakeBasicLoggingApi(); - - @Mock - private TaskQueue mTaskQueue; - @Mock - private FeedSessionManager mFeedSessionManager; - @Mock - private ThreadUtils mThreadUtils; - @Mock - private Configuration mConfig; - - private ModelChild mContinuationToken; - private TimingUtils mTimingUtils = new TimingUtils(); - private FakeMainThreadRunner mFakeMainThreadRunner; - - private List<PayloadWithId> mChildBindings = new ArrayList<>(); - - @Before - public void setUp() { - initMocks(this); - mChildBindings.clear(); - when(mFeedSessionManager.getStreamFeatures(any())) - .thenReturn(Result.success(mChildBindings)); - mFakeMainThreadRunner = FakeMainThreadRunner.runTasksImmediately(); - } - - @Test - public void testMinimalModelProvider() { - FeedModelProvider modelProvider = createFeedModelProviderWithConfig(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - // Add a root to the model provider - ModelMutation mutator = modelProvider.edit(); - assertThat(mutator).isNotNull(); - - StreamFeature rootStreamFeature = getRootFeature(); - mutator.addChild(createStreamStructureAndBinding(rootStreamFeature)); - mutator.commit(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - - // Verify that we have a root - ModelFeature rootFeature = modelProvider.getRootFeature(); - assertThat(rootFeature).isNotNull(); - assertThat(rootFeature.getStreamFeature()).isEqualTo(rootStreamFeature); - - // Verify that the cursor exists but is at end - ModelCursor modelCursor = rootFeature.getCursor(); - assertThat(modelCursor).isNotNull(); - assertThat(modelCursor.isAtEnd()).isTrue(); - } - - @Test - public void testRemoveWithAppend() { - // Enable synthetic tokens. - initSyntheticTokenConfig( - /* initialPageSize= */ 10, /* minPageSize= */ 0, /* pageSize= */ 0); - FeedModelProvider modelProvider = createFeedModelProvider(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - // Create a root with three children attached. - modelProvider.edit() - .addChild(createStreamStructureAndBinding(getRootFeature())) - .addChild(createStreamStructureAndBinding(createFeature(1, mRootContentId))) - .addChild(createStreamStructureAndBinding(createFeature(2, mRootContentId))) - .addChild(createStreamStructureAndBinding(createFeature(3, mRootContentId))) - .commit(); - - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - ModelFeature rootFeature = modelProvider.getRootFeature(); - ModelCursor modelCursor = rootFeature.getCursor(); - assertThat(modelCursor.getNextItem().getModelFeature().getStreamFeature()) - .isEqualTo(mChildBindings.get(1).payload.getStreamFeature()); - assertThat(modelCursor.getNextItem().getModelFeature().getStreamFeature()) - .isEqualTo(mChildBindings.get(2).payload.getStreamFeature()); - assertThat(modelCursor.getNextItem().getModelFeature().getStreamFeature()) - .isEqualTo(mChildBindings.get(3).payload.getStreamFeature()); - - // Now remove the second and third children, and add more children. - modelProvider.edit() - .removeChild(createRemove(mRootContentId, createFeatureContentId(2))) - .removeChild(createRemove(mRootContentId, createFeatureContentId(3))) - .addChild(createStreamStructureAndBinding(createFeature(4, mRootContentId))) - .addChild(createStreamStructureAndBinding(createFeature(5, mRootContentId))) - .commit(); - - // The children should now be #1, #4, and #5; they all should be bound. - modelCursor = rootFeature.getCursor(); - assertThat(modelCursor.getNextItem().getModelFeature().getStreamFeature()) - .isEqualTo(mChildBindings.get(1).payload.getStreamFeature()); - assertThat(modelCursor.getNextItem().getModelFeature().getStreamFeature()) - .isEqualTo(mChildBindings.get(4).payload.getStreamFeature()); - assertThat(modelCursor.getNextItem().getModelFeature().getStreamFeature()) - .isEqualTo(mChildBindings.get(5).payload.getStreamFeature()); - } - - @Test - public void testEmptyStream() { - FeedModelProvider modelProvider = createFeedModelProviderWithConfig(); - - modelProvider.edit().commit(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - assertThat(modelProvider.getRootFeature()).isNull(); - } - - @Test - public void testCursor() { - FeedModelProvider modelProvider = createFeedModelProviderWithConfig(); - int featureCnt = 2; - createTopLevelFeatures(modelProvider, featureCnt).commit(); - - ModelFeature rootFeature = modelProvider.getRootFeature(); - assertThat(rootFeature).isNotNull(); - ModelCursor modelCursor = rootFeature.getCursor(); - assertThat(modelCursor).isNotNull(); - assertThat(modelCursor.isAtEnd()).isFalse(); - - int cnt = 0; - while (modelCursor.getNextItem() != null) { - cnt++; - } - assertThat(cnt).isEqualTo(featureCnt); - assertThat(modelCursor.isAtEnd()).isTrue(); - } - - @Test - public void testRemove() { - FeedModelProvider modelProvider = createFeedModelProviderWithConfig(); - int featureCnt = 2; - createTopLevelFeatures(modelProvider, featureCnt) - .removeChild(createRemove(mRootContentId, createFeatureContentId(2))) - .commit(); - - ModelFeature rootFeature = modelProvider.getRootFeature(); - assertThat(rootFeature).isNotNull(); - ModelCursor modelCursor = rootFeature.getCursor(); - - // Verify that one of the features was removed by a the last operation - int cnt = 0; - while (modelCursor.getNextItem() != null) { - cnt++; - } - assertThat(cnt).isEqualTo(featureCnt - 1); - } - - @Test - public void testMultiLevelCursors() { - FeedModelProvider modelProvider = createFeedModelProviderWithConfig(); - int featureCnt = 3; - ModelMutation mutator = createTopLevelFeatures(modelProvider, featureCnt); - String featureParent = createFeatureContentId(2); - for (int i = 0; i < featureCnt; i++) { - mutator.addChild(createStreamStructureAndBinding( - createFeature(i + 1 + featureCnt, featureParent))); - } - mutator.commit(); - - ModelFeature rootFeature = modelProvider.getRootFeature(); - assertThat(rootFeature).isNotNull(); - ModelCursor modelCursor = rootFeature.getCursor(); - assertThat(modelCursor).isNotNull(); - assertThat(modelCursor.isAtEnd()).isFalse(); - - int cnt = 0; - ModelChild child; - while ((child = modelCursor.getNextItem()) != null) { - cnt++; - if (child.getType() == Type.FEATURE) { - ModelFeature feature = child.getModelFeature(); - ModelCursor nextCursor = feature.getCursor(); - while (nextCursor.getNextItem() != null) { - cnt++; - } - } - } - assertThat(cnt).isEqualTo(featureCnt + featureCnt); - } - - @Test - public void testSharedState() { - ContentId contentId = ContentId.getDefaultInstance(); - StreamSharedState streamSharedState = StreamSharedState.getDefaultInstance(); - when(mFeedSessionManager.getSharedState(contentId)).thenReturn(streamSharedState); - - FeedModelProvider modelProvider = createFeedModelProviderWithConfig(); - assertThat(modelProvider.getSharedState(contentId)).isEqualTo(streamSharedState); - } - - @Test - public void testTokenTracking() { - UpdatableModelToken continuationToken = - new UpdatableModelToken(StreamToken.getDefaultInstance(), false); - ArrayList<UpdatableModelChild> location = new ArrayList<>(); - String parentContentId = "parent.content.id"; - TokenTracking tokenTracking = - new TokenTracking(continuationToken, parentContentId, location); - assertThat(tokenTracking.mTokenChild).isEqualTo(continuationToken); - assertThat(tokenTracking.mParentContentId).isEqualTo(parentContentId); - assertThat(tokenTracking.mLocation).isEqualTo(location); - } - - @Test - public void testHandleToken() { - StreamToken streamToken = StreamToken.getDefaultInstance(); - ModelToken modelToken = mock(ModelToken.class); - when(modelToken.getStreamToken()).thenReturn(streamToken); - - FeedModelProvider modelProvider = createFeedModelProviderWithConfig(); - modelProvider.mSessionId = SESSION_ID; - modelProvider.handleToken(modelToken); - verify(mFeedSessionManager).handleToken(SESSION_ID, streamToken); - } - - @Test - public void testForceRefresh() { - FeedModelProvider modelProvider = createFeedModelProviderWithConfig(); - modelProvider.mSessionId = SESSION_ID; - modelProvider.triggerRefresh(RequestReason.OPEN_WITH_CONTENT); - assertThat(modelProvider.getDelayedTriggerRefreshForTest()).isFalse(); - verify(mFeedSessionManager) - .triggerRefresh(SESSION_ID, RequestReason.OPEN_WITH_CONTENT, - UiContext.getDefaultInstance()); - } - - @Test - public void testForceRefresh_differentReason() { - FeedModelProvider modelProvider = createFeedModelProviderWithConfig(); - modelProvider.mSessionId = SESSION_ID; - modelProvider.triggerRefresh(RequestReason.HOST_REQUESTED); - assertThat(modelProvider.getDelayedTriggerRefreshForTest()).isFalse(); - verify(mFeedSessionManager) - .triggerRefresh( - SESSION_ID, RequestReason.HOST_REQUESTED, UiContext.getDefaultInstance()); - } - - @Test - public void testForceRefresh_delayed() { - FeedModelProvider modelProvider = createFeedModelProviderWithConfig(); - assertThat(modelProvider.getDelayedTriggerRefreshForTest()).isFalse(); - assertThat(modelProvider.getRequestReasonForTest()).isEqualTo(RequestReason.UNKNOWN); - modelProvider.triggerRefresh(RequestReason.HOST_REQUESTED); - assertThat(modelProvider.getDelayedTriggerRefreshForTest()).isTrue(); - assertThat(modelProvider.getRequestReasonForTest()).isEqualTo(RequestReason.HOST_REQUESTED); - verify(mFeedSessionManager, never()) - .triggerRefresh(eq(null), anyInt(), any(UiContext.class)); - } - - @Test - public void testInvalidate() { - // Create a valid model - FeedModelProvider modelProvider = createFeedModelProviderWithConfig(); - StreamFeature rootStreamFeature = getRootFeature(); - modelProvider.edit().addChild(createStreamStructureAndBinding(rootStreamFeature)).commit(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - - ModelFeature rootFeature = modelProvider.getRootFeature(); - assertThat(rootFeature).isNotNull(); - ModelCursor modelCursor = rootFeature.getCursor(); - - modelProvider.invalidate(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INVALIDATED); - assertThat(modelCursor.isAtEnd()).isTrue(); - } - - @Test - public void testInvalidate_unregister() { - mFakeMainThreadRunner = FakeMainThreadRunner.queueAllTasks(); - FeedModelProvider modelProvider = createFeedModelProviderWithConfig(); - mFakeMainThreadRunner.runAllTasks(); - - ModelProviderObserver observer = mock(ModelProviderObserver.class); - modelProvider.registerObserver(observer); - modelProvider.invalidate(); - modelProvider.unregisterObserver(observer); - mFakeMainThreadRunner.runAllTasks(); - verify(observer, never()).onSessionFinished(UiContext.getDefaultInstance()); - } - - @Test - public void testObserverLifecycle() { - FeedModelProvider modelProvider = createFeedModelProviderWithConfig(); - ModelProviderObserver observer1 = mock(ModelProviderObserver.class); - modelProvider.registerObserver(observer1); - verify(observer1, never()).onSessionStart(UiContext.getDefaultInstance()); - - StreamFeature rootStreamFeature = getRootFeature(); - modelProvider.edit().addChild(createStreamStructureAndBinding(rootStreamFeature)).commit(); - verify(observer1).onSessionStart(UiContext.getDefaultInstance()); - - ModelProviderObserver observer2 = mock(ModelProviderObserver.class); - modelProvider.registerObserver(observer2); - verify(observer2).onSessionStart(UiContext.getDefaultInstance()); - - modelProvider.invalidate(); - verify(observer1).onSessionFinished(UiContext.getDefaultInstance()); - verify(observer2).onSessionFinished(UiContext.getDefaultInstance()); - - ModelProviderObserver observer3 = mock(ModelProviderObserver.class); - modelProvider.registerObserver(observer3); - verify(observer3).onSessionFinished(UiContext.getDefaultInstance()); - } - - @Test - public void testObserverLifecycle_resetRoot() { - FeedModelProvider modelProvider = createFeedModelProviderWithConfig(); - ModelProviderObserver observer = mock(ModelProviderObserver.class); - modelProvider.registerObserver(observer); - verify(observer, never()).onSessionStart(UiContext.getDefaultInstance()); - - StreamFeature rootStreamFeature = getRootFeature(); - modelProvider.edit().addChild(createStreamStructureAndBinding(rootStreamFeature)).commit(); - verify(observer).onSessionStart(UiContext.getDefaultInstance()); - - String anotherRootId = mIdGenerators.createRootContentId(100); - rootStreamFeature = StreamFeature.newBuilder().setContentId(anotherRootId).build(); - modelProvider.edit().addChild(createStreamStructureAndBinding(rootStreamFeature)).commit(); - verify(observer).onSessionFinished(UiContext.getDefaultInstance()); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INVALIDATED); - } - - @Test - public void testObserverList() { - FeedModelProvider modelProvider = createFeedModelProviderWithConfig(); - ModelProviderObserver observer = mock(ModelProviderObserver.class); - modelProvider.registerObserver(observer); - - Collection<ModelProviderObserver> observers = modelProvider.getObserversToNotify(); - assertThat(observers.size()).isEqualTo(1); - assertThat(observers).contains(observer); - } - - @Test - public void testRaiseError_noCards() { - FeedModelProvider modelProvider = createFeedModelProviderWithConfig(); - ModelProviderObserver observer = mock(ModelProviderObserver.class); - modelProvider.registerObserver(observer); - - ModelError modelError = new ModelError(ErrorType.NO_CARDS_ERROR, null); - modelProvider.raiseError(modelError); - verify(observer).onError(modelError); - } - - @Test - public void testRaiseError_pagination() { - FeedModelProvider modelProvider = createFeedModelProviderWithConfig(); - - int featureCnt = 3; - StreamToken streamToken = initializeStreamWithToken(modelProvider, featureCnt); - ModelChild tokenChild = getContinuationToken(modelProvider.getRootFeature()); - assertThat(tokenChild).isNotNull(); - - ModelError modelError = - new ModelError(ErrorType.PAGINATION_ERROR, streamToken.getNextPageToken()); - TokenCompletedObserver observer = mock(TokenCompletedObserver.class); - tokenChild.getModelToken().registerObserver(observer); - modelProvider.raiseError(modelError); - verify(observer).onError(modelError); - } - - @Test - public void testInitializationModelMutationHandler() { - FeedModelProvider modelProvider = createFeedModelProviderWithConfig(); - ModelProviderObserver observer = mock(ModelProviderObserver.class); - modelProvider.registerObserver(observer); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - InitializeModel initializeModel = - modelProvider.new InitializeModel(UiContext.getDefaultInstance()); - initializeModel.postMutation(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - verify(observer).onSessionStart(UiContext.getDefaultInstance()); - } - - @Test - public void testTokens() { - FeedModelProvider modelProvider = createFeedModelProviderWithConfig(); - - int featureCnt = 3; - StreamToken streamToken = initializeStreamWithToken(modelProvider, featureCnt); - - ModelFeature rootFeature = modelProvider.getRootFeature(); - assertThat(rootFeature).isNotNull(); - ModelCursor modelCursor = rootFeature.getCursor(); - int cnt = 0; - mContinuationToken = null; - ModelChild child; - while ((child = modelCursor.getNextItem()) != null) { - cnt++; - if (child.getType() == Type.TOKEN) { - mContinuationToken = child; - } - } - assertThat(cnt).isEqualTo(featureCnt + 1); - assertThat(mContinuationToken).isNotNull(); - assertThat(mContinuationToken.getModelToken().getStreamToken()).isEqualTo(streamToken); - } - - @Test - public void testTokenMutation() { - FeedModelProvider modelProvider = createFeedModelProviderWithConfig(); - - int featureCnt = 3; - StreamToken streamToken = initializeStreamWithToken(modelProvider, featureCnt); - Map<ByteString, TokenTracking> tokens = modelProvider.getTokensForTest(); - assertThat(tokens).hasSize(1); - - ModelFeature rootFeature = modelProvider.getRootFeature(); - assertThat(rootFeature).isNotNull(); - ModelCursor modelCursor = rootFeature.getCursor(); - mContinuationToken = null; - ModelChild child; - while ((child = modelCursor.getNextItem()) != null) { - if (child.getType() == Type.TOKEN) { - mContinuationToken = child; - } - } - assertThat(mContinuationToken).isNotNull(); - - TokenMutation tokenMutation = modelProvider.new TokenMutation(streamToken); - TokenTracking tokenTracking = tokenMutation.getTokenTrackingForTest(); - assertThat(tokenTracking.mLocation.size()).isEqualTo(featureCnt + 1); - - tokenMutation.preMutation(); - assertThat(tokenTracking.mLocation.size()).isEqualTo(featureCnt + 1); - assertThat(tokenMutation.mNewCursorStart).isEqualTo(tokenTracking.mLocation.size() - 1); - tokens = modelProvider.getTokensForTest(); - assertThat(tokens).hasSize(0); - - TokenCompletedObserver tokenCompletedObserver = new TokenCompletedObserver() { - @Override - public void onTokenCompleted(TokenCompleted tokenCompleted) { - assertThat(tokenCompleted).isNotNull(); - } - - @Override - public void onError(ModelError error) {} - }; - mContinuationToken.getModelToken().registerObserver(tokenCompletedObserver); - tokenMutation.postMutation(); - } - - @Test - public void testSyntheticToken() { - int initialPageSize = 4; - int pageSize = 4; - initSyntheticTokenConfig( - /* initialPageSize= */ initialPageSize, /* minPageSize= */ 2, - /* pageSize= */ pageSize); - - doAnswer(invocation -> { - Object[] args = invocation.getArguments(); - ((Runnable) args[2]).run(); - return null; - }) - .when(mTaskQueue) - .execute(anyInt(), anyInt(), any()); - - FeedModelProvider modelProvider = createFeedModelProvider(); - int featureCnt = 11; - createTopLevelFeatures(modelProvider, featureCnt).commit(); - - ModelFeature rootFeature = modelProvider.getRootFeature(); - assertThat(rootFeature).isNotNull(); - ModelCursor modelCursor = rootFeature.getCursor(); - assertThat(modelCursor).isNotNull(); - - ModelChild lastChild = assertCursorSize(modelCursor, initialPageSize + 1); - assertThat(lastChild.getType()).isEqualTo(Type.TOKEN); - assertThat(lastChild.getModelToken().isSynthetic()).isTrue(); - - // The token should be handled in the FeedModelProvider - modelProvider.handleToken(lastChild.getModelToken()); - modelCursor = rootFeature.getCursor(); - assertThat(modelCursor).isNotNull(); - - lastChild = assertCursorSize(modelCursor, initialPageSize + pageSize + 1); - assertThat(lastChild.getType()).isEqualTo(Type.TOKEN); - assertThat(lastChild.getModelToken().isSynthetic()).isTrue(); - - // last page - modelProvider.handleToken(lastChild.getModelToken()); - modelCursor = rootFeature.getCursor(); - assertThat(modelCursor).isNotNull(); - - lastChild = assertCursorSize(modelCursor, featureCnt); - assertThat(lastChild.getType()).isEqualTo(Type.FEATURE); - } - - @Test - public void testSyntheticToken_missingToken() { - int initialPageSize = 4; - int pageSize = 4; - initSyntheticTokenConfig( - /* initialPageSize= */ initialPageSize, /* minPageSize= */ 2, - /* pageSize= */ pageSize); - - doAnswer(invocation -> { - Object[] args = invocation.getArguments(); - ((Runnable) args[2]).run(); - return null; - }) - .when(mTaskQueue) - .execute(anyInt(), anyInt(), any()); - - FeedModelProvider modelProvider = createFeedModelProvider(); - createTopLevelFeatures(modelProvider, /* featureCount= */ 11).commit(); - - ModelCursor modelCursor = modelProvider.getRootFeature().getCursor(); - ModelChild lastChild = assertCursorSize(modelCursor, initialPageSize + 1); - assertThat(lastChild.getType()).isEqualTo(Type.TOKEN); - assertThat(lastChild.getModelToken().isSynthetic()).isTrue(); - - // Simulate removing the synthetic token from the root. - FakeTokenCompletedObserver observer = new FakeTokenCompletedObserver(); - lastChild.getModelToken().registerObserver(observer); - modelProvider.clearRootChildrenForTest(); - modelProvider.handleToken(lastChild.getModelToken()); - assertThat(observer.mErrorThrown).isNotNull(); - assertThat(observer.mErrorThrown.getErrorType()).isEqualTo(ErrorType.SYNTHETIC_TOKEN_ERROR); - } - - @Test - public void testViewDepthProvider_null() { - FeedModelProvider modelProvider = createFeedModelProviderWithConfig(); - assertThat(modelProvider.getViewDepthProvider(null)).isNull(); - } - - @Test - public void testViewDepthProvider_delegatedNull() { - FeedModelProvider modelProvider = createFeedModelProviderWithConfig(); - ViewDepthProvider mockProvider = mock(ViewDepthProvider.class); - when(mockProvider.getChildViewDepth()).thenReturn(null); - assertThat(modelProvider.getViewDepthProvider(null)).isNull(); - } - - @Test - public void testViewDepthProvider_delegated() { - FeedModelProvider modelProvider = createFeedModelProviderWithConfig(); - int featureCnt = 3; - ModelMutation mutator = createTopLevelFeatures(modelProvider, featureCnt); - String featureParent = createFeatureContentId(2); - for (int i = 0; i < featureCnt; i++) { - mutator.addChild(createStreamStructureAndBinding( - createFeature(i + 1 + featureCnt, featureParent))); - } - String childFeatureContentId = createFeatureContentId(1 + featureCnt); - mutator.commit(); - - ViewDepthProvider mockProvider = mock(ViewDepthProvider.class); - when(mockProvider.getChildViewDepth()).thenReturn(childFeatureContentId); - - ViewDepthProvider provider = modelProvider.getViewDepthProvider(mockProvider); - assertThat(provider.getChildViewDepth()).isEqualTo(featureParent); - } - - @Test - public void testGetEmptyRoot() { - FeedModelProvider modelProvider = createFeedModelProviderWithConfig(); - ModelMutation mutation = getRootedModelMutator(modelProvider); - mChildBindings.clear(); - mutation.commit(); - - assertThat(modelProvider.getRootFeature()).isNull(); - assertThat(mFakeBasicLoggingApi.lastInternalError) - .isEqualTo(InternalFeedError.ROOT_NOT_BOUND_TO_FEATURE); - } - - @Test - public void testGetAllRootChildren() { - FeedModelProvider modelProvider = createFeedModelProviderWithConfig(); - int featureCnt = 3; - createTopLevelFeatures(modelProvider, featureCnt).commit(); - - List<ModelChild> rootChildren = modelProvider.getAllRootChildren(); - assertThat(rootChildren).hasSize(featureCnt); - } - - private ModelChild getContinuationToken(ModelFeature rootFeature) { - ModelCursor modelCursor = rootFeature.getCursor(); - ModelChild token = null; - ModelChild child; - while ((child = modelCursor.getNextItem()) != null) { - if (child.getType() == Type.TOKEN) { - token = child; - } - } - assertThat(token).isNotNull(); - return token; - } - - private ModelChild assertCursorSize(ModelCursor cursor, int size) { - int cnt = 0; - ModelChild lastChild = null; - ModelChild child; - while ((child = cursor.getNextItem()) != null) { - cnt++; - lastChild = child; - } - assertThat(cnt).isEqualTo(size); - assertThat(lastChild).isNotNull(); - return lastChild; - } - - private void initDefaultConfig() { - initSyntheticTokenConfig( - /* initialPageSize= */ 0L, /* minPageSize= */ 0L, /* pageSize= */ 0L); - } - - private void initSyntheticTokenConfig(long initialPageSize, long minPageSize, long pageSize) { - when(mConfig.getValueOrDefault(ConfigKey.INITIAL_NON_CACHED_PAGE_SIZE, 0L)) - .thenReturn(initialPageSize); - when(mConfig.getValueOrDefault(ConfigKey.NON_CACHED_PAGE_SIZE, 0L)).thenReturn(pageSize); - when(mConfig.getValueOrDefault(ConfigKey.NON_CACHED_MIN_PAGE_SIZE, 0L)) - .thenReturn(minPageSize); - } - - private StreamToken initializeStreamWithToken(FeedModelProvider modelProvider, int featureCnt) { - ModelMutation mutator = createTopLevelFeatures(modelProvider, featureCnt); - - // Populate the model provider with a continuation token at the end. - ByteString bytes = ByteString.copyFrom("continuation", Charset.defaultCharset()); - StreamToken streamToken = StreamToken.newBuilder() - .setNextPageToken(bytes) - .setParentId(mRootContentId) - .build(); - mutator.addChild(createStreamStructureAndBinding(streamToken)); - mutator.commit(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - return streamToken; - } - - private FeedModelProvider createFeedModelProviderWithConfig() { - initDefaultConfig(); - return createFeedModelProvider(); - } - - private FeedModelProvider createFeedModelProvider() { - return new FeedModelProvider(mFeedSessionManager, mThreadUtils, mTimingUtils, mTaskQueue, - mFakeMainThreadRunner, null, mConfig, mFakeBasicLoggingApi); - } - - private ModelMutation createTopLevelFeatures(ModelProvider modelProvider, int featureCount) { - ModelMutation mutator = getRootedModelMutator(modelProvider); - for (int i = 0; i < featureCount; i++) { - mutator.addChild(createStreamStructureAndBinding(createFeature(i + 1, mRootContentId))); - } - return mutator; - } - - private StreamFeature createFeature(int i, String parentContentId) { - return StreamFeature.newBuilder() - .setParentId(parentContentId) - .setContentId(createFeatureContentId(i)) - .setCard(Card.getDefaultInstance()) - .build(); - } - - private String createFeatureContentId(int i) { - return mIdGenerators.createFeatureContentId(i); - } - - private ModelMutation getRootedModelMutator(ModelProvider modelProvider) { - ModelMutation mutator = modelProvider.edit(); - assertThat(mutator).isNotNull(); - StreamFeature rootStreamFeature = getRootFeature(); - mutator.addChild(createStreamStructureAndBinding(rootStreamFeature)); - return mutator; - } - - private StreamStructure createStreamStructureFromFeature(StreamFeature feature) { - StreamStructure.Builder builder = StreamStructure.newBuilder() - .setContentId(feature.getContentId()) - .setOperation(Operation.UPDATE_OR_APPEND); - if (feature.hasParentId()) { - builder.setParentContentId(feature.getParentId()); - } - return builder.build(); - } - - private StreamStructure createStreamStructureFromToken(StreamToken token) { - StreamStructure.Builder builder = StreamStructure.newBuilder() - .setContentId(token.getContentId()) - .setOperation(Operation.UPDATE_OR_APPEND); - if (token.hasParentId()) { - builder.setParentContentId(token.getParentId()); - } - return builder.build(); - } - - private StreamStructure createRemove(String parentContentId, String contentId) { - return StreamStructure.newBuilder() - .setContentId(contentId) - .setParentContentId(parentContentId) - .setOperation(Operation.REMOVE) - .build(); - } - - /** - * This has the side affect of populating {@code childBindings} with a {@code PayloadWithId}. - */ - private StreamStructure createStreamStructureAndBinding(StreamFeature feature) { - StreamPayload payload = StreamPayload.newBuilder().setStreamFeature(feature).build(); - mChildBindings.add(new PayloadWithId(feature.getContentId(), payload)); - return createStreamStructureFromFeature(feature); - } - - /** - * This has the side affect of populating {@code childBindings} with a {@code PayloadWithId}. - */ - private StreamStructure createStreamStructureAndBinding(StreamToken token) { - StreamPayload payload = StreamPayload.newBuilder().setStreamToken(token).build(); - mChildBindings.add(new PayloadWithId(token.getContentId(), payload)); - return createStreamStructureFromToken(token); - } - - private StreamFeature getRootFeature() { - return StreamFeature.newBuilder().setContentId(mRootContentId).build(); - } - - private static class FakeTokenCompletedObserver implements TokenCompletedObserver { - private ModelError mErrorThrown; - - @Override - public void onTokenCompleted(TokenCompleted tokenCompleted) {} - - @Override - public void onError(ModelError modelError) { - mErrorThrown = modelError; - } - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedmodelprovider/internal/FeatureChangeImplTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedmodelprovider/internal/FeatureChangeImplTest.java deleted file mode 100644 index 9c1bc6b..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedmodelprovider/internal/FeatureChangeImplTest.java +++ /dev/null
@@ -1,75 +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. - -package org.chromium.chrome.browser.feed.library.feedmodelprovider.internal; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.internal.common.testing.ContentIdGenerators; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelChild; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelFeature; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamFeature; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests of the {@link FeatureChangeImpl} class. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class FeatureChangeImplTest { - @Mock - private ModelFeature mModelFeature; - - private String mModelContentId; - private ContentIdGenerators mIdGenerators = new ContentIdGenerators(); - - @Before - public void setup() { - initMocks(this); - mModelContentId = mIdGenerators.createFeatureContentId(1); - StreamFeature streamFeature = - StreamFeature.newBuilder().setContentId(mModelContentId).build(); - when(mModelFeature.getStreamFeature()).thenReturn(streamFeature); - } - - @Test - public void testStreamFeatureChange() { - FeatureChangeImpl featureChange = new FeatureChangeImpl(mModelFeature); - - assertThat(featureChange.getModelFeature()).isEqualTo(mModelFeature); - assertThat(featureChange.getContentId()).isEqualTo(mModelContentId); - assertThat(featureChange.getChildChanges().getAppendedChildren()).isEmpty(); - assertThat(featureChange.getChildChanges().getRemovedChildren()).isEmpty(); - assertThat(featureChange.isFeatureChanged()).isFalse(); - - featureChange.setFeatureChanged(true); - assertThat(featureChange.isFeatureChanged()).isTrue(); - } - - @Test - public void testAppendChild() { - ModelChild modelChild = mock(ModelChild.class); - FeatureChangeImpl featureChange = new FeatureChangeImpl(mModelFeature); - featureChange.getChildChangesImpl().addAppendChild(modelChild); - assertThat(featureChange.getChildChanges().getAppendedChildren()).hasSize(1); - assertThat(featureChange.getChildChanges().getAppendedChildren()).contains(modelChild); - } - - @Test - public void testRemoveChild() { - ModelChild modelChild = mock(ModelChild.class); - FeatureChangeImpl featureChange = new FeatureChangeImpl(mModelFeature); - featureChange.getChildChangesImpl().removeChild(modelChild); - assertThat(featureChange.getChildChanges().getRemovedChildren()).hasSize(1); - assertThat(featureChange.getChildChanges().getRemovedChildren()).contains(modelChild); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedmodelprovider/internal/ModelCursorImplTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedmodelprovider/internal/ModelCursorImplTest.java deleted file mode 100644 index fa646de..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedmodelprovider/internal/ModelCursorImplTest.java +++ /dev/null
@@ -1,132 +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. - -package org.chromium.chrome.browser.feed.library.feedmodelprovider.internal; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.mock; -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.internal.common.testing.ContentIdGenerators; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelFeature; -import org.chromium.chrome.browser.feed.library.feedmodelprovider.internal.ModelCursorImpl.CursorIterator; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.ArrayList; -import java.util.List; - -/** Tests of the {@link ModelCursorImpl}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ModelCursorImplTest { - private List<UpdatableModelChild> mModelChildren; - private String mParentContentId; - private final ContentIdGenerators mContentIdGenerators = new ContentIdGenerators(); - - @Before - public void setup() { - initMocks(this); - mModelChildren = new ArrayList<>(); - mParentContentId = "parent.content.id"; - } - - @Test - public void testEmptyCursor() { - ModelCursorImpl cursor = new ModelCursorImpl(mParentContentId, mModelChildren); - assertThat(cursor.isAtEnd()).isTrue(); - } - - @Test - public void testReleaseCursor() { - mModelChildren.add(new UpdatableModelChild("contentId", "parentId")); - ModelCursorImpl cursor = new ModelCursorImpl(mParentContentId, mModelChildren); - assertThat(cursor.isAtEnd()).isFalse(); - - cursor.release(); - assertThat(cursor.isAtEnd()).isTrue(); - - assertThat(cursor.getNextItem()).isNull(); - } - - @Test - public void testIteration() { - int childrenToAdd = 3; - for (int i = 0; i < childrenToAdd; i++) { - mModelChildren.add(new UpdatableModelChild("contentId", "parentId")); - } - ModelCursorImpl cursor = new ModelCursorImpl(mParentContentId, mModelChildren); - int childCount = 0; - for (int i = 0; i < childrenToAdd; i++) { - childCount++; - assertThat(cursor.getNextItem()).isNotNull(); - } - assertThat(cursor.getNextItem()).isNull(); - assertThat(cursor.isAtEnd()).isTrue(); - assertThat(childCount).isEqualTo(childrenToAdd); - } - - @Test - public void testUpdateIterator_append() { - int childrenToAdd = 3; - for (int i = 0; i < childrenToAdd; i++) { - mModelChildren.add(new UpdatableModelChild("contentId", "parentId")); - } - ModelCursorImpl cursor = new ModelCursorImpl(mParentContentId, mModelChildren); - ModelFeature modelFeature = mock(ModelFeature.class); - FeatureChangeImpl featureChange = new FeatureChangeImpl(modelFeature); - UpdatableModelChild newChild = new UpdatableModelChild("contentId", "parentId"); - featureChange.getChildChangesImpl().addAppendChild(newChild); - cursor.updateIterator(featureChange); - List<UpdatableModelChild> children = cursor.getChildListForTesting(); - assertThat(children).hasSize(4); - assertThat(children.get(3)).isEqualTo(newChild); - } - - @Test - public void testUpdateIterator_remove() { - int childrenToAdd = 3; - for (int i = 0; i < childrenToAdd; i++) { - String contentId = mContentIdGenerators.createFeatureContentId(i); - UpdatableModelChild child = new UpdatableModelChild(contentId, "parentId"); - mModelChildren.add(child); - } - ModelCursorImpl cursor = new ModelCursorImpl(mParentContentId, mModelChildren); - ModelFeature modelFeature = mock(ModelFeature.class); - FeatureChangeImpl featureChange = new FeatureChangeImpl(modelFeature); - featureChange.getChildChangesImpl().removeChild(mModelChildren.get(1)); - cursor.updateIterator(featureChange); - List<UpdatableModelChild> children = cursor.getChildListForTesting(); - assertThat(children).hasSize(2); - } - - @Test - public void testCursorIterator() { - int childrenToAdd = 3; - for (int i = 0; i < childrenToAdd; i++) { - mModelChildren.add(new UpdatableModelChild("contentId", "parentId")); - } - CursorIterator cursorIterator = - new ModelCursorImpl(mParentContentId, mModelChildren).new CursorIterator(); - assertThat(cursorIterator.getPosition()).isEqualTo(0); - assertThat(cursorIterator.hasNext()).isTrue(); - assertThat(cursorIterator.next()).isEqualTo(mModelChildren.get(0)); - assertThat(cursorIterator.getPosition()).isEqualTo(1); - } - - @Test - public void testCopiesList() { - UpdatableModelChild child1 = new UpdatableModelChild("content id", null); - mModelChildren.add(child1); - ModelCursorImpl modelCursor = new ModelCursorImpl(mParentContentId, mModelChildren); - UpdatableModelChild child2 = new UpdatableModelChild("content id 2", null); - mModelChildren.add(child2); - assertThat(modelCursor.getChildListForTesting()).containsExactly(child1); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedmodelprovider/internal/ModelFeatureImplTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedmodelprovider/internal/ModelFeatureImplTest.java deleted file mode 100644 index 516becf..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedmodelprovider/internal/ModelFeatureImplTest.java +++ /dev/null
@@ -1,47 +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. - -package org.chromium.chrome.browser.feed.library.feedmodelprovider.internal; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelCursor; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamFeature; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests of the {@link UpdatableModelFeature}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ModelFeatureImplTest { - private StreamFeature mStreamFeature; - @Mock - private CursorProvider mCursorProvider; - @Mock - private ModelCursor mModelCursor; - - @Before - public void setup() { - initMocks(this); - String contentId = "content-id"; - mStreamFeature = StreamFeature.newBuilder().setContentId(contentId).build(); - when(mCursorProvider.getCursor(contentId)).thenReturn(mModelCursor); - } - - @Test - public void testBase() { - UpdatableModelFeature modelFeature = - new UpdatableModelFeature(mStreamFeature, mCursorProvider); - assertThat(modelFeature.getStreamFeature()).isEqualTo(mStreamFeature); - assertThat(modelFeature.getCursor()).isEqualTo(mModelCursor); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedmodelprovider/internal/ModelMutationImplTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedmodelprovider/internal/ModelMutationImplTest.java deleted file mode 100644 index 515cf99..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedmodelprovider/internal/ModelMutationImplTest.java +++ /dev/null
@@ -1,97 +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. - -package org.chromium.chrome.browser.feed.library.feedmodelprovider.internal; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.verify; -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.common.MutationContext; -import org.chromium.chrome.browser.feed.library.common.functional.Committer; -import org.chromium.chrome.browser.feed.library.feedmodelprovider.internal.ModelMutationImpl.Change; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamFeature; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamStructure; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamStructure.Operation; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamToken; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests of {@link ModelMutationImpl}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ModelMutationImplTest { - @Mock - private Committer<Void, Change> mCommitter; - - @Before - public void setup() { - initMocks(this); - } - - @Test - public void testFeature() { - ModelMutationImpl modelMutator = new ModelMutationImpl(mCommitter); - StreamFeature streamFeature = StreamFeature.newBuilder().build(); - modelMutator.addChild(mCreateStreamStructureFromFeature(streamFeature)); - assertThat(modelMutator.mChange.mStructureChanges).hasSize(1); - modelMutator.commit(); - verify(mCommitter).commit(modelMutator.mChange); - } - - @Test - public void testToken() { - ModelMutationImpl modelMutator = new ModelMutationImpl(mCommitter); - StreamToken streamToken = StreamToken.newBuilder().build(); - modelMutator.addChild(mCreateStreamStructureFromToken(streamToken)); - assertThat(modelMutator.mChange.mStructureChanges).hasSize(1); - modelMutator.commit(); - verify(mCommitter).commit(modelMutator.mChange); - } - - @Test - public void testMutationContext() { - ModelMutationImpl modelMutator = new ModelMutationImpl(mCommitter); - MutationContext mutationContext = MutationContext.EMPTY_CONTEXT; - modelMutator.setMutationContext(mutationContext); - assertThat(modelMutator.mChange.mStructureChanges).isEmpty(); - modelMutator.commit(); - verify(mCommitter).commit(modelMutator.mChange); - assertThat(modelMutator.mChange.mMutationContext).isEqualTo(mutationContext); - } - - @Test - public void testRemove() { - ModelMutationImpl modelMutator = new ModelMutationImpl(mCommitter); - assertThat(modelMutator.mChange.mStructureChanges).isEmpty(); - modelMutator.removeChild(StreamStructure.getDefaultInstance()); - assertThat(modelMutator.mChange.mStructureChanges).hasSize(1); - } - - private StreamStructure mCreateStreamStructureFromFeature(StreamFeature feature) { - StreamStructure.Builder builder = StreamStructure.newBuilder() - .setContentId(feature.getContentId()) - .setOperation(Operation.UPDATE_OR_APPEND); - if (feature.hasParentId()) { - builder.setParentContentId(feature.getParentId()); - } - return builder.build(); - } - - private StreamStructure mCreateStreamStructureFromToken(StreamToken token) { - StreamStructure.Builder builder = StreamStructure.newBuilder() - .setContentId(token.getContentId()) - .setOperation(Operation.UPDATE_OR_APPEND); - if (token.hasParentId()) { - builder.setParentContentId(token.getParentId()); - } - return builder.build(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedmodelprovider/internal/ModelTokenImplTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedmodelprovider/internal/ModelTokenImplTest.java deleted file mode 100644 index b0d6dac..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedmodelprovider/internal/ModelTokenImplTest.java +++ /dev/null
@@ -1,51 +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. - -package org.chromium.chrome.browser.feed.library.feedmodelprovider.internal; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.TokenCompletedObserver; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamToken; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.List; - -/** Tests of {@link UpdatableModelToken}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ModelTokenImplTest { - @Mock - private TokenCompletedObserver mChangeObserver; - - @Before - public void setUp() { - initMocks(this); - } - - @Test - public void testFeature() { - StreamToken token = StreamToken.newBuilder().build(); - UpdatableModelToken modelToken = new UpdatableModelToken(token, false); - assertThat(modelToken.getStreamToken()).isEqualTo(token); - } - - @Test - public void testChangeObserverList() { - StreamToken token = StreamToken.newBuilder().build(); - UpdatableModelToken modelToken = new UpdatableModelToken(token, false); - modelToken.registerObserver(mChangeObserver); - List<TokenCompletedObserver> observers = modelToken.getObserversToNotify(); - assertThat(observers.size()).isEqualTo(1); - assertThat(observers.get(0)).isEqualTo(mChangeObserver); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedprotocoladapter/FeedProtocolAdapterTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedprotocoladapter/FeedProtocolAdapterTest.java deleted file mode 100644 index 1430452..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedprotocoladapter/FeedProtocolAdapterTest.java +++ /dev/null
@@ -1,235 +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. - -package org.chromium.chrome.browser.feed.library.feedprotocoladapter; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import com.google.common.collect.ImmutableList; -import com.google.protobuf.ByteString; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.internal.common.Model; -import org.chromium.chrome.browser.feed.library.api.internal.protocoladapter.RequiredContentAdapter; -import org.chromium.chrome.browser.feed.library.common.Result; -import org.chromium.chrome.browser.feed.library.common.testing.ResponseBuilder; -import org.chromium.chrome.browser.feed.library.common.time.TimingUtils; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamDataOperation; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamStructure; -import org.chromium.components.feed.core.proto.wire.ContentIdProto.ContentId; -import org.chromium.components.feed.core.proto.wire.DataOperationProto.DataOperation; -import org.chromium.components.feed.core.proto.wire.ResponseProto.Response; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.nio.charset.Charset; -import java.util.List; - -/** Tests of the {@link FeedProtocolAdapter} class. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class FeedProtocolAdapterTest { - private final TimingUtils mTimingUtils = new TimingUtils(); - private final FeedProtocolAdapter mProtocolAdapter = - new FeedProtocolAdapter(ImmutableList.of(), mTimingUtils); - - @Mock - private RequiredContentAdapter mAdapter; - private ResponseBuilder mResponseBuilder; - - @Before - public void init() { - initMocks(this); - mResponseBuilder = new ResponseBuilder(); - } - - @Test - public void testConvertContentId() { - ContentId contentId = ResponseBuilder.createFeatureContentId(13); - String streamContentId = mProtocolAdapter.getStreamContentId(contentId); - assertThat(streamContentId).isNotNull(); - assertThat(streamContentId).contains(contentId.getContentDomain()); - assertThat(streamContentId).contains(Long.toString(contentId.getId())); - assertThat(streamContentId).contains(contentId.getTable()); - } - - @Test - public void testConvertContentId_malformed_notThreeParts() { - String streamContentId = "test" + FeedProtocolAdapter.CONTENT_ID_DELIMITER + "break"; - Result<ContentId> contentIdResult = mProtocolAdapter.getWireContentId(streamContentId); - assertThat(contentIdResult.isSuccessful()).isFalse(); - } - - @Test - public void testConvertContentId_malformed_nonNumericId() { - String streamContentId = "test" + FeedProtocolAdapter.CONTENT_ID_DELIMITER + "break" - + FeedProtocolAdapter.CONTENT_ID_DELIMITER + "test"; - Result<ContentId> contentIdResult = mProtocolAdapter.getWireContentId(streamContentId); - assertThat(contentIdResult.isSuccessful()).isFalse(); - } - - @Test - public void testConvertContentId_roundTrip() { - ContentId contentId = ResponseBuilder.createFeatureContentId(13); - String streamContentId = mProtocolAdapter.getStreamContentId(contentId); - Result<ContentId> contentIdResult = mProtocolAdapter.getWireContentId(streamContentId); - assertThat(contentIdResult.isSuccessful()).isTrue(); - assertThat(contentIdResult.getValue()).isNotNull(); - assertThat(contentIdResult.getValue()).isEqualTo(contentId); - } - - @Test - public void testConvertContentId_roundTrip_partialContentId() { - ContentId contentId = ContentId.newBuilder().setId(13).build(); - String streamContentId = mProtocolAdapter.getStreamContentId(contentId); - Result<ContentId> contentIdResult = mProtocolAdapter.getWireContentId(streamContentId); - assertThat(contentIdResult.isSuccessful()).isTrue(); - assertThat(contentIdResult.getValue()).isNotNull(); - assertThat(contentIdResult.getValue()).isEqualTo(contentId); - } - - @Test - public void testSimpleResponse_clear() { - Response response = mResponseBuilder.addClearOperation().build(); - Result<Model> results = mProtocolAdapter.createModel(response); - assertThat(results.isSuccessful()).isTrue(); - assertThat(results.getValue().streamDataOperations).hasSize(1); - } - - @Test - public void testSimpleResponse_feature() { - Response response = mResponseBuilder.addRootFeature().build(); - - Result<Model> results = mProtocolAdapter.createModel(response); - assertThat(results.isSuccessful()).isTrue(); - assertThat(results.getValue().streamDataOperations).hasSize(1); - - StreamDataOperation sdo = results.getValue().streamDataOperations.get(0); - assertThat(sdo.hasStreamPayload()).isTrue(); - assertThat(sdo.getStreamPayload().hasStreamFeature()).isTrue(); - assertThat(sdo.hasStreamStructure()).isTrue(); - assertThat(sdo.getStreamStructure().hasContentId()).isTrue(); - // Added the root - assertThat(sdo.getStreamStructure().hasParentContentId()).isFalse(); - } - - @Test - public void testSimpleResponse_feature_semanticProperties() { - ContentId contentId = ResponseBuilder.createFeatureContentId(13); - ByteString semanticData = ByteString.copyFromUtf8("helloWorld"); - Response response = - new ResponseBuilder().addCardWithSemanticData(contentId, semanticData).build(); - - Result<Model> results = mProtocolAdapter.createModel(response); - assertThat(results.isSuccessful()).isTrue(); - // Note that 2 operations are created (the card and the semantic data). We want the latter. - assertThat(results.getValue().streamDataOperations).hasSize(2); - StreamDataOperation sdo = results.getValue().streamDataOperations.get(1); - assertThat(sdo.getStreamPayload().hasSemanticData()).isTrue(); - assertThat(sdo.getStreamPayload().getSemanticData()).isEqualTo(semanticData); - } - - @Test - public void testResponse_rootClusterCardContent() { - ContentId rootId = ContentId.newBuilder().setId(1).build(); - ContentId clusterId = ContentId.newBuilder().setId(2).build(); - ContentId cardId = ContentId.newBuilder().setId(3).build(); - Response response = mResponseBuilder.addRootFeature(rootId) - .addClusterFeature(clusterId, rootId) - .addCard(cardId, clusterId) - .build(); - - Result<Model> results = mProtocolAdapter.createModel(response); - assertThat(results.isSuccessful()).isTrue(); - List<StreamDataOperation> operations = results.getValue().streamDataOperations; - - assertThat(operations).hasSize(4); - assertThat(operations.get(0).getStreamPayload().getStreamFeature().hasStream()).isTrue(); - assertThat(operations.get(1).getStreamPayload().getStreamFeature().hasCluster()).isTrue(); - assertThat(operations.get(2).getStreamPayload().getStreamFeature().hasCard()).isTrue(); - assertThat(operations.get(3).getStreamPayload().getStreamFeature().hasContent()).isTrue(); - } - - @Test - public void testResponse_remove() { - Response response = mResponseBuilder - .removeFeature(ContentId.getDefaultInstance(), - ContentId.getDefaultInstance()) - .build(); - Result<Model> results = mProtocolAdapter.createModel(response); - assertThat(results.isSuccessful()).isTrue(); - assertThat(results.getValue().streamDataOperations).hasSize(1); - } - - @Test - public void testPietSharedState() { - Response response = mResponseBuilder.addPietSharedState().build(); - Result<Model> results = mProtocolAdapter.createModel(response); - assertThat(results.isSuccessful()).isTrue(); - assertThat(results.getValue().streamDataOperations).hasSize(1); - StreamDataOperation sdo = results.getValue().streamDataOperations.get(0); - assertThat(sdo.hasStreamPayload()).isTrue(); - assertThat(sdo.getStreamPayload().hasStreamSharedState()).isTrue(); - assertThat(sdo.hasStreamStructure()).isTrue(); - assertThat(sdo.getStreamStructure().hasContentId()).isTrue(); - } - - @Test - public void testContinuationToken_nextPageToken() { - ByteString tokenForMutation = ByteString.copyFrom("token", Charset.defaultCharset()); - Response response = mResponseBuilder.addStreamToken(1, tokenForMutation).build(); - - Result<Model> results = mProtocolAdapter.createModel(response); - assertThat(results.isSuccessful()).isTrue(); - assertThat(results.getValue().streamDataOperations).hasSize(1); - StreamDataOperation sdo = results.getValue().streamDataOperations.get(0); - assertThat(sdo.hasStreamPayload()).isTrue(); - assertThat(sdo.getStreamPayload().hasStreamToken()).isTrue(); - } - - @Test - public void testRequiredContentAdapter() { - when(mAdapter.determineRequiredContentIds(any(DataOperation.class))) - .thenReturn(ImmutableList.of(ContentId.newBuilder().setId(1).build())) - .thenReturn(ImmutableList.of(ContentId.newBuilder().setId(2).build())) - .thenReturn(ImmutableList.of(ContentId.newBuilder().setId(1).build(), - ContentId.newBuilder().setId(2).build(), - ContentId.newBuilder().setId(3).build())); - Response response = - mResponseBuilder.addRootFeature(ContentId.getDefaultInstance()) - .addClusterFeature( - ContentId.getDefaultInstance(), ContentId.getDefaultInstance()) - .addCard(ContentId.getDefaultInstance(), ContentId.getDefaultInstance()) - .build(); - - FeedProtocolAdapter mProtocolAdapter = - new FeedProtocolAdapter(ImmutableList.of(mAdapter), mTimingUtils); - Result<Model> result = mProtocolAdapter.createModel(response); - - verify(mAdapter, times(4)).determineRequiredContentIds(any(DataOperation.class)); - assertThat(result.isSuccessful()).isTrue(); - List<StreamDataOperation> operations = result.getValue().streamDataOperations; - assertThat(operations).hasSize(7); - assertThat(operations.get(4).getStreamStructure().getOperation()) - .isEqualTo(StreamStructure.Operation.REQUIRED_CONTENT); - assertThat(operations.get(5).getStreamStructure().getOperation()) - .isEqualTo(StreamStructure.Operation.REQUIRED_CONTENT); - assertThat(operations.get(6).getStreamStructure().getOperation()) - .isEqualTo(StreamStructure.Operation.REQUIRED_CONTENT); - assertThat(ImmutableList.of(operations.get(4).getStreamStructure().getContentId(), - operations.get(5).getStreamStructure().getContentId(), - operations.get(6).getStreamStructure().getContentId())) - .containsExactly("::::1", "::::2", "::::3"); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedprotocoladapter/internal/transformers/ContentDataOperationTransformerTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedprotocoladapter/internal/transformers/ContentDataOperationTransformerTest.java deleted file mode 100644 index aab3290..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedprotocoladapter/internal/transformers/ContentDataOperationTransformerTest.java +++ /dev/null
@@ -1,100 +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. - -package org.chromium.chrome.browser.feed.library.feedprotocoladapter.internal.transformers; - -import static com.google.common.truth.Truth.assertThat; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.ClientBasicLoggingMetadata; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamDataOperation; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamFeature; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamPayload; -import org.chromium.components.feed.core.proto.ui.stream.StreamStructureProto.BasicLoggingMetadata; -import org.chromium.components.feed.core.proto.ui.stream.StreamStructureProto.Content; -import org.chromium.components.feed.core.proto.ui.stream.StreamStructureProto.Content.Type; -import org.chromium.components.feed.core.proto.wire.DataOperationProto.DataOperation; -import org.chromium.components.feed.core.proto.wire.FeatureProto.Feature; -import org.chromium.components.feed.core.proto.wire.FeatureProto.Feature.RenderableUnit; -import org.chromium.components.feed.core.proto.wire.FeedResponseProto.FeedResponseMetadata; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link ContentDataOperationTransformer}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ContentDataOperationTransformerTest { - private static final String CONTENT_ID = "content-11"; - private static final long RESPONSE_TIME = 1000; - private static final FeedResponseMetadata METADATA = - FeedResponseMetadata.newBuilder().setResponseTimeMs(RESPONSE_TIME).build(); - private ContentDataOperationTransformer mContentDataOperationTransformer; - private DataOperation.Builder mDataOperation; - private StreamDataOperation.Builder mDataOperationBuilder; - private StreamFeature mStreamFeature; - - @Before - public void setUp() { - mContentDataOperationTransformer = new ContentDataOperationTransformer(); - mDataOperation = DataOperation.newBuilder(); - mStreamFeature = StreamFeature.newBuilder().setContentId(CONTENT_ID).build(); - mDataOperationBuilder = StreamDataOperation.newBuilder().setStreamPayload( - StreamPayload.newBuilder().setStreamFeature(mStreamFeature)); - } - - @Test - public void transform_setsContent() { - BasicLoggingMetadata basicLoggingMetadata = - BasicLoggingMetadata.newBuilder().setScore(.2f).build(); - ClientBasicLoggingMetadata clientBasicLoggingMetadata = - ClientBasicLoggingMetadata.newBuilder() - .setAvailabilityTimeSeconds(RESPONSE_TIME) - .build(); - Content content = Content.newBuilder() - .setType(Type.UNKNOWN_CONTENT) - .setBasicLoggingMetadata(basicLoggingMetadata) - .build(); - mDataOperation.setFeature(Feature.newBuilder() - .setExtension(Content.contentExtension, content) - .setRenderableUnit(RenderableUnit.CONTENT)); - - StreamDataOperation.Builder operation = mContentDataOperationTransformer.transform( - mDataOperation.build(), mDataOperationBuilder, METADATA); - - assertThat(operation.getStreamPayload().getStreamFeature().getContent()) - .isEqualTo( - content.toBuilder() - .setBasicLoggingMetadata( - basicLoggingMetadata.toBuilder() - .setExtension(ClientBasicLoggingMetadata - .clientBasicLoggingMetadata, - clientBasicLoggingMetadata) - .build()) - .build()); - } - - @Test - public void transform_responseTimeNotSet() { - mDataOperation.setFeature( - Feature.newBuilder() - .setExtension(Content.contentExtension, Content.getDefaultInstance()) - .setRenderableUnit(RenderableUnit.CONTENT)); - StreamDataOperation.Builder operation = - mContentDataOperationTransformer.transform(mDataOperation.build(), - mDataOperationBuilder, FeedResponseMetadata.getDefaultInstance()); - - assertThat(operation).isSameInstanceAs(mDataOperationBuilder); - } - - @Test - public void transform_featureIsNotContent() { - StreamDataOperation.Builder operation = mContentDataOperationTransformer.transform( - mDataOperation.build(), mDataOperationBuilder, METADATA); - - assertThat(operation).isSameInstanceAs(mDataOperationBuilder); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedprotocoladapter/internal/transformers/FeatureDataOperationTransformerTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedprotocoladapter/internal/transformers/FeatureDataOperationTransformerTest.java deleted file mode 100644 index 912e108..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedprotocoladapter/internal/transformers/FeatureDataOperationTransformerTest.java +++ /dev/null
@@ -1,99 +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. - -package org.chromium.chrome.browser.feed.library.feedprotocoladapter.internal.transformers; - -import static com.google.common.truth.Truth.assertThat; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamDataOperation; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamFeature; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamPayload; -import org.chromium.components.feed.core.proto.ui.stream.StreamStructureProto.Card; -import org.chromium.components.feed.core.proto.ui.stream.StreamStructureProto.Cluster; -import org.chromium.components.feed.core.proto.ui.stream.StreamStructureProto.Stream; -import org.chromium.components.feed.core.proto.wire.DataOperationProto.DataOperation; -import org.chromium.components.feed.core.proto.wire.FeatureProto.Feature; -import org.chromium.components.feed.core.proto.wire.FeatureProto.Feature.RenderableUnit; -import org.chromium.components.feed.core.proto.wire.FeedResponseProto.FeedResponseMetadata; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link FeatureDataOperationTransformer}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class FeatureDataOperationTransformerTest { - private static final String CONTENT_ID = "123"; - private DataOperation.Builder mDataOperation; - private StreamDataOperation.Builder mDataOperationBuilder; - private StreamFeature mStreamFeature; - private FeatureDataOperationTransformer mFeatureDataOperationTransformer; - - @Before - public void setUp() { - mFeatureDataOperationTransformer = new FeatureDataOperationTransformer(); - mDataOperation = DataOperation.newBuilder(); - mStreamFeature = StreamFeature.newBuilder().setContentId(CONTENT_ID).build(); - mDataOperationBuilder = StreamDataOperation.newBuilder().setStreamPayload( - StreamPayload.newBuilder().setStreamFeature(mStreamFeature)); - } - - @Test - public void testTransformSetStream() { - Feature feature = Feature.newBuilder() - .setRenderableUnit(RenderableUnit.STREAM) - .setExtension(Stream.streamExtension, Stream.getDefaultInstance()) - .build(); - mDataOperation.setFeature(feature); - StreamFeature expectedStreamFeature = - mStreamFeature.toBuilder().setStream(Stream.getDefaultInstance()).build(); - - StreamDataOperation.Builder operation = - mFeatureDataOperationTransformer.transform(mDataOperation.build(), - mDataOperationBuilder, FeedResponseMetadata.getDefaultInstance()); - - assertThat(operation.getStreamPayload().getStreamFeature()) - .isEqualTo(expectedStreamFeature); - } - - @Test - public void testTransformSetCard() { - Feature feature = Feature.newBuilder() - .setRenderableUnit(RenderableUnit.CARD) - .setExtension(Card.cardExtension, Card.getDefaultInstance()) - .build(); - mDataOperation.setFeature(feature); - StreamFeature expectedStreamFeature = - mStreamFeature.toBuilder().setCard(Card.getDefaultInstance()).build(); - - StreamDataOperation.Builder operation = - mFeatureDataOperationTransformer.transform(mDataOperation.build(), - mDataOperationBuilder, FeedResponseMetadata.getDefaultInstance()); - - assertThat(operation.getStreamPayload().getStreamFeature()) - .isEqualTo(expectedStreamFeature); - } - - @Test - public void testTransformSetCluster() { - Feature feature = - Feature.newBuilder() - .setRenderableUnit(RenderableUnit.CLUSTER) - .setExtension(Cluster.clusterExtension, Cluster.getDefaultInstance()) - .build(); - mDataOperation.setFeature(feature); - StreamFeature expectedStreamFeature = - mStreamFeature.toBuilder().setCluster(Cluster.getDefaultInstance()).build(); - - StreamDataOperation.Builder operation = - mFeatureDataOperationTransformer.transform(mDataOperation.build(), - mDataOperationBuilder, FeedResponseMetadata.getDefaultInstance()); - - assertThat(operation.getStreamPayload().getStreamFeature()) - .isEqualTo(expectedStreamFeature); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedrequestmanager/FeedActionUploadRequestManagerTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedrequestmanager/FeedActionUploadRequestManagerTest.java deleted file mode 100644 index 3beb6c8f..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedrequestmanager/FeedActionUploadRequestManagerTest.java +++ /dev/null
@@ -1,491 +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. - -package org.chromium.chrome.browser.feed.library.feedrequestmanager; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.MockitoAnnotations.initMocks; - -import android.os.Build; -import android.os.Build.VERSION_CODES; -import android.util.Base64; - -import com.google.protobuf.ByteString; -import com.google.protobuf.CodedOutputStream; -import com.google.protobuf.ExtensionRegistryLite; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; -import org.robolectric.util.ReflectionHelpers; - -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration.ConfigKey; -import org.chromium.chrome.browser.feed.library.api.host.network.HttpRequest; -import org.chromium.chrome.browser.feed.library.api.host.network.HttpRequest.HttpMethod; -import org.chromium.chrome.browser.feed.library.api.host.network.HttpResponse; -import org.chromium.chrome.browser.feed.library.common.Result; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeMainThreadRunner; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeTaskQueue; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeThreadUtils; -import org.chromium.chrome.browser.feed.library.common.protoextensions.FeedExtensionRegistry; -import org.chromium.chrome.browser.feed.library.common.testing.RequiredConsumer; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.testing.actionmanager.FakeViewActionManager; -import org.chromium.chrome.browser.feed.library.testing.network.FakeNetworkClient; -import org.chromium.chrome.browser.feed.library.testing.protocoladapter.FakeProtocolAdapter; -import org.chromium.chrome.browser.feed.library.testing.store.FakeStore; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamUploadableAction; -import org.chromium.components.feed.core.proto.wire.ActionRequestProto.ActionRequest; -import org.chromium.components.feed.core.proto.wire.ConsistencyTokenProto.ConsistencyToken; -import org.chromium.components.feed.core.proto.wire.FeedActionRequestProto.FeedActionRequest; -import org.chromium.components.feed.core.proto.wire.FeedActionResponseProto.FeedActionResponse; -import org.chromium.components.feed.core.proto.wire.FeedRequestProto.FeedRequest; -import org.chromium.components.feed.core.proto.wire.ResponseProto.Response; -import org.chromium.components.feed.core.proto.wire.SemanticPropertiesProto.SemanticProperties; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.Set; - -/** Test of the {@link FeedActionUploadRequestManager} class. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class FeedActionUploadRequestManagerTest { - public static final long ID = 42; - private static final ConsistencyToken TOKEN_1 = - ConsistencyToken.newBuilder() - .setToken(ByteString.copyFrom(new byte[] {0x1, 0xa})) - .build(); - private static final ConsistencyToken TOKEN_2 = - ConsistencyToken.newBuilder() - .setToken(ByteString.copyFrom(new byte[] {0x1, 0xf})) - .build(); - private static final ConsistencyToken TOKEN_3 = - ConsistencyToken.newBuilder() - .setToken(ByteString.copyFrom(new byte[] {0x2, 0xa})) - .build(); - private static final String CONTENT_ID = "contentId"; - private static final String CONTENT_ID_2 = "contentId2"; - private static final String CONTENT_ID_LONG = - "extremely-long-content-id-that-should-take-a-lot-of-bytes"; - private static final byte[] SEMANTIC_PROPERTIES_BYTES = new byte[] {0x1, 0xa}; - private static final SemanticProperties SEMANTIC_PROPERTIES = - SemanticProperties.newBuilder() - .setSemanticPropertiesData(ByteString.copyFrom(SEMANTIC_PROPERTIES_BYTES)) - .build(); - private static final Response RESPONSE_1 = - Response.newBuilder() - .setExtension(FeedActionResponse.feedActionResponse, - FeedActionResponse.newBuilder().setConsistencyToken(TOKEN_2).build()) - .build(); - private static final Response RESPONSE_2 = - Response.newBuilder() - .setExtension(FeedActionResponse.feedActionResponse, - FeedActionResponse.newBuilder().setConsistencyToken(TOKEN_3).build()) - .build(); - - private final Configuration mConfiguration = new Configuration.Builder().build(); - private final FakeClock mFakeClock = new FakeClock(); - private FakeViewActionManager mFakeViewActionManager; - private ExtensionRegistryLite mRegistry; - private FakeNetworkClient mFakeNetworkClient; - private FakeProtocolAdapter mFakeProtocolAdapter; - private FakeStore mFakeStore; - private FakeMainThreadRunner mFakeMainThreadRunner = FakeMainThreadRunner.runTasksImmediately(); - private FakeTaskQueue mFakeTaskQueue; - private FakeThreadUtils mFakeThreadUtils; - private FeedActionUploadRequestManager mRequestManager; - private RequiredConsumer<Result<ConsistencyToken>> mConsumer; - - @Before - public void setUp() { - initMocks(this); - mRegistry = ExtensionRegistryLite.newInstance(); - mRegistry.add(FeedRequest.feedRequest); - mRegistry.add(FeedActionRequest.feedActionRequest); - mFakeThreadUtils = FakeThreadUtils.withThreadChecks(); - mFakeNetworkClient = new FakeNetworkClient(mFakeThreadUtils); - mFakeTaskQueue = new FakeTaskQueue(mFakeClock, mFakeThreadUtils); - mFakeProtocolAdapter = new FakeProtocolAdapter(); - mFakeStore = new FakeStore(mConfiguration, mFakeThreadUtils, mFakeTaskQueue, mFakeClock); - mFakeViewActionManager = new FakeViewActionManager(mFakeStore); - mConsumer = new RequiredConsumer<>(input -> { mFakeThreadUtils.checkNotMainThread(); }); - - ReflectionHelpers.setStaticField(Build.VERSION.class, "SDK_INT", VERSION_CODES.KITKAT); - ReflectionHelpers.setStaticField(Build.VERSION.class, "RELEASE", "4.4.3"); - ReflectionHelpers.setStaticField(Build.class, "CPU_ABI", "armeabi"); - ReflectionHelpers.setStaticField(Build.class, "TAGS", "dev-keys"); - mRequestManager = createRequestManager(mConfiguration); - mFakeThreadUtils.enforceMainThread(false); - mFakeTaskQueue.initialize(() -> {}); - } - - @Test - public void testTriggerUploadActions_ttlExceededRemove() throws Exception { - Configuration configuration = - new Configuration.Builder() - .put(ConfigKey.FEED_ACTION_SERVER_METHOD, HttpMethod.GET) - .put(ConfigKey.FEED_ACTION_TTL_SECONDS, 1L) - .put(ConfigKey.FEED_ACTION_MAX_UPLOAD_ATTEMPTS, 5L) - .build(); - mRequestManager = createRequestManager(configuration); - StreamUploadableAction action = StreamUploadableAction.newBuilder() - .setUploadAttempts(1) - .setTimestampSeconds(1L) - .setFeatureContentId(CONTENT_ID) - .build(); - mFakeStore.setStreamUploadableActions(action); - mFakeClock.set(5000L); - mFakeNetworkClient.addResponse( - createHttpResponse(/* responseCode= */ 200, Response.getDefaultInstance())); - mRequestManager.triggerUploadActions( - setOf(action), ConsistencyToken.getDefaultInstance(), mConsumer); - - assertThat(mConsumer.isCalled()).isTrue(); - assertThat(mFakeStore.getContentById(CONTENT_ID)).isEmpty(); - } - - @Test - public void testTriggerUploadActions_maxUploadsRemove() throws Exception { - Configuration configuration = - new Configuration.Builder() - .put(ConfigKey.FEED_ACTION_SERVER_METHOD, HttpMethod.GET) - .put(ConfigKey.FEED_ACTION_TTL_SECONDS, 1000L) - .put(ConfigKey.FEED_ACTION_MAX_UPLOAD_ATTEMPTS, 2L) - .build(); - mRequestManager = createRequestManager(configuration); - StreamUploadableAction action = StreamUploadableAction.newBuilder() - .setUploadAttempts(2) - .setFeatureContentId(CONTENT_ID) - .build(); - mFakeNetworkClient.addResponse( - createHttpResponse(/* responseCode= */ 200, Response.getDefaultInstance())); - mRequestManager.triggerUploadActions( - setOf(action), ConsistencyToken.getDefaultInstance(), mConsumer); - - assertThat(mConsumer.isCalled()).isTrue(); - assertThat(mFakeStore.getContentById(CONTENT_ID)).isEmpty(); - } - - @Test - public void testTriggerUploadActions_batchSuccess() throws Exception { - Configuration configuration = - new Configuration.Builder() - .put(ConfigKey.FEED_ACTION_SERVER_METHOD, HttpMethod.GET) - .put(ConfigKey.FEED_ACTION_TTL_SECONDS, 1000L) - .put(ConfigKey.FEED_ACTION_SERVER_MAX_SIZE_PER_REQUEST, 20L) - .put(ConfigKey.FEED_ACTION_MAX_UPLOAD_ATTEMPTS, 1L) - .put(ConfigKey.FEED_ACTION_SERVER_MAX_ACTIONS_PER_REQUEST, 2L) - .build(); - mRequestManager = createRequestManager(configuration); - - Set<StreamUploadableAction> actionSet = setOf( - StreamUploadableAction.newBuilder().setFeatureContentId(CONTENT_ID).build(), - StreamUploadableAction.newBuilder().setFeatureContentId(CONTENT_ID_2).build()); - mConsumer = new RequiredConsumer<>(input -> { - mFakeThreadUtils.checkNotMainThread(); - assertThat(input.isSuccessful()).isTrue(); - assertThat(input.getValue().toByteArray()).isEqualTo(TOKEN_3.toByteArray()); - }); - mFakeNetworkClient.addResponse(createHttpResponse(/* responseCode= */ 200, RESPONSE_1)) - .addResponse(createHttpResponse(/* responseCode= */ 200, RESPONSE_2)); - mRequestManager.triggerUploadActions(actionSet, TOKEN_1, mConsumer); - - assertThat(mConsumer.isCalled()).isTrue(); - } - - @Test - public void testTriggerUploadActions_batchFirstFailure() throws Exception { - Configuration configuration = - new Configuration.Builder() - .put(ConfigKey.FEED_ACTION_SERVER_METHOD, HttpMethod.GET) - .put(ConfigKey.FEED_ACTION_TTL_SECONDS, 1000L) - .put(ConfigKey.FEED_ACTION_MAX_UPLOAD_ATTEMPTS, 2L) - .put(ConfigKey.FEED_ACTION_SERVER_MAX_SIZE_PER_REQUEST, 20L) - .put(ConfigKey.FEED_ACTION_SERVER_MAX_ACTIONS_PER_REQUEST, 2L) - .build(); - mRequestManager = createRequestManager(configuration); - Set<StreamUploadableAction> actionSet = setOf( - StreamUploadableAction.newBuilder().setFeatureContentId(CONTENT_ID).build(), - StreamUploadableAction.newBuilder().setFeatureContentId(CONTENT_ID_2).build()); - mConsumer = new RequiredConsumer<>(input -> { - mFakeThreadUtils.checkNotMainThread(); - assertThat(input.isSuccessful()).isFalse(); - }); - mFakeNetworkClient.addResponse(createHttpResponse(/* responseCode= */ 500, RESPONSE_1)); - mRequestManager.triggerUploadActions(actionSet, TOKEN_1, mConsumer); - - assertThat(mConsumer.isCalled()).isTrue(); - } - - @Test - public void testTriggerUploadActions_batchFirstSuccessSecondFailure() throws Exception { - Configuration configuration = - new Configuration.Builder() - .put(ConfigKey.FEED_ACTION_SERVER_METHOD, HttpMethod.GET) - .put(ConfigKey.FEED_ACTION_TTL_SECONDS, 1000L) - .put(ConfigKey.FEED_ACTION_MAX_UPLOAD_ATTEMPTS, 2L) - .put(ConfigKey.FEED_ACTION_SERVER_MAX_SIZE_PER_REQUEST, 20L) - .put(ConfigKey.FEED_ACTION_SERVER_MAX_ACTIONS_PER_REQUEST, 2L) - .build(); - mRequestManager = createRequestManager(configuration); - Set<StreamUploadableAction> actionSet = setOf( - StreamUploadableAction.newBuilder().setFeatureContentId(CONTENT_ID).build(), - StreamUploadableAction.newBuilder().setFeatureContentId(CONTENT_ID_2).build()); - mConsumer = new RequiredConsumer<>(input -> { - mFakeThreadUtils.checkNotMainThread(); - assertThat(input.isSuccessful()).isTrue(); - assertThat(input.getValue().toByteArray()).isEqualTo(TOKEN_2.toByteArray()); - }); - mFakeNetworkClient.addResponse(createHttpResponse(/* responseCode= */ 200, RESPONSE_1)) - .addResponse(createHttpResponse(/* responseCode= */ 500, RESPONSE_2)); - mRequestManager.triggerUploadActions(actionSet, TOKEN_1, mConsumer); - - assertThat(mConsumer.isCalled()).isTrue(); - } - - @Test - public void testTriggerUploadActions_batchFirstReachesMaxNumActions() throws Exception { - Configuration configuration = - new Configuration.Builder() - .put(ConfigKey.FEED_ACTION_SERVER_METHOD, HttpMethod.GET) - .put(ConfigKey.FEED_ACTION_TTL_SECONDS, 1000L) - .put(ConfigKey.FEED_ACTION_MAX_UPLOAD_ATTEMPTS, 2L) - .put(ConfigKey.FEED_ACTION_SERVER_MAX_SIZE_PER_REQUEST, 20L) - .put(ConfigKey.FEED_ACTION_SERVER_MAX_ACTIONS_PER_REQUEST, 1L) - .build(); - mRequestManager = createRequestManager(configuration); - Set<StreamUploadableAction> actionSet = setOf( - StreamUploadableAction.newBuilder().setFeatureContentId(CONTENT_ID).build(), - StreamUploadableAction.newBuilder().setFeatureContentId(CONTENT_ID_2).build()); - mConsumer = new RequiredConsumer<>(input -> { - mFakeThreadUtils.checkNotMainThread(); - assertThat(input.isSuccessful()).isTrue(); - assertThat(input.getValue().toByteArray()).isEqualTo(TOKEN_2.toByteArray()); - }); - mFakeNetworkClient.addResponse(createHttpResponse(/* responseCode= */ 200, RESPONSE_1)); - mRequestManager.triggerUploadActions(actionSet, TOKEN_1, mConsumer); - - assertThat(mConsumer.isCalled()).isTrue(); - } - - @Test - public void testTriggerUploadActions_batchFirstReachesMaxSize() throws Exception { - Configuration configuration = - new Configuration.Builder() - .put(ConfigKey.FEED_ACTION_SERVER_METHOD, HttpMethod.GET) - .put(ConfigKey.FEED_ACTION_TTL_SECONDS, 1000L) - .put(ConfigKey.FEED_ACTION_MAX_UPLOAD_ATTEMPTS, 2L) - .put(ConfigKey.FEED_ACTION_SERVER_MAX_SIZE_PER_REQUEST, 20L) - .put(ConfigKey.FEED_ACTION_SERVER_MAX_ACTIONS_PER_REQUEST, 1L) - .build(); - mRequestManager = createRequestManager(configuration); - Set<StreamUploadableAction> actionSet = orderedSetOf( - StreamUploadableAction.newBuilder().setFeatureContentId(CONTENT_ID_LONG).build(), - StreamUploadableAction.newBuilder().setFeatureContentId(CONTENT_ID).build()); - mConsumer = new RequiredConsumer<>(input -> { - mFakeThreadUtils.checkNotMainThread(); - assertThat(input.isSuccessful()).isTrue(); - assertThat(input.getValue().toByteArray()).isEqualTo(TOKEN_2.toByteArray()); - }); - mFakeNetworkClient.addResponse(createHttpResponse(/* responseCode= */ 200, RESPONSE_1)); - mRequestManager.triggerUploadActions(actionSet, TOKEN_1, mConsumer); - - assertThat(mConsumer.isCalled()).isTrue(); - } - - @Test - public void testTriggerUploadActions_batchNoUploadableActions() throws Exception { - Configuration configuration = - new Configuration.Builder() - .put(ConfigKey.FEED_ACTION_SERVER_METHOD, HttpMethod.GET) - .put(ConfigKey.FEED_ACTION_TTL_SECONDS, 1000L) - .put(ConfigKey.FEED_ACTION_MAX_UPLOAD_ATTEMPTS, 2L) - .put(ConfigKey.FEED_ACTION_SERVER_MAX_SIZE_PER_REQUEST, 20L) - .put(ConfigKey.FEED_ACTION_SERVER_MAX_ACTIONS_PER_REQUEST, 1L) - .build(); - mRequestManager = createRequestManager(configuration); - Set<StreamUploadableAction> actionSet = setOf( - StreamUploadableAction.newBuilder().setFeatureContentId(CONTENT_ID_LONG).build()); - mConsumer = new RequiredConsumer<>(input -> { - mFakeThreadUtils.checkNotMainThread(); - assertThat(input.isSuccessful()).isFalse(); - }); - mRequestManager.triggerUploadActions(actionSet, TOKEN_1, mConsumer); - - assertThat(mConsumer.isCalled()).isTrue(); - } - - @Test - public void testTriggerUploadActions_getMethod() throws Exception { - Configuration configuration = - new Configuration.Builder() - .put(ConfigKey.FEED_ACTION_SERVER_METHOD, HttpMethod.GET) - .put(ConfigKey.FEED_ACTION_TTL_SECONDS, 1000L) - .put(ConfigKey.FEED_ACTION_MAX_UPLOAD_ATTEMPTS, 2L) - .build(); - mRequestManager = createRequestManager(configuration); - StreamUploadableAction action = - StreamUploadableAction.newBuilder().setFeatureContentId(CONTENT_ID).build(); - Set<StreamUploadableAction> actionSet = setOf(action); - mFakeNetworkClient.addResponse( - createHttpResponse(/* responseCode= */ 200, Response.getDefaultInstance())); - mRequestManager.triggerUploadActions( - actionSet, ConsistencyToken.getDefaultInstance(), mConsumer); - - HttpRequest httpRequest = mFakeNetworkClient.getLatestRequest(); - assertHttpRequestFormattedCorrectly(httpRequest); - - ActionRequest request = getActionRequestFromHttpRequest(httpRequest); - UploadableActionsRequestBuilder builder = - new UploadableActionsRequestBuilder(mFakeProtocolAdapter); - ActionRequest expectedRequest = - builder.setConsistencyToken(ConsistencyToken.getDefaultInstance()) - .setActions(actionSet) - .build(); - assertThat(request.toByteArray()).isEqualTo(expectedRequest.toByteArray()); - assertThat(mConsumer.isCalled()).isTrue(); - assertThat(mFakeStore.getContentById(CONTENT_ID)) - .contains(StreamUploadableAction.newBuilder() - .setFeatureContentId(CONTENT_ID) - .setUploadAttempts(1) - .build()); - } - - @Test - public void testTriggerUploadActions_defaultMethod() throws Exception { - Set<StreamUploadableAction> actionSet = - setOf(StreamUploadableAction.newBuilder().setFeatureContentId(CONTENT_ID).build()); - mFakeNetworkClient.addResponse( - createHttpResponse(/* responseCode= */ 200, Response.getDefaultInstance())); - mRequestManager.triggerUploadActions( - actionSet, ConsistencyToken.getDefaultInstance(), mConsumer); - - HttpRequest httpRequest = mFakeNetworkClient.getLatestRequest(); - - ActionRequest request = getActionRequestFromHttpRequestBody(httpRequest); - UploadableActionsRequestBuilder builder = - new UploadableActionsRequestBuilder(mFakeProtocolAdapter); - Set<StreamUploadableAction> expectedActionSet = - setOf(StreamUploadableAction.newBuilder() - .setFeatureContentId(CONTENT_ID) - .setUploadAttempts(1) - .build()); - ActionRequest expectedRequest = - builder.setConsistencyToken(ConsistencyToken.getDefaultInstance()) - .setActions(expectedActionSet) - .build(); - assertThat(request.toByteArray()).isEqualTo(expectedRequest.toByteArray()); - - assertThat(mConsumer.isCalled()).isTrue(); - } - - @Test - public void testTriggerUploadActions_withSemanticProperties() throws Exception { - mFakeStore.addSemanticProperties(CONTENT_ID, SEMANTIC_PROPERTIES); - Set<StreamUploadableAction> actionSet = - setOf(StreamUploadableAction.newBuilder().setFeatureContentId(CONTENT_ID).build()); - mFakeNetworkClient.addResponse( - createHttpResponse(/* responseCode= */ 200, Response.getDefaultInstance())); - mRequestManager.triggerUploadActions( - actionSet, ConsistencyToken.getDefaultInstance(), mConsumer); - - HttpRequest httpRequest = mFakeNetworkClient.getLatestRequest(); - - ActionRequest request = getActionRequestFromHttpRequestBody(httpRequest); - assertThat(request.getExtension(FeedActionRequest.feedActionRequest) - .getFeedActionList() - .get(0) - .getSemanticProperties() - .getSemanticPropertiesData()) - .isEqualTo(SEMANTIC_PROPERTIES.getSemanticPropertiesData()); - } - - @Test - public void testTriggerUploadAllActions() throws Exception { - Configuration configuration = - new Configuration.Builder() - .put(ConfigKey.FEED_ACTION_SERVER_METHOD, HttpMethod.GET) - .put(ConfigKey.FEED_ACTION_TTL_SECONDS, 1000L) - .put(ConfigKey.FEED_ACTION_SERVER_MAX_SIZE_PER_REQUEST, 20L) - .put(ConfigKey.FEED_ACTION_MAX_UPLOAD_ATTEMPTS, 1L) - .put(ConfigKey.FEED_ACTION_SERVER_MAX_ACTIONS_PER_REQUEST, 2L) - .build(); - mRequestManager = createRequestManager(configuration); - - Set<StreamUploadableAction> actionSet = setOf( - StreamUploadableAction.newBuilder().setFeatureContentId(CONTENT_ID).build(), - StreamUploadableAction.newBuilder().setFeatureContentId(CONTENT_ID_2).build()); - mFakeViewActionManager.mViewActions.addAll(actionSet); - mConsumer = new RequiredConsumer<>(input -> { - mFakeThreadUtils.checkNotMainThread(); - assertThat(input.isSuccessful()).isTrue(); - assertThat(input.getValue().toByteArray()).isEqualTo(TOKEN_3.toByteArray()); - }); - mFakeNetworkClient.addResponse(createHttpResponse(/* responseCode= */ 200, RESPONSE_1)) - .addResponse(createHttpResponse(/* responseCode= */ 200, RESPONSE_2)); - mRequestManager.triggerUploadAllActions(TOKEN_1, mConsumer); - - assertThat(mConsumer.isCalled()).isTrue(); - } - - private static void assertHttpRequestFormattedCorrectly(HttpRequest httpRequest) { - assertThat(httpRequest.getBody()).hasLength(0); - assertThat(httpRequest.getMethod()).isEqualTo(HttpMethod.GET); - assertThat(httpRequest.getUri().getQueryParameter("fmt")).isEqualTo("bin"); - assertThat(httpRequest.getUri().getQueryParameter(RequestHelper.MOTHERSHIP_PARAM_PAYLOAD)) - .isNotNull(); - } - - private static HttpResponse createHttpResponse(int responseCode, Response response) - throws IOException { - byte[] rawResponse = response.toByteArray(); - ByteBuffer buffer = ByteBuffer.allocate(rawResponse.length + (Integer.SIZE / 8)); - CodedOutputStream codedOutputStream = CodedOutputStream.newInstance(buffer); - codedOutputStream.writeUInt32NoTag(rawResponse.length); - codedOutputStream.writeRawBytes(rawResponse); - codedOutputStream.flush(); - return new HttpResponse(responseCode, buffer.array(), false); - } - - private ActionRequest getActionRequestFromHttpRequest(HttpRequest httpRequest) - throws Exception { - return ActionRequest.parseFrom( - Base64.decode(httpRequest.getUri().getQueryParameter( - RequestHelper.MOTHERSHIP_PARAM_PAYLOAD), - Base64.URL_SAFE), - mRegistry); - } - - private ActionRequest getActionRequestFromHttpRequestBody(HttpRequest httpRequest) - throws Exception { - return ActionRequest.parseFrom(httpRequest.getBody(), mRegistry); - } - - private FeedActionUploadRequestManager createRequestManager(Configuration configuration) { - return new FeedActionUploadRequestManager(mFakeViewActionManager, configuration, - mFakeNetworkClient, mFakeProtocolAdapter, new FeedExtensionRegistry(ArrayList::new), - mFakeMainThreadRunner, mFakeTaskQueue, mFakeThreadUtils, mFakeStore, mFakeClock); - } - - private static <T> Set<T> setOf(T... items) { - Set<T> result = new HashSet<>(); - Collections.addAll(result, items); - return result; - } - - private static <T> Set<T> orderedSetOf(T... items) { - Set<T> result = new LinkedHashSet<>(); - Collections.addAll(result, items); - return result; - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedrequestmanager/FeedRequestManagerImplTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedrequestmanager/FeedRequestManagerImplTest.java deleted file mode 100644 index 040507d..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedrequestmanager/FeedRequestManagerImplTest.java +++ /dev/null
@@ -1,1219 +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. - -package org.chromium.chrome.browser.feed.library.feedrequestmanager; - -import static com.google.common.truth.Truth.assertThat; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.anyBoolean; -import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import android.app.Activity; -import android.content.Context; -import android.os.Build; -import android.os.Build.VERSION_CODES; -import android.util.Base64; - -import com.google.protobuf.ByteString; -import com.google.protobuf.CodedOutputStream; -import com.google.protobuf.ExtensionRegistryLite; - -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestRule; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; -import org.robolectric.util.ReflectionHelpers; - -import org.chromium.base.metrics.test.ShadowRecordHistogram; -import org.chromium.base.test.util.JniMocker; -import org.chromium.base.test.util.MetricsUtils; -import org.chromium.chrome.browser.feed.library.api.host.config.ApplicationInfo; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration.ConfigKey; -import org.chromium.chrome.browser.feed.library.api.host.logging.RequestReason; -import org.chromium.chrome.browser.feed.library.api.host.network.HttpRequest; -import org.chromium.chrome.browser.feed.library.api.host.network.HttpRequest.HttpMethod; -import org.chromium.chrome.browser.feed.library.api.host.network.HttpResponse; -import org.chromium.chrome.browser.feed.library.api.host.scheduler.SchedulerApi; -import org.chromium.chrome.browser.feed.library.api.host.stream.TooltipInfo.FeatureName; -import org.chromium.chrome.browser.feed.library.api.internal.common.DismissActionWithSemanticProperties; -import org.chromium.chrome.browser.feed.library.api.internal.common.Model; -import org.chromium.chrome.browser.feed.library.common.Result; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeMainThreadRunner; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeTaskQueue; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeThreadUtils; -import org.chromium.chrome.browser.feed.library.common.locale.LocaleUtils; -import org.chromium.chrome.browser.feed.library.common.protoextensions.FeedExtensionRegistry; -import org.chromium.chrome.browser.feed.library.common.testing.RequiredConsumer; -import org.chromium.chrome.browser.feed.library.common.time.TimingUtils; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.testing.actionmanager.FakeActionReader; -import org.chromium.chrome.browser.feed.library.testing.host.logging.FakeBasicLoggingApi; -import org.chromium.chrome.browser.feed.library.testing.host.stream.FakeTooltipSupportedApi; -import org.chromium.chrome.browser.feed.library.testing.network.FakeNetworkClient; -import org.chromium.chrome.browser.feed.library.testing.protocoladapter.FakeProtocolAdapter; -import org.chromium.chrome.browser.flags.ChromeFeatureList; -import org.chromium.chrome.browser.preferences.Pref; -import org.chromium.chrome.browser.profiles.Profile; -import org.chromium.chrome.browser.signin.services.IdentityServicesProvider; -import org.chromium.chrome.browser.signin.services.IdentityServicesProviderJni; -import org.chromium.chrome.test.util.browser.Features; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamToken; -import org.chromium.components.feed.core.proto.wire.ActionTypeProto.ActionType; -import org.chromium.components.feed.core.proto.wire.CapabilityProto.Capability; -import org.chromium.components.feed.core.proto.wire.ClientInfoProto.ClientInfo; -import org.chromium.components.feed.core.proto.wire.ClientInfoProto.ClientInfo.AppType; -import org.chromium.components.feed.core.proto.wire.ClientInfoProto.ClientInfo.PlatformType; -import org.chromium.components.feed.core.proto.wire.ConsistencyTokenProto.ConsistencyToken; -import org.chromium.components.feed.core.proto.wire.ContentIdProto.ContentId; -import org.chromium.components.feed.core.proto.wire.DisplayInfoProto.DisplayInfo; -import org.chromium.components.feed.core.proto.wire.FeedActionQueryDataProto.Action; -import org.chromium.components.feed.core.proto.wire.FeedActionQueryDataProto.FeedActionQueryData; -import org.chromium.components.feed.core.proto.wire.FeedActionQueryDataProto.FeedActionQueryDataItem; -import org.chromium.components.feed.core.proto.wire.FeedQueryProto.FeedQuery; -import org.chromium.components.feed.core.proto.wire.FeedRequestProto.FeedRequest; -import org.chromium.components.feed.core.proto.wire.FeedResponseProto.FeedResponse; -import org.chromium.components.feed.core.proto.wire.RequestProto.Request; -import org.chromium.components.feed.core.proto.wire.RequestProto.Request.RequestVersion; -import org.chromium.components.feed.core.proto.wire.ResponseProto.Response; -import org.chromium.components.feed.core.proto.wire.SemanticPropertiesProto.SemanticProperties; -import org.chromium.components.feed.core.proto.wire.VersionProto.Version; -import org.chromium.components.feed.core.proto.wire.VersionProto.Version.Architecture; -import org.chromium.components.feed.core.proto.wire.VersionProto.Version.BuildType; -import org.chromium.components.prefs.PrefService; -import org.chromium.components.signin.identitymanager.IdentityManager; -import org.chromium.components.user_prefs.UserPrefs; -import org.chromium.components.user_prefs.UserPrefsJni; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.EnumSet; -import java.util.List; -import java.util.Locale; -import java.util.Set; - -/** Test of the {@link FeedRequestManagerImpl} class. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE, shadows = {ShadowRecordHistogram.class}) -@Features.EnableFeatures(ChromeFeatureList.INTEREST_FEED_CONTENT_SUGGESTIONS) -@Features. -DisableFeatures({ChromeFeatureList.REPORT_FEED_USER_ACTIONS, ChromeFeatureList.INTEREST_FEED_V2, - ChromeFeatureList.INTEREST_FEED_NOTICE_CARD_AUTO_DISMISS}) -public class FeedRequestManagerImplTest { - private static final int NOT_FOUND = 404; - private static final String TABLE = "table"; - private static final String TABLE_2 = "table2"; - private static final String CONTENT_DOMAIN = "contentDomain"; - private static final String CONTENT_DOMAIN_2 = "contentDomain2"; - public static final long ID = 42; - private static final long ID_2 = 2; - private static final String APP_VERSION_STRING = "5.7"; - - private final FakeClock mFakeClock = new FakeClock(); - private final TimingUtils mTimingUtils = new TimingUtils(); - private final Configuration mConfiguration = new Configuration.Builder().build(); - - @Rule - public JniMocker mocker = new JniMocker(); - - @Mock - private SchedulerApi mScheduler; - @Mock - private ApplicationInfo mApplicationInfo; - @Mock - private IdentityServicesProvider.Natives mIdentityServicesProviderJniMock; - @Mock - private Profile mProfileMock; - @Mock - private IdentityManager mIdentifiyManagerMock; - @Mock - private UserPrefs.Natives mUserPrefsJniMock; - @Mock - private Profile mProfile; - @Mock - private PrefService mPrefService; - - private Context mContext; - private ExtensionRegistryLite mRegistry; - private FeedRequestManagerImpl mRequestManager; - private FakeActionReader mFakeActionReader; - private FakeMainThreadRunner mFakeMainThreadRunner; - private FakeProtocolAdapter mFakeProtocolAdapter; - private FakeThreadUtils mFakeThreadUtils; - private FakeTaskQueue mFakeTaskQueue; - private FakeBasicLoggingApi mFakeBasicLoggingApi; - private FakeNetworkClient mFakeNetworkClient; - private FakeTooltipSupportedApi mFakeTooltipSupportedApi; - private RequiredConsumer<Result<Model>> mConsumer; - private Result<Model> mConsumedResult = Result.failure(); - private HttpResponse mFailingResponse; - - @Rule - public JniMocker jniMocker = new JniMocker(); - - @Rule - public TestRule mFeaturesProcessorRule = new Features.JUnitProcessor(); - - @Before - public void setUp() throws Exception { - initMocks(this); - mContext = Robolectric.buildActivity(Activity.class).get(); - mContext.getResources().getConfiguration().locale = Locale.US; - FeedExtensionRegistry feedExtensionRegistry = new FeedExtensionRegistry(ArrayList::new); - mRegistry = ExtensionRegistryLite.newInstance(); - mRegistry.add(FeedRequest.feedRequest); - mFakeActionReader = new FakeActionReader(); - mFakeProtocolAdapter = new FakeProtocolAdapter(); - mFakeBasicLoggingApi = new FakeBasicLoggingApi(); - mFakeThreadUtils = FakeThreadUtils.withThreadChecks(); - mFakeMainThreadRunner = - FakeMainThreadRunner.runTasksImmediatelyWithThreadChecks(mFakeThreadUtils); - mFakeNetworkClient = new FakeNetworkClient(mFakeThreadUtils); - mFakeNetworkClient.setDefaultResponse( - createHttpResponse(/* responseCode= */ 200, Response.getDefaultInstance())); - mFakeTaskQueue = new FakeTaskQueue(mFakeClock, mFakeThreadUtils); - mFakeTaskQueue.initialize(() -> {}); - mFakeTooltipSupportedApi = new FakeTooltipSupportedApi(mFakeThreadUtils); - mFailingResponse = - createHttpResponse(/* responseCode= */ NOT_FOUND, Response.getDefaultInstance()); - mConsumer = new RequiredConsumer<>(input -> { mConsumedResult = input; }); - ReflectionHelpers.setStaticField(Build.VERSION.class, "SDK_INT", VERSION_CODES.KITKAT); - ReflectionHelpers.setStaticField(Build.VERSION.class, "RELEASE", "4.4.3"); - ReflectionHelpers.setStaticField(Build.class, "CPU_ABI", "armeabi"); - ReflectionHelpers.setStaticField(Build.class, "TAGS", "dev-keys"); - when(mApplicationInfo.getAppType()).thenReturn(ApplicationInfo.AppType.CHROME); - when(mApplicationInfo.getArchitecture()).thenReturn(ApplicationInfo.Architecture.ARM); - when(mApplicationInfo.getBuildType()).thenReturn(ApplicationInfo.BuildType.DEV); - when(mApplicationInfo.getVersionString()).thenReturn(APP_VERSION_STRING); - - Profile.setLastUsedProfileForTesting(mProfileMock); - jniMocker.mock(IdentityServicesProviderJni.TEST_HOOKS, mIdentityServicesProviderJniMock); - when(mIdentityServicesProviderJniMock.getIdentityManager(mProfileMock)) - .thenReturn(mIdentifiyManagerMock); - - jniMocker.mock(UserPrefsJni.TEST_HOOKS, mUserPrefsJniMock); - when(mUserPrefsJniMock.get(mProfileMock)).thenReturn(mPrefService); - - mRequestManager = new FeedRequestManagerImpl(mConfiguration, mFakeNetworkClient, - mFakeProtocolAdapter, feedExtensionRegistry, mScheduler, mFakeTaskQueue, - mTimingUtils, mFakeThreadUtils, mFakeActionReader, mContext, mApplicationInfo, - mFakeMainThreadRunner, mFakeBasicLoggingApi, mFakeTooltipSupportedApi); - } - - @After - public void tearDown() { - Profile.setLastUsedProfileForTesting(null); - } - - @Test - public void testTriggerRefresh() throws Exception { - mRequestManager.triggerRefresh(RequestReason.HOST_REQUESTED, input -> {}); - - assertThat(mFakeTooltipSupportedApi.getLatestFeatureName()).isNull(); - - HttpRequest httpRequest = mFakeNetworkClient.getLatestRequest(); - assertHttpRequestFormattedCorrectly(httpRequest, mContext); - assertThat(httpRequest.getUri().getQueryParameter(RequestHelper.PRIORITY_PARAM)) - .isEqualTo(RequestHelper.PRIORITY_VALUE_BACKGROUND); - - Request request = getRequestFromHttpRequest(httpRequest); - Request expectedRequest = - Request.newBuilder() - .setRequestVersion(RequestVersion.FEED_QUERY) - .setExtension(FeedRequest.feedRequest, - getTestFeedRequestBuilder() - .setFeedQuery(FeedQuery.newBuilder().setReason( - FeedQuery.RequestReason.SCHEDULED_REFRESH)) - .addClientCapability(Capability.SEND_FEEDBACK) - .addClientCapability(Capability.BASE_UI) - .build()) - .build(); - assertThat(request).isEqualTo(expectedRequest); - } - - @Test - public void testTriggerRefresh_setNoticeCardPrefAndRecordBothHistograms() throws Exception { - MetricsUtils.HistogramDelta obsoleteNoticeCardNotFulfilledDelta = - new MetricsUtils.HistogramDelta( - "ContentSuggestions.Feed.NoticeCardFulfilled", 0 /*false*/); - MetricsUtils.HistogramDelta obsoleteNoticeCardFulfilledDelta = - new MetricsUtils.HistogramDelta( - "ContentSuggestions.Feed.NoticeCardFulfilled", 1 /*true*/); - MetricsUtils.HistogramDelta noticeCardNotFulfilledDelta = new MetricsUtils.HistogramDelta( - "ContentSuggestions.Feed.NoticeCardFulfilled2", 0 /*false*/); - MetricsUtils.HistogramDelta noticeCardFulfilledDelta = new MetricsUtils.HistogramDelta( - "ContentSuggestions.Feed.NoticeCardFulfilled2", 1 /*true*/); - - // Skip the read of the int that determines the length of the encoded proto. This is to - // avoid having to encode the length which is a feature we don't want to test here. - Configuration configuration = - new Configuration.Builder() - .put(ConfigKey.FEED_SERVER_RESPONSE_LENGTH_PREFIXED, false) - .build(); - - mRequestManager = new FeedRequestManagerImpl(configuration, mFakeNetworkClient, - mFakeProtocolAdapter, new FeedExtensionRegistry(ArrayList::new), mScheduler, - mFakeTaskQueue, mTimingUtils, mFakeThreadUtils, mFakeActionReader, mContext, - mApplicationInfo, mFakeMainThreadRunner, mFakeBasicLoggingApi, - mFakeTooltipSupportedApi); - - // Trigger a refresh that has a notice card. - Response response = - Response.newBuilder() - .setExtension(FeedResponse.feedResponse, - FeedResponse.newBuilder() - .addServerCapabilities( - Capability.REPORT_FEED_USER_ACTIONS_NOTICE_CARD) - .build()) - .build(); - mFakeNetworkClient.addResponse(new HttpResponse(200, response.toByteArray(), false)); - mRequestManager.triggerRefresh(RequestReason.HOST_REQUESTED, input -> {}); - verify(mPrefService, times(1)).setBoolean(Pref.LAST_FETCH_HAD_NOTICE_CARD, true); - assertThat(noticeCardNotFulfilledDelta.getDelta()).isEqualTo(0); - assertThat(noticeCardFulfilledDelta.getDelta()).isEqualTo(1); - - // Trigger a refresh that doesn't have a notice card. - mFakeNetworkClient.addResponse( - new HttpResponse(200, Response.getDefaultInstance().toByteArray(), false)); - mRequestManager.triggerRefresh(RequestReason.HOST_REQUESTED, input -> {}); - assertThat(obsoleteNoticeCardNotFulfilledDelta.getDelta()).isEqualTo(1); - assertThat(obsoleteNoticeCardFulfilledDelta.getDelta()).isEqualTo(1); - assertThat(noticeCardNotFulfilledDelta.getDelta()).isEqualTo(1); - assertThat(noticeCardFulfilledDelta.getDelta()).isEqualTo(1); - } - - @Test - public void testTriggerRefresh_setLastRefreshWasSignedInPref() throws Exception { - // Skip the read of the int that determines the length of the encoded proto. This is to - // avoid having to encode the length which is a feature we don't want to test here. - Configuration configuration = - new Configuration.Builder() - .put(ConfigKey.FEED_SERVER_RESPONSE_LENGTH_PREFIXED, false) - .build(); - - mRequestManager = new FeedRequestManagerImpl(configuration, mFakeNetworkClient, - mFakeProtocolAdapter, new FeedExtensionRegistry(ArrayList::new), mScheduler, - mFakeTaskQueue, mTimingUtils, mFakeThreadUtils, mFakeActionReader, mContext, - mApplicationInfo, mFakeMainThreadRunner, mFakeBasicLoggingApi, - mFakeTooltipSupportedApi); - - mFakeNetworkClient.addResponse( - new HttpResponse(200, Response.getDefaultInstance().toByteArray(), true)); - mRequestManager.triggerRefresh(RequestReason.HOST_REQUESTED, input -> {}); - - verify(mPrefService, times(1)).setBoolean(Pref.LAST_REFRESH_WAS_SIGNED_IN, true); - } - - @Test - public void testLoadMore_dontSetNoticeCardPrefAndOnlyRecordObsoleteHistogram() - throws Exception { - MetricsUtils.HistogramDelta obsoleteNoticeCardNotFulfilledDelta = - new MetricsUtils.HistogramDelta( - "ContentSuggestions.Feed.NoticeCardFulfilled", 0 /*false*/); - MetricsUtils.HistogramDelta obsoleteNoticeCardFulfilledDelta = - new MetricsUtils.HistogramDelta( - "ContentSuggestions.Feed.NoticeCardFulfilled", 1 /*true*/); - MetricsUtils.HistogramDelta noticeCardNotFulfilledDelta = new MetricsUtils.HistogramDelta( - "ContentSuggestions.Feed.NoticeCardFulfilled2", 0 /*false*/); - MetricsUtils.HistogramDelta noticeCardFulfilledDelta = new MetricsUtils.HistogramDelta( - "ContentSuggestions.Feed.NoticeCardFulfilled2", 1 /*true*/); - - // Skip the read of the int that determines the length of the encoded proto. This is to - // avoid having to encode the length which is a feature we don't want to test here. - Configuration configuration = - new Configuration.Builder() - .put(ConfigKey.FEED_SERVER_RESPONSE_LENGTH_PREFIXED, false) - .build(); - - mRequestManager = new FeedRequestManagerImpl(configuration, mFakeNetworkClient, - mFakeProtocolAdapter, new FeedExtensionRegistry(ArrayList::new), mScheduler, - mFakeTaskQueue, mTimingUtils, mFakeThreadUtils, mFakeActionReader, mContext, - mApplicationInfo, mFakeMainThreadRunner, mFakeBasicLoggingApi, - mFakeTooltipSupportedApi); - - mFakeThreadUtils.enforceMainThread(false); - - // Trigger a load more with a notice card in the query response. - Response response = - Response.newBuilder() - .setExtension(FeedResponse.feedResponse, - FeedResponse.newBuilder() - .addServerCapabilities( - Capability.REPORT_FEED_USER_ACTIONS_NOTICE_CARD) - .build()) - .build(); - mFakeNetworkClient.addResponse(new HttpResponse(200, response.toByteArray(), false)); - StreamToken token = - StreamToken.newBuilder() - .setNextPageToken(ByteString.copyFrom("abc", Charset.defaultCharset())) - .build(); - mRequestManager.loadMore(token, ConsistencyToken.getDefaultInstance(), input -> {}); - - // Trigger a load more without a notice card in the query response. - mFakeNetworkClient.addResponse( - new HttpResponse(200, Response.getDefaultInstance().toByteArray(), false)); - mRequestManager.loadMore(token, ConsistencyToken.getDefaultInstance(), input -> {}); - - // Verify that only the obsolete histograms were recorded. - assertThat(noticeCardNotFulfilledDelta.getDelta()).isEqualTo(0); - assertThat(noticeCardFulfilledDelta.getDelta()).isEqualTo(0); - assertThat(obsoleteNoticeCardNotFulfilledDelta.getDelta()).isEqualTo(1); - assertThat(obsoleteNoticeCardFulfilledDelta.getDelta()).isEqualTo(1); - // Verify that no attempts were made to update the notice card presence pref. - verify(mPrefService, never()).setBoolean(eq(Pref.LAST_FETCH_HAD_NOTICE_CARD), anyBoolean()); - } - - @Test - public void testLoadMore_dontSetLastRefreshWasSignedInPref() throws Exception { - // Skip the read of the int that determines the length of the encoded proto. This is to - // avoid having to encode the length which is a feature we don't want to test here. - Configuration configuration = - new Configuration.Builder() - .put(ConfigKey.FEED_SERVER_RESPONSE_LENGTH_PREFIXED, false) - .build(); - - mRequestManager = new FeedRequestManagerImpl(configuration, mFakeNetworkClient, - mFakeProtocolAdapter, new FeedExtensionRegistry(ArrayList::new), mScheduler, - mFakeTaskQueue, mTimingUtils, mFakeThreadUtils, mFakeActionReader, mContext, - mApplicationInfo, mFakeMainThreadRunner, mFakeBasicLoggingApi, - mFakeTooltipSupportedApi); - - mFakeNetworkClient.addResponse( - new HttpResponse(200, Response.getDefaultInstance().toByteArray(), false)); - StreamToken token = - StreamToken.newBuilder() - .setNextPageToken(ByteString.copyFrom("abc", Charset.defaultCharset())) - .build(); - mFakeThreadUtils.enforceMainThread(false); - mRequestManager.loadMore(token, ConsistencyToken.getDefaultInstance(), input -> {}); - - verify(mPrefService, never()).setBoolean(Pref.LAST_REFRESH_WAS_SIGNED_IN, true); - } - - @Test - public void testTriggerRefresh_FeedUiCapabilityAddedWhenFlagIsOn() throws Exception { - testCapabilityAdded(ConfigKey.FEED_UI_ENABLED, Capability.FEED_UI); - } - - @Test - public void testTriggerRefresh_undoableActionCapabilityAddedWhenFlagIsOn() throws Exception { - testCapabilityAdded(ConfigKey.UNDOABLE_ACTIONS_ENABLED, Capability.UNDOABLE_ACTIONS); - } - - @Test - public void testTriggerRefresh_manageInterestsCapabilityAddedWhenFlagIsOn() throws Exception { - testCapabilityAdded(ConfigKey.MANAGE_INTERESTS_ENABLED, Capability.MANAGE_INTERESTS); - } - - @Test - public void testTriggerRefresh_sendFeedbackCapabilityAdded() throws Exception { - testCapabilityAdded(Capability.SEND_FEEDBACK); - } - - @Test - public void testTriggerRefresh_tooltipCapabilityAddedWhenFlagIsOn() throws Exception { - testCapabilityAdded(ConfigKey.CARD_MENU_TOOLTIP_ELIGIBLE, Capability.CARD_MENU_TOOLTIP); - } - - @Test - public void testTriggerRefresh_tooltipCapabilityNotAdded() throws Exception { - // If the config key for card menu tool tip is set but the - // TooltipSupportedApi.wouldTriggerHelpUi() returns false, then the capability should not be - // added and only the BASE_UI should be present. - mFakeTooltipSupportedApi.addUnsupportedFeature(FeatureName.CARD_MENU_TOOLTIP); - testCapabilityAdded(ConfigKey.CARD_MENU_TOOLTIP_ELIGIBLE /* capability= empty */); - } - - @Test - public void testTriggerRefresh_useSecondaryPageRequestAdded() throws Exception { - testCapabilityAdded( - ConfigKey.USE_SECONDARY_PAGE_REQUEST, Capability.USE_SECONDARY_PAGE_REQUEST); - } - - @Test - public void testTriggerRefresh_articleSnippetsAdded() throws Exception { - testCapabilityAdded(ConfigKey.SNIPPETS_ENABLED, Capability.ARTICLE_SNIPPETS); - } - - @Test - public void testTriggerRefresh_enableCarouselsAdded() throws Exception { - testCapabilityAdded(ConfigKey.ENABLE_CAROUSELS, Capability.CAROUSELS); - } - - @Test - @Features.EnableFeatures(ChromeFeatureList.REPORT_FEED_USER_ACTIONS) - public void testTriggerRefresh_enableFeedActions() throws Exception { - testCapabilityAdded(Capability.CLICK_ACTION, Capability.VIEW_ACTION, - Capability.REPORT_FEED_USER_ACTIONS_NOTICE_CARD); - } - - @Test - @Features.EnableFeatures({ChromeFeatureList.INTEREST_FEED_NOTICE_CARD_AUTO_DISMISS}) - public void testTriggerRefresh_acknowledgeNoticeCard_whenClicksThresholdReached() - throws Exception { - // Simulate enough clicks. - when(mPrefService.getInteger(Pref.NOTICE_CARD_CLICKS_COUNT)).thenReturn(1); - when(mPrefService.getInteger(Pref.NOTICE_CARD_VIEWS_COUNT)).thenReturn(0); - - mRequestManager.triggerRefresh(RequestReason.HOST_REQUESTED, input -> {}); - - HttpRequest httpRequest = mFakeNetworkClient.getLatestRequest(); - assertHttpRequestFormattedCorrectly(httpRequest, mContext); - - assertTrue(getRequestFromHttpRequest(httpRequest) - .getExtension(FeedRequest.feedRequest) - .getFeedQuery() - .getChromeFulfillmentInfo() - .getNoticeCardAcknowledged()); - } - - @Test - @Features.EnableFeatures({ChromeFeatureList.INTEREST_FEED_NOTICE_CARD_AUTO_DISMISS}) - public void testTriggerRefresh_acknowledgeNoticeCard_whenViewsThresholdReached() - throws Exception { - // Simulate enough views. - when(mPrefService.getInteger(Pref.NOTICE_CARD_CLICKS_COUNT)).thenReturn(0); - when(mPrefService.getInteger(Pref.NOTICE_CARD_VIEWS_COUNT)).thenReturn(3); - - mRequestManager.triggerRefresh(RequestReason.HOST_REQUESTED, input -> {}); - - HttpRequest httpRequest = mFakeNetworkClient.getLatestRequest(); - assertHttpRequestFormattedCorrectly(httpRequest, mContext); - - assertTrue(getRequestFromHttpRequest(httpRequest) - .getExtension(FeedRequest.feedRequest) - .getFeedQuery() - .getChromeFulfillmentInfo() - .getNoticeCardAcknowledged()); - } - - @Test - public void testTriggerRefresh_dontAcknowledgeNoticeCard_whenFeatureDisabled() - throws Exception { - // Simulate enough views and clicks. - when(mPrefService.getInteger(Pref.NOTICE_CARD_CLICKS_COUNT)).thenReturn(1); - when(mPrefService.getInteger(Pref.NOTICE_CARD_VIEWS_COUNT)).thenReturn(3); - - mRequestManager.triggerRefresh(RequestReason.HOST_REQUESTED, input -> {}); - - HttpRequest httpRequest = mFakeNetworkClient.getLatestRequest(); - assertHttpRequestFormattedCorrectly(httpRequest, mContext); - - assertFalse(getRequestFromHttpRequest(httpRequest) - .getExtension(FeedRequest.feedRequest) - .getFeedQuery() - .getChromeFulfillmentInfo() - .getNoticeCardAcknowledged()); - } - - @Test - @Features.EnableFeatures({ChromeFeatureList.INTEREST_FEED_NOTICE_CARD_AUTO_DISMISS}) - public void testTriggerRefresh_dontAcknowledgeNoticeCard_whenCountThresholdsNotReached() - throws Exception { - // Simulate not enough views nor clicks. - when(mPrefService.getInteger(Pref.NOTICE_CARD_CLICKS_COUNT)).thenReturn(0); - when(mPrefService.getInteger(Pref.NOTICE_CARD_VIEWS_COUNT)).thenReturn(2); - - mRequestManager.triggerRefresh(RequestReason.HOST_REQUESTED, input -> {}); - - HttpRequest httpRequest = mFakeNetworkClient.getLatestRequest(); - assertHttpRequestFormattedCorrectly(httpRequest, mContext); - - assertFalse(getRequestFromHttpRequest(httpRequest) - .getExtension(FeedRequest.feedRequest) - .getFeedQuery() - .getChromeFulfillmentInfo() - .getNoticeCardAcknowledged()); - } - - @Test - public void testActionData_simpleDismiss() throws Exception { - mFakeActionReader.addDismissActionsWithSemanticProperties( - buildDismissAction(ID, CONTENT_DOMAIN, TABLE, null)); - mRequestManager.triggerRefresh(RequestReason.HOST_REQUESTED, input -> {}); - - HttpRequest httpRequest = mFakeNetworkClient.getLatestRequest(); - assertHttpRequestFormattedCorrectly(httpRequest, mContext); - - Request request = getRequestFromHttpRequest(httpRequest); - - List<Long> expectedIds = Collections.singletonList(ID); - List<String> expectedContentDomains = Collections.singletonList(CONTENT_DOMAIN); - List<String> expectedTables = Collections.singletonList(TABLE); - List<SemanticProperties> expectedSemanticProperties = Collections.emptyList(); - List<FeedActionQueryDataItem> expectedDataItems = - Collections.singletonList(FeedActionQueryDataItem.newBuilder() - .setIdIndex(0) - .setContentDomainIndex(0) - .setTableIndex(0) - .build()); - - Request expectedRequest = - Request.newBuilder() - .setRequestVersion(RequestVersion.FEED_QUERY) - .setExtension(FeedRequest.feedRequest, - getTestFeedRequestBuilder() - .setFeedQuery(FeedQuery.newBuilder().setReason( - FeedQuery.RequestReason.SCHEDULED_REFRESH)) - .addFeedActionQueryData( - FeedActionQueryData.newBuilder() - .setAction( - Action.newBuilder().setActionType( - ActionType.DISMISS)) - .addAllUniqueId(expectedIds) - .addAllUniqueContentDomain( - expectedContentDomains) - .addAllUniqueTable(expectedTables) - .addAllUniqueSemanticProperties( - expectedSemanticProperties) - .addAllFeedActionQueryDataItem( - expectedDataItems)) - .addClientCapability(Capability.SEND_FEEDBACK) - .addClientCapability(Capability.BASE_UI) - .build()) - .build(); - assertThat(request).isEqualTo(expectedRequest); - } - - @Test - public void testActionData_uniqueDismisses() throws Exception { - mFakeActionReader.addDismissActionsWithSemanticProperties( - buildDismissAction(ID, CONTENT_DOMAIN, TABLE, null), - buildDismissAction(ID_2, CONTENT_DOMAIN_2, TABLE_2, null)); - mRequestManager.triggerRefresh(RequestReason.HOST_REQUESTED, input -> {}); - - HttpRequest httpRequest = mFakeNetworkClient.getLatestRequest(); - assertHttpRequestFormattedCorrectly(httpRequest, mContext); - - Request request = getRequestFromHttpRequest(httpRequest); - - List<Long> expectedIds = Arrays.asList(ID, ID_2); - List<String> expectedContentDomains = Arrays.asList(CONTENT_DOMAIN, CONTENT_DOMAIN_2); - List<String> expectedTables = Arrays.asList(TABLE, TABLE_2); - List<SemanticProperties> expectedSemanticProperties = Collections.emptyList(); - List<FeedActionQueryDataItem> expectedDataItems = - Arrays.asList(FeedActionQueryDataItem.newBuilder() - .setIdIndex(0) - .setContentDomainIndex(0) - .setTableIndex(0) - .build(), - FeedActionQueryDataItem.newBuilder() - .setIdIndex(1) - .setContentDomainIndex(1) - .setTableIndex(1) - .build()); - - Request expectedRequest = - Request.newBuilder() - .setRequestVersion(RequestVersion.FEED_QUERY) - .setExtension(FeedRequest.feedRequest, - getTestFeedRequestBuilder() - .setFeedQuery(FeedQuery.newBuilder().setReason( - FeedQuery.RequestReason.SCHEDULED_REFRESH)) - .addFeedActionQueryData( - FeedActionQueryData.newBuilder() - .setAction( - Action.newBuilder().setActionType( - ActionType.DISMISS)) - .addAllUniqueId(expectedIds) - .addAllUniqueContentDomain( - expectedContentDomains) - .addAllUniqueTable(expectedTables) - .addAllUniqueSemanticProperties( - expectedSemanticProperties) - .addAllFeedActionQueryDataItem( - expectedDataItems)) - .addClientCapability(Capability.SEND_FEEDBACK) - .addClientCapability(Capability.BASE_UI) - .build()) - .build(); - assertThat(request).isEqualTo(expectedRequest); - } - - @Test - public void testActionData_overlappingDismisses() throws Exception { - mFakeActionReader.addDismissActionsWithSemanticProperties( - buildDismissAction(ID, CONTENT_DOMAIN, TABLE, null), - buildDismissAction(ID_2, CONTENT_DOMAIN, TABLE, null)); - mRequestManager.triggerRefresh(RequestReason.HOST_REQUESTED, input -> {}); - - HttpRequest httpRequest = mFakeNetworkClient.getLatestRequest(); - assertHttpRequestFormattedCorrectly(httpRequest, mContext); - - Request request = getRequestFromHttpRequest(httpRequest); - - List<Long> expectedIds = Arrays.asList(ID, ID_2); - List<String> expectedContentDomains = Collections.singletonList(CONTENT_DOMAIN); - List<String> expectedTables = Collections.singletonList(TABLE); - List<SemanticProperties> expectedSemanticProperties = Collections.emptyList(); - List<FeedActionQueryDataItem> expectedDataItems = - Arrays.asList(FeedActionQueryDataItem.newBuilder() - .setIdIndex(0) - .setContentDomainIndex(0) - .setTableIndex(0) - .build(), - FeedActionQueryDataItem.newBuilder() - .setIdIndex(1) - .setContentDomainIndex(0) - .setTableIndex(0) - .build()); - - Request expectedRequest = - Request.newBuilder() - .setRequestVersion(RequestVersion.FEED_QUERY) - .setExtension(FeedRequest.feedRequest, - getTestFeedRequestBuilder() - .setFeedQuery(FeedQuery.newBuilder().setReason( - FeedQuery.RequestReason.SCHEDULED_REFRESH)) - .addFeedActionQueryData( - FeedActionQueryData.newBuilder() - .setAction( - Action.newBuilder().setActionType( - ActionType.DISMISS)) - .addAllUniqueId(expectedIds) - .addAllUniqueContentDomain( - expectedContentDomains) - .addAllUniqueTable(expectedTables) - .addAllUniqueSemanticProperties( - expectedSemanticProperties) - .addAllFeedActionQueryDataItem( - expectedDataItems)) - .addClientCapability(Capability.SEND_FEEDBACK) - .addClientCapability(Capability.BASE_UI) - .build()) - .build(); - assertThat(request).isEqualTo(expectedRequest); - } - - @Test - public void testActionData_simpleDismissWithSemanticProperties() throws Exception { - byte[] semanticPropertiesBytes = {42, 17, 88}; - mFakeActionReader.addDismissActionsWithSemanticProperties( - buildDismissAction(ID, CONTENT_DOMAIN, TABLE, semanticPropertiesBytes)); - mRequestManager.triggerRefresh(RequestReason.HOST_REQUESTED, input -> {}); - - HttpRequest httpRequest = mFakeNetworkClient.getLatestRequest(); - assertHttpRequestFormattedCorrectly(httpRequest, mContext); - - Request request = getRequestFromHttpRequest(httpRequest); - - List<Long> expectedIds = Collections.singletonList(ID); - List<String> expectedContentDomains = Collections.singletonList(CONTENT_DOMAIN); - List<String> expectedTables = Collections.singletonList(TABLE); - List<SemanticProperties> expectedSemanticProperties = Collections.singletonList( - SemanticProperties.newBuilder() - .setSemanticPropertiesData(ByteString.copyFrom(semanticPropertiesBytes)) - .build()); - List<FeedActionQueryDataItem> expectedDataItems = - Collections.singletonList(FeedActionQueryDataItem.newBuilder() - .setIdIndex(0) - .setContentDomainIndex(0) - .setTableIndex(0) - .setSemanticPropertiesIndex(0) - .build()); - - Request expectedRequest = - Request.newBuilder() - .setRequestVersion(RequestVersion.FEED_QUERY) - .setExtension(FeedRequest.feedRequest, - getTestFeedRequestBuilder() - .setFeedQuery(FeedQuery.newBuilder().setReason( - FeedQuery.RequestReason.SCHEDULED_REFRESH)) - .addFeedActionQueryData( - FeedActionQueryData.newBuilder() - .setAction( - Action.newBuilder().setActionType( - ActionType.DISMISS)) - .addAllUniqueId(expectedIds) - .addAllUniqueContentDomain( - expectedContentDomains) - .addAllUniqueTable(expectedTables) - .addAllUniqueSemanticProperties( - expectedSemanticProperties) - .addAllFeedActionQueryDataItem( - expectedDataItems)) - .addClientCapability(Capability.SEND_FEEDBACK) - .addClientCapability(Capability.BASE_UI) - .build()) - .build(); - assertThat(request).isEqualTo(expectedRequest); - } - - @Test - public void testActionData_uniqueDismissesWithSemanticProperties() throws Exception { - byte[] semanticPropertiesBytes = {42, 17, 88}; - byte[] semanticPropertiesBytes2 = {7, 43, 91}; - mFakeActionReader.addDismissActionsWithSemanticProperties( - buildDismissAction(ID, CONTENT_DOMAIN, TABLE, semanticPropertiesBytes), - buildDismissAction(ID_2, CONTENT_DOMAIN_2, TABLE_2, semanticPropertiesBytes2)); - mRequestManager.triggerRefresh(RequestReason.HOST_REQUESTED, input -> {}); - - HttpRequest httpRequest = mFakeNetworkClient.getLatestRequest(); - assertHttpRequestFormattedCorrectly(httpRequest, mContext); - - Request request = getRequestFromHttpRequest(httpRequest); - - List<Long> expectedIds = Arrays.asList(ID, ID_2); - List<String> expectedContentDomains = Arrays.asList(CONTENT_DOMAIN, CONTENT_DOMAIN_2); - List<String> expectedTables = Arrays.asList(TABLE, TABLE_2); - List<SemanticProperties> expectedSemanticProperties = Arrays.asList( - SemanticProperties.newBuilder() - .setSemanticPropertiesData(ByteString.copyFrom(semanticPropertiesBytes)) - .build(), - SemanticProperties.newBuilder() - .setSemanticPropertiesData(ByteString.copyFrom(semanticPropertiesBytes2)) - .build()); - List<FeedActionQueryDataItem> expectedDataItems = - Arrays.asList(FeedActionQueryDataItem.newBuilder() - .setIdIndex(0) - .setContentDomainIndex(0) - .setTableIndex(0) - .setSemanticPropertiesIndex(0) - .build(), - FeedActionQueryDataItem.newBuilder() - .setIdIndex(1) - .setContentDomainIndex(1) - .setTableIndex(1) - .setSemanticPropertiesIndex(1) - .build()); - - Request expectedRequest = - Request.newBuilder() - .setRequestVersion(RequestVersion.FEED_QUERY) - .setExtension(FeedRequest.feedRequest, - getTestFeedRequestBuilder() - .setFeedQuery(FeedQuery.newBuilder().setReason( - FeedQuery.RequestReason.SCHEDULED_REFRESH)) - .addFeedActionQueryData( - FeedActionQueryData.newBuilder() - .setAction( - Action.newBuilder().setActionType( - ActionType.DISMISS)) - .addAllUniqueId(expectedIds) - .addAllUniqueContentDomain( - expectedContentDomains) - .addAllUniqueTable(expectedTables) - .addAllUniqueSemanticProperties( - expectedSemanticProperties) - .addAllFeedActionQueryDataItem( - expectedDataItems)) - .addClientCapability(Capability.SEND_FEEDBACK) - .addClientCapability(Capability.BASE_UI) - .build()) - .build(); - assertThat(request).isEqualTo(expectedRequest); - } - - @Test - public void testActionData_overlappingDismissesWithSemanticProperties() throws Exception { - byte[] semanticPropertiesBytes = {42, 17, 88}; - mFakeActionReader.addDismissActionsWithSemanticProperties( - buildDismissAction(ID, CONTENT_DOMAIN, TABLE, semanticPropertiesBytes), - buildDismissAction(ID_2, CONTENT_DOMAIN, TABLE_2, semanticPropertiesBytes)); - mRequestManager.triggerRefresh(RequestReason.HOST_REQUESTED, input -> {}); - - HttpRequest httpRequest = mFakeNetworkClient.getLatestRequest(); - assertHttpRequestFormattedCorrectly(httpRequest, mContext); - - Request request = getRequestFromHttpRequest(httpRequest); - - List<Long> expectedIds = Arrays.asList(ID, ID_2); - List<String> expectedContentDomains = Collections.singletonList(CONTENT_DOMAIN); - List<String> expectedTables = Arrays.asList(TABLE, TABLE_2); - List<SemanticProperties> expectedSemanticProperties = Collections.singletonList( - SemanticProperties.newBuilder() - .setSemanticPropertiesData(ByteString.copyFrom(semanticPropertiesBytes)) - .build()); - List<FeedActionQueryDataItem> expectedDataItems = - Arrays.asList(FeedActionQueryDataItem.newBuilder() - .setIdIndex(0) - .setContentDomainIndex(0) - .setTableIndex(0) - .setSemanticPropertiesIndex(0) - .build(), - FeedActionQueryDataItem.newBuilder() - .setIdIndex(1) - .setContentDomainIndex(0) - .setTableIndex(1) - .setSemanticPropertiesIndex(0) - .build()); - - Request expectedRequest = - Request.newBuilder() - .setRequestVersion(RequestVersion.FEED_QUERY) - .setExtension(FeedRequest.feedRequest, - getTestFeedRequestBuilder() - .setFeedQuery(FeedQuery.newBuilder().setReason( - FeedQuery.RequestReason.SCHEDULED_REFRESH)) - .addFeedActionQueryData( - FeedActionQueryData.newBuilder() - .setAction( - Action.newBuilder().setActionType( - ActionType.DISMISS)) - .addAllUniqueId(expectedIds) - .addAllUniqueContentDomain( - expectedContentDomains) - .addAllUniqueTable(expectedTables) - .addAllUniqueSemanticProperties( - expectedSemanticProperties) - .addAllFeedActionQueryDataItem( - expectedDataItems)) - .addClientCapability(Capability.SEND_FEEDBACK) - .addClientCapability(Capability.BASE_UI) - .build()) - .build(); - assertThat(request).isEqualTo(expectedRequest); - } - - @Test - public void testActionData_someDismissesWithSemanticProperties() throws Exception { - byte[] semanticPropertiesBytes = {42, 17, 88}; - mFakeActionReader.addDismissActionsWithSemanticProperties( - buildDismissAction(ID, CONTENT_DOMAIN, TABLE, null), - buildDismissAction(ID_2, CONTENT_DOMAIN_2, TABLE_2, semanticPropertiesBytes)); - mRequestManager.triggerRefresh(RequestReason.HOST_REQUESTED, input -> {}); - - HttpRequest httpRequest = mFakeNetworkClient.getLatestRequest(); - assertHttpRequestFormattedCorrectly(httpRequest, mContext); - - Request request = getRequestFromHttpRequest(httpRequest); - - List<Long> expectedIds = Arrays.asList(ID, ID_2); - List<String> expectedContentDomains = Arrays.asList(CONTENT_DOMAIN, CONTENT_DOMAIN_2); - List<String> expectedTables = Arrays.asList(TABLE, TABLE_2); - List<SemanticProperties> expectedSemanticProperties = Collections.singletonList( - SemanticProperties.newBuilder() - .setSemanticPropertiesData(ByteString.copyFrom(semanticPropertiesBytes)) - .build()); - List<FeedActionQueryDataItem> expectedDataItems = - Arrays.asList(FeedActionQueryDataItem.newBuilder() - .setIdIndex(0) - .setContentDomainIndex(0) - .setTableIndex(0) - .build(), - FeedActionQueryDataItem.newBuilder() - .setIdIndex(1) - .setContentDomainIndex(1) - .setTableIndex(1) - .setSemanticPropertiesIndex(0) - .build()); - - Request expectedRequest = - Request.newBuilder() - .setRequestVersion(RequestVersion.FEED_QUERY) - .setExtension(FeedRequest.feedRequest, - getTestFeedRequestBuilder() - .setFeedQuery(FeedQuery.newBuilder().setReason( - FeedQuery.RequestReason.SCHEDULED_REFRESH)) - .addFeedActionQueryData( - FeedActionQueryData.newBuilder() - .setAction( - Action.newBuilder().setActionType( - ActionType.DISMISS)) - .addAllUniqueId(expectedIds) - .addAllUniqueContentDomain( - expectedContentDomains) - .addAllUniqueTable(expectedTables) - .addAllUniqueSemanticProperties( - expectedSemanticProperties) - .addAllFeedActionQueryDataItem( - expectedDataItems)) - .addClientCapability(Capability.SEND_FEEDBACK) - .addClientCapability(Capability.BASE_UI) - .build()) - .build(); - assertThat(request).isEqualTo(expectedRequest); - } - - @Test - public void testHandleResponse() throws Exception { - mRequestManager.triggerRefresh(RequestReason.HOST_REQUESTED, mConsumer); - - assertThat(mFakeProtocolAdapter.getLastResponse()).isEqualTo(Response.getDefaultInstance()); - assertThat(mConsumer.isCalled()).isTrue(); - assertThat(mConsumedResult.isSuccessful()).isTrue(); - } - - @Test - public void testHandleResponse_notFound() throws Exception { - mFakeNetworkClient.addResponse(mFailingResponse); - mRequestManager.triggerRefresh(RequestReason.HOST_REQUESTED, mConsumer); - - verify(mScheduler).onRequestError(NOT_FOUND); - assertThat(mConsumer.isCalled()).isTrue(); - assertThat(mConsumedResult.isSuccessful()).isFalse(); - } - - @Test - public void testHandleResponse_pageNotFound() throws Exception { - mFakeNetworkClient.addResponse(mFailingResponse); - StreamToken token = - StreamToken.newBuilder() - .setNextPageToken(ByteString.copyFrom("abc", Charset.defaultCharset())) - .build(); - mFakeThreadUtils.enforceMainThread(false); - mRequestManager.loadMore(token, ConsistencyToken.getDefaultInstance(), mConsumer); - - verify(mScheduler, never()).onRequestError(NOT_FOUND); - assertThat(mConsumer.isCalled()).isTrue(); - assertThat(mConsumedResult.isSuccessful()).isFalse(); - } - - @Test - public void testHandleResponse_missingLengthPrefixNotSupported() { - mFakeNetworkClient.addResponse(new HttpResponse( - /* responseCode= */ 200, Response.getDefaultInstance().toByteArray(), false)); - mRequestManager.triggerRefresh(RequestReason.HOST_REQUESTED, mConsumer); - assertThat(mConsumer.isCalled()).isTrue(); - assertThat(mConsumedResult.isSuccessful()).isFalse(); - assertThat(mFakeProtocolAdapter.getLastResponse()).isNull(); - } - - @Test - public void testGetWireRequestResponse_unknown() throws Exception { - testReason(RequestReason.UNKNOWN, FeedQuery.RequestReason.UNKNOWN_REQUEST_REASON, - RequestHelper.PRIORITY_VALUE_INTERACTIVE); - } - - @Test - public void testGetWireRequestResponse_zeroState() throws Exception { - testReason(RequestReason.ZERO_STATE, FeedQuery.RequestReason.ZERO_STATE_REFRESH, - RequestHelper.PRIORITY_VALUE_INTERACTIVE); - } - - @Test - public void testGetWireRequestResponse_hostRequested() throws Exception { - testReason(RequestReason.HOST_REQUESTED, FeedQuery.RequestReason.SCHEDULED_REFRESH, - RequestHelper.PRIORITY_VALUE_BACKGROUND); - } - - @Test - public void testGetWireRequestResponse_openWithContent() throws Exception { - testReason(RequestReason.OPEN_WITH_CONTENT, FeedQuery.RequestReason.WITH_CONTENT, - RequestHelper.PRIORITY_VALUE_BACKGROUND); - } - - @Test - public void testGetWireRequestResponse_manualContinuation() throws Exception { - testReason(RequestReason.MANUAL_CONTINUATION, FeedQuery.RequestReason.NEXT_PAGE_SCROLL, - RequestHelper.PRIORITY_VALUE_INTERACTIVE); - } - - @Test - public void testGetWireRequestResponse_automaticContinuation() throws Exception { - testReason(RequestReason.AUTOMATIC_CONTINUATION, FeedQuery.RequestReason.NEXT_PAGE_SCROLL, - RequestHelper.PRIORITY_VALUE_INTERACTIVE); - } - - @Test - public void testGetWireRequestResponse_openWithoutContent() throws Exception { - testReason(RequestReason.OPEN_WITHOUT_CONTENT, FeedQuery.RequestReason.INITIAL_LOAD, - RequestHelper.PRIORITY_VALUE_INTERACTIVE); - } - - @Test - public void testGetWireRequestResponse_clearAll() throws Exception { - testReason(RequestReason.CLEAR_ALL, FeedQuery.RequestReason.CLEAR_ALL, - RequestHelper.PRIORITY_VALUE_INTERACTIVE); - } - - @Test - @Config(qualifiers = "en-rGB", sdk = VERSION_CODES.LOLLIPOP) - public void testClientInfo_postLollipop() throws Exception { - ReflectionHelpers.setStaticField(Build.VERSION.class, "SDK_INT", VERSION_CODES.LOLLIPOP); - ReflectionHelpers.setStaticField(Build.VERSION.class, "RELEASE", "7.1.2b4.1"); - ReflectionHelpers.setStaticField(Build.class, "SUPPORTED_ABIS", new String[] {"arm64-v8a"}); - ReflectionHelpers.setStaticField(Build.class, "CPU_ABI", "armeabi"); - ReflectionHelpers.setStaticField(Build.class, "TAGS", "release-keys"); - when(mApplicationInfo.getAppType()).thenReturn(ApplicationInfo.AppType.SEARCH_APP); - when(mApplicationInfo.getArchitecture()).thenReturn(ApplicationInfo.Architecture.ARM64); - when(mApplicationInfo.getBuildType()).thenReturn(ApplicationInfo.BuildType.RELEASE); - when(mApplicationInfo.getVersionString()).thenReturn("1.2.3.4"); - - mRequestManager.triggerRefresh(RequestReason.HOST_REQUESTED, input -> {}); - - HttpRequest httpRequest = mFakeNetworkClient.getLatestRequest(); - - Request request = getRequestFromHttpRequest(httpRequest); - Request expectedRequest = - Request.newBuilder() - .setRequestVersion(RequestVersion.FEED_QUERY) - .setExtension(FeedRequest.feedRequest, - getTestFeedRequestBuilder() - .setFeedQuery(FeedQuery.newBuilder().setReason( - FeedQuery.RequestReason.SCHEDULED_REFRESH)) - .setClientInfo( - ClientInfo.newBuilder() - .setPlatformType(PlatformType.ANDROID_ID) - .setPlatformVersion( - Version.newBuilder() - .setMajor(7) - .setMinor(1) - .setBuild(2) - .setRevision(1) - .setArchitecture( - Architecture.ARM64) - .setBuildType( - BuildType.RELEASE) - .setApiVersion( - VERSION_CODES - .LOLLIPOP) - .build()) - .setLocale(LocaleUtils.getLanguageTag( - mContext)) - .setAppType(AppType.GSA) - .setAppVersion( - Version.newBuilder() - .setMajor(1) - .setMinor(2) - .setBuild(3) - .setRevision(4) - .setArchitecture( - Architecture.ARM64) - .setBuildType( - BuildType.RELEASE) - .build()) - .addDisplayInfo( - DisplayInfo.newBuilder() - .setScreenDensity(1.0f) - .setScreenWidthInPixels(320) - .setScreenHeightInPixels( - 470)) - .build()) - .addClientCapability(Capability.SEND_FEEDBACK) - .addClientCapability(Capability.BASE_UI) - .build()) - .build(); - assertThat(request).isEqualTo(expectedRequest); - } - - private void testReason(@RequestReason int reason, FeedQuery.RequestReason expectedReason, - String expectedPriority) throws Exception { - mFakeNetworkClient.addResponse(mFailingResponse); - mRequestManager.triggerRefresh(reason, input -> {}); - - HttpRequest httpRequest = mFakeNetworkClient.getLatestRequest(); - Request request = getRequestFromHttpRequest(httpRequest); - assertThat(request.getExtension(FeedRequest.feedRequest).getFeedQuery().getReason()) - .isEqualTo(expectedReason); - assertThat(mFakeBasicLoggingApi.serverRequestReason).isEqualTo(reason); - assertThat(httpRequest.getUri().getQueryParameter(RequestHelper.PRIORITY_PARAM)) - .isEqualTo(expectedPriority); - } - - private static void assertHttpRequestFormattedCorrectly( - HttpRequest httpRequest, Context context) { - assertThat(httpRequest.getBody()).hasLength(0); - assertThat(httpRequest.getMethod()).isEqualTo(HttpMethod.GET); - assertThat(httpRequest.getUri().getQueryParameter("fmt")).isEqualTo("bin"); - assertThat(httpRequest.getUri().getQueryParameter(RequestHelper.MOTHERSHIP_PARAM_PAYLOAD)) - .isNotNull(); - assertThat(httpRequest.getUri().getQueryParameter(RequestHelper.LOCALE_PARAM)) - .isEqualTo(LocaleUtils.getLanguageTag(context)); - } - - private static HttpResponse createHttpResponse(int responseCode, Response response) - throws IOException { - byte[] rawResponse = response.toByteArray(); - ByteBuffer buffer = ByteBuffer.allocate(rawResponse.length + (Integer.SIZE / 8)); - CodedOutputStream codedOutputStream = CodedOutputStream.newInstance(buffer); - codedOutputStream.writeUInt32NoTag(rawResponse.length); - codedOutputStream.writeRawBytes(rawResponse); - codedOutputStream.flush(); - return new HttpResponse(responseCode, buffer.array(), false); - } - - private static DismissActionWithSemanticProperties buildDismissAction( - long id, String contentDomain, String table, byte /*@Nullable*/[] semanticProperties) { - ContentId contentId = ContentId.newBuilder() - .setTable(table) - .setContentDomain(contentDomain) - .setId(id) - .build(); - return new DismissActionWithSemanticProperties(contentId, semanticProperties); - } - - private Request getRequestFromHttpRequest(HttpRequest httpRequest) throws Exception { - return Request.parseFrom(Base64.decode(httpRequest.getUri().getQueryParameter( - RequestHelper.MOTHERSHIP_PARAM_PAYLOAD), - Base64.URL_SAFE), - mRegistry); - } - - private static FeedRequest.Builder getTestFeedRequestBuilder() { - return FeedRequest.newBuilder() - .setConsistencyToken(ConsistencyToken.getDefaultInstance()) - .setClientInfo( - ClientInfo.newBuilder() - .setPlatformType(PlatformType.ANDROID_ID) - .setPlatformVersion(Version.newBuilder() - .setMajor(4) - .setMinor(4) - .setBuild(3) - .setArchitecture(Architecture.ARM) - .setBuildType(BuildType.DEV) - .setApiVersion(VERSION_CODES.KITKAT) - .build()) - .setLocale(Locale.US.toLanguageTag()) - .setAppType(AppType.CHROME) - .setAppVersion(Version.newBuilder() - .setMajor(5) - .setMinor(7) - .setArchitecture(Architecture.ARM) - .setBuildType(BuildType.DEV) - .build()) - .addDisplayInfo(DisplayInfo.newBuilder() - .setScreenDensity(1.0f) - .setScreenWidthInPixels(320) - .setScreenHeightInPixels(470)) - .build()); - } - - private void testCapabilityAdded(String configKey, Capability... capability) throws Exception { - Configuration configuration = new Configuration.Builder().put(configKey, true).build(); - testCapabilityAddedWithConfig(configuration, capability); - } - - private void testCapabilityAdded(Capability... capability) throws Exception { - Configuration configuration = new Configuration.Builder().build(); - testCapabilityAddedWithConfig(configuration, capability); - } - - private void testCapabilityAddedWithConfig( - Configuration configuration, Capability... capability) throws Exception { - mRequestManager = new FeedRequestManagerImpl(configuration, mFakeNetworkClient, - mFakeProtocolAdapter, new FeedExtensionRegistry(ArrayList::new), mScheduler, - mFakeTaskQueue, mTimingUtils, mFakeThreadUtils, mFakeActionReader, mContext, - mApplicationInfo, mFakeMainThreadRunner, mFakeBasicLoggingApi, - mFakeTooltipSupportedApi); - mRequestManager.triggerRefresh(RequestReason.HOST_REQUESTED, input -> {}); - - HttpRequest httpRequest = mFakeNetworkClient.getLatestRequest(); - assertHttpRequestFormattedCorrectly(httpRequest, mContext); - - Set<Capability> expectedCap = EnumSet.of(Capability.BASE_UI, Capability.SEND_FEEDBACK); - Collections.addAll(expectedCap, capability); - - Request request = getRequestFromHttpRequest(httpRequest); - assertThat(request.getExtension(FeedRequest.feedRequest).getClientCapabilityList()) - .containsExactlyElementsIn(expectedCap); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedrequestmanager/RequestManagerImplTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedrequestmanager/RequestManagerImplTest.java deleted file mode 100644 index 9eac15a..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedrequestmanager/RequestManagerImplTest.java +++ /dev/null
@@ -1,53 +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. - -package org.chromium.chrome.browser.feed.library.feedrequestmanager; - -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.base.Consumer; -import org.chromium.chrome.browser.feed.library.api.common.MutationContext; -import org.chromium.chrome.browser.feed.library.api.host.logging.RequestReason; -import org.chromium.chrome.browser.feed.library.api.internal.common.Model; -import org.chromium.chrome.browser.feed.library.api.internal.requestmanager.FeedRequestManager; -import org.chromium.chrome.browser.feed.library.api.internal.sessionmanager.FeedSessionManager; -import org.chromium.chrome.browser.feed.library.common.Result; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Test of the {@link RequestManagerImpl} class. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public final class RequestManagerImplTest { - @Mock - private FeedRequestManager mFeedRequestManager; - @Mock - private FeedSessionManager mFeedSessionManager; - @Mock - private Consumer<Result<Model>> mUpdateConsumer; - - private RequestManagerImpl mRequestManager; - - @Before - public void createRequestManager() { - initMocks(this); - mRequestManager = new RequestManagerImpl(mFeedRequestManager, mFeedSessionManager); - when(mFeedSessionManager.getUpdateConsumer(MutationContext.EMPTY_CONTEXT)) - .thenReturn(mUpdateConsumer); - } - - @Test - public void testTriggerScheduledRefresh() { - mRequestManager.triggerScheduledRefresh(); - - verify(mFeedRequestManager).triggerRefresh(RequestReason.HOST_REQUESTED, mUpdateConsumer); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedrequestmanager/UploadableActionsRequestBuilderTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedrequestmanager/UploadableActionsRequestBuilderTest.java deleted file mode 100644 index 1e5d460..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedrequestmanager/UploadableActionsRequestBuilderTest.java +++ /dev/null
@@ -1,133 +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. - -package org.chromium.chrome.browser.feed.library.feedrequestmanager; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.MockitoAnnotations.initMocks; - -import com.google.protobuf.ByteString; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.internal.common.SemanticPropertiesWithId; -import org.chromium.chrome.browser.feed.library.testing.protocoladapter.FakeProtocolAdapter; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamUploadableAction; -import org.chromium.components.feed.core.proto.wire.ActionPayloadForTestProto.ActionPayloadForTest; -import org.chromium.components.feed.core.proto.wire.ActionPayloadProto.ActionPayload; -import org.chromium.components.feed.core.proto.wire.ActionRequestProto.ActionRequest; -import org.chromium.components.feed.core.proto.wire.ConsistencyTokenProto.ConsistencyToken; -import org.chromium.components.feed.core.proto.wire.ContentIdProto.ContentId; -import org.chromium.components.feed.core.proto.wire.FeedActionProto.FeedAction; -import org.chromium.components.feed.core.proto.wire.FeedActionRequestProto.FeedActionRequest; -import org.chromium.components.feed.core.proto.wire.SemanticPropertiesProto.SemanticProperties; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.Arrays; -import java.util.HashSet; - -/** Test of the {@link UploadableActionsRequestBuilder} class. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class UploadableActionsRequestBuilderTest { - private static final String CONTENT_ID = "contentId"; - private static final int TIME = 100; - private static final long DURATION = 20; - private static final byte[] SEMANTIC_PROPERTIES_BYTES = new byte[] {0x1, 0xf}; - private static final SemanticProperties SEMANTIC_PROPERTIES = - SemanticProperties.newBuilder() - .setSemanticPropertiesData(ByteString.copyFrom(SEMANTIC_PROPERTIES_BYTES)) - .build(); - private static final SemanticPropertiesWithId SEMANTIC_PROPERTIES_WITH_ID = - new SemanticPropertiesWithId(CONTENT_ID, SEMANTIC_PROPERTIES_BYTES); - private final ActionPayload mPayload = - ActionPayload.newBuilder() - .setExtension(ActionPayloadForTest.actionPayloadForTestExtension, - ActionPayloadForTest.newBuilder().setId(CONTENT_ID).build()) - .build(); - private UploadableActionsRequestBuilder mBuilder; - private HashSet<StreamUploadableAction> mActionSet = new HashSet<>(); - private ConsistencyToken mToken = ConsistencyToken.newBuilder() - .setToken(ByteString.copyFrom(new byte[] {0x1, 0xf})) - .build(); - private ActionRequest.Builder mRequestBuilder; - private FeedActionRequest.Builder mFeedActionRequestBuilder; - private FakeProtocolAdapter mFakeProtocolAdapter; - - @Before - public void setUp() { - initMocks(this); - mFakeProtocolAdapter = new FakeProtocolAdapter(); - mFakeProtocolAdapter.addContentId(CONTENT_ID, ContentId.getDefaultInstance()); - mBuilder = new UploadableActionsRequestBuilder(mFakeProtocolAdapter); - mActionSet.add(StreamUploadableAction.newBuilder() - .setFeatureContentId(CONTENT_ID) - .setPayload(mPayload) - .setTimestampSeconds(TIME) - .setDurationMs(DURATION) - .build()); - mRequestBuilder = ActionRequest.newBuilder().setRequestVersion( - ActionRequest.RequestVersion.FEED_UPLOAD_ACTION); - mFeedActionRequestBuilder = FeedActionRequest.newBuilder(); - } - - @Test - public void testUploadableActionsRequest_noToken() throws Exception { - FeedAction feedAction = FeedAction.newBuilder() - .setContentId(ContentId.getDefaultInstance()) - .setActionPayload(mPayload) - .setClientData(FeedAction.ClientData.newBuilder() - .setTimestampSeconds(TIME) - .setDurationMs(DURATION) - .build()) - .build(); - mFeedActionRequestBuilder.addFeedAction(feedAction); - mRequestBuilder.setExtension( - FeedActionRequest.feedActionRequest, mFeedActionRequestBuilder.build()); - - ActionRequest expectedResult = mRequestBuilder.build(); - ActionRequest result = mBuilder.setActions(mActionSet).build(); - assertThat(result).isEqualTo(expectedResult); - } - - @Test - public void testUploadableActionsRequest_noActions() throws Exception { - mFeedActionRequestBuilder.setConsistencyToken(mToken); - mRequestBuilder.setExtension( - FeedActionRequest.feedActionRequest, mFeedActionRequestBuilder.build()); - - ActionRequest expectedResult = mRequestBuilder.build(); - ActionRequest result = mBuilder.setConsistencyToken(mToken).build(); - assertThat(result).isEqualTo(expectedResult); - } - - @Test - public void testUploadableActionsRequest() throws Exception { - FeedAction feedAction = FeedAction.newBuilder() - .setContentId(ContentId.getDefaultInstance()) - .setSemanticProperties(SEMANTIC_PROPERTIES) - .setActionPayload(mPayload) - .setClientData(FeedAction.ClientData.newBuilder() - .setTimestampSeconds(TIME) - .setDurationMs(DURATION) - .build()) - .build(); - mFeedActionRequestBuilder.addFeedAction(feedAction); - mFeedActionRequestBuilder.setConsistencyToken(mToken); - mRequestBuilder.setExtension( - FeedActionRequest.feedActionRequest, mFeedActionRequestBuilder.build()); - - ActionRequest expectedResult = mRequestBuilder.build(); - ActionRequest result = - mBuilder.setActions(mActionSet) - .setConsistencyToken(mToken) - .setSemanticProperties(Arrays.asList(SEMANTIC_PROPERTIES_WITH_ID)) - .build(); - assertThat(result).isEqualTo(expectedResult); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedrequestmanager/internal/UtilsTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedrequestmanager/internal/UtilsTest.java deleted file mode 100644 index 0b24eab6..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedrequestmanager/internal/UtilsTest.java +++ /dev/null
@@ -1,48 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.feed.library.feedrequestmanager.internal; - -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.components.feed.core.proto.wire.VersionProto.Version; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests of the {@link Utils}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class UtilsTest { - @Test - public void fillVersionsFromString_allValid() { - Version.Builder builder = Version.newBuilder(); - Utils.fillVersionsFromString(builder, "1.2.3.4"); - Assert.assertEquals(1, builder.getMajor()); - Assert.assertEquals(2, builder.getMinor()); - Assert.assertEquals(3, builder.getBuild()); - Assert.assertEquals(4, builder.getRevision()); - } - - @Test - public void fillVersionsFromString_ignoresExtraStrings() { - Version.Builder builder = Version.newBuilder(); - Utils.fillVersionsFromString(builder, "1.2.3b5"); - Assert.assertEquals(1, builder.getMajor()); - Assert.assertEquals(2, builder.getMinor()); - Assert.assertEquals(3, builder.getBuild()); - Assert.assertFalse(builder.hasRevision()); - } - - @Test - public void fillVersionsFromString_emptyVersion() { - Version.Builder builder = Version.newBuilder(); - Utils.fillVersionsFromString(builder, ""); - Assert.assertFalse(builder.hasMajor()); - Assert.assertFalse(builder.hasMinor()); - Assert.assertFalse(builder.hasBuild()); - Assert.assertFalse(builder.hasRevision()); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedsessionmanager/FeedSessionManagerImplTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedsessionmanager/FeedSessionManagerImplTest.java deleted file mode 100644 index 6e2c16d..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedsessionmanager/FeedSessionManagerImplTest.java +++ /dev/null
@@ -1,876 +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. - -package org.chromium.chrome.browser.feed.library.feedsessionmanager; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import static org.chromium.chrome.browser.feed.library.api.internal.store.Store.HEAD_SESSION_ID; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; -import com.google.protobuf.ByteString; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestRule; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.ParameterizedRobolectricTestRunner; -import org.robolectric.ParameterizedRobolectricTestRunner.Parameter; -import org.robolectric.ParameterizedRobolectricTestRunner.Parameters; -import org.robolectric.annotation.Config; - -import org.chromium.base.Consumer; -import org.chromium.base.test.util.JniMocker; -import org.chromium.chrome.browser.feed.library.api.common.MutationContext; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration.ConfigKey; -import org.chromium.chrome.browser.feed.library.api.host.logging.InternalFeedError; -import org.chromium.chrome.browser.feed.library.api.host.logging.RequestReason; -import org.chromium.chrome.browser.feed.library.api.host.scheduler.SchedulerApi; -import org.chromium.chrome.browser.feed.library.api.host.scheduler.SchedulerApi.RequestBehavior; -import org.chromium.chrome.browser.feed.library.api.host.scheduler.SchedulerApi.SessionState; -import org.chromium.chrome.browser.feed.library.api.internal.actionmanager.ActionManager; -import org.chromium.chrome.browser.feed.library.api.internal.common.Model; -import org.chromium.chrome.browser.feed.library.api.internal.common.SemanticPropertiesWithId; -import org.chromium.chrome.browser.feed.library.api.internal.common.testing.ContentIdGenerators; -import org.chromium.chrome.browser.feed.library.api.internal.common.testing.InternalProtocolBuilder; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelCursor; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelError; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelError.ErrorType; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProviderFactory; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProviderObserver; -import org.chromium.chrome.browser.feed.library.api.internal.sessionmanager.FeedSessionManager; -import org.chromium.chrome.browser.feed.library.common.Result; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeMainThreadRunner; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeTaskQueue; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeThreadUtils; -import org.chromium.chrome.browser.feed.library.common.intern.Interner; -import org.chromium.chrome.browser.feed.library.common.time.TimingUtils; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.feedapplifecyclelistener.FeedAppLifecycleListener; -import org.chromium.chrome.browser.feed.library.feedapplifecyclelistener.FeedLifecycleListener.LifecycleEvent; -import org.chromium.chrome.browser.feed.library.feedmodelprovider.FeedModelProviderFactory; -import org.chromium.chrome.browser.feed.library.feedsessionmanager.FeedSessionManagerImpl.SessionMutationTracker; -import org.chromium.chrome.browser.feed.library.feedsessionmanager.FeedSessionManagerImpl.StreamSharedStateInterner; -import org.chromium.chrome.browser.feed.library.feedsessionmanager.internal.HeadSessionImpl; -import org.chromium.chrome.browser.feed.library.feedsessionmanager.internal.Session; -import org.chromium.chrome.browser.feed.library.feedsessionmanager.internal.SessionCache; -import org.chromium.chrome.browser.feed.library.testing.actionmanager.FakeViewActionManager; -import org.chromium.chrome.browser.feed.library.testing.host.logging.FakeBasicLoggingApi; -import org.chromium.chrome.browser.feed.library.testing.protocoladapter.FakeProtocolAdapter; -import org.chromium.chrome.browser.feed.library.testing.requestmanager.FakeActionUploadRequestManager; -import org.chromium.chrome.browser.feed.library.testing.requestmanager.FakeFeedRequestManager; -import org.chromium.chrome.browser.feed.library.testing.store.FakeStore; -import org.chromium.chrome.browser.flags.ChromeFeatureList; -import org.chromium.chrome.browser.preferences.Pref; -import org.chromium.chrome.browser.profiles.Profile; -import org.chromium.chrome.test.util.browser.Features; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamDataOperation; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamPayload; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamSharedState; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamStructure; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamStructure.Operation; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamToken; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamUploadableAction; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.UiContext; -import org.chromium.components.feed.core.proto.libraries.testing.UiContextForTestProto.UiContextForTest; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.PietSharedState; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.Stylesheet; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.Template; -import org.chromium.components.feed.core.proto.wire.ConsistencyTokenProto.ConsistencyToken; -import org.chromium.components.feed.core.proto.wire.ContentIdProto.ContentId; -import org.chromium.components.feed.core.proto.wire.PietSharedStateItemProto.PietSharedStateItem; -import org.chromium.components.feed.core.proto.wire.ResponseProto.Response; -import org.chromium.components.prefs.PrefService; -import org.chromium.components.user_prefs.UserPrefs; -import org.chromium.components.user_prefs.UserPrefsJni; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.nio.charset.Charset; -import java.util.Arrays; -import java.util.List; - -/** Tests of the {@link FeedSessionManagerImpl} class. */ -@RunWith(ParameterizedRobolectricTestRunner.class) -@Config(sdk = LocalRobolectricTestRunner.DEFAULT_SDK, manifest = Config.NONE) -public class FeedSessionManagerImplTest { - private static final MutationContext EMPTY_MUTATION = new MutationContext.Builder().build(); - private static final ContentId SHARED_STATE_ID = ContentId.newBuilder() - .setContentDomain("piet-shared-state") - .setId(1) - .setTable("piet-shared-state") - .build(); - private static final String SESSION_ID = "session:1"; - private static final int STORAGE_MISS_THRESHOLD = 4; - - private final ContentIdGenerators mContentIdGenerators = new ContentIdGenerators(); - private final ContentIdGenerators mIdGenerators = new ContentIdGenerators(); - private final FakeClock mFakeClock = new FakeClock(); - private final String mRootContentId = mIdGenerators.createRootContentId(0); - private final TimingUtils mTimingUtils = new TimingUtils(); - - private Configuration mConfiguration; - private FakeActionUploadRequestManager mFakeActionUploadRequestManager; - private FakeBasicLoggingApi mFakeBasicLoggingApi; - private FakeMainThreadRunner mFakeMainThreadRunner; - private FakeProtocolAdapter mFakeProtocolAdapter; - private FakeFeedRequestManager mFakeRequestManager; - private FakeStore mFakeStore; - private FakeTaskQueue mFakeTaskQueue; - private FakeThreadUtils mFakeThreadUtils; - private FeedAppLifecycleListener mAppLifecycleListener; - - @Rule - public TestRule mFeaturesProcessorRule = new Features.JUnitProcessor(); - - @Rule - public JniMocker mocker = new JniMocker(); - - @Mock - private SchedulerApi mSchedulerApi; - @Mock - private UserPrefs.Natives mUserPrefsJniMock; - @Mock - private Profile mProfile; - @Mock - private PrefService mPrefService; - @Mock - private ActionManager mActionManager; - - @Parameters - public static List<Object[]> data() { - return Arrays.asList(new Object[][] {{true}, {false}}); - } - - @Parameter(0) - public boolean mUploadingActionsEnabled; - - @Before - public void setUp() { - initMocks(this); - - mocker.mock(UserPrefsJni.TEST_HOOKS, mUserPrefsJniMock); - Profile.setLastUsedProfileForTesting(mProfile); - when(mUserPrefsJniMock.get(mProfile)).thenReturn(mPrefService); - - mConfiguration = new Configuration.Builder() - .put(ConfigKey.UNDOABLE_ACTIONS_ENABLED, mUploadingActionsEnabled) - .put(ConfigKey.STORAGE_MISS_THRESHOLD, STORAGE_MISS_THRESHOLD) - .build(); - mFakeBasicLoggingApi = new FakeBasicLoggingApi(); - mFakeThreadUtils = FakeThreadUtils.withThreadChecks(); - mFakeMainThreadRunner = - FakeMainThreadRunner.runTasksImmediatelyWithThreadChecks(mFakeThreadUtils); - mFakeTaskQueue = new FakeTaskQueue(mFakeClock, mFakeThreadUtils); - mAppLifecycleListener = new FeedAppLifecycleListener(mFakeThreadUtils); - mFakeStore = new FakeStore(mConfiguration, mFakeThreadUtils, mFakeTaskQueue, mFakeClock); - mFakeActionUploadRequestManager = new FakeActionUploadRequestManager( - mFakeStore, new FakeViewActionManager(mFakeStore), mFakeThreadUtils); - mFakeProtocolAdapter = new FakeProtocolAdapter(); - mFakeRequestManager = new FakeFeedRequestManager( - mFakeThreadUtils, mFakeMainThreadRunner, mFakeProtocolAdapter, mFakeTaskQueue); - mFakeRequestManager.queueResponse(Response.getDefaultInstance()); - when(mSchedulerApi.shouldSessionRequestData(any(SessionState.class))) - .thenReturn(RequestBehavior.NO_REQUEST_WITH_CONTENT); - } - - @Test - public void testInitialization() { - StreamSharedState sharedState = - StreamSharedState.newBuilder() - .setContentId(mIdGenerators.createFeatureContentId(0)) - .setPietSharedStateItem(PietSharedStateItem.getDefaultInstance()) - .build(); - StreamStructure operation = - StreamStructure.newBuilder() - .setContentId(mIdGenerators.createFeatureContentId(0)) - .setOperation(StreamStructure.Operation.UPDATE_OR_APPEND) - .build(); - mFakeStore.setSharedStates(sharedState).setStreamStructures(HEAD_SESSION_ID, operation); - - FeedSessionManagerImpl sessionManager = createFeedSessionManager(mConfiguration); - assertThat(sessionManager.mInitialized.get()).isFalse(); - sessionManager.initialize(); - assertThat(sessionManager.mInitialized.get()).isTrue(); - assertThat(sessionManager.getSharedStateCacheForTest()).hasSize(1); - - SessionCache sessionCache = sessionManager.getSessionCacheForTest(); - Session head = sessionCache.getHead(); - assertThat(head).isInstanceOf(HeadSessionImpl.class); - String itemKey = mIdGenerators.createFeatureContentId(0); - assertThat(head.getContentInSession()).containsExactly(itemKey); - } - - // This is testing a condition similar to the one that caused [INTERNAL LINK]. - @Test - public void testInitialization_equalSharedStatesDifferentContentIds() throws Exception { - StreamSharedState sharedState1 = - StreamSharedState.newBuilder() - .setContentId("shared-state-1") - .setPietSharedStateItem(PietSharedStateItem.newBuilder().setPietSharedState( - PietSharedState.newBuilder().addStylesheets( - Stylesheet.newBuilder().setStylesheetId( - "shared-stylesheet")))) - .build(); - StreamSharedState sharedState2 = - StreamSharedState.newBuilder() - .setContentId("shared-state-2") // Different ContentId - .setPietSharedStateItem( // Equal PietSharedStateItem - PietSharedStateItem.parseFrom( - sharedState1.getPietSharedStateItem().toByteString())) - .build(); - assertThat(sharedState1).isNotEqualTo(sharedState2); - - // Initial PietSharedStateItem messages are equal but not the same between the 2 shared - // states. - assertThat(sharedState1.getPietSharedStateItem()) - .isEqualTo(sharedState2.getPietSharedStateItem()); - assertThat(sharedState1.getPietSharedStateItem()) - .isNotSameInstanceAs(sharedState2.getPietSharedStateItem()); - - StreamStructure operation = - StreamStructure.newBuilder() - .setContentId(mIdGenerators.createFeatureContentId(0)) - .setOperation(StreamStructure.Operation.UPDATE_OR_APPEND) - .build(); - mFakeStore.setSharedStates(sharedState1, sharedState2) - .setStreamStructures(HEAD_SESSION_ID, operation); - - ContentId contentId1 = SHARED_STATE_ID.toBuilder().setId(1).build(); - ContentId contentId2 = SHARED_STATE_ID.toBuilder().setId(2).build(); - mFakeProtocolAdapter.addContentId("shared-state-1", contentId1) - .addContentId("shared-state-2", contentId2); - - FeedSessionManagerImpl sessionManager = createFeedSessionManager(mConfiguration); - assertThat(sessionManager.mInitialized.get()).isFalse(); - sessionManager.initialize(); - assertThat(sessionManager.mInitialized.get()).isTrue(); - assertThat(sessionManager.getSharedStateCacheForTest()).hasSize(2); - - StreamSharedState cachedSharedState1 = sessionManager.getSharedState(contentId1); - StreamSharedState cachedSharedState2 = sessionManager.getSharedState(contentId2); - assertThat(cachedSharedState1).isEqualTo(sharedState1); - assertThat(cachedSharedState2).isEqualTo(sharedState2); - - // Cached PietSharedStateItem messages the same between the 2 shared states (memoized). - assertThat(cachedSharedState1.getPietSharedStateItem()) - .isSameInstanceAs(cachedSharedState2.getPietSharedStateItem()); - } - - @Test - public void testLifecycleInitialization() { - FeedSessionManagerImpl sessionManager = createFeedSessionManager(mConfiguration); - assertThat(sessionManager.mInitialized.get()).isFalse(); - sessionManager.onLifecycleEvent(LifecycleEvent.INITIALIZE); - assertThat(sessionManager.mInitialized.get()).isTrue(); - sessionManager.onLifecycleEvent(LifecycleEvent.INITIALIZE); - assertThat(sessionManager.mInitialized.get()).isTrue(); - } - - @Test - public void testSessionWithContent() { - FeedSessionManagerImpl sessionManager = getInitializedSessionManager(); - int featureCnt = 3; - populateSession(sessionManager, featureCnt, 1, true, null); - - ModelProvider modelProvider = getModelProvider(sessionManager); - assertThat(modelProvider).isNotNull(); - assertThat(modelProvider.getRootFeature()).isNotNull(); - - ModelCursor cursor = modelProvider.getRootFeature().getCursor(); - int cursorCount = 0; - while (cursor.getNextItem() != null) { - cursorCount++; - } - assertThat(cursorCount).isEqualTo(featureCnt); - - // append a couple of others - populateSession(sessionManager, featureCnt, featureCnt + 1, false, null); - - cursor = modelProvider.getRootFeature().getCursor(); - cursorCount = 0; - while (cursor.getNextItem() != null) { - cursorCount++; - } - assertThat(cursorCount).isEqualTo(featureCnt * 2); - } - - @Test - public void testNoRequestWithContent_populateIsImmediate() { - when(mSchedulerApi.shouldSessionRequestData(any(SessionState.class))) - .thenReturn(RequestBehavior.NO_REQUEST_WITH_CONTENT); - - FeedSessionManagerImpl sessionManager = getInitializedSessionManager(); - populateSession(sessionManager, 3, 1, true, null); - mFakeTaskQueue.resetCounts(); - - // Population will happen in an immediate task and no request is sent. - ModelProvider modelProvider = getModelProvider(sessionManager); - assertThat(modelProvider).isNotNull(); - assertThat(mFakeTaskQueue.getImmediateTaskCount()).isEqualTo(1); - assertThat(mFakeTaskQueue.getBackgroundTaskCount()).isEqualTo(0); - assertThat(mFakeTaskQueue.getUserFacingTaskCount()).isEqualTo(0); - assertThat(mFakeTaskQueue.isMakingRequest()).isFalse(); - } - - @Test - public void testRequestWithContent_populateIsImmediate() { - when(mSchedulerApi.shouldSessionRequestData(any(SessionState.class))) - .thenReturn(RequestBehavior.REQUEST_WITH_CONTENT); - - FeedSessionManagerImpl sessionManager = getInitializedSessionManager(); - populateSession(sessionManager, 3, 1, true, null); - mFakeTaskQueue.resetCounts(); - - // Population will happen immediately and a request is sent. - ModelProvider modelProvider = getModelProvider(sessionManager); - assertThat(modelProvider).isNotNull(); - assertThat(mFakeTaskQueue.getImmediateTaskCount()).isEqualTo(1); - assertThat(mFakeTaskQueue.getBackgroundTaskCount()).isEqualTo(0); - assertThat(mFakeTaskQueue.getUserFacingTaskCount()).isEqualTo(1); - assertThat(mFakeTaskQueue.isMakingRequest()).isTrue(); - } - - @Test - public void testRequestWithWait_populateIsUserFacing() { - when(mSchedulerApi.shouldSessionRequestData(any(SessionState.class))) - .thenReturn(RequestBehavior.REQUEST_WITH_WAIT); - - FeedSessionManagerImpl sessionManager = getInitializedSessionManager(); - populateSession(sessionManager, 3, 1, true, null); - mFakeTaskQueue.resetCounts(); - - // Population will happen in a user-facing task and a request is sent. - ModelProvider modelProvider = getModelProvider(sessionManager); - assertThat(modelProvider).isNotNull(); - assertThat(mFakeTaskQueue.getImmediateTaskCount()).isEqualTo(0); - assertThat(mFakeTaskQueue.getBackgroundTaskCount()).isEqualTo(0); - assertThat(mFakeTaskQueue.getUserFacingTaskCount()).isEqualTo(2); - assertThat(mFakeTaskQueue.isMakingRequest()).isTrue(); - } - - @Test - public void testGetExistingSession_populateIsImmediate() { - FeedSessionManagerImpl sessionManager = getInitializedSessionManager(); - populateSession(sessionManager, - /* featureCnt= */ 2, - /* idStart= */ 1, - /* reset= */ true, - /* sharedStateId= */ null); - ModelProvider modelProvider = getModelProvider(sessionManager); - String sessionId = modelProvider.getSessionId(); - modelProvider.detachModelProvider(); - mFakeTaskQueue.resetCounts(); - - // Population will happen in an immediate task. - modelProvider = getModelProvider(sessionManager, sessionId, UiContext.getDefaultInstance()); - assertThat(modelProvider).isNotNull(); - assertThat(mFakeTaskQueue.getImmediateTaskCount()).isEqualTo(1); - assertThat(mFakeTaskQueue.getBackgroundTaskCount()).isEqualTo(0); - assertThat(mFakeTaskQueue.getUserFacingTaskCount()).isEqualTo(0); - } - - @Test - public void testMissingFeaturesBeyondThreshold_switchToEphemeralMode() { - FeedSessionManagerImpl sessionManager = getInitializedSessionManager(); - populateSession(sessionManager, STORAGE_MISS_THRESHOLD, 1, true, null); - mFakeStore.clearContent(); - - ModelProvider modelProvider = getModelProvider(sessionManager); - assertThat(modelProvider).isNotNull(); - assertThat(mFakeStore.isEphemeralMode()).isTrue(); - assertThat(mFakeBasicLoggingApi.lastInternalError) - .isEqualTo(InternalFeedError.STORAGE_MISS_BEYOND_THRESHOLD); - } - - @Test - public void testMissingFeaturesAtThreshold_doesNotSwitchToEphemeralMode() { - FeedSessionManagerImpl sessionManager = getInitializedSessionManager(); - populateSession(sessionManager, STORAGE_MISS_THRESHOLD - 1, 1, true, null); - mFakeStore.clearContent(); - - ModelProvider modelProvider = getModelProvider(sessionManager); - assertThat(modelProvider).isNotNull(); - assertThat(mFakeStore.isEphemeralMode()).isFalse(); - assertThat(mFakeBasicLoggingApi.lastInternalError) - .isEqualTo(InternalFeedError.CONTENT_STORAGE_MISSING_ITEM); - } - - @Test - public void testNoCardsError() { - FeedSessionManagerImpl sessionManager = getInitializedSessionManager(); - sessionManager.getUpdateConsumer(EMPTY_MUTATION).accept(Result.failure()); - - ModelProvider modelProvider = getModelProvider(sessionManager); - assertThat(modelProvider.getRootFeature()).isNull(); - - // Verify the failed session is correct - SessionCache sessionCache = sessionManager.getSessionCacheForTest(); - assertThat(sessionCache.getAttachedSessions()).hasSize(1); - Session session = sessionCache.getAttached(modelProvider.getSessionId()); - assertThat(session).isNotNull(); - } - - @Test - public void testNoCardsError_populatedHeadSuppressesError() { - FeedSessionManagerImpl sessionManager = getInitializedSessionManager(); - populateSession(sessionManager, - /* featureCnt= */ 2, - /* idStart= */ 1, - /* reset= */ true, - /* sharedStateId= */ null); - sessionManager.getUpdateConsumer(EMPTY_MUTATION).accept(Result.failure()); - - ModelProvider modelProvider = getModelProvider(sessionManager); - assertThat(modelProvider.getRootFeature()).isNotNull(); - - // Verify the failed session is correct - SessionCache sessionCache = sessionManager.getSessionCacheForTest(); - assertThat(sessionCache.getAttachedSessions()).hasSize(1); - Session session = sessionCache.getAttached(modelProvider.getSessionId()); - assertThat(session).isNotNull(); - } - - @Test - public void testModelErrorObserver() { - FeedSessionManagerImpl sessionManager = getInitializedSessionManager(); - // verify this runs. Another method that can'be be verified on a single thread since - // the noCardsError will be set and unset. - sessionManager.modelErrorObserver(null, new ModelError(ErrorType.NO_CARDS_ERROR, null)); - } - - @Test - public void testReset() { - FeedSessionManagerImpl sessionManager = getInitializedSessionManager(); - int featureCnt = 3; - int fullFeatureCount = populateSession(sessionManager, featureCnt, 1, true, null); - assertThat(fullFeatureCount).isEqualTo(featureCnt + 1); - - fullFeatureCount = populateSession(sessionManager, featureCnt, 1, true, null); - assertThat(fullFeatureCount).isEqualTo(featureCnt + 1); - } - - @Test - public void testHandleToken() { - ByteString bytes = ByteString.copyFrom("continuation", Charset.defaultCharset()); - StreamToken streamToken = StreamToken.newBuilder() - .setNextPageToken(bytes) - .setParentId(mRootContentId) - .build(); - FeedSessionManagerImpl sessionManager = getInitializedSessionManager(); - sessionManager.handleToken(SESSION_ID, streamToken); - - assertThat(mFakeRequestManager.getLatestStreamToken()).isEqualTo(streamToken); - assertThat(mFakeStore.getContentById(SessionCache.CONSISTENCY_TOKEN_CONTENT_ID)) - .hasSize(mUploadingActionsEnabled ? 1 : 0); - } - - @Test - public void testForceRefresh() { - FeedSessionManagerImpl sessionManager = getInitializedSessionManager(); - sessionManager.triggerRefresh( - SESSION_ID, RequestReason.ZERO_STATE, UiContext.getDefaultInstance()); - - assertThat(mFakeRequestManager.getLatestRequestReason()) - .isEqualTo(RequestReason.ZERO_STATE); - } - - @Test - public void testForceRefresh_scheduledRefresh() { - FeedSessionManagerImpl sessionManager = getInitializedSessionManager(); - sessionManager.triggerRefresh( - SESSION_ID, RequestReason.HOST_REQUESTED, UiContext.getDefaultInstance()); - - assertThat(mFakeRequestManager.getLatestRequestReason()) - .isEqualTo(RequestReason.HOST_REQUESTED); - } - - @Test - public void testGetSharedState() { - FeedSessionManagerImpl sessionManager = getInitializedSessionManager(); - String sharedStateId = mIdGenerators.createSharedStateContentId(0); - ContentId undefinedSharedStateId = ContentId.newBuilder() - .setContentDomain("shared-state") - .setId(5) - .setTable("shared-states") - .build(); - String undefinedStreamSharedStateId = - mIdGenerators.createSharedStateContentId(undefinedSharedStateId.getId()); - mFakeProtocolAdapter.addContentId(sharedStateId, SHARED_STATE_ID) - .addContentId(undefinedStreamSharedStateId, undefinedSharedStateId); - - populateSession(sessionManager, 3, 1, true, sharedStateId); - assertThat(sessionManager.getSharedState(SHARED_STATE_ID)).isNotNull(); - - // test the null condition - assertThat(sessionManager.getSharedState(undefinedSharedStateId)).isNull(); - } - - @Test - public void testUpdateConsumer() { - FeedSessionManagerImpl sessionManager = getInitializedSessionManager(); - assertThat(sessionManager.mOutstandingMutations).isEmpty(); - Consumer<Result<Model>> updateConsumer = sessionManager.getUpdateConsumer(EMPTY_MUTATION); - assertThat(updateConsumer).isInstanceOf(SessionMutationTracker.class); - assertThat(sessionManager.mOutstandingMutations).hasSize(1); - assertThat(sessionManager.mOutstandingMutations).contains(updateConsumer); - updateConsumer.accept(Result.success(Model.empty())); - assertThat(sessionManager.mOutstandingMutations).isEmpty(); - } - - @Test - public void testUpdateConsumer_clearAll() { - FeedSessionManagerImpl sessionManager = getInitializedSessionManager(); - assertThat(sessionManager.mOutstandingMutations).isEmpty(); - Consumer<Result<Model>> updateConsumer = sessionManager.getUpdateConsumer(EMPTY_MUTATION); - assertThat(sessionManager.mOutstandingMutations).hasSize(1); - mAppLifecycleListener.onClearAll(); - assertThat(sessionManager.mOutstandingMutations).isEmpty(); - - // verify this still runs (as a noop) - updateConsumer.accept(Result.success(Model.empty())); - assertThat(sessionManager.mOutstandingMutations).isEmpty(); - } - - @Test - public void testUpdateConsumer_clearAllWithRefresh() { - FeedSessionManagerImpl sessionManager = getInitializedSessionManager(); - assertThat(sessionManager.mOutstandingMutations).isEmpty(); - Consumer<Result<Model>> updateConsumer = sessionManager.getUpdateConsumer(EMPTY_MUTATION); - assertThat(sessionManager.mOutstandingMutations).hasSize(1); - mAppLifecycleListener.onClearAllWithRefresh(); - assertThat(sessionManager.mOutstandingMutations).isEmpty(); - - // verify this still runs (as a noop) - updateConsumer.accept(Result.success(Model.empty())); - assertThat(sessionManager.mOutstandingMutations).isEmpty(); - } - - @Test - public void testEdit_semanticProperties() { - FeedSessionManagerImpl sessionManager = getInitializedSessionManager(); - - ByteString semanticData = ByteString.copyFromUtf8("helloWorld"); - StreamDataOperation streamDataOperation = - StreamDataOperation.newBuilder() - .setStreamPayload(StreamPayload.newBuilder().setSemanticData(semanticData)) - .setStreamStructure(StreamStructure.newBuilder() - .setContentId(mRootContentId) - .setOperation(Operation.UPDATE_OR_APPEND)) - .build(); - - Consumer<Result<Model>> updateConsumer = sessionManager.getUpdateConsumer(EMPTY_MUTATION); - Result<Model> result = Result.success(Model.of(ImmutableList.of(streamDataOperation))); - updateConsumer.accept(result); - - assertThat(mFakeStore.getContentById(mRootContentId)) - .contains(new SemanticPropertiesWithId(mRootContentId, semanticData.toByteArray())); - } - - @Test - public void testSwitchToEphemeralMode() { - FeedSessionManagerImpl sessionManager = getUninitializedSessionManager(); - mFakeThreadUtils.enforceMainThread(false); - sessionManager.switchToEphemeralMode("An Error Message"); - assertThat(mFakeStore.isEphemeralMode()).isTrue(); - } - - @Test - public void testOnSwitchToEphemeralMode() { - FeedSessionManagerImpl sessionManager = getInitializedSessionManager(); - String sharedStateId = mIdGenerators.createSharedStateContentId(0); - - int featureCount = 3; - populateSession(sessionManager, featureCount, 1, true, sharedStateId); - - assertThat(sessionManager.getSharedStateCacheForTest()).hasSize(1); - SessionCache sessionCache = sessionManager.getSessionCacheForTest(); - assertThat(sessionCache.getAttachedSessions()).isEmpty(); - Session session = sessionCache.getHead(); - assertThat(session).isNotNull(); - assertThat(session.getContentInSession()).hasSize(featureCount + 1); - - mFakeThreadUtils.enforceMainThread(false); - sessionManager.onSwitchToEphemeralMode(); - - assertThat(sessionManager.getSharedStateCacheForTest()).isEmpty(); - assertThat(sessionCache.getAttachedSessions()).isEmpty(); - session = sessionCache.getHead(); - assertThat(session).isNotNull(); - assertThat(session.getContentInSession()).isEmpty(); - } - - @Test - public void testErrors_initializationSharedStateError() { - mFakeStore.setAllowGetSharedStates(false); - FeedSessionManagerImpl sessionManager = getUninitializedSessionManager(); - sessionManager.initialize(); - assertThat(mFakeStore.isEphemeralMode()).isTrue(); - } - - @Test - public void testErrors_initializationStreamStructureError() { - mFakeStore.setAllowGetStreamStructures(false); - FeedSessionManagerImpl sessionManager = getUninitializedSessionManager(); - sessionManager.initialize(); - assertThat(mFakeStore.isEphemeralMode()).isTrue(); - } - - @Test - public void testErrors_createNewSessionError() { - mFakeStore.setAllowCreateNewSession(false); - FeedSessionManagerImpl sessionManager = getUninitializedSessionManager(); - sessionManager.initialize(); - populateSession(sessionManager, 5, 1, true, null); - - ModelProvider unused = getModelProvider(sessionManager); - assertThat(mFakeStore.isEphemeralMode()).isTrue(); - } - - @Test - public void testErrors_getStreamStructuresError() { - FeedSessionManagerImpl sessionManager = getUninitializedSessionManager(); - sessionManager.initialize(); - mFakeStore.setAllowGetStreamStructures(false); - populateSession(sessionManager, 5, 1, true, null); - - ModelProvider unused = getModelProvider(sessionManager); - assertThat(mFakeStore.isEphemeralMode()).isTrue(); - } - - @Test - public void testTriggerUploadActions() { - FeedSessionManagerImpl sessionManager = getInitializedSessionManager( - new Configuration.Builder().put(ConfigKey.UNDOABLE_ACTIONS_ENABLED, true).build()); - ImmutableSet<StreamUploadableAction> actionSet = - ImmutableSet.of(StreamUploadableAction.getDefaultInstance()); - ConsistencyToken token = ConsistencyToken.newBuilder() - .setToken(ByteString.copyFrom(new byte[] {0x1, 0xf})) - .build(); - mFakeThreadUtils.enforceMainThread(false); - sessionManager.getConsistencyTokenConsumer().accept(Result.success(token)); - sessionManager.triggerUploadActions(actionSet); - assertThat(mFakeActionUploadRequestManager.getLatestActions()) - .containsExactlyElementsIn(actionSet); - } - - @Test - public void testGetConsistencyToken() { - FeedSessionManagerImpl sessionManager = getInitializedSessionManager( - new Configuration.Builder().put(ConfigKey.UNDOABLE_ACTIONS_ENABLED, true).build()); - ConsistencyToken token = ConsistencyToken.newBuilder() - .setToken(ByteString.copyFrom(new byte[] {0x1, 0xf})) - .build(); - mFakeThreadUtils.enforceMainThread(false); - sessionManager.getConsistencyTokenConsumer().accept(Result.success(token)); - assertThat(sessionManager.getConsistencyToken()).isEqualTo(token); - } - - @Test - public void testGetConsistencyTokenEmpty() { - FeedSessionManagerImpl sessionManager = getInitializedSessionManager(); - mFakeThreadUtils.enforceMainThread(false); - assertThat(sessionManager.getConsistencyToken()) - .isEqualTo(ConsistencyToken.getDefaultInstance()); - } - - @Test - public void testFetchActionsAndUpload() { - FeedSessionManagerImpl sessionManager = getInitializedSessionManager(); - ConsistencyToken token = ConsistencyToken.newBuilder() - .setToken(ByteString.copyFrom(new byte[] {0x1, 0xf})) - .build(); - ConsistencyToken expectedToken = - mUploadingActionsEnabled ? token : ConsistencyToken.getDefaultInstance(); - Consumer<Result<ConsistencyToken>> consumer = result -> { - assertThat(result.isSuccessful()).isTrue(); - assertThat(result.getValue()).isEqualTo(expectedToken); - }; - mFakeActionUploadRequestManager.setResult(Result.success(token)); - mFakeThreadUtils.enforceMainThread(false); - sessionManager.getConsistencyTokenConsumer().accept(Result.success(token)); - sessionManager.fetchActionsAndUpload(consumer); - assertThat(mFakeActionUploadRequestManager.getLatestActions()).isNotNull(); - } - - @Test - public void testStreamSharedStateInterner() { - Interner<StreamSharedState> interner = new StreamSharedStateInterner(); - StreamSharedState first = - StreamSharedState.newBuilder() - .setContentId("foo") - .setPietSharedStateItem(PietSharedStateItem.newBuilder().setPietSharedState( - PietSharedState.newBuilder().addTemplates( - Template.newBuilder().setTemplateId("equal")))) - .build(); - StreamSharedState second = - StreamSharedState.newBuilder() - .setContentId("baz") - .setPietSharedStateItem(PietSharedStateItem.newBuilder().setPietSharedState( - PietSharedState.newBuilder().addTemplates( - Template.newBuilder().setTemplateId("equal")))) - .build(); - StreamSharedState third = - StreamSharedState.newBuilder() - .setContentId("bar") - .setPietSharedStateItem(PietSharedStateItem.newBuilder().setPietSharedState( - PietSharedState.newBuilder().addTemplates( - Template.newBuilder().setTemplateId("different")))) - .build(); - assertThat(first).isNotSameInstanceAs(second); - assertThat(first.getPietSharedStateItem()).isEqualTo(second.getPietSharedStateItem()); - assertThat(first).isNotEqualTo(third); - assertThat(first.getPietSharedStateItem()).isNotEqualTo(third.getPietSharedStateItem()); - - // Pool is empty so first is added/returned. - StreamSharedState internedFirst = interner.intern(first); - assertThat(interner.size()).isEqualTo(1); - assertThat(internedFirst).isSameInstanceAs(first); - - // Pool already has an identical inner PietSharedStateItem proto, which is used. - StreamSharedState internedSecond = interner.intern(second); - assertThat(interner.size()).isEqualTo(1); - // The returned proto is equal to second, but its internal PietSharedStateItem is the same - // as the one in first (memoized). - assertThat(internedSecond).isNotSameInstanceAs(second); - assertThat(internedSecond).isEqualTo(second); - assertThat(internedSecond.getPietSharedStateItem()) - .isSameInstanceAs(first.getPietSharedStateItem()); - - // Third has a new PietSharedStateItem (not equal with any previous) so it is added to the - // pool. - StreamSharedState internedThird = interner.intern(third); - assertThat(interner.size()).isEqualTo(2); - assertThat(internedThird).isSameInstanceAs(third); - } - - @Test - public void testGetNewSession() { - FeedSessionManagerImpl sessionManager = getInitializedSessionManager(); - - UiContext uiContext = UiContext.newBuilder() - .setExtension(UiContextForTest.uiContextForTest, - UiContextForTest.newBuilder().setValue(3).build()) - .build(); - - ModelProvider modelProvider = getModelProvider(sessionManager, uiContext); - - sessionManager.getNewSession(modelProvider, /* viewDepthProvider= */ null, uiContext); - ModelProviderObserver modelProviderObserver = mock(ModelProviderObserver.class); - modelProvider.registerObserver(modelProviderObserver); - - verify(modelProviderObserver).onSessionStart(uiContext); - } - - @Test - @Features.EnableFeatures(ChromeFeatureList.INTEREST_FEEDV1_CLICKS_AND_VIEWS_CONDITIONAL_UPLOAD) - public void testLifecycleEventsWhenConditionalUploadFeatureEnabled() { - when(mPrefService.getBoolean(Pref.HAS_REACHED_CLICK_AND_VIEW_ACTIONS_UPLOAD_CONDITIONS)) - .thenReturn(false); - - FeedSessionManagerImpl sessionManager = createFeedSessionManager(mConfiguration); - - sessionManager.onLifecycleEvent(LifecycleEvent.ENTER_FOREGROUND); - sessionManager.onLifecycleEvent(LifecycleEvent.ENTER_BACKGROUND); - sessionManager.onLifecycleEvent(LifecycleEvent.SIGNED_IN); - sessionManager.onLifecycleEvent(LifecycleEvent.SIGNED_OUT); - - verify(mActionManager, times(4)).setCanUploadClicksAndViewsWhenNoticeCardIsPresent(false); - } - - @Test - @Features.DisableFeatures(ChromeFeatureList.INTEREST_FEEDV1_CLICKS_AND_VIEWS_CONDITIONAL_UPLOAD) - public void testLifecycleEventsWhenConditionalUploadFeatureDisabled() { - when(mPrefService.getBoolean(Pref.HAS_REACHED_CLICK_AND_VIEW_ACTIONS_UPLOAD_CONDITIONS)) - .thenReturn(false); - - FeedSessionManagerImpl sessionManager = createFeedSessionManager(mConfiguration); - - sessionManager.onLifecycleEvent(LifecycleEvent.ENTER_FOREGROUND); - sessionManager.onLifecycleEvent(LifecycleEvent.ENTER_BACKGROUND); - sessionManager.onLifecycleEvent(LifecycleEvent.SIGNED_IN); - sessionManager.onLifecycleEvent(LifecycleEvent.SIGNED_OUT); - - verify(mActionManager, times(4)).setCanUploadClicksAndViewsWhenNoticeCardIsPresent(true); - } - - private int populateSession(FeedSessionManagerImpl sessionManager, int featureCnt, int idStart, - boolean reset, - /*@Nullable*/ String sharedStateId) { - int operationCount = 0; - - InternalProtocolBuilder internalProtocolBuilder = new InternalProtocolBuilder(); - if (reset) { - internalProtocolBuilder.addClearOperation().addRootFeature(); - operationCount++; - } - for (int i = 0; i < featureCnt; i++) { - internalProtocolBuilder.addFeature( - mContentIdGenerators.createFeatureContentId(idStart++), - mIdGenerators.createRootContentId(0)); - operationCount++; - } - if (sharedStateId != null) { - internalProtocolBuilder.addSharedState(sharedStateId); - operationCount++; - } - Consumer<Result<Model>> updateConsumer = sessionManager.getUpdateConsumer(EMPTY_MUTATION); - updateConsumer.accept(Result.success(Model.of(internalProtocolBuilder.build()))); - return operationCount; - } - - private ModelProvider getModelProvider(FeedSessionManager sessionManager) { - return getModelProvider( - sessionManager, /* sessionId= */ null, UiContext.getDefaultInstance()); - } - - private ModelProvider getModelProvider(FeedSessionManager sessionManager, UiContext uiContext) { - return getModelProvider(sessionManager, /* sessionId= */ null, uiContext); - } - - private ModelProvider getModelProvider( - FeedSessionManager sessionManager, String sessionId, UiContext uiContext) { - ModelProviderFactory modelProviderFactory = new FeedModelProviderFactory(sessionManager, - mFakeThreadUtils, mTimingUtils, mFakeTaskQueue, mFakeMainThreadRunner, - mConfiguration, mFakeBasicLoggingApi); - if (sessionId == null) { - return modelProviderFactory.createNew(/* viewDepthProvider= */ null, uiContext); - } else { - return modelProviderFactory.create(sessionId, uiContext); - } - } - - private FeedSessionManagerImpl getInitializedSessionManager() { - return getInitializedSessionManager(mConfiguration); - } - - private FeedSessionManagerImpl getInitializedSessionManager(Configuration config) { - FeedSessionManagerImpl fsm = createFeedSessionManager(config); - fsm.initialize(); - return fsm; - } - - private FeedSessionManagerImpl getUninitializedSessionManager() { - return createFeedSessionManager(mConfiguration); - } - - private FeedSessionManagerImpl createFeedSessionManager(Configuration configuration) { - return new FeedSessionManagerFactory(mFakeTaskQueue, mFakeStore, mTimingUtils, - mFakeThreadUtils, mFakeProtocolAdapter, mFakeRequestManager, - mFakeActionUploadRequestManager, mSchedulerApi, configuration, mFakeClock, - mAppLifecycleListener, mFakeMainThreadRunner, mFakeBasicLoggingApi, mActionManager) - .create(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedsessionmanager/internal/ContentCacheTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedsessionmanager/internal/ContentCacheTest.java deleted file mode 100644 index 3542ae7..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedsessionmanager/internal/ContentCacheTest.java +++ /dev/null
@@ -1,93 +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. - -package org.chromium.chrome.browser.feed.library.feedsessionmanager.internal; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.internal.common.testing.ContentIdGenerators; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamPayload; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests of the {@link ContentCache} class. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ContentCacheTest { - private final ContentIdGenerators mIdGenerators = new ContentIdGenerators(); - - @Before - public void setUp() { - initMocks(this); - } - - @Test - public void testBasicCaching() { - ContentCache cache = new ContentCache(); - assertThat(cache.size()).isEqualTo(0); - - StreamPayload payload = StreamPayload.getDefaultInstance(); - String contentId = mIdGenerators.createFeatureContentId(1); - cache.put(contentId, payload); - assertThat(cache.size()).isEqualTo(1); - assertThat(cache.get(contentId)).isEqualTo(payload); - - String missingId = mIdGenerators.createFeatureContentId(2); - assertThat(cache.get(missingId)).isNull(); - } - - @Test - public void testLifecycle() { - ContentCache cache = new ContentCache(); - assertThat(cache.size()).isEqualTo(0); - - cache.startMutation(); - assertThat(cache.size()).isEqualTo(0); - - StreamPayload payload = StreamPayload.getDefaultInstance(); - String contentId = mIdGenerators.createFeatureContentId(1); - cache.put(contentId, payload); - assertThat(cache.size()).isEqualTo(1); - assertThat(cache.get(contentId)).isEqualTo(payload); - } - - @Test - public void testStartMutation_resetsCache() { - ContentCache cache = new ContentCache(); - cache.put(mIdGenerators.createFeatureContentId(1), StreamPayload.getDefaultInstance()); - - cache.startMutation(); - assertThat(cache.size()).isEqualTo(0); - } - - @Test - public void testFinishMutation_resetsCache() { - ContentCache cache = new ContentCache(); - - cache.startMutation(); - cache.put(mIdGenerators.createFeatureContentId(1), StreamPayload.getDefaultInstance()); - cache.finishMutation(); - assertThat(cache.size()).isEqualTo(0); - } - - @Test - public void testReset() { - ContentCache cache = new ContentCache(); - StreamPayload payload = StreamPayload.getDefaultInstance(); - int featureCount = 4; - for (int i = 0; i < featureCount; i++) { - String contentId = mIdGenerators.createFeatureContentId(i); - cache.put(contentId, payload); - } - assertThat(cache.size()).isEqualTo(featureCount); - cache.reset(); - assertThat(cache.size()).isEqualTo(0); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedsessionmanager/internal/HeadAsStructureTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedsessionmanager/internal/HeadAsStructureTest.java deleted file mode 100644 index a1525ab..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedsessionmanager/internal/HeadAsStructureTest.java +++ /dev/null
@@ -1,252 +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. - -package org.chromium.chrome.browser.feed.library.feedsessionmanager.internal; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.MockitoAnnotations.initMocks; - -import static org.chromium.chrome.browser.feed.library.api.internal.common.testing.ContentIdGenerators.ROOT_PREFIX; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration; -import org.chromium.chrome.browser.feed.library.api.internal.common.testing.ContentIdGenerators; -import org.chromium.chrome.browser.feed.library.api.internal.common.testing.InternalProtocolBuilder; -import org.chromium.chrome.browser.feed.library.api.internal.store.Store; -import org.chromium.chrome.browser.feed.library.common.Result; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeTaskQueue; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeThreadUtils; -import org.chromium.chrome.browser.feed.library.common.time.TimingUtils; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.feedsessionmanager.internal.HeadAsStructure.TreeNode; -import org.chromium.chrome.browser.feed.library.testing.store.FakeStore; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamFeature; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamPayload; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.List; - -/** Tests of the {@link HeadAsStructure}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class HeadAsStructureTest { - private final ContentIdGenerators mIdGenerators = new ContentIdGenerators(); - private final FakeThreadUtils mFakeThreadUtils = FakeThreadUtils.withThreadChecks(); - private final String mRootContentId = mIdGenerators.createRootContentId(0); - private final TimingUtils mTimingUtils = new TimingUtils(); - private final FakeClock mFakeClock = new FakeClock(); - - private FakeStore mFakeStore; - - @Before - public void setUp() { - initMocks(this); - mFakeStore = new FakeStore(Configuration.getDefaultInstance(), mFakeThreadUtils, - new FakeTaskQueue(mFakeClock, mFakeThreadUtils), mFakeClock); - mFakeThreadUtils.enforceMainThread(false); - } - - @Test - public void testUninitialized() { - HeadAsStructure headAsStructure = - new HeadAsStructure(mFakeStore, mTimingUtils, mFakeThreadUtils); - Result<List<Void>> result = headAsStructure.filter(payload -> null); - assertThat(result.isSuccessful()).isFalse(); - } - - @Test - public void testInitialization() { - InternalProtocolBuilder protocolBuilder = new InternalProtocolBuilder(); - protocolBuilder.addClearOperation().addRootFeature(); - for (int i = 0; i < 3; i++) { - String contentId = mIdGenerators.createFeatureContentId(i); - protocolBuilder.addFeature(contentId, mRootContentId); - } - mFakeStore - .setStreamStructures( - Store.HEAD_SESSION_ID, protocolBuilder.buildAsStreamStructure()) - .setContent(protocolBuilder.buildAsPayloadWithId()); - - HeadAsStructure headAsStructure = - new HeadAsStructure(mFakeStore, mTimingUtils, mFakeThreadUtils); - headAsStructure.initialize(result -> assertThat(result.isSuccessful()).isTrue()); - assertThat(headAsStructure.mRoot).isNotNull(); - assertThat(headAsStructure.mContent).hasSize(4); - assertThat(headAsStructure.mTree).hasSize(4); - TreeNode root = headAsStructure.mContent.get(mRootContentId); - assertThat(root).isNotNull(); - assertThat(headAsStructure.mRoot).isEqualTo(root); - List<TreeNode> rootChildren = headAsStructure.mTree.get(mRootContentId); - assertThat(rootChildren).isNotNull(); - assertThat(rootChildren).hasSize(3); - } - - @Test - public void testInitialization_withRemove() { - InternalProtocolBuilder protocolBuilder = new InternalProtocolBuilder(); - protocolBuilder.addClearOperation().addRootFeature(); - for (int i = 0; i < 3; i++) { - String contentId = mIdGenerators.createFeatureContentId(i); - protocolBuilder.addFeature(contentId, mRootContentId); - } - String contentId = mIdGenerators.createFeatureContentId(2); - protocolBuilder.removeFeature(contentId, mRootContentId); - mFakeStore - .setStreamStructures( - Store.HEAD_SESSION_ID, protocolBuilder.buildAsStreamStructure()) - .setContent(protocolBuilder.buildAsPayloadWithId()); - - HeadAsStructure headAsStructure = - new HeadAsStructure(mFakeStore, mTimingUtils, mFakeThreadUtils); - headAsStructure.initialize(result -> assertThat(result.isSuccessful()).isTrue()); - assertThat(headAsStructure.mRoot).isNotNull(); - assertThat(headAsStructure.mContent).hasSize(3); - assertThat(headAsStructure.mTree).hasSize(3); - List<TreeNode> rootChildren = headAsStructure.mTree.get(mRootContentId); - assertThat(rootChildren).isNotNull(); - assertThat(rootChildren).hasSize(2); - } - - @Test - public void testInitialization_doubleInitialization() { - InternalProtocolBuilder protocolBuilder = new InternalProtocolBuilder(); - protocolBuilder.addClearOperation().addRootFeature(); - for (int i = 0; i < 3; i++) { - String contentId = mIdGenerators.createFeatureContentId(i); - protocolBuilder.addFeature(contentId, mRootContentId); - } - mFakeStore - .setStreamStructures( - Store.HEAD_SESSION_ID, protocolBuilder.buildAsStreamStructure()) - .setContent(protocolBuilder.buildAsPayloadWithId()); - - HeadAsStructure headAsStructure = - new HeadAsStructure(mFakeStore, mTimingUtils, mFakeThreadUtils); - headAsStructure.initialize(result -> assertThat(result.isSuccessful()).isTrue()); - headAsStructure.initialize(result -> assertThat(result.isSuccessful()).isFalse()); - } - - @Test - public void testInitialization_buildTreeFailure() { - InternalProtocolBuilder protocolBuilder = new InternalProtocolBuilder(); - protocolBuilder.addClearOperation().addRootFeature(); - for (int i = 0; i < 3; i++) { - String contentId = mIdGenerators.createFeatureContentId(i); - protocolBuilder.addFeature(contentId, mRootContentId); - } - mFakeStore.setAllowGetStreamStructures(false).setContent( - protocolBuilder.buildAsPayloadWithId()); - - HeadAsStructure headAsStructure = - new HeadAsStructure(mFakeStore, mTimingUtils, mFakeThreadUtils); - headAsStructure.initialize(result -> assertThat(result.isSuccessful()).isFalse()); - } - - @Test - public void testInitialization_bindTreeFailure() { - InternalProtocolBuilder protocolBuilder = new InternalProtocolBuilder(); - protocolBuilder.addClearOperation().addRootFeature(); - for (int i = 0; i < 3; i++) { - String contentId = mIdGenerators.createFeatureContentId(i); - protocolBuilder.addFeature(contentId, mRootContentId); - } - mFakeStore - .setStreamStructures( - Store.HEAD_SESSION_ID, protocolBuilder.buildAsStreamStructure()) - .setAllowGetPayloads(false); - - HeadAsStructure headAsStructure = - new HeadAsStructure(mFakeStore, mTimingUtils, mFakeThreadUtils); - headAsStructure.initialize(result -> assertThat(result.isSuccessful()).isFalse()); - } - - @Test - public void testFiltering_payload() { - InternalProtocolBuilder protocolBuilder = new InternalProtocolBuilder(); - protocolBuilder.addClearOperation().addRootFeature(); - for (int i = 0; i < 3; i++) { - String contentId = mIdGenerators.createFeatureContentId(i); - protocolBuilder.addFeature(contentId, mRootContentId); - } - mFakeStore - .setStreamStructures( - Store.HEAD_SESSION_ID, protocolBuilder.buildAsStreamStructure()) - .setContent(protocolBuilder.buildAsPayloadWithId()); - - HeadAsStructure headAsStructure = - new HeadAsStructure(mFakeStore, mTimingUtils, mFakeThreadUtils); - headAsStructure.initialize(result -> assertThat(result.isSuccessful()).isTrue()); - Result<List<StreamFeature>> results = headAsStructure.filter(node -> { - StreamPayload payload = node.getStreamPayload(); - assertThat(payload).isNotNull(); - if (payload.hasStreamFeature()) { - return payload.getStreamFeature(); - } else { - return null; - } - }); - assertThat(results.isSuccessful()).isTrue(); - assertThat(results.getValue()).hasSize(4); - } - - @Test - public void testFiltering_childrenOfRoot() { - InternalProtocolBuilder protocolBuilder = new InternalProtocolBuilder(); - protocolBuilder.addClearOperation().addRootFeature(); - for (int i = 0; i < 3; i++) { - String contentId = mIdGenerators.createFeatureContentId(i); - protocolBuilder.addFeature(contentId, mRootContentId); - } - mFakeStore - .setStreamStructures( - Store.HEAD_SESSION_ID, protocolBuilder.buildAsStreamStructure()) - .setContent(protocolBuilder.buildAsPayloadWithId()); - - HeadAsStructure headAsStructure = - new HeadAsStructure(mFakeStore, mTimingUtils, mFakeThreadUtils); - headAsStructure.initialize(result -> assertThat(result.isSuccessful()).isTrue()); - Result<List<String>> results = headAsStructure.filter(node - -> !node.getStreamStructure().getContentId().startsWith(ROOT_PREFIX) - ? node.getStreamStructure().getContentId() - : null); - assertThat(results.isSuccessful()).isTrue(); - assertThat(results.getValue()).hasSize(3); - } - - @Test - public void testFiltering_withRemove() { - InternalProtocolBuilder protocolBuilder = new InternalProtocolBuilder(); - protocolBuilder.addClearOperation().addRootFeature(); - for (int i = 0; i < 3; i++) { - String contentId = mIdGenerators.createFeatureContentId(i); - protocolBuilder.addFeature(contentId, mRootContentId); - } - String contentId = mIdGenerators.createFeatureContentId(2); - protocolBuilder.removeFeature(contentId, mRootContentId); - mFakeStore - .setStreamStructures( - Store.HEAD_SESSION_ID, protocolBuilder.buildAsStreamStructure()) - .setContent(protocolBuilder.buildAsPayloadWithId()); - - HeadAsStructure headAsStructure = - new HeadAsStructure(mFakeStore, mTimingUtils, mFakeThreadUtils); - headAsStructure.initialize(result -> assertThat(result.isSuccessful()).isTrue()); - Result<List<StreamFeature>> results = headAsStructure.filter(node -> { - StreamPayload payload = node.getStreamPayload(); - assertThat(payload).isNotNull(); - if (payload.hasStreamFeature()) { - return payload.getStreamFeature(); - } else { - return null; - } - }); - assertThat(results.isSuccessful()).isTrue(); - assertThat(results.getValue()).hasSize(3); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedsessionmanager/internal/HeadSessionImplTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedsessionmanager/internal/HeadSessionImplTest.java deleted file mode 100644 index 406ac952..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedsessionmanager/internal/HeadSessionImplTest.java +++ /dev/null
@@ -1,333 +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. - -package org.chromium.chrome.browser.feed.library.feedsessionmanager.internal; - -import static com.google.common.truth.Truth.assertThat; - -import com.google.common.collect.ImmutableList; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.common.MutationContext; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration; -import org.chromium.chrome.browser.feed.library.api.internal.common.testing.ContentIdGenerators; -import org.chromium.chrome.browser.feed.library.api.internal.common.testing.InternalProtocolBuilder; -import org.chromium.chrome.browser.feed.library.api.internal.store.Store; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeTaskQueue; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeThreadUtils; -import org.chromium.chrome.browser.feed.library.common.time.TimingUtils; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.testing.store.FakeStore; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamStructure; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamToken; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.List; -import java.util.Set; - -/** Tests of the {@link HeadSessionImpl} class. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class HeadSessionImplTest { - private static final int SCHEMA_VERSION = 1; - - private final ContentIdGenerators mContentIdGenerators = new ContentIdGenerators(); - private final FakeClock mFakeClock = new FakeClock(); - private final FakeThreadUtils mFakeThreadUtils = FakeThreadUtils.withoutThreadChecks(); - private final TimingUtils mTimingUtils = new TimingUtils(); - private final FakeStore mFakeStore = new FakeStore(Configuration.getDefaultInstance(), - mFakeThreadUtils, new FakeTaskQueue(mFakeClock, mFakeThreadUtils), mFakeClock); - private final HeadSessionImpl mHeadSession = - new HeadSessionImpl(mFakeStore, mTimingUtils, /* limitPageUpdatesInHead= */ false); - - @Test - public void testMinimalSessionManager() { - assertThat(mHeadSession.getSessionId()).isEqualTo(Store.HEAD_SESSION_ID); - } - - @Test - public void testInvalidateOnResetHead() { - assertThat(mHeadSession.invalidateOnResetHead()).isFalse(); - } - - @Test - public void testUpdateSession_features() { - int featureCnt = 3; - InternalProtocolBuilder protocolBuilder = new InternalProtocolBuilder().addClearOperation(); - addFeatures(protocolBuilder, featureCnt, 1); - List<StreamStructure> streamStructures = protocolBuilder.buildAsStreamStructure(); - - // 1 clear, 3 features - assertThat(streamStructures).hasSize(featureCnt + 1); - mHeadSession.updateSession(false, streamStructures, SCHEMA_VERSION, null); - - // expect: 3 features - assertThat(mHeadSession.getContentInSession()).hasSize(featureCnt); - assertThat(mHeadSession.getContentInSession()) - .contains(mContentIdGenerators.createFeatureContentId(1)); - assertThat(getContentInSession()).hasSize(featureCnt); - } - - @Test - public void testReset() { - int featureCnt = 5; - InternalProtocolBuilder protocolBuilder = new InternalProtocolBuilder().addClearOperation(); - addFeatures(protocolBuilder, featureCnt, 1); - List<StreamStructure> streamStructures = protocolBuilder.buildAsStreamStructure(); - assertThat(streamStructures).hasSize(featureCnt + 1); - mHeadSession.updateSession(false, streamStructures, SCHEMA_VERSION, null); - assertThat(mHeadSession.getContentInSession()).hasSize(featureCnt); - - mHeadSession.reset(); - assertThat(mHeadSession.getContentInSession()).isEmpty(); - } - - @Test - public void testUpdateSession_token() { - int featureCnt = 3; - InternalProtocolBuilder protocolBuilder = new InternalProtocolBuilder().addClearOperation(); - addFeatures(protocolBuilder, featureCnt, 1); - protocolBuilder.addToken(mContentIdGenerators.createTokenContentId(1)); - List<StreamStructure> streamStructures = protocolBuilder.buildAsStreamStructure(); - - // 1 clear, 3 features, token - assertThat(streamStructures).hasSize(5); - mHeadSession.updateSession(false, streamStructures, SCHEMA_VERSION, null); - - // expect: 3 features, 1 token - assertThat(mHeadSession.getContentInSession()).hasSize(featureCnt + 1); - assertThat(mHeadSession.getContentInSession()) - .contains(mContentIdGenerators.createFeatureContentId(1)); - assertThat(getContentInSession()).hasSize(featureCnt + 1); - } - - @Test - public void testUpdateFromToken() { - int featureCnt = 3; - InternalProtocolBuilder protocolBuilder = new InternalProtocolBuilder(); - addFeatures(protocolBuilder, featureCnt, 1); - List<StreamStructure> streamStructures = protocolBuilder.buildAsStreamStructure(); - - StreamToken token = StreamToken.newBuilder() - .setContentId(mContentIdGenerators.createTokenContentId(2)) - .build(); - - // The token needs to be in the session so update its content IDs with the token. - List<StreamStructure> tokenStructures = new InternalProtocolBuilder() - .addToken(token.getContentId()) - .buildAsStreamStructure(); - mHeadSession.updateSession(false, tokenStructures, SCHEMA_VERSION, null); - - MutationContext context = new MutationContext.Builder().setContinuationToken(token).build(); - mHeadSession.updateSession(false, streamStructures, SCHEMA_VERSION, context); - // features 3, plus the token added above - assertThat(mHeadSession.getContentInSession()).hasSize(featureCnt + 1); - } - - @Test - public void testUpdateFromToken_limitPageUpdatesInHead() { - HeadSessionImpl headSession = - new HeadSessionImpl(mFakeStore, mTimingUtils, /* limitPageUpdatesInHead= */ true); - - int featureCnt = 3; - InternalProtocolBuilder protocolBuilder = new InternalProtocolBuilder(); - addFeatures(protocolBuilder, featureCnt, 1); - List<StreamStructure> streamStructures = protocolBuilder.buildAsStreamStructure(); - - StreamToken token = StreamToken.newBuilder() - .setContentId(mContentIdGenerators.createTokenContentId(2)) - .build(); - - // The token needs to be in the session so update its content IDs with the token. - List<StreamStructure> tokenStructures = new InternalProtocolBuilder() - .addToken(token.getContentId()) - .buildAsStreamStructure(); - headSession.updateSession(false, tokenStructures, SCHEMA_VERSION, null); - - MutationContext context = new MutationContext.Builder().setContinuationToken(token).build(); - headSession.updateSession(false, streamStructures, SCHEMA_VERSION, context); - assertThat(headSession.getContentInSession()).hasSize(1); - } - - @Test - public void testUpdateFromToken_notInSession() { - int featureCnt = 3; - InternalProtocolBuilder protocolBuilder = new InternalProtocolBuilder(); - addFeatures(protocolBuilder, featureCnt, 1); - List<StreamStructure> streamStructures = protocolBuilder.buildAsStreamStructure(); - - StreamToken token = StreamToken.newBuilder() - .setContentId(mContentIdGenerators.createTokenContentId(2)) - .build(); - - // The token needs to be in the session, if not we ignore the update - MutationContext context = new MutationContext.Builder().setContinuationToken(token).build(); - mHeadSession.updateSession(false, streamStructures, SCHEMA_VERSION, context); - assertThat(mHeadSession.getContentInSession()).isEmpty(); - } - - @Test - public void testUpdateSession_remove() { - int featureCnt = 3; - InternalProtocolBuilder protocolBuilder = new InternalProtocolBuilder().addClearOperation(); - addFeatures(protocolBuilder, featureCnt, 1); - protocolBuilder.removeFeature(mContentIdGenerators.createFeatureContentId(1), - mContentIdGenerators.createRootContentId(0)); - List<StreamStructure> streamStructures = protocolBuilder.buildAsStreamStructure(); - - // 1 clear, 3 features, 1 remove - assertThat(streamStructures).hasSize(5); - mHeadSession.updateSession(false, streamStructures, SCHEMA_VERSION, null); - - // expect: 2 features (3 added, then 1 removed) - assertThat(mHeadSession.getContentInSession()).hasSize(featureCnt - 1); - assertThat(mHeadSession.getContentInSession()) - .contains(mContentIdGenerators.createFeatureContentId(2)); - assertThat(mHeadSession.getContentInSession()) - .contains(mContentIdGenerators.createFeatureContentId(3)); - assertThat(getContentInSession()).hasSize(featureCnt - 1); - } - - @Test - public void testUpdateSession_updates() { - int featureCnt = 3; - InternalProtocolBuilder protocolBuilder = new InternalProtocolBuilder().addClearOperation(); - addFeatures(protocolBuilder, featureCnt, 1); - List<StreamStructure> streamStructures = protocolBuilder.buildAsStreamStructure(); - assertThat(streamStructures).hasSize(4); - - // 1 clear, 3 features - mHeadSession.updateSession(false, streamStructures, SCHEMA_VERSION, null); - assertThat(mHeadSession.getContentInSession()).hasSize(featureCnt); - assertThat(getContentInSession()).hasSize(featureCnt); - - // Now we will update feature 2 - protocolBuilder = new InternalProtocolBuilder(); - addFeatures(protocolBuilder, 1, 2); - streamStructures = protocolBuilder.buildAsStreamStructure(); - assertThat(streamStructures).hasSize(1); - - // 0 features - mHeadSession.updateSession(false, streamStructures, SCHEMA_VERSION, null); - assertThat(mHeadSession.getContentInSession()).hasSize(featureCnt); - assertThat(getContentInSession()).hasSize(featureCnt); - } - - @Test - public void testUpdateSession_paging() { - int featureCnt = 3; - InternalProtocolBuilder protocolBuilder = new InternalProtocolBuilder().addClearOperation(); - addFeatures(protocolBuilder, featureCnt, 1); - List<StreamStructure> streamStructures = protocolBuilder.buildAsStreamStructure(); - assertThat(streamStructures).hasSize(4); - - // 1 clear, 3 features - mHeadSession.updateSession(false, streamStructures, SCHEMA_VERSION, null); - assertThat(mHeadSession.getContentInSession()).hasSize(featureCnt); - assertThat(getContentInSession()).hasSize(featureCnt); - - // Now we add two new features - int additionalFeatureCnt = 2; - protocolBuilder = new InternalProtocolBuilder(); - addFeatures(protocolBuilder, additionalFeatureCnt, featureCnt + 1); - streamStructures = protocolBuilder.buildAsStreamStructure(); - assertThat(streamStructures).hasSize(additionalFeatureCnt); - - // 0 features - mHeadSession.updateSession(false, streamStructures, SCHEMA_VERSION, null); - assertThat(mHeadSession.getContentInSession()).hasSize(featureCnt + additionalFeatureCnt); - assertThat(getContentInSession()).hasSize(featureCnt + additionalFeatureCnt); - } - - @Test - public void testUpdateSession_storeClearHead() { - mHeadSession.initializeSession(ImmutableList.of(), SCHEMA_VERSION); - - int featureCnt = 3; - InternalProtocolBuilder protocolBuilder = new InternalProtocolBuilder().addClearOperation(); - addFeatures(protocolBuilder, featureCnt, 1); - List<StreamStructure> streamStructures = protocolBuilder.buildAsStreamStructure(); - assertThat(streamStructures).hasSize(4); - - // 1 clear, 3 features - mHeadSession.updateSession(false, streamStructures, SCHEMA_VERSION + 1, null); - assertThat(mHeadSession.getContentInSession()).hasSize(featureCnt); - assertThat(getContentInSession()).hasSize(featureCnt); - assertThat(mHeadSession.getSchemaVersion()).isEqualTo(SCHEMA_VERSION); - - // Clear head and add 2 features, make sure we have new content ids - int newFeatureCnt = 2; - protocolBuilder = new InternalProtocolBuilder().addClearOperation(); - addFeatures(protocolBuilder, newFeatureCnt, featureCnt + 1); - streamStructures = protocolBuilder.buildAsStreamStructure(); - - // 2 features, 1 clear - assertThat(streamStructures).hasSize(3); - - // 0 features - mFakeStore.clearHead(); - mHeadSession.updateSession(false, streamStructures, SCHEMA_VERSION + 1, null); - assertThat(mHeadSession.getContentInSession()).hasSize(newFeatureCnt); - assertThat(getContentInSession()).hasSize(newFeatureCnt); - assertThat(mHeadSession.getSchemaVersion()).isEqualTo(SCHEMA_VERSION); - } - - @Test - public void testUpdateSession_clearHeadUpdatesSchemaVersion() { - mHeadSession.initializeSession(ImmutableList.of(), SCHEMA_VERSION); - mHeadSession.updateSession( - /* clearHead= */ true, ImmutableList.of(), SCHEMA_VERSION + 1, - /* mutationContext= */ null); - assertThat(mHeadSession.getSchemaVersion()).isEqualTo(SCHEMA_VERSION + 1); - } - - @Test - public void testUpdateSession_schemaVersionUnchanged() { - mHeadSession.initializeSession(ImmutableList.of(), SCHEMA_VERSION); - mHeadSession.updateSession( - /* clearHead= */ false, ImmutableList.of(), SCHEMA_VERSION + 1, - /* mutationContext= */ null); - assertThat(mHeadSession.getSchemaVersion()).isEqualTo(SCHEMA_VERSION); - } - - @Test - public void testUpdateSession_requiredContent() { - String contentId = mContentIdGenerators.createFeatureContentId(1); - InternalProtocolBuilder protocolBuilder = - new InternalProtocolBuilder().addRequiredContent(contentId); - - mHeadSession.updateSession( - /* clearHead= */ false, protocolBuilder.buildAsStreamStructure(), SCHEMA_VERSION, - /* mutationContext= */ null); - assertThat(mHeadSession.getContentInSession()).hasSize(1); - assertThat(getContentInSession()).hasSize(1); - } - - @Test - public void testInitializeSession_schemaVersion() { - int schemaVersion = 3; - mHeadSession.initializeSession(ImmutableList.of(), schemaVersion); - assertThat(mHeadSession.getSchemaVersion()).isEqualTo(schemaVersion); - } - - private void addFeatures(InternalProtocolBuilder protocolBuilder, int featureCnt, int startId) { - for (int i = 0; i < featureCnt; i++) { - protocolBuilder.addFeature(mContentIdGenerators.createFeatureContentId(startId++), - mContentIdGenerators.createRootContentId(0)); - } - } - - /** Re-read the session from disk and return the set of content. */ - private Set<String> getContentInSession() { - HeadSessionImpl headSession = - new HeadSessionImpl(mFakeStore, mTimingUtils, /* limitPageUpdatesInHead= */ false); - headSession.initializeSession( - mFakeStore.getStreamStructures(Store.HEAD_SESSION_ID).getValue(), - /* schemaVersion= */ 0); - return headSession.getContentInSession(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedsessionmanager/internal/SessionCacheTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedsessionmanager/internal/SessionCacheTest.java deleted file mode 100644 index 50a6ee19..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedsessionmanager/internal/SessionCacheTest.java +++ /dev/null
@@ -1,556 +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. - -package org.chromium.chrome.browser.feed.library.feedsessionmanager.internal; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration; -import org.chromium.chrome.browser.feed.library.api.internal.common.PayloadWithId; -import org.chromium.chrome.browser.feed.library.api.internal.common.testing.ContentIdGenerators; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider.ViewDepthProvider; -import org.chromium.chrome.browser.feed.library.api.internal.store.Store; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeDirectExecutor; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeTaskQueue; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeThreadUtils; -import org.chromium.chrome.browser.feed.library.common.time.TimingUtils; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.testing.modelprovider.FakeModelProvider; -import org.chromium.chrome.browser.feed.library.testing.store.FakeStore; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.SessionMetadata; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamFeature; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamPayload; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamSession; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamSessions; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamSharedState; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamStructure; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamStructure.Operation; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.UiContext; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.ArrayList; -import java.util.List; - -/** Tests of the {@link SessionCache} class. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class SessionCacheTest { - private static final long DEFAULT_LIFETIME_MS = 10; - private static final int SCHEMA_VERSION = 4; - - private final Configuration mConfiguration = new Configuration.Builder().build(); - private final ContentIdGenerators mIdGenerators = new ContentIdGenerators(); - private final FakeClock mFakeClock = new FakeClock(); - private final FakeThreadUtils mFakeThreadUtils = FakeThreadUtils.withThreadChecks(); - private final TimingUtils mTimingUtils = new TimingUtils(); - - private FakeStore mFakeStore; - private FakeTaskQueue mFakeTaskQueue; - private SessionFactory mSessionFactory; - private SessionCache mSessionCache; - - protected final FakeModelProvider mFakeModelProvider = new FakeModelProvider(); - - @Before - public void setUp() { - initMocks(this); - mFakeTaskQueue = new FakeTaskQueue(mFakeClock, mFakeThreadUtils); - mFakeStore = new FakeStore(mConfiguration, mFakeThreadUtils, mFakeTaskQueue, mFakeClock); - mFakeThreadUtils.enforceMainThread(false); - mFakeTaskQueue.initialize(() -> {}); - mSessionCache = getSessionCache(); - } - - @Test - public void testInitialization() { - int schemaVersion = 3; - populateHead(); - mockStreamSessions( - StreamSessions.newBuilder() - .addStreamSession( - StreamSession.newBuilder() - .setSessionId(Store.HEAD_SESSION_ID) - .setSessionMetadata( - SessionMetadata.newBuilder().setSchemaVersion( - schemaVersion))) - .build()); - assertThat(mSessionCache.getAttachedSessions()).isEmpty(); - assertThat(mSessionCache.isHeadInitialized()).isFalse(); - assertThat(mSessionCache.getHead()).isNotNull(); - assertThat(mSessionCache.getHead().isHeadEmpty()).isTrue(); - mSessionCache.initialize(); - - // Initialization adds $HEAD - assertThat(mSessionCache.isHeadInitialized()).isTrue(); - assertThat(mSessionCache.getAttachedSessions()).isEmpty(); - assertThat(mSessionCache.getHead()).isNotNull(); - assertThat(mSessionCache.getHead().isHeadEmpty()).isFalse(); - assertThat(mSessionCache.getHead().getSchemaVersion()).isEqualTo(schemaVersion); - } - - @Test - public void testInitialization_accessibleContentShouldBeDeterminedAtGcTime() { - FakeDirectExecutor fakeDirectExecutor = FakeDirectExecutor.queueAllTasks(mFakeThreadUtils); - mFakeTaskQueue = new FakeTaskQueue(mFakeClock, fakeDirectExecutor); - mFakeStore = new FakeStore(mConfiguration, mFakeThreadUtils, mFakeTaskQueue, mFakeClock); - mFakeThreadUtils.enforceMainThread(false); - mFakeTaskQueue.initialize(() -> {}); - mSessionCache = getSessionCache(); - - Session session = populateSession(1, 2, /* commitToStore= */ true); - mSessionCache.initialize(); - setSessions(session); - fakeDirectExecutor.runAllTasks(); // Run GC. - - assertThat(fakeDirectExecutor.hasTasks()).isFalse(); - assertPayloads(/* featureCnt= */ 2); - } - - @Test - public void testInitialization_contentGcShouldKeepSharedStates() { - mFakeStore.setContent("foo", - StreamPayload.newBuilder() - .setStreamSharedState( - StreamSharedState.newBuilder().setContentId("foo").build()) - .build()); - mockStreamSessions( - StreamSessions.newBuilder() - .addStreamSession( - StreamSession.newBuilder() - .setSessionId(Store.HEAD_SESSION_ID) - .setSessionMetadata( - // clang-format off - SessionMetadata.newBuilder().setSchemaVersion( - SessionCache.MIN_SCHEMA_VERSION_FOR_PIET_SHARED_STATE_REQUIRED_CONTENT - 1) - // clang-format on - )) - .build()); - - assertThat(mFakeStore.getSharedStates().getValue()).hasSize(1); - mSessionCache.initialize(); - assertThat(mFakeStore.getSharedStates().getValue()).hasSize(1); - } - - @Test - public void testInitialization_contentGcShouldDiscardSharedStates() { - mFakeStore.setContent("foo", - StreamPayload.newBuilder() - .setStreamSharedState( - StreamSharedState.newBuilder().setContentId("foo").build()) - .build()); - mockStreamSessions( - StreamSessions.newBuilder() - .addStreamSession( - StreamSession.newBuilder() - .setSessionId(Store.HEAD_SESSION_ID) - .setSessionMetadata( - // clang-format off - SessionMetadata.newBuilder().setSchemaVersion( - SessionCache.MIN_SCHEMA_VERSION_FOR_PIET_SHARED_STATE_REQUIRED_CONTENT) - // clang-format on - )) - .build()); - - assertThat(mFakeStore.getSharedStates().getValue()).hasSize(1); - mSessionCache.initialize(); - assertThat(mFakeStore.getSharedStates().getValue()).isEmpty(); - } - - @Test - public void testPutGet() { - mSessionCache.initialize(); - Session session = populateSession(1, 2); - mSessionCache.putAttachedAndRetainMetadata(session.getSessionId(), session); - - Session ret = mSessionCache.getAttached(session.getSessionId()); - assertThat(ret).isEqualTo(session); - } - - @Test - public void testPut_persisted() { - mSessionCache.initialize(); - Session session = populateSession(1, 2); - mSessionCache.putAttached( - session.getSessionId(), /* creationTimeMillis= */ 0L, SCHEMA_VERSION, session); - - Session ret = mSessionCache.getAttached(session.getSessionId()); - assertThat(ret).isEqualTo(session); - - session = populateSession(2, 2); - mSessionCache.putAttached( - session.getSessionId(), /* creationTimeMillis= */ 0L, SCHEMA_VERSION, session); - - List<StreamSession> streamSessionList = mSessionCache.getPersistedSessions(); - assertThat(streamSessionList).hasSize(3); - } - - @Test - public void testRemove() { - mSessionCache.initialize(); - Session session = populateSession(1, 2); - mSessionCache.putAttached( - session.getSessionId(), /* creationTimeMillis= */ 0L, SCHEMA_VERSION, session); - - List<StreamSession> streamSessionList = mSessionCache.getPersistedSessions(); - assertThat(streamSessionList).hasSize(2); - - String id = session.getSessionId(); - mSessionCache.removeAttached(id); - assertThat(mSessionCache.getAttached(id)).isNull(); - - streamSessionList = mSessionCache.getPersistedSessions(); - assertThat(streamSessionList).hasSize(1); - } - - @Test - public void testDetach() { - mSessionCache.initialize(); - Session s1 = populateSession(1, 2); - String s1Id = s1.getSessionId(); - mSessionCache.putAttachedAndRetainMetadata(s1Id, s1); - - List<Session> sessions = mSessionCache.getAttachedSessions(); - assertThat(sessions).hasSize(1); - assertThat(sessions).contains(s1); - assertThat(s1.getModelProvider()).isNotNull(); - - mSessionCache.detachModelProvider(s1Id); - assertThat(mSessionCache.getAttachedSessions()).isEmpty(); - assertThat(s1.getModelProvider()).isNull(); - } - - @Test - public void testGetAttachedSessions() { - mSessionCache.initialize(); - Session s1 = populateSession(1, 2); - mSessionCache.putAttachedAndRetainMetadata(s1.getSessionId(), s1); - Session s2 = populateSession(2, 2); - mSessionCache.putAttachedAndRetainMetadata(s2.getSessionId(), s2); - - List<Session> sessions = mSessionCache.getAttachedSessions(); - assertThat(sessions).hasSize(2); - assertThat(sessions).contains(mSessionCache.getAttached(s1.getSessionId())); - assertThat(sessions).contains(mSessionCache.getAttached(s2.getSessionId())); - } - - @Test - public void testGetAllSessions() { - mSessionCache.initialize(); - Session headSession = mSessionCache.getHead(); - - Session s1 = populateSession(1, 2, /* commitToStore= */ true); - String s1Id = s1.getSessionId(); - mSessionCache.putAttached(s1Id, 1L, SCHEMA_VERSION, s1); - - assertThat(mSessionCache.getAttachedSessions()).containsExactly(s1); - assertThat(mSessionCache.getAllSessions()).containsExactly(s1, headSession); - - Session s2 = populateSession(2, 2, /* commitToStore= */ true); - String s2Id = s2.getSessionId(); - mSessionCache.putAttached(s2Id, 2L, SCHEMA_VERSION, s2); - - assertThat(mSessionCache.getAttachedSessions()).containsExactly(s1, s2); - assertThat(mSessionCache.getAllSessions()).containsExactly(s1, s2, headSession); - - // Detach the session, which will throw it away from SessionCache. - mSessionCache.detachModelProvider(s1Id); - assertThat(mSessionCache.getAttachedSessions()).containsExactly(s2); - - List<Session> allSessions = new ArrayList<>(mSessionCache.getAllSessions()); - assertThat(allSessions).hasSize(3); - assertThat(allSessions).containsAtLeast(s2, headSession); - allSessions.remove(s2); - allSessions.remove(headSession); - - // A new unbound session was created for the detached one, with the same ID. - Session unboundSession = allSessions.get(0); - assertThat(unboundSession.getSessionId()).isEqualTo(s1.getSessionId()); - assertThat(unboundSession.getContentInSession()).isEqualTo(s1.getContentInSession()); - assertThat(unboundSession).isNotSameInstanceAs(s1); - } - - @Test - public void testReset_headOnly() { - mSessionCache.initialize(); - assertThat(mSessionCache.getAttachedSessions()).isEmpty(); - - mSessionCache.reset(); - assertThat(mSessionCache.getAttachedSessions()).isEmpty(); - } - - @Test - public void testReset_sessions() { - mSessionCache.initialize(); - int sessionCount = 2; - for (int i = 0; i < sessionCount; i++) { - Session session = populateSession(i, 2); - mSessionCache.putAttachedAndRetainMetadata(session.getSessionId(), session); - } - List<Session> sessions = mSessionCache.getAttachedSessions(); - assertThat(sessions).hasSize(sessionCount); - - mSessionCache.reset(); - assertThat(mSessionCache.getAttachedSessions()).isEmpty(); - } - - @Test - public void testIsSessionAlive() { - mSessionCache.initialize(); - mFakeClock.set(DEFAULT_LIFETIME_MS + 2); - assertThat(mSessionCache.isSessionAlive("stream:1", SessionMetadata.getDefaultInstance())) - .isFalse(); - assertThat(mSessionCache.isSessionAlive( - Store.HEAD_SESSION_ID, SessionMetadata.getDefaultInstance())) - .isTrue(); - assertThat(mSessionCache.isSessionAlive("stream:2", - SessionMetadata.newBuilder() - .setCreationTimeMillis(DEFAULT_LIFETIME_MS - 1) - .build())) - .isTrue(); - } - - @Test - public void testGetPersistedSessions() { - StreamSession streamSession = StreamSession.getDefaultInstance(); - mockStreamSessions(StreamSessions.newBuilder().addStreamSession(streamSession).build()); - - List<StreamSession> sessionList = mSessionCache.getPersistedSessions(); - assertThat(sessionList).containsExactly(streamSession); - } - - @Test - public void testCleanupJournals() { - String sessionId1 = "stream:1"; - String sessionId2 = "stream:2"; - mFakeStore.setStreamStructures(sessionId1, StreamStructure.getDefaultInstance()) - .setStreamStructures(sessionId2, StreamStructure.getDefaultInstance()); - - Session s2 = mock(Session.class); - when(s2.getSessionId()).thenReturn(sessionId2); - setSessions(s2); - mSessionCache.cleanupSessionJournals(); - assertThat(mFakeStore.getAllSessions().getValue()).containsExactly(sessionId2); - assertThat(mSessionCache.getAttached(sessionId2)).isEqualTo(s2); - } - - @Test - public void testInitializePersistedSessions_emptyStreamSessions() { - mFakeClock.set(DEFAULT_LIFETIME_MS + 2); - - mockStreamSessions(StreamSessions.getDefaultInstance()); - mSessionCache.initialize(); - - assertThat(mSessionCache.getAttachedSessions()).isEmpty(); - } - - @Test - public void testInitializePersistedSessions_legacyStreamSession() { - StreamSessions streamSessions = - StreamSessions.newBuilder() - .addStreamSession(StreamSession.newBuilder() - .setSessionId("stream:1") - .setLegacyTimeMillis(0)) - .addStreamSession(StreamSession.newBuilder() - .setSessionId("stream:2") - .setLegacyTimeMillis(DEFAULT_LIFETIME_MS - 1)) - .addStreamSession(StreamSession.newBuilder() - .setSessionId(Store.HEAD_SESSION_ID) - .setLegacyTimeMillis(1)) - .build(); - - mFakeClock.set(DEFAULT_LIFETIME_MS + 2); - - mockStreamSessions(streamSessions); - mSessionCache.initialize(); - - assertThat(mSessionCache.hasSession("stream:1")).isFalse(); - assertThat(mSessionCache.hasSession("stream:2")).isTrue(); - assertThat(mSessionCache.getCreationTimeMillis("stream:2")) - .isEqualTo(DEFAULT_LIFETIME_MS - 1); - assertThat(mSessionCache.getHeadLastAddedTimeMillis()).isEqualTo(1); - } - - @Test - public void testInitializePersistedSessions_sessionMetadata() { - StreamSessions streamSessions = - StreamSessions.newBuilder() - .addStreamSession( - StreamSession.newBuilder() - .setSessionId("stream:1") - .setSessionMetadata(SessionMetadata.getDefaultInstance())) - .addStreamSession( - StreamSession.newBuilder() - .setSessionId("stream:2") - .setSessionMetadata( - SessionMetadata.newBuilder().setCreationTimeMillis( - DEFAULT_LIFETIME_MS - 1))) - .build(); - - mFakeClock.set(DEFAULT_LIFETIME_MS + 2); - - mockStreamSessions(streamSessions); - mSessionCache.initialize(); - - assertThat(mSessionCache.hasSession("stream:1")).isFalse(); - assertThat(mSessionCache.hasSession("stream:2")).isTrue(); - assertThat(mSessionCache.getCreationTimeMillis("stream:2")) - .isEqualTo(DEFAULT_LIFETIME_MS - 1); - } - - @Test - public void testUpdateHeadMetadata() { - long currentTime = 2L; - int schemaVersion = 3; - StreamSessions streamSessions = - StreamSessions.newBuilder() - .addStreamSession(StreamSession.newBuilder() - .setSessionId(Store.HEAD_SESSION_ID) - .setLegacyTimeMillis(1)) - .build(); - - mockStreamSessions(streamSessions); - mSessionCache.initialize(); - mSessionCache.updateHeadMetadata(currentTime, schemaVersion); - - List<Object> content = mFakeStore.getContentById(SessionCache.STREAM_SESSION_CONTENT_ID); - assertThat(content).hasSize(1); - assertThat(((PayloadWithId) content.get(0)).payload) - .isEqualTo( - StreamPayload.newBuilder() - .setStreamSessions(StreamSessions.newBuilder().addStreamSession( - StreamSession.newBuilder() - .setSessionId(Store.HEAD_SESSION_ID) - .setSessionMetadata( - SessionMetadata.newBuilder() - .setLastAddedTimeMillis(currentTime) - .setSchemaVersion(schemaVersion)))) - .build()); - } - - @Test - public void testUpdatePersistedSessions() { - mSessionCache.initialize(); - - // persist HEAD into the store - mSessionCache.updatePersistedSessionsMetadata(); - List<StreamSession> streamSessionList = mSessionCache.getPersistedSessions(); - assertThat(streamSessionList).hasSize(1); - - // add additional sessions - StreamSession session1 = - StreamSession.newBuilder() - .setSessionId("stream:1") - .setSessionMetadata(SessionMetadata.newBuilder() - .setCreationTimeMillis(0L) - .setSchemaVersion(SCHEMA_VERSION)) - .build(); - StreamSession session2 = - StreamSession.newBuilder() - .setSessionId("stream:2") - .setSessionMetadata(SessionMetadata.newBuilder() - .setCreationTimeMillis(0L) - .setSchemaVersion(SCHEMA_VERSION)) - .build(); - Session s1 = mock(Session.class); - when(s1.getSessionId()).thenReturn(session1.getSessionId()); - Session s2 = mock(Session.class); - when(s2.getSessionId()).thenReturn(session2.getSessionId()); - setSessions(s1, s2); - - mSessionCache.updatePersistedSessionsMetadata(); - streamSessionList = mSessionCache.getPersistedSessions(); - assertThat(streamSessionList).hasSize(3); - assertThat(streamSessionList).contains(session1); - assertThat(streamSessionList).contains(session2); - } - - @Test - public void testErrors_persistedSession() { - mSessionCache.initialize(); - mSessionCache.updatePersistedSessionsMetadata(); - - mFakeStore.setAllowGetPayloads(false); - assertThat(mSessionCache.getPersistedSessions()).isEmpty(); - } - - private SessionCache getSessionCache() { - mSessionFactory = new SessionFactory( - mFakeStore, mFakeTaskQueue, mTimingUtils, mFakeThreadUtils, mConfiguration); - return new SessionCache(mFakeStore, mFakeTaskQueue, mSessionFactory, 10, mTimingUtils, - mFakeThreadUtils, mFakeClock); - } - - private void mockStreamSessions(StreamSessions streamSessions) { - mFakeStore.setContent(SessionCache.STREAM_SESSION_CONTENT_ID, - StreamPayload.newBuilder().setStreamSessions(streamSessions).build()); - } - - private Session populateSession(int id, int featureCnt) { - return populateSession(id, featureCnt, /* commitToStore= */ false); - } - - private Session populateSession(int id, int featureCnt, boolean commitToStore) { - InitializableSession session = mSessionFactory.getSession(); - String rootId = mIdGenerators.createRootContentId(1); - List<StreamStructure> head = new ArrayList<>(); - head.add(StreamStructure.newBuilder() - .setOperation(Operation.UPDATE_OR_APPEND) - .setContentId(rootId) - .build()); - for (int i = 0; i < featureCnt; i++) { - String contentId = mIdGenerators.createFeatureContentId(i); - head.add(StreamStructure.newBuilder() - .setOperation(Operation.UPDATE_OR_APPEND) - .setContentId(contentId) - .setParentContentId(rootId) - .build()); - if (commitToStore) { - mFakeStore.setContent(contentId, - StreamPayload.newBuilder() - .setStreamFeature(StreamFeature.getDefaultInstance()) - .build()); - } - } - session.setSessionId("stream:" + id); - session.bindModelProvider(mFakeModelProvider, mock(ViewDepthProvider.class)); - session.populateModelProvider(head, true, false, UiContext.getDefaultInstance()); - - if (commitToStore) { - mFakeStore.setStreamStructures(session.getSessionId(), head); - } - - return session; - } - - private void populateHead() { - mFakeStore.setStreamStructures(Store.HEAD_SESSION_ID, - StreamStructure.newBuilder() - .setOperation(Operation.UPDATE_OR_APPEND) - .setContentId(mIdGenerators.createRootContentId(1)) - .build()); - } - - private void setSessions(Session... testSessions) { - for (Session session : testSessions) { - mSessionCache.putAttached( - session.getSessionId(), /* creationTimeMillis= */ 0L, SCHEMA_VERSION, session); - } - } - - private void assertPayloads(int featureCnt) { - for (int i = 0; i < featureCnt; i++) { - String contentId = mIdGenerators.createFeatureContentId(i); - assertThat(mFakeStore.getContentById(contentId)).hasSize(1); - } - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedsessionmanager/internal/SessionContentTrackerTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedsessionmanager/internal/SessionContentTrackerTest.java deleted file mode 100644 index fff6bda..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedsessionmanager/internal/SessionContentTrackerTest.java +++ /dev/null
@@ -1,122 +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. - -package org.chromium.chrome.browser.feed.library.feedsessionmanager.internal; - -import static com.google.common.truth.Truth.assertThat; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.internal.common.testing.ContentIdGenerators; -import org.chromium.chrome.browser.feed.library.api.internal.common.testing.InternalProtocolBuilder; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamStructure; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.List; - -/** Tests of the {@link SessionContentTracker} class. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class SessionContentTrackerTest { - private final ContentIdGenerators mContentIdGenerators = new ContentIdGenerators(); - - private InternalProtocolBuilder mProtocolBuilder; - private SessionContentTracker mSessionContentTracker; - - @Before - public void setUp() { - mProtocolBuilder = new InternalProtocolBuilder(); - mSessionContentTracker = new SessionContentTracker(/* supportsClearAll= */ true); - } - - @Test - public void testUpdate_features() { - int featureCnt = 3; - addFeatures(featureCnt); - List<StreamStructure> streamStructures = mProtocolBuilder.buildAsStreamStructure(); - - // 3 features. - assertThat(streamStructures).hasSize(3); - mSessionContentTracker.update(streamStructures); - assertThat(mSessionContentTracker.getContentIds()).hasSize(featureCnt); - assertThat(mSessionContentTracker.contains(mContentIdGenerators.createFeatureContentId(1))) - .isTrue(); - } - - @Test - public void testUpdate_clearWithfeatures() { - int featureCnt = 3; - mProtocolBuilder.addClearOperation(); - addFeatures(featureCnt); - List<StreamStructure> streamStructures = mProtocolBuilder.buildAsStreamStructure(); - - // 1 clear, 3 features. - assertThat(streamStructures).hasSize(4); - mSessionContentTracker.update(streamStructures); - assertThat(mSessionContentTracker.getContentIds()).hasSize(featureCnt); - assertThat(mSessionContentTracker.contains(mContentIdGenerators.createFeatureContentId(1))) - .isTrue(); - } - - @Test - public void testUpdate_featuresWithClear_enabled() { - int featureCnt = 3; - addFeatures(featureCnt); - mProtocolBuilder.addClearOperation(); - List<StreamStructure> streamStructures = mProtocolBuilder.buildAsStreamStructure(); - - // 3 features, 1 clear. - assertThat(streamStructures).hasSize(4); - mSessionContentTracker.update(streamStructures); - assertThat(mSessionContentTracker.isEmpty()).isTrue(); - } - - @Test - public void testUpdate_featuresWithClear_disabled() { - mSessionContentTracker = new SessionContentTracker(/* supportsClearAll= */ false); - - int featureCnt = 3; - addFeatures(featureCnt); - mProtocolBuilder.addClearOperation(); - List<StreamStructure> streamStructures = mProtocolBuilder.buildAsStreamStructure(); - - // 3 features, 1 clear. - assertThat(streamStructures).hasSize(4); - mSessionContentTracker.update(streamStructures); - assertThat(mSessionContentTracker.isEmpty()).isFalse(); - } - - @Test - public void testUpdate_remove() { - int featureCnt = 2; - addFeatures(featureCnt); - mProtocolBuilder.removeFeature(mContentIdGenerators.createFeatureContentId(1), - mContentIdGenerators.createRootContentId(0)); - List<StreamStructure> streamStructures = mProtocolBuilder.buildAsStreamStructure(); - - // 2 features, 1 remove. - assertThat(streamStructures).hasSize(3); - mSessionContentTracker.update(streamStructures); - assertThat(mSessionContentTracker.getContentIds()).hasSize(1); - } - - @Test - public void testUpdate_requiredContent() { - String contentId = mContentIdGenerators.createFeatureContentId(1); - mProtocolBuilder.addRequiredContent(contentId); - mSessionContentTracker.update(mProtocolBuilder.buildAsStreamStructure()); - assertThat(mSessionContentTracker.getContentIds()).hasSize(1); - assertThat(mSessionContentTracker.contains(contentId)).isTrue(); - } - - private void addFeatures(int featureCnt) { - for (int i = 0; i < featureCnt; i++) { - mProtocolBuilder.addFeature(mContentIdGenerators.createFeatureContentId(i + 1), - mContentIdGenerators.createRootContentId(0)); - } - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedsessionmanager/internal/SessionImplTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedsessionmanager/internal/SessionImplTest.java deleted file mode 100644 index 426c5be..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedsessionmanager/internal/SessionImplTest.java +++ /dev/null
@@ -1,133 +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. - -package org.chromium.chrome.browser.feed.library.feedsessionmanager.internal; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.mock; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.common.MutationContext; -import org.chromium.chrome.browser.feed.library.api.internal.common.testing.InternalProtocolBuilder; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider.ViewDepthProvider; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeTaskQueue; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeThreadUtils; -import org.chromium.chrome.browser.feed.library.common.time.TimingUtils; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.feedsessionmanager.internal.testing.AbstractSessionImplTest; -import org.chromium.chrome.browser.feed.library.testing.modelprovider.FakeModelMutation; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamStructure; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamToken; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.UiContext; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.ArrayList; -import java.util.List; - -/** Tests of the {@link SessionImpl} class. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class SessionImplTest extends AbstractSessionImplTest { - private final FakeClock mFakeClock = new FakeClock(); - private final FakeThreadUtils mFakeThreadUtils = FakeThreadUtils.withThreadChecks(); - private final TimingUtils mTimingUtils = new TimingUtils(); - private SessionImpl mSession; - - @Before - @Override - public void setUp() { - super.setUp(); - mFakeThreadUtils.enforceMainThread(false); - mSession = getSessionImpl(); - } - - @Test - public void testInvalidateOnResetHead() { - assertThat(mSession.invalidateOnResetHead()).isTrue(); - } - - @Test - public void testClearHead() { - mSession.setSessionId(TEST_SESSION_ID); - mSession.populateModelProvider( - new ArrayList<>(), false, false, UiContext.getDefaultInstance()); - int featureCnt = 3; - InternalProtocolBuilder protocolBuilder = new InternalProtocolBuilder().addClearOperation(); - addFeatures(protocolBuilder, featureCnt, 1); - List<StreamStructure> streamStructures = protocolBuilder.buildAsStreamStructure(); - - // clear head will be ignored - assertThat(streamStructures).hasSize(4); - mSession.updateSession(true, streamStructures, SCHEMA_VERSION, null); - assertThat(mFakeSessionMutation.streamStructures).isEmpty(); - FakeModelMutation fakeModelMutation = mFakeModelProvider.getLatestModelMutation(); - assertThat(fakeModelMutation.mAddedChildren).isEmpty(); - assertThat(mSession.getContentInSession()).isEmpty(); - } - - @Test - public void testClearHead_paginationRequest() { - ViewDepthProvider mockDepthProvider = mock(ViewDepthProvider.class); - mSession.setSessionId(TEST_SESSION_ID); - mSession.bindModelProvider(mFakeModelProvider, mockDepthProvider); - mSession.populateModelProvider( - new ArrayList<>(), false, false, UiContext.getDefaultInstance()); - int featureCnt = 3; - InternalProtocolBuilder protocolBuilder = new InternalProtocolBuilder().addClearOperation(); - addFeatures(protocolBuilder, featureCnt, 1); - List<StreamStructure> streamStructures = protocolBuilder.buildAsStreamStructure(); - mSession.updateSession(true, streamStructures, SCHEMA_VERSION, - new MutationContext.Builder() - .setContinuationToken( - StreamToken.newBuilder().setContentId("token").build()) - .setRequestingSessionId(TEST_SESSION_ID) - .build()); - - assertThat(mFakeModelProvider.isInvalidated()).isTrue(); - } - - @Test - public void testModelProviderBinding_withDetach() { - ViewDepthProvider mockDepthProvider = mock(ViewDepthProvider.class); - mSession.bindModelProvider(mFakeModelProvider, mockDepthProvider); - assertThat(mSession.mModelProvider).isEqualTo(mFakeModelProvider); - assertThat(mSession.mViewDepthProvider).isEqualTo(mockDepthProvider); - - mSession.bindModelProvider(null, null); - assertThat(mSession.mViewDepthProvider).isNull(); - assertThat(mSession.mModelProvider).isNull(); - } - - @Test - public void testUpdateSession_requiredContent() { - String contentId = mContentIdGenerators.createFeatureContentId(1); - InternalProtocolBuilder protocolBuilder = - new InternalProtocolBuilder().addRequiredContent(contentId); - mSession.setSessionId(TEST_SESSION_ID); - mSession.updateSession( - /* clearHead= */ false, protocolBuilder.buildAsStreamStructure(), SCHEMA_VERSION, - /* mutationContext= */ null); - - assertThat(mFakeSessionMutation.streamStructures).hasSize(1); - assertThat(mFakeModelProvider.getLatestModelMutation().mAddedChildren).isEmpty(); - assertThat(mFakeModelProvider.getLatestModelMutation().mRemovedChildren).isEmpty(); - assertThat(mFakeModelProvider.getLatestModelMutation().mUpdateChildren).isEmpty(); - assertThat(mFakeModelProvider.getLatestModelMutation().isCommitted()).isTrue(); - } - - @Override - protected SessionImpl getSessionImpl() { - FakeTaskQueue fakeTaskQueue = new FakeTaskQueue(mFakeClock, mFakeThreadUtils); - fakeTaskQueue.initialize(() -> {}); - SessionImpl session = - new SessionImpl(mStore, false, fakeTaskQueue, mTimingUtils, mFakeThreadUtils); - session.bindModelProvider(mFakeModelProvider, null); - return session; - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedsessionmanager/internal/SessionManagerMutationTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedsessionmanager/internal/SessionManagerMutationTest.java deleted file mode 100644 index 1ec16c2..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedsessionmanager/internal/SessionManagerMutationTest.java +++ /dev/null
@@ -1,376 +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. - -package org.chromium.chrome.browser.feed.library.feedsessionmanager.internal; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import static org.chromium.chrome.browser.feed.library.api.common.MutationContext.EMPTY_CONTEXT; - -import android.util.Pair; - -import com.google.common.collect.ImmutableList; -import com.google.protobuf.ByteString; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.base.supplier.Supplier; -import org.chromium.chrome.browser.feed.library.api.client.knowncontent.KnownContent; -import org.chromium.chrome.browser.feed.library.api.common.MutationContext; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration; -import org.chromium.chrome.browser.feed.library.api.host.logging.InternalFeedError; -import org.chromium.chrome.browser.feed.library.api.host.scheduler.SchedulerApi; -import org.chromium.chrome.browser.feed.library.api.internal.common.Model; -import org.chromium.chrome.browser.feed.library.api.internal.common.PayloadWithId; -import org.chromium.chrome.browser.feed.library.api.internal.common.SemanticPropertiesWithId; -import org.chromium.chrome.browser.feed.library.api.internal.common.testing.ContentIdGenerators; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelError; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelError.ErrorType; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider.State; -import org.chromium.chrome.browser.feed.library.common.Result; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeMainThreadRunner; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeTaskQueue; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeThreadUtils; -import org.chromium.chrome.browser.feed.library.common.time.TimingUtils; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.feedsessionmanager.internal.SessionManagerMutation.MutationCommitter; -import org.chromium.chrome.browser.feed.library.testing.host.logging.FakeBasicLoggingApi; -import org.chromium.chrome.browser.feed.library.testing.store.FakeStore; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamDataOperation; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamFeature; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamPayload; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamStructure; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamStructure.Operation; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamToken; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.List; - -/** - * Tests of the {@link SessionManagerMutation} and the actual committer {@link - * SessionManagerMutation.MutationCommitter}. - */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class SessionManagerMutationTest { - private final Configuration mConfiguration = new Configuration.Builder().build(); - private final ContentIdGenerators mIdGenerators = new ContentIdGenerators(); - private final FakeBasicLoggingApi mFakeBasicLoggingApi = new FakeBasicLoggingApi(); - private final FakeClock mFakeClock = new FakeClock(); - private final FakeMainThreadRunner mFakeMainThreadRunner = - FakeMainThreadRunner.runTasksImmediately(); - private final FakeThreadUtils mFakeThreadUtils = FakeThreadUtils.withThreadChecks(); - private final String mRootContentId = mIdGenerators.createRootContentId(0); - private final TimingUtils mTimingUtils = new TimingUtils(); - - @Mock - private KnownContent.Listener mKnownContentListener; - @Mock - private SchedulerApi mSchedulerApi; - private ContentCache mContentCache; - private FakeTaskQueue mFakeTaskQueue; - private ModelError mNotifyError; - private Session mNotifySession; - private SessionCache mSessionCache; - private FakeStore mFakeStore; - - @Before - public void setUp() { - initMocks(this); - mNotifySession = null; - mFakeTaskQueue = new FakeTaskQueue(mFakeClock, mFakeThreadUtils); - mFakeTaskQueue.initialize(() -> {}); - mFakeThreadUtils.enforceMainThread(false); - mFakeStore = new FakeStore(mConfiguration, mFakeThreadUtils, mFakeTaskQueue, mFakeClock); - SessionFactory sessionFactory = new SessionFactory( - mFakeStore, mFakeTaskQueue, mTimingUtils, mFakeThreadUtils, mConfiguration); - mSessionCache = new SessionCache(mFakeStore, mFakeTaskQueue, sessionFactory, 10L, - mTimingUtils, mFakeThreadUtils, mFakeClock); - mSessionCache.initialize(); - mContentCache = new ContentCache(); - } - - @Test - public void testResultError() { - String sessionId = "session:1"; - Session session = getSession(sessionId); - - MutationContext mutationContext = - new MutationContext.Builder() - .setContinuationToken(StreamToken.getDefaultInstance()) - .setRequestingSessionId(sessionId) - .build(); - MutationCommitter mutationCommitter = getMutationCommitter(mutationContext); - mutationCommitter.accept(Result.failure()); - assertThat(mNotifySession).isEqualTo(session); - assertThat(mNotifyError.getErrorType()).isEqualTo(ErrorType.PAGINATION_ERROR); - } - - @Test - public void testResultError_noSession() { - MutationCommitter mutationCommitter = getMutationCommitter(MutationContext.EMPTY_CONTEXT); - mutationCommitter.accept(Result.failure()); - assertThat(mNotifySession).isEqualTo(null); - assertThat(mNotifyError.getErrorType()).isEqualTo(ErrorType.NO_CARDS_ERROR); - } - - @Test - public void testResetHead() { - mFakeClock.set(5L); - List<StreamDataOperation> dataOperations = new ArrayList<>(); - dataOperations.add(getStreamDataOperation( - StreamStructure.newBuilder().setOperation(Operation.CLEAR_ALL).build(), null)); - String sessionId = "session:1"; - - MutationCommitter mutationCommitter = getMutationCommitter( - new MutationContext.Builder().setRequestingSessionId(sessionId).build()); - mutationCommitter.accept(Result.success(Model.of(dataOperations))); - assertThat(mutationCommitter.mClearedHead).isTrue(); - verify(mSchedulerApi).onReceiveNewContent(5L); - verify(mKnownContentListener).onNewContentReceived(true, 5L); - } - - @Test - public void testUpdateHeadMetadata() { - int schemaVersion = 3; - long currentTime = 8L; - mFakeClock.set(currentTime); - MutationCommitter mutationCommitter = getMutationCommitter(MutationContext.EMPTY_CONTEXT); - mutationCommitter.accept(Result.success(Model.of( - ImmutableList.of(getStreamDataOperation( - StreamStructure.newBuilder().setOperation(Operation.CLEAR_ALL).build(), - /* payload= */ null)), - schemaVersion))); - assertThat(mSessionCache.getHead().getSchemaVersion()).isEqualTo(schemaVersion); - assertThat(mSessionCache.getHeadLastAddedTimeMillis()).isEqualTo(currentTime); - } - - @Test - public void testUpdateContent() { - mFakeClock.set(8L); - List<String> contentIds = getContentIds(3); - List<Pair<StreamStructure, StreamPayload>> features = getFeatures(contentIds, - () - -> StreamPayload.newBuilder() - .setStreamFeature(StreamFeature.getDefaultInstance()) - .build()); - List<StreamDataOperation> dataOperations = new ArrayList<>(); - for (Pair<StreamStructure, StreamPayload> feature : features) { - dataOperations.add(getStreamDataOperation(feature.first, feature.second)); - } - MutationCommitter mutationCommitter = getMutationCommitter(EMPTY_CONTEXT); - mutationCommitter.accept(Result.success(Model.of(dataOperations))); - - Result<List<PayloadWithId>> result = mFakeStore.getPayloads(contentIds); - assertThat(result.isSuccessful()).isTrue(); - assertThat(result.getValue()).hasSize(contentIds.size()); - for (PayloadWithId payload : result.getValue()) { - assertThat(contentIds).contains(payload.contentId); - } - assertThat(mContentCache.size()).isEqualTo(0); - verify(mSchedulerApi, never()).onReceiveNewContent(anyLong()); - verify(mKnownContentListener).onNewContentReceived(false, 8L); - } - - @Test - public void testUpdateContent_failedCommitLogsError() { - mFakeStore.setAllowEditContent(false); - - List<String> contentIds = getContentIds(3); - List<Pair<StreamStructure, StreamPayload>> features = getFeatures(contentIds, - () - -> StreamPayload.newBuilder() - .setStreamFeature(StreamFeature.getDefaultInstance()) - .build()); - List<StreamDataOperation> dataOperations = new ArrayList<>(); - for (Pair<StreamStructure, StreamPayload> feature : features) { - dataOperations.add(getStreamDataOperation(feature.first, feature.second)); - } - MutationCommitter mutationCommitter = getMutationCommitter(EMPTY_CONTEXT); - mutationCommitter.accept(Result.success(Model.of(dataOperations))); - - assertThat(mFakeBasicLoggingApi.lastInternalError) - .isEqualTo(InternalFeedError.CONTENT_MUTATION_FAILED); - } - - @Test - public void testSemanticData() { - List<String> contentIds = getContentIds(2); - List<Pair<StreamStructure, StreamPayload>> features = getFeatures(contentIds, - () - -> StreamPayload.newBuilder() - .setSemanticData( - ByteString.copyFrom("foo", Charset.defaultCharset())) - .build()); - List<StreamDataOperation> dataOperations = new ArrayList<>(); - for (Pair<StreamStructure, StreamPayload> feature : features) { - dataOperations.add(getStreamDataOperation(feature.first, feature.second)); - } - MutationCommitter mutationCommitter = getMutationCommitter(EMPTY_CONTEXT); - mutationCommitter.accept(Result.success(Model.of(dataOperations))); - - Result<List<SemanticPropertiesWithId>> result = - mFakeStore.getSemanticProperties(contentIds); - assertThat(result.isSuccessful()).isTrue(); - assertThat(result.getValue()).hasSize(contentIds.size()); - for (SemanticPropertiesWithId payload : result.getValue()) { - assertThat(contentIds).contains(payload.contentId); - } - } - - @Test - public void testValidDataOperation() { - StreamDataOperation operation = StreamDataOperation.getDefaultInstance(); - assertThat(SessionManagerMutation.validDataOperation(operation)).isFalse(); - - operation = StreamDataOperation.newBuilder() - .setStreamPayload(StreamPayload.getDefaultInstance()) - .build(); - assertThat(SessionManagerMutation.validDataOperation(operation)).isFalse(); - - operation = StreamDataOperation.newBuilder() - .setStreamStructure(StreamStructure.getDefaultInstance()) - .build(); - assertThat(SessionManagerMutation.validDataOperation(operation)).isFalse(); - - operation = StreamDataOperation.newBuilder() - .setStreamPayload(StreamPayload.getDefaultInstance()) - .setStreamStructure(StreamStructure.getDefaultInstance()) - .build(); - assertThat(SessionManagerMutation.validDataOperation(operation)).isFalse(); - - operation = StreamDataOperation.newBuilder() - .setStreamPayload(StreamPayload.getDefaultInstance()) - .setStreamStructure( - StreamStructure.newBuilder().setContentId("content").build()) - .build(); - assertThat(SessionManagerMutation.validDataOperation(operation)).isTrue(); - } - - @Test - public void testInvalidateHead() { - MutationCommitter mutationCommitter = getMutationCommitter(EMPTY_CONTEXT); - mutationCommitter.resetHead(null); - assertThat(mFakeStore.getClearHeadCalled()).isTrue(); - } - - @Test - public void testShouldInvalidateSession_modelProviderInitializing() { - MutationCommitter mutationCommitter = getMutationCommitter(EMPTY_CONTEXT); - ModelProvider modelProvider = mock(ModelProvider.class); - when(modelProvider.getCurrentState()).thenReturn(State.INITIALIZING); - assertThat(mutationCommitter.shouldInvalidateSession(null, modelProvider)).isFalse(); - } - - @Test - public void testShouldInvalidateSession_modelProviderInvalidated() { - MutationCommitter mutationCommitter = getMutationCommitter(EMPTY_CONTEXT); - ModelProvider modelProvider = mock(ModelProvider.class); - when(modelProvider.getCurrentState()).thenReturn(State.INVALIDATED); - assertThat(mutationCommitter.shouldInvalidateSession(null, modelProvider)).isFalse(); - } - - @Test - public void testShouldInvalidateSession_modelProviderReady() { - MutationCommitter mutationCommitter = getMutationCommitter(EMPTY_CONTEXT); - ModelProvider modelProvider = mock(ModelProvider.class); - when(modelProvider.getCurrentState()).thenReturn(State.READY); - assertThat(mutationCommitter.shouldInvalidateSession(null, modelProvider)).isTrue(); - } - - @Test - public void testShouldInvalidateSession_noModelProviderSession() { - MutationCommitter mutationCommitter = getMutationCommitter(EMPTY_CONTEXT); - ModelProvider modelProvider = mock(ModelProvider.class); - when(modelProvider.getCurrentState()).thenReturn(State.READY); - assertThat(mutationCommitter.shouldInvalidateSession("session:2", modelProvider)).isTrue(); - } - - @Test - public void testShouldInvalidateSession_differentSession() { - MutationCommitter mutationCommitter = getMutationCommitter(EMPTY_CONTEXT); - String sessionId = "session:1"; - ModelProvider modelProvider = mock(ModelProvider.class); - when(modelProvider.getCurrentState()).thenReturn(State.READY); - when(modelProvider.getSessionId()).thenReturn(sessionId); - assertThat(mutationCommitter.shouldInvalidateSession("session:2", modelProvider)).isFalse(); - } - - @Test - public void testShouldInvalidateSession_sameSession() { - MutationCommitter mutationCommitter = getMutationCommitter(EMPTY_CONTEXT); - String sessionId = "session:1"; - ModelProvider modelProvider = mock(ModelProvider.class); - when(modelProvider.getCurrentState()).thenReturn(State.READY); - when(modelProvider.getSessionId()).thenReturn(sessionId); - assertThat(mutationCommitter.shouldInvalidateSession(sessionId, modelProvider)).isTrue(); - } - - private MutationCommitter getMutationCommitter(MutationContext mutationContext) { - SessionManagerMutation mutation = new SessionManagerMutation(mFakeStore, mSessionCache, - mContentCache, mFakeTaskQueue, mSchedulerApi, mFakeThreadUtils, mTimingUtils, - mFakeClock, mFakeMainThreadRunner, mFakeBasicLoggingApi); - return (MutationCommitter) mutation.createCommitter( - "task", mutationContext, this::notifySessionError, mKnownContentListener); - } - - private List<String> getContentIds(int count) { - List<String> contentIds = new ArrayList<>(); - for (int i = 0; i < count; i++) { - contentIds.add(mIdGenerators.createFeatureContentId(i)); - } - return contentIds; - } - - private Session getSession(String sessionId) { - Session session = mock(Session.class); - when(session.getSessionId()).thenReturn(sessionId); - mSessionCache.putAttachedAndRetainMetadata(sessionId, session); - return session; - } - - private List<Pair<StreamStructure, StreamPayload>> getFeatures( - List<String> contentIds, Supplier<StreamPayload> payloadConsumer) { - List<Pair<StreamStructure, StreamPayload>> values = new ArrayList<>(); - for (String contentId : contentIds) { - StreamStructure streamStructure = StreamStructure.newBuilder() - .setOperation(Operation.UPDATE_OR_APPEND) - .setParentContentId(mRootContentId) - .setContentId(contentId) - .build(); - StreamPayload streamPayload = payloadConsumer.get(); - values.add(new Pair<>(streamStructure, streamPayload)); - } - return values; - } - - private StreamDataOperation getStreamDataOperation( - StreamStructure streamStructure, StreamPayload payload) { - StreamDataOperation.Builder builder = - StreamDataOperation.newBuilder().setStreamStructure(streamStructure); - if (payload != null) { - builder.setStreamPayload(payload); - } - return builder.build(); - } - - private void notifySessionError(Session session, ModelError error) { - mNotifySession = session; - mNotifyError = error; - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedsessionmanager/internal/TimeoutSessionImplTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedsessionmanager/internal/TimeoutSessionImplTest.java deleted file mode 100644 index 073d163a..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedsessionmanager/internal/TimeoutSessionImplTest.java +++ /dev/null
@@ -1,276 +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. - -package org.chromium.chrome.browser.feed.library.feedsessionmanager.internal; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.when; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.common.MutationContext; -import org.chromium.chrome.browser.feed.library.api.internal.common.testing.InternalProtocolBuilder; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelChild; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider.ViewDepthProvider; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeTaskQueue; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeThreadUtils; -import org.chromium.chrome.browser.feed.library.common.time.TimingUtils; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.feedsessionmanager.internal.testing.AbstractSessionImplTest; -import org.chromium.chrome.browser.feed.library.testing.modelprovider.FakeModelChild; -import org.chromium.chrome.browser.feed.library.testing.modelprovider.FakeModelCursor; -import org.chromium.chrome.browser.feed.library.testing.modelprovider.FakeModelFeature; -import org.chromium.chrome.browser.feed.library.testing.modelprovider.FakeModelMutation; -import org.chromium.chrome.browser.feed.library.testing.modelprovider.FakeModelToken; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamStructure; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamToken; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.UiContext; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.ArrayList; -import java.util.List; - -/** Tests of the {@link TimeoutSessionImpl} class. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class TimeoutSessionImplTest extends AbstractSessionImplTest { - private final FakeClock mFakeClock = new FakeClock(); - private final FakeThreadUtils mFakeThreadUtils = FakeThreadUtils.withThreadChecks(); - private final TimingUtils mTimingUtils = new TimingUtils(); - - @Mock - private ViewDepthProvider mViewDepthProvider; - - @Before - @Override - public void setUp() { - super.setUp(); - mFakeThreadUtils.enforceMainThread(false); - } - - @Test - public void testInvalidateOnResetHead() { - TimeoutSessionImpl session = getSessionImpl(); - assertThat(session.invalidateOnResetHead()).isFalse(); - } - - @Test - public void testClearHead() { - SessionImpl session = getSessionImpl(); - session.setSessionId(TEST_SESSION_ID); - session.populateModelProvider( - new ArrayList<>(), false, true, UiContext.getDefaultInstance()); - int featureCnt = 3; - int featureId = 5; - InternalProtocolBuilder protocolBuilder = new InternalProtocolBuilder().addClearOperation(); - addFeatures(protocolBuilder, featureCnt, featureId); - List<StreamStructure> streamStructures = protocolBuilder.buildAsStreamStructure(); - - // 1 clear, 3 features - assertThat(streamStructures).hasSize(4); - session.updateSession(true, streamStructures, SCHEMA_VERSION, null); - assertThat(mFakeSessionMutation.streamStructures).hasSize(featureCnt); - FakeModelMutation fakeModelMutation = mFakeModelProvider.getLatestModelMutation(); - assertThat(fakeModelMutation.mAddedChildren).hasSize(featureCnt); - assertThat(session.getContentInSession()).hasSize(featureCnt); - assertThat(session.getContentInSession()) - .contains(mContentIdGenerators.createFeatureContentId(featureId)); - } - - @Test - public void testClearHead_onPaginationRequest() { - SessionImpl session = getSessionImpl(); - session.setSessionId(TEST_SESSION_ID); - session.populateModelProvider( - new ArrayList<>(), false, true, UiContext.getDefaultInstance()); - int featureCnt = 3; - int featureId = 5; - InternalProtocolBuilder protocolBuilder = new InternalProtocolBuilder().addClearOperation(); - addFeatures(protocolBuilder, featureCnt, featureId); - List<StreamStructure> streamStructures = protocolBuilder.buildAsStreamStructure(); - - session.bindModelProvider(mFakeModelProvider, mViewDepthProvider); - session.populateModelProvider( - new ArrayList<>(), false, false, UiContext.getDefaultInstance()); - session.updateSession(true, streamStructures, SCHEMA_VERSION, - new MutationContext.Builder() - .setRequestingSessionId(TEST_SESSION_ID) - .setContinuationToken( - StreamToken.newBuilder().setContentId("token").build()) - .build()); - assertThat(mFakeModelProvider.isInvalidated()).isTrue(); - } - - @Test - public void testPopulateModelProviderState() { - TimeoutSessionImpl session = getSessionImpl(); - assertThat(session.mLegacyHeadContent).isFalse(); - assertThat(session.mViewDepthProvider).isNull(); - - session.setSessionId(TEST_SESSION_ID); - session.bindModelProvider(mFakeModelProvider, mViewDepthProvider); - session.populateModelProvider( - new ArrayList<>(), false, true, UiContext.getDefaultInstance()); - assertThat(session.mLegacyHeadContent).isTrue(); - assertThat(session.mViewDepthProvider).isEqualTo(mViewDepthProvider); - } - - @Test - public void testCreateRemoveFeature() { - TimeoutSessionImpl session = getSessionImpl(); - String contentId = "contentId"; - String parentContentId = "parentId"; - - StreamStructure streamStructure = session.createRemoveFeature(contentId, parentContentId); - assertThat(streamStructure.getContentId()).isEqualTo(contentId); - assertThat(streamStructure.getParentContentId()).isEqualTo(parentContentId); - } - - @Test - public void testCreateRemoveFeature_nullParent() { - TimeoutSessionImpl session = getSessionImpl(); - String contentId = "contentId"; - - StreamStructure streamStructure = session.createRemoveFeature(contentId, null); - assertThat(streamStructure.getContentId()).isEqualTo(contentId); - assertThat(streamStructure.getParentContentId()).isEmpty(); - } - - @Test - public void testCaptureRootContent() { - TimeoutSessionImpl session = getSessionImpl(); - setupModelProviderRoot(); - - List<ModelChild> children = session.captureRootContent(); - assertThat(children).isNotNull(); - assertThat(children).hasSize(1); - } - - @Test - public void testCaptureRootContent_nullRoot() { - TimeoutSessionImpl session = getSessionImpl(); - - List<ModelChild> children = session.captureRootContent(); - assertThat(children).isEmpty(); - } - - @Test - public void testRemoveItems() { - TimeoutSessionImpl session = getSessionImpl(); - List<ModelChild> modelChildren = new ArrayList<>(); - for (int i = 0; i < 10; i++) { - modelChildren.add(createModelChild(i, ModelChild.Type.FEATURE)); - } - setupForViewDepthProvider( - session, mContentIdGenerators.createFeatureContentId(6), modelChildren); - - // Items below the lowest child should be removed. - session.updateSession( - /* clearHead= */ true, new ArrayList<>(), SCHEMA_VERSION, - /* mutationContext= */ null); - FakeModelMutation fakeModelMutation = mFakeModelProvider.getLatestModelMutation(); - assertThat(fakeModelMutation.mRemovedChildren).hasSize(3); - assertThat(fakeModelMutation.mRemovedChildren.get(0).getContentId()) - .isEqualTo(mContentIdGenerators.createFeatureContentId(7)); - assertThat(fakeModelMutation.mRemovedChildren.get(1).getContentId()) - .isEqualTo(mContentIdGenerators.createFeatureContentId(8)); - assertThat(fakeModelMutation.mRemovedChildren.get(2).getContentId()) - .isEqualTo(mContentIdGenerators.createFeatureContentId(9)); - } - - @Test - public void testRemoveItems_visibleTokenIsRemoved() { - TimeoutSessionImpl session = getSessionImpl(); - List<ModelChild> modelChildren = new ArrayList<>(); - modelChildren.add(createModelChild(0, ModelChild.Type.TOKEN)); - String tokenContentId = mContentIdGenerators.createFeatureContentId(0); - setupForViewDepthProvider(session, tokenContentId, modelChildren); - - // Because the lowest child is a token it should also be removed. - session.updateSession( - /* clearHead= */ true, new ArrayList<>(), SCHEMA_VERSION, - /* mutationContext= */ null); - FakeModelMutation fakeModelMutation = mFakeModelProvider.getLatestModelMutation(); - assertThat(fakeModelMutation.mRemovedChildren).hasSize(1); - assertThat(fakeModelMutation.mRemovedChildren.get(0).getContentId()) - .isEqualTo(tokenContentId); - } - - @Test - public void testRemoveItems_nullLowestChildShouldRemoveToken() { - TimeoutSessionImpl session = getSessionImpl(); - List<ModelChild> modelChildren = new ArrayList<>(); - for (int i = 0; i < 10; i++) { - modelChildren.add(createModelChild(i, ModelChild.Type.FEATURE)); - } - modelChildren.add(createModelChild(11, ModelChild.Type.TOKEN)); - setupForViewDepthProvider(session, /* lowestChild= */ null, modelChildren); - - // The token should be removed even when there is a null lowest child. - session.updateSession( - /* clearHead= */ true, new ArrayList<>(), SCHEMA_VERSION, - /* mutationContext= */ null); - FakeModelMutation fakeModelMutation = mFakeModelProvider.getLatestModelMutation(); - assertThat(fakeModelMutation.mRemovedChildren).hasSize(1); - assertThat(fakeModelMutation.mRemovedChildren.get(0).getContentId()) - .isEqualTo(mContentIdGenerators.createFeatureContentId(11)); - } - - private ModelChild createModelChild(long id, @ModelChild.Type int type) { - String contentId = mContentIdGenerators.createFeatureContentId(id); - switch (type) { - case ModelChild.Type.FEATURE: - return FakeModelChild.newBuilder() - .setContentId(contentId) - .setModelFeature(FakeModelFeature.newBuilder().build()) - .build(); - case ModelChild.Type.TOKEN: - return FakeModelChild.newBuilder() - .setContentId(contentId) - .setModelToken(FakeModelToken.newBuilder().build()) - .build(); - default: - return FakeModelChild.newBuilder().setContentId(contentId).build(); - } - } - - private void setupModelProviderRoot() { - mFakeModelProvider.triggerOnSessionStart( - FakeModelFeature.newBuilder() - .setModelCursor(FakeModelCursor.newBuilder() - .addChild(FakeModelChild.newBuilder().build()) - .build()) - .build()); - } - - @Override - protected TimeoutSessionImpl getSessionImpl() { - FakeTaskQueue fakeTaskQueue = new FakeTaskQueue(mFakeClock, mFakeThreadUtils); - fakeTaskQueue.initialize(() -> {}); - TimeoutSessionImpl session = new TimeoutSessionImpl( - mStore, false, fakeTaskQueue, mTimingUtils, mFakeThreadUtils); - session.bindModelProvider(mFakeModelProvider, /* viewDepthProvider= */ null); - return session; - } - - private void setupForViewDepthProvider( - TimeoutSessionImpl session, String lowestChild, List<ModelChild> modelChildren) { - when(mViewDepthProvider.getChildViewDepth()).thenReturn(lowestChild); - mFakeModelProvider.triggerOnSessionStart( - FakeModelFeature.newBuilder() - .setModelCursor( - FakeModelCursor.newBuilder().addChildren(modelChildren).build()) - .build()); - session.setSessionId(TEST_SESSION_ID); - session.bindModelProvider(mFakeModelProvider, mViewDepthProvider); - session.populateModelProvider(new ArrayList<>(), - /* cachedBindings= */ false, - /* legacyHeadContent= */ true, UiContext.getDefaultInstance()); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedstore/FeedStoreEphemeralModeTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedstore/FeedStoreEphemeralModeTest.java deleted file mode 100644 index e5681067..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedstore/FeedStoreEphemeralModeTest.java +++ /dev/null
@@ -1,62 +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. - -package org.chromium.chrome.browser.feed.library.feedstore; - -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration.ConfigKey; -import org.chromium.chrome.browser.feed.library.api.host.storage.ContentStorageDirect; -import org.chromium.chrome.browser.feed.library.api.internal.store.Store; -import org.chromium.chrome.browser.feed.library.common.concurrent.MainThreadRunner; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeTaskQueue; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeThreadUtils; -import org.chromium.chrome.browser.feed.library.common.protoextensions.FeedExtensionRegistry; -import org.chromium.chrome.browser.feed.library.feedstore.testing.AbstractFeedStoreTest; -import org.chromium.chrome.browser.feed.library.hostimpl.storage.testing.InMemoryContentStorage; -import org.chromium.chrome.browser.feed.library.hostimpl.storage.testing.InMemoryJournalStorage; -import org.chromium.chrome.browser.feed.library.testing.host.logging.FakeBasicLoggingApi; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.ArrayList; - -/** Tests of the {@link FeedStore} class when running in ephemeral mode */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class FeedStoreEphemeralModeTest extends AbstractFeedStoreTest { - private final FakeBasicLoggingApi mFakeBasicLoggingApi = new FakeBasicLoggingApi(); - private final FakeThreadUtils mFakeThreadUtils = FakeThreadUtils.withThreadChecks(); - private final FeedExtensionRegistry mExtensionRegistry = - new FeedExtensionRegistry(ArrayList::new); - private final ContentStorageDirect mContentStorage = new InMemoryContentStorage(); - - @Mock - private Configuration mConfiguration; - - @Before - public void setUp() throws Exception { - initMocks(this); - when(mConfiguration.getValueOrDefault(ConfigKey.USE_DIRECT_STORAGE, false)) - .thenReturn(false); - } - - @Override - protected Store getStore(MainThreadRunner mainThreadRunner) { - FakeTaskQueue fakeTaskQueue = new FakeTaskQueue(mFakeClock, mFakeThreadUtils); - fakeTaskQueue.initialize(() -> {}); - FeedStore feedStore = new FeedStore(mConfiguration, mTimingUtils, mExtensionRegistry, - mContentStorage, new InMemoryJournalStorage(), mFakeThreadUtils, fakeTaskQueue, - mFakeClock, mFakeBasicLoggingApi, mainThreadRunner); - mFakeThreadUtils.enforceMainThread(false); - feedStore.switchToEphemeralMode(); - return feedStore; - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedstore/FeedStoreTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedstore/FeedStoreTest.java deleted file mode 100644 index 36a9a722..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedstore/FeedStoreTest.java +++ /dev/null
@@ -1,195 +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. - -package org.chromium.chrome.browser.feed.library.feedstore; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import static org.chromium.chrome.browser.feed.library.feedstore.internal.FeedStoreConstants.DISMISS_ACTION_JOURNAL; -import static org.chromium.chrome.browser.feed.library.feedstore.internal.FeedStoreConstants.SEMANTIC_PROPERTIES_PREFIX; - -import com.google.protobuf.ByteString; -import com.google.protobuf.InvalidProtocolBufferException; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration.ConfigKey; -import org.chromium.chrome.browser.feed.library.api.host.logging.BasicLoggingApi; -import org.chromium.chrome.browser.feed.library.api.host.logging.InternalFeedError; -import org.chromium.chrome.browser.feed.library.api.host.storage.ContentMutation; -import org.chromium.chrome.browser.feed.library.api.host.storage.ContentOperation; -import org.chromium.chrome.browser.feed.library.api.host.storage.ContentOperation.Upsert; -import org.chromium.chrome.browser.feed.library.api.host.storage.ContentStorageDirect; -import org.chromium.chrome.browser.feed.library.api.host.storage.JournalMutation; -import org.chromium.chrome.browser.feed.library.api.host.storage.JournalOperation; -import org.chromium.chrome.browser.feed.library.api.host.storage.JournalOperation.Append; -import org.chromium.chrome.browser.feed.library.api.host.storage.JournalStorageDirect; -import org.chromium.chrome.browser.feed.library.api.internal.store.LocalActionMutation.ActionType; -import org.chromium.chrome.browser.feed.library.api.internal.store.Store; -import org.chromium.chrome.browser.feed.library.api.internal.store.StoreListener; -import org.chromium.chrome.browser.feed.library.common.concurrent.MainThreadRunner; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeMainThreadRunner; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeTaskQueue; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeThreadUtils; -import org.chromium.chrome.browser.feed.library.common.protoextensions.FeedExtensionRegistry; -import org.chromium.chrome.browser.feed.library.feedapplifecyclelistener.FeedLifecycleListener.LifecycleEvent; -import org.chromium.chrome.browser.feed.library.feedstore.testing.AbstractFeedStoreTest; -import org.chromium.chrome.browser.feed.library.feedstore.testing.DelegatingContentStorage; -import org.chromium.chrome.browser.feed.library.feedstore.testing.DelegatingJournalStorage; -import org.chromium.chrome.browser.feed.library.hostimpl.storage.testing.InMemoryContentStorage; -import org.chromium.chrome.browser.feed.library.hostimpl.storage.testing.InMemoryJournalStorage; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamFeature; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamLocalAction; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamPayload; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamStructure; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamStructure.Operation; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.ArrayList; - -/** Tests of the {@link FeedStore} class. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class FeedStoreTest extends AbstractFeedStoreTest { - private static final String CONTENT_ID = "contentId"; - private static final StreamStructure STREAM_STRUCTURE = - StreamStructure.newBuilder() - .setContentId(CONTENT_ID) - .setOperation(Operation.UPDATE_OR_APPEND) - .build(); - private static final StreamPayload PAYLOAD = - StreamPayload.newBuilder() - .setStreamFeature(StreamFeature.newBuilder().setContentId(CONTENT_ID)) - .build(); - private static final byte[] SEMANTIC_PROPERTIES = new byte[] {4, 12, 18, 5}; - - private final ContentStorageDirect mContentStorage = new InMemoryContentStorage(); - private final FakeThreadUtils mFakeThreadUtils = FakeThreadUtils.withThreadChecks(); - private final FeedExtensionRegistry mExtensionRegistry = - new FeedExtensionRegistry(ArrayList::new); - - @Mock - private BasicLoggingApi mBasicLoggingApi; - @Mock - private Configuration mConfiguration; - @Mock - private StoreListener mListener; - private FakeMainThreadRunner mMainThreadRunner; - private FakeTaskQueue mTaskQueue; - - @Before - public void setUp() throws Exception { - initMocks(this); - when(mConfiguration.getValueOrDefault(ConfigKey.USE_DIRECT_STORAGE, false)) - .thenReturn(false); - mTaskQueue = new FakeTaskQueue(mFakeClock, mFakeThreadUtils); - mTaskQueue.initialize(() -> {}); - mMainThreadRunner = FakeMainThreadRunner.runTasksImmediately(); - mFakeThreadUtils.enforceMainThread(false); - } - - @Override - protected Store getStore(MainThreadRunner mainThreadRunner) { - return new FeedStore(mConfiguration, mTimingUtils, mExtensionRegistry, mContentStorage, - new InMemoryJournalStorage(), mFakeThreadUtils, mTaskQueue, mFakeClock, - mBasicLoggingApi, this.mMainThreadRunner); - } - - @Test - public void testSwitchToEphemeralMode() { - FeedStore store = (FeedStore) getStore(mMainThreadRunner); - assertThat(store.isEphemeralMode()).isFalse(); - store.switchToEphemeralMode(); - assertThat(store.isEphemeralMode()).isTrue(); - verify(mBasicLoggingApi).onInternalError(InternalFeedError.SWITCH_TO_EPHEMERAL); - } - - @Test - public void testSwitchToEphemeralMode_listeners() { - FeedStore store = (FeedStore) getStore(mMainThreadRunner); - assertThat(store.isEphemeralMode()).isFalse(); - - store.registerObserver(mListener); - - store.switchToEphemeralMode(); - assertThat(store.isEphemeralMode()).isTrue(); - verify(mListener).onSwitchToEphemeralMode(); - } - - @Test - public void testDumpEphemeralActions_notEphemeralMode() { - JournalStorageDirect journalStorageSpy = - spy(new DelegatingJournalStorage(new InMemoryJournalStorage())); - ContentStorageDirect contentStorageSpy = - spy(new DelegatingContentStorage(this.mContentStorage)); - FeedStore store = new FeedStore(mConfiguration, mTimingUtils, mExtensionRegistry, - contentStorageSpy, journalStorageSpy, mFakeThreadUtils, mTaskQueue, mFakeClock, - mBasicLoggingApi, mMainThreadRunner); - store.onLifecycleEvent(LifecycleEvent.ENTER_BACKGROUND); - verifyZeroInteractions(journalStorageSpy, contentStorageSpy); - } - - @Test - public void testDumpEphemeralActions_ephemeralMode() throws InvalidProtocolBufferException { - JournalStorageDirect journalStorageSpy = - spy(new DelegatingJournalStorage(new InMemoryJournalStorage())); - ContentStorageDirect contentStorageSpy = - spy(new DelegatingContentStorage(this.mContentStorage)); - FeedStore store = new FeedStore(mConfiguration, mTimingUtils, mExtensionRegistry, - contentStorageSpy, journalStorageSpy, mFakeThreadUtils, mTaskQueue, mFakeClock, - mBasicLoggingApi, mMainThreadRunner); - store.switchToEphemeralMode(); - reset(journalStorageSpy, contentStorageSpy); - - // Add ephemeral semantic properties, content, and actions - store.editSemanticProperties() - .add(CONTENT_ID, ByteString.copyFrom(SEMANTIC_PROPERTIES)) - .commit(); - store.editLocalActions().add(ActionType.DISMISS, CONTENT_ID).commit(); - store.editContent().add(CONTENT_ID, PAYLOAD).commit(); - store.editSession(Store.HEAD_SESSION_ID).add(STREAM_STRUCTURE).commit(); - - store.onLifecycleEvent(LifecycleEvent.ENTER_BACKGROUND); - - // Verify content is written for semantic properties and actions only - ArgumentCaptor<JournalMutation> journalMutationArgumentCaptor = - ArgumentCaptor.forClass(JournalMutation.class); - verify(journalStorageSpy).commit(journalMutationArgumentCaptor.capture()); - - JournalMutation journalMutation = journalMutationArgumentCaptor.getValue(); - assertThat(journalMutation.getJournalName()).isEqualTo(DISMISS_ACTION_JOURNAL); - assertThat(journalMutation.getOperations()).hasSize(1); - assertThat(journalMutation.getOperations().get(0).getType()) - .isEqualTo(JournalOperation.Type.APPEND); - byte[] journalMutationBytes = ((Append) journalMutation.getOperations().get(0)).getValue(); - StreamLocalAction action = StreamLocalAction.parseFrom(journalMutationBytes); - assertThat(action.getAction()).isEqualTo(ActionType.DISMISS); - assertThat(action.getFeatureContentId()).isEqualTo(CONTENT_ID); - - ArgumentCaptor<ContentMutation> contentMutationArgumentCaptor = - ArgumentCaptor.forClass(ContentMutation.class); - verify(contentStorageSpy).commit(contentMutationArgumentCaptor.capture()); - - ContentMutation contentMutation = contentMutationArgumentCaptor.getValue(); - assertThat(contentMutation.getOperations()).hasSize(1); - assertThat(contentMutation.getOperations().get(0).getType()) - .isEqualTo(ContentOperation.Type.UPSERT); - Upsert upsert = (Upsert) contentMutation.getOperations().get(0); - assertThat(upsert.getKey()).isEqualTo(SEMANTIC_PROPERTIES_PREFIX + CONTENT_ID); - assertThat(upsert.getValue()).isEqualTo(SEMANTIC_PROPERTIES); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedstore/internal/ContentGcTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedstore/internal/ContentGcTest.java deleted file mode 100644 index 63346fd..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedstore/internal/ContentGcTest.java +++ /dev/null
@@ -1,334 +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. -package org.chromium.chrome.browser.feed.library.feedstore.internal; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import static org.chromium.chrome.browser.feed.library.feedstore.internal.FeedStoreConstants.SEMANTIC_PROPERTIES_PREFIX; -import static org.chromium.chrome.browser.feed.library.feedstore.internal.FeedStoreConstants.SHARED_STATE_PREFIX; -import static org.chromium.chrome.browser.feed.library.feedstore.internal.FeedStoreConstants.UPLOADABLE_ACTION_PREFIX; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration.ConfigKey; -import org.chromium.chrome.browser.feed.library.api.host.logging.Task; -import org.chromium.chrome.browser.feed.library.api.host.storage.CommitResult; -import org.chromium.chrome.browser.feed.library.api.host.storage.ContentMutation; -import org.chromium.chrome.browser.feed.library.api.host.storage.ContentOperation; -import org.chromium.chrome.browser.feed.library.api.host.storage.ContentStorageDirect; -import org.chromium.chrome.browser.feed.library.api.internal.store.LocalActionMutation.ActionType; -import org.chromium.chrome.browser.feed.library.common.Result; -import org.chromium.chrome.browser.feed.library.common.concurrent.TaskQueue.TaskType; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeDirectExecutor; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeTaskQueue; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeThreadUtils; -import org.chromium.chrome.browser.feed.library.common.time.TimingUtils; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamLocalAction; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.ArrayList; -import java.util.List; - -/** Tests of the {@link ContentGc} class. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ContentGcTest { - @Captor - private ArgumentCaptor<ContentMutation> mContentMutationCaptor; - @Mock - private ContentStorageDirect mContentStorage; - - private static final String CONTENT_ID_1 = "contentId1"; - private static final String CONTENT_ID_2 = "contentId2"; - private static final String SEMANTIC_PROPERTIES_1 = SEMANTIC_PROPERTIES_PREFIX + CONTENT_ID_1; - private static final String SEMANTIC_PROPERTIES_2 = SEMANTIC_PROPERTIES_PREFIX + CONTENT_ID_2; - private static final String ACTION_1 = UPLOADABLE_ACTION_PREFIX + CONTENT_ID_1; - private static final long MAXIMUM_GC_ATTEMPTS = 3L; - - private final Configuration mConfiguration = - new Configuration.Builder() - .put(ConfigKey.MAXIMUM_GC_ATTEMPTS, MAXIMUM_GC_ATTEMPTS) - .build(); - private final FakeClock mFakeClock = new FakeClock(); - private final FakeThreadUtils mFakeThreadUtils = FakeThreadUtils.withThreadChecks(); - private final FakeDirectExecutor mFakeDirectExecutor = - FakeDirectExecutor.queueAllTasks(mFakeThreadUtils); - private final TimingUtils mTimingUtils = new TimingUtils(); - - private FakeTaskQueue mFakeTaskQueue; - - @Before - public void setUp() throws Exception { - initMocks(this); - mFakeTaskQueue = new FakeTaskQueue(mFakeClock, mFakeDirectExecutor); - mFakeTaskQueue.initialize(() -> {}); - } - - @Test - public void gc() { - List<String> contentKeys = new ArrayList<>(); - contentKeys.add(CONTENT_ID_1); - contentKeys.add(CONTENT_ID_2); - mockContentStorageWithContents(contentKeys); - ContentGc contentGc = new ContentGc(mConfiguration, ImmutableSet::of, ImmutableSet.of(), - ImmutableSet::of, mContentStorage, mFakeTaskQueue, mTimingUtils, - /* keepSharedStates= */ true); - contentGc.gc(); - verify(mContentStorage).commit(mContentMutationCaptor.capture()); - List<ContentOperation> expectedOperations = new ContentMutation.Builder() - .delete(CONTENT_ID_1) - .delete(CONTENT_ID_2) - .build() - .getOperations(); - List<ContentOperation> resultOperations = mContentMutationCaptor.getValue().getOperations(); - assertListsContainSameElements(expectedOperations, resultOperations); - } - - @Test - public void gc_accessible() { - List<String> contentKeys = new ArrayList<>(); - contentKeys.add(CONTENT_ID_1); - contentKeys.add(CONTENT_ID_2); - mockContentStorageWithContents(contentKeys); - ContentGc contentGc = new ContentGc(mConfiguration, - () - -> ImmutableSet.of(CONTENT_ID_1), - ImmutableSet.of(), ImmutableSet::of, mContentStorage, mFakeTaskQueue, mTimingUtils, - /* keepSharedStates= */ true); - contentGc.gc(); - verify(mContentStorage).commit(mContentMutationCaptor.capture()); - List<ContentOperation> expectedOperations = - new ContentMutation.Builder().delete(CONTENT_ID_2).build().getOperations(); - List<ContentOperation> resultOperations = mContentMutationCaptor.getValue().getOperations(); - assertListsContainSameElements(expectedOperations, resultOperations); - } - - @Test - public void gc_reserved() { - List<String> contentKeys = new ArrayList<>(); - contentKeys.add(CONTENT_ID_1); - contentKeys.add(CONTENT_ID_2); - mockContentStorageWithContents(contentKeys); - ContentGc contentGc = - new ContentGc(mConfiguration, ImmutableSet::of, ImmutableSet.of(CONTENT_ID_1), - ImmutableSet::of, mContentStorage, mFakeTaskQueue, mTimingUtils, - /* keepSharedStates= */ true); - contentGc.gc(); - verify(mContentStorage).commit(mContentMutationCaptor.capture()); - List<ContentOperation> expectedOperations = - new ContentMutation.Builder().delete(CONTENT_ID_2).build().getOperations(); - List<ContentOperation> resultOperations = mContentMutationCaptor.getValue().getOperations(); - assertListsContainSameElements(expectedOperations, resultOperations); - } - - @Test - public void gc_actionUploads_validAction() { - List<String> contentKeys = new ArrayList<>(); - contentKeys.add(ACTION_1); - mockContentStorageWithContents(contentKeys); - ContentGc contentGc = new ContentGc(mConfiguration, ImmutableSet::of, ImmutableSet.of(), - ImmutableSet::of, mContentStorage, mFakeTaskQueue, mTimingUtils, - /* keepSharedStates= */ true); - contentGc.gc(); - verify(mContentStorage).commit(mContentMutationCaptor.capture()); - List<ContentOperation> expectedOperations = - new ContentMutation.Builder().build().getOperations(); - List<ContentOperation> resultOperations = mContentMutationCaptor.getValue().getOperations(); - assertListsContainSameElements(expectedOperations, resultOperations); - } - - @Test - public void gc_semanticProperties_noAction() { - List<String> contentKeys = new ArrayList<>(); - contentKeys.add(SEMANTIC_PROPERTIES_1); - contentKeys.add(SEMANTIC_PROPERTIES_2); - mockContentStorageWithContents(contentKeys); - ContentGc contentGc = new ContentGc(mConfiguration, ImmutableSet::of, ImmutableSet.of(), - ImmutableSet::of, mContentStorage, mFakeTaskQueue, mTimingUtils, - /* keepSharedStates= */ true); - contentGc.gc(); - verify(mContentStorage).commit(mContentMutationCaptor.capture()); - List<ContentOperation> expectedOperations = new ContentMutation.Builder() - .delete(SEMANTIC_PROPERTIES_1) - .delete(SEMANTIC_PROPERTIES_2) - .build() - .getOperations(); - List<ContentOperation> resultOperations = mContentMutationCaptor.getValue().getOperations(); - assertListsContainSameElements(expectedOperations, resultOperations); - } - - @Test - public void gc_semanticProperties_validAction() { - List<String> contentKeys = new ArrayList<>(); - contentKeys.add(SEMANTIC_PROPERTIES_1); - contentKeys.add(SEMANTIC_PROPERTIES_2); - mockContentStorageWithContents(contentKeys); - ContentGc contentGc = new ContentGc(mConfiguration, ImmutableSet::of, ImmutableSet.of(), - () - -> ImmutableSet.of(StreamLocalAction.newBuilder() - .setAction(ActionType.DISMISS) - .setFeatureContentId(CONTENT_ID_1) - .build()), - mContentStorage, mFakeTaskQueue, mTimingUtils, - /* keepSharedStates= */ true); - contentGc.gc(); - verify(mContentStorage).commit(mContentMutationCaptor.capture()); - List<ContentOperation> expectedOperations = - new ContentMutation.Builder().delete(SEMANTIC_PROPERTIES_2).build().getOperations(); - List<ContentOperation> resultOperations = mContentMutationCaptor.getValue().getOperations(); - assertListsContainSameElements(expectedOperations, resultOperations); - } - - @Test - public void gc_semanticProperties_accessibleContent() { - List<String> contentKeys = new ArrayList<>(); - contentKeys.add(CONTENT_ID_1); - contentKeys.add(SEMANTIC_PROPERTIES_1); - contentKeys.add(SEMANTIC_PROPERTIES_2); - mockContentStorageWithContents(contentKeys); - ContentGc contentGc = new ContentGc(mConfiguration, - () - -> ImmutableSet.of(CONTENT_ID_1), - ImmutableSet.of(), ImmutableSet::of, mContentStorage, mFakeTaskQueue, mTimingUtils, - /* keepSharedStates= */ true); - contentGc.gc(); - verify(mContentStorage).commit(mContentMutationCaptor.capture()); - List<ContentOperation> expectedOperations = - new ContentMutation.Builder().delete(SEMANTIC_PROPERTIES_2).build().getOperations(); - List<ContentOperation> resultOperations = mContentMutationCaptor.getValue().getOperations(); - assertListsContainSameElements(expectedOperations, resultOperations); - } - - @Test - public void gc_prefixed_sharedState() { - List<String> contentKeys = new ArrayList<>(); - contentKeys.add(SHARED_STATE_PREFIX + CONTENT_ID_1); - contentKeys.add(CONTENT_ID_2); - mockContentStorageWithContents(contentKeys); - ContentGc contentGc = new ContentGc(mConfiguration, ImmutableSet::of, ImmutableSet.of(), - ImmutableSet::of, mContentStorage, mFakeTaskQueue, mTimingUtils, - /* keepSharedStates= */ true); - contentGc.gc(); - verify(mContentStorage).commit(mContentMutationCaptor.capture()); - List<ContentOperation> expectedOperations = - new ContentMutation.Builder().delete(CONTENT_ID_2).build().getOperations(); - List<ContentOperation> resultOperations = mContentMutationCaptor.getValue().getOperations(); - assertListsContainSameElements(expectedOperations, resultOperations); - } - - @Test - public void gc_deleteSharedState() { - List<String> contentKeys = new ArrayList<>(); - contentKeys.add(SHARED_STATE_PREFIX + CONTENT_ID_1); - contentKeys.add(CONTENT_ID_2); - mockContentStorageWithContents(contentKeys); - ContentGc contentGc = new ContentGc(mConfiguration, ImmutableSet::of, ImmutableSet.of(), - ImmutableSet::of, mContentStorage, mFakeTaskQueue, mTimingUtils, - /* keepSharedStates= */ false); - contentGc.gc(); - verify(mContentStorage).commit(mContentMutationCaptor.capture()); - List<ContentOperation> expectedOperations = - new ContentMutation.Builder() - .delete(SHARED_STATE_PREFIX + CONTENT_ID_1) - .delete(CONTENT_ID_2) - .build() - .getOperations(); - List<ContentOperation> resultOperations = mContentMutationCaptor.getValue().getOperations(); - assertListsContainSameElements(expectedOperations, resultOperations); - } - - @Test - public void gc_keepAccessibleSharedState() { - List<String> contentKeys = new ArrayList<>(); - contentKeys.add(SHARED_STATE_PREFIX + CONTENT_ID_1); - contentKeys.add(CONTENT_ID_2); - mockContentStorageWithContents(contentKeys); - ContentGc contentGc = new ContentGc(mConfiguration, - () - -> ImmutableSet.of(CONTENT_ID_1), - ImmutableSet.of(), ImmutableSet::of, mContentStorage, mFakeTaskQueue, mTimingUtils, - /* keepSharedStates= */ false); - contentGc.gc(); - verify(mContentStorage).commit(mContentMutationCaptor.capture()); - List<ContentOperation> expectedOperations = - new ContentMutation.Builder().delete(CONTENT_ID_2).build().getOperations(); - List<ContentOperation> resultOperations = mContentMutationCaptor.getValue().getOperations(); - assertListsContainSameElements(expectedOperations, resultOperations); - } - - @Test - public void gc_delayWhileTaskEnqueued() { - mFakeTaskQueue.execute(Task.UNKNOWN, TaskType.BACKGROUND, () -> {}); - List<String> contentKeys = ImmutableList.of(CONTENT_ID_1, CONTENT_ID_2); - mockContentStorageWithContents(contentKeys); - ContentGc contentGc = new ContentGc(mConfiguration, ImmutableSet::of, ImmutableSet.of(), - ImmutableSet::of, mContentStorage, mFakeTaskQueue, mTimingUtils, - /* keepSharedStates= */ false); - contentGc.gc(); - - assertThat(mFakeTaskQueue.getBackgroundTaskCount()).isEqualTo(2); - verify(mContentStorage, never()).commit(mContentMutationCaptor.capture()); - } - - @Test - public void gc_runWhenMaximumAttemptsReached() { - mFakeTaskQueue.execute(Task.UNKNOWN, TaskType.BACKGROUND, () -> {}); - List<String> contentKeys = ImmutableList.of(CONTENT_ID_1, CONTENT_ID_2); - mockContentStorageWithContents(contentKeys); - ContentGc contentGc = new ContentGc(mConfiguration, ImmutableSet::of, ImmutableSet.of(), - ImmutableSet::of, mContentStorage, mFakeTaskQueue, mTimingUtils, - /* keepSharedStates= */ false); - for (int i = 0; i < MAXIMUM_GC_ATTEMPTS; i++) { - contentGc.gc(); - assertThat(mFakeTaskQueue.getBackgroundTaskCount()).isEqualTo(2 + i); - verify(mContentStorage, never()).commit(mContentMutationCaptor.capture()); - } - - contentGc.gc(); - verify(mContentStorage).commit(mContentMutationCaptor.capture()); - } - - @Test - public void gc_runWhenMaximumIsZero() { - mFakeTaskQueue.execute(Task.UNKNOWN, TaskType.BACKGROUND, () -> {}); - List<String> contentKeys = ImmutableList.of(CONTENT_ID_1, CONTENT_ID_2); - mockContentStorageWithContents(contentKeys); - ContentGc contentGc = new ContentGc( - new Configuration.Builder().put(ConfigKey.MAXIMUM_GC_ATTEMPTS, 0L).build(), - ImmutableSet::of, ImmutableSet.of(), ImmutableSet::of, mContentStorage, - mFakeTaskQueue, mTimingUtils, - /* keepSharedStates= */ false); - contentGc.gc(); - - verify(mContentStorage).commit(mContentMutationCaptor.capture()); - } - - private void mockContentStorageWithContents(List<String> contentKeys) { - when(mContentStorage.getAllKeys()).thenReturn(Result.success(contentKeys)); - when(mContentStorage.commit(any(ContentMutation.class))).thenReturn(CommitResult.SUCCESS); - } - - private void assertListsContainSameElements( - List<ContentOperation> expectedOperations, List<ContentOperation> resultOperations) { - assertThat(resultOperations.size()).isEqualTo(expectedOperations.size()); - assertThat(resultOperations.containsAll(expectedOperations)).isTrue(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedstore/internal/EphemeralFeedStoreTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedstore/internal/EphemeralFeedStoreTest.java deleted file mode 100644 index 7e9bf6c..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedstore/internal/EphemeralFeedStoreTest.java +++ /dev/null
@@ -1,30 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -package org.chromium.chrome.browser.feed.library.feedstore.internal; - -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.internal.store.Store; -import org.chromium.chrome.browser.feed.library.common.concurrent.MainThreadRunner; -import org.chromium.chrome.browser.feed.library.feedstore.testing.AbstractClearableFeedStoreTest; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests of the {@link EphemeralFeedStore} class. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class EphemeralFeedStoreTest extends AbstractClearableFeedStoreTest { - @Before - public void setUp() throws Exception { - initMocks(this); - } - - @Override - protected Store getStore(MainThreadRunner mainThreadRunner) { - return new EphemeralFeedStore(mFakeClock, mTimingUtils, new FeedStoreHelper()); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedstore/internal/LocalActionGcTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedstore/internal/LocalActionGcTest.java deleted file mode 100644 index dacf9c1..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedstore/internal/LocalActionGcTest.java +++ /dev/null
@@ -1,170 +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. -package org.chromium.chrome.browser.feed.library.feedstore.internal; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.verify; -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.storage.JournalMutation; -import org.chromium.chrome.browser.feed.library.api.host.storage.JournalOperation; -import org.chromium.chrome.browser.feed.library.api.host.storage.JournalOperation.Append; -import org.chromium.chrome.browser.feed.library.api.host.storage.JournalOperation.Type; -import org.chromium.chrome.browser.feed.library.api.host.storage.JournalStorageDirect; -import org.chromium.chrome.browser.feed.library.api.internal.store.LocalActionMutation.ActionType; -import org.chromium.chrome.browser.feed.library.common.time.TimingUtils; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamLocalAction; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.TimeUnit; - -/** Tests of the {@link LocalActionGc} class. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class LocalActionGcTest { - private static final String DISMISS_JOURNAL_NAME = "DISMISS"; - private static final String CONTENT_ID_1 = "contentId1"; - private static final String CONTENT_ID_2 = "contentId2"; - - @Mock - private JournalStorageDirect mJournalStorage; - private TimingUtils mTimingUtils = new TimingUtils(); - - @Before - public void setUp() throws Exception { - initMocks(this); - } - - @Test - public void gc_empty() throws Exception { - // Probably won't be called with empty actions - List<StreamLocalAction> allActions = Collections.emptyList(); - List<String> validContentIds = Collections.emptyList(); - - ArgumentCaptor<JournalMutation> journalMutationCaptor = - ArgumentCaptor.forClass(JournalMutation.class); - - LocalActionGc localActionGc = new LocalActionGc( - allActions, validContentIds, mJournalStorage, mTimingUtils, DISMISS_JOURNAL_NAME); - localActionGc.gc(); - - verify(mJournalStorage).commit(journalMutationCaptor.capture()); - - JournalMutation journalMutation = journalMutationCaptor.getValue(); - assertThat(journalMutation.getJournalName()).isEqualTo(DISMISS_JOURNAL_NAME); - List<JournalOperation> journalOperations = journalMutation.getOperations(); - assertThat(journalOperations).hasSize(1); - assertThat(journalOperations.get(0).getType()).isEqualTo(Type.DELETE); - } - - @Test - public void gc_allValid() throws Exception { - StreamLocalAction action1 = StreamLocalAction.newBuilder() - .setAction(ActionType.DISMISS) - .setFeatureContentId(CONTENT_ID_1) - .setTimestampSeconds(TimeUnit.DAYS.toSeconds(43)) - .build(); - StreamLocalAction action2 = StreamLocalAction.newBuilder() - .setAction(ActionType.DISMISS) - .setFeatureContentId(CONTENT_ID_2) - .setTimestampSeconds(TimeUnit.DAYS.toSeconds(44)) - .build(); - List<StreamLocalAction> allActions = Arrays.asList(action1, action2); - List<String> validContentIds = Arrays.asList(CONTENT_ID_1, CONTENT_ID_2); - - ArgumentCaptor<JournalMutation> journalMutationCaptor = - ArgumentCaptor.forClass(JournalMutation.class); - - LocalActionGc localActionGc = new LocalActionGc( - allActions, validContentIds, mJournalStorage, mTimingUtils, DISMISS_JOURNAL_NAME); - localActionGc.gc(); - - verify(mJournalStorage).commit(journalMutationCaptor.capture()); - - JournalMutation journalMutation = journalMutationCaptor.getValue(); - assertThat(journalMutation.getJournalName()).isEqualTo(DISMISS_JOURNAL_NAME); - List<JournalOperation> journalOperations = journalMutation.getOperations(); - assertThat(journalOperations).hasSize(3); - assertThat(journalOperations.get(0).getType()).isEqualTo(Type.DELETE); - assertThat(journalOperations.get(1).getType()).isEqualTo(Type.APPEND); - assertThat(((Append) journalOperations.get(1)).getValue()).isEqualTo(action1.toByteArray()); - assertThat(journalOperations.get(2).getType()).isEqualTo(Type.APPEND); - assertThat(((Append) journalOperations.get(2)).getValue()).isEqualTo(action2.toByteArray()); - } - - @Test - public void gc_allInvalid() throws Exception { - StreamLocalAction action1 = StreamLocalAction.newBuilder() - .setAction(ActionType.DISMISS) - .setFeatureContentId(CONTENT_ID_1) - .setTimestampSeconds(TimeUnit.DAYS.toSeconds(43)) - .build(); - StreamLocalAction action2 = StreamLocalAction.newBuilder() - .setAction(ActionType.DISMISS) - .setFeatureContentId(CONTENT_ID_2) - .setTimestampSeconds(TimeUnit.DAYS.toSeconds(44)) - .build(); - List<StreamLocalAction> allActions = Arrays.asList(action1, action2); - List<String> validContentIds = Collections.emptyList(); - - ArgumentCaptor<JournalMutation> journalMutationCaptor = - ArgumentCaptor.forClass(JournalMutation.class); - - LocalActionGc localActionGc = new LocalActionGc( - allActions, validContentIds, mJournalStorage, mTimingUtils, DISMISS_JOURNAL_NAME); - localActionGc.gc(); - - verify(mJournalStorage).commit(journalMutationCaptor.capture()); - - JournalMutation journalMutation = journalMutationCaptor.getValue(); - assertThat(journalMutation.getJournalName()).isEqualTo(DISMISS_JOURNAL_NAME); - List<JournalOperation> journalOperations = journalMutation.getOperations(); - assertThat(journalOperations).hasSize(1); - assertThat(journalOperations.get(0).getType()).isEqualTo(Type.DELETE); - } - - @Test - public void gc_someValid() throws Exception { - StreamLocalAction action1 = StreamLocalAction.newBuilder() - .setAction(ActionType.DISMISS) - .setFeatureContentId(CONTENT_ID_1) - .setTimestampSeconds(TimeUnit.DAYS.toSeconds(43)) - .build(); - StreamLocalAction action2 = StreamLocalAction.newBuilder() - .setAction(ActionType.DISMISS) - .setFeatureContentId(CONTENT_ID_2) - .setTimestampSeconds(TimeUnit.DAYS.toSeconds(44)) - .build(); - List<StreamLocalAction> allActions = Arrays.asList(action1, action2); - List<String> validContentIds = Collections.singletonList(CONTENT_ID_2); - - ArgumentCaptor<JournalMutation> journalMutationCaptor = - ArgumentCaptor.forClass(JournalMutation.class); - - LocalActionGc localActionGc = new LocalActionGc( - allActions, validContentIds, mJournalStorage, mTimingUtils, DISMISS_JOURNAL_NAME); - localActionGc.gc(); - - verify(mJournalStorage).commit(journalMutationCaptor.capture()); - - JournalMutation journalMutation = journalMutationCaptor.getValue(); - assertThat(journalMutation.getJournalName()).isEqualTo(DISMISS_JOURNAL_NAME); - List<JournalOperation> journalOperations = journalMutation.getOperations(); - assertThat(journalOperations).hasSize(2); - assertThat(journalOperations.get(0).getType()).isEqualTo(Type.DELETE); - assertThat(journalOperations.get(1).getType()).isEqualTo(Type.APPEND); - assertThat(((Append) journalOperations.get(1)).getValue()).isEqualTo(action2.toByteArray()); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedstore/internal/PersistentFeedStoreTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedstore/internal/PersistentFeedStoreTest.java deleted file mode 100644 index 7fcdeb9..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedstore/internal/PersistentFeedStoreTest.java +++ /dev/null
@@ -1,463 +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. - -package org.chromium.chrome.browser.feed.library.feedstore.internal; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.spy; -import static org.mockito.MockitoAnnotations.initMocks; - -import static org.chromium.chrome.browser.feed.library.feedstore.internal.FeedStoreConstants.SHARED_STATE_PREFIX; - -import com.google.common.collect.ImmutableList; -import com.google.protobuf.ByteString; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration; -import org.chromium.chrome.browser.feed.library.api.host.logging.InternalFeedError; -import org.chromium.chrome.browser.feed.library.api.host.storage.CommitResult; -import org.chromium.chrome.browser.feed.library.api.host.storage.ContentMutation; -import org.chromium.chrome.browser.feed.library.api.host.storage.ContentStorageDirect; -import org.chromium.chrome.browser.feed.library.api.host.storage.JournalMutation; -import org.chromium.chrome.browser.feed.library.api.host.storage.JournalStorageDirect; -import org.chromium.chrome.browser.feed.library.api.internal.common.PayloadWithId; -import org.chromium.chrome.browser.feed.library.api.internal.common.SemanticPropertiesWithId; -import org.chromium.chrome.browser.feed.library.api.internal.store.LocalActionMutation.ActionType; -import org.chromium.chrome.browser.feed.library.api.internal.store.Store; -import org.chromium.chrome.browser.feed.library.common.Result; -import org.chromium.chrome.browser.feed.library.common.concurrent.MainThreadRunner; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeMainThreadRunner; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeTaskQueue; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeThreadUtils; -import org.chromium.chrome.browser.feed.library.common.protoextensions.FeedExtensionRegistry; -import org.chromium.chrome.browser.feed.library.feedstore.testing.AbstractClearableFeedStoreTest; -import org.chromium.chrome.browser.feed.library.feedstore.testing.DelegatingContentStorage; -import org.chromium.chrome.browser.feed.library.feedstore.testing.DelegatingJournalStorage; -import org.chromium.chrome.browser.feed.library.hostimpl.storage.testing.InMemoryContentStorage; -import org.chromium.chrome.browser.feed.library.hostimpl.storage.testing.InMemoryJournalStorage; -import org.chromium.chrome.browser.feed.library.testing.host.logging.FakeBasicLoggingApi; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamFeature; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamLocalAction; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamPayload; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamSharedState; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamStructure; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamUploadableAction; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Set; - -/** - * Tests of the {@link - * org.chromium.chrome.browser.feed.library.feedstore.internal.PersistentFeedStore} class. - */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class PersistentFeedStoreTest extends AbstractClearableFeedStoreTest { - private final FakeThreadUtils mFakeThreadUtils = FakeThreadUtils.withThreadChecks(); - private final FeedExtensionRegistry mExtensionRegistry = - new FeedExtensionRegistry(ArrayList::new); - private final ContentStorageDirect mContentStorage = new InMemoryContentStorage(); - private final JournalStorageDirect mJournalStorage = new InMemoryJournalStorage(); - private final FakeBasicLoggingApi mBasicLoggingApi = new FakeBasicLoggingApi(); - private final FakeMainThreadRunner mMainThreadRunner = - FakeMainThreadRunner.runTasksImmediately(); - - private FakeTaskQueue mFakeTaskQueue; - - @Before - public void setUp() throws Exception { - initMocks(this); - mFakeTaskQueue = new FakeTaskQueue(mFakeClock, mFakeThreadUtils); - mFakeTaskQueue.initialize(() -> {}); - mFakeThreadUtils.enforceMainThread(false); - } - - @Override - protected Store getStore(MainThreadRunner mainThreadRunner) { - return new PersistentFeedStore(Configuration.getDefaultInstance(), mTimingUtils, - mExtensionRegistry, mContentStorage, mJournalStorage, mFakeTaskQueue, - mFakeThreadUtils, mFakeClock, new FeedStoreHelper(), mBasicLoggingApi, - mainThreadRunner); - } - - @Test - public void clearStorage_contentStorage_failure_getAllContent() { - ContentStorageDirect contentStorageSpy = spy(new DelegatingContentStorage(mContentStorage)); - PersistentFeedStore store = new PersistentFeedStore(Configuration.getDefaultInstance(), - mTimingUtils, mExtensionRegistry, contentStorageSpy, mJournalStorage, - mFakeTaskQueue, mFakeThreadUtils, mFakeClock, new FeedStoreHelper(), - mBasicLoggingApi, mMainThreadRunner); - doAnswer(ans -> Result.failure()).when(contentStorageSpy).getAllKeys(); - - boolean clearSuccess = store.clearNonActionContent(); - assertThat(clearSuccess).isFalse(); - } - - @Test - public void clearStorage_contentStorage_failure_commit() { - ContentStorageDirect contentStorageSpy = spy(new DelegatingContentStorage(mContentStorage)); - PersistentFeedStore store = new PersistentFeedStore(Configuration.getDefaultInstance(), - mTimingUtils, mExtensionRegistry, contentStorageSpy, mJournalStorage, - mFakeTaskQueue, mFakeThreadUtils, mFakeClock, new FeedStoreHelper(), - mBasicLoggingApi, mMainThreadRunner); - - CommitResult commitResult = store.editContent().add(CONTENT_ID, STREAM_PAYLOAD).commit(); - assertThat(commitResult).isEqualTo(CommitResult.SUCCESS); - - Result<List<PayloadWithId>> payloadsResult = - store.getPayloads(Collections.singletonList(CONTENT_ID)); - assertThat(payloadsResult.isSuccessful()).isTrue(); - assertThat(payloadsResult.getValue()).hasSize(1); - assertThat(payloadsResult.getValue().get(0).contentId).isEqualTo(CONTENT_ID); - assertThat(payloadsResult.getValue().get(0).payload).isEqualTo(STREAM_PAYLOAD); - doAnswer(ans -> CommitResult.FAILURE) - .when(contentStorageSpy) - .commit(any(ContentMutation.class)); - - boolean clearSuccess = store.clearNonActionContent(); - assertThat(clearSuccess).isFalse(); - } - - @Test - public void clearStorage_journalStorage_failure_getAllJournals() { - JournalStorageDirect journalStorageSpy = spy(new DelegatingJournalStorage(mJournalStorage)); - PersistentFeedStore store = new PersistentFeedStore(Configuration.getDefaultInstance(), - mTimingUtils, mExtensionRegistry, mContentStorage, journalStorageSpy, - mFakeTaskQueue, mFakeThreadUtils, mFakeClock, new FeedStoreHelper(), - mBasicLoggingApi, mMainThreadRunner); - - boolean commitResult = - store.editSession(SESSION_ID) - .add(StreamStructure.newBuilder().setContentId(CONTENT_ID).build()) - .commit(); - assertThat(commitResult).isTrue(); - - Result<List<String>> sessionsResult = store.getAllSessions(); - assertThat(sessionsResult.isSuccessful()).isTrue(); - assertThat(sessionsResult.getValue()).hasSize(1); - assertThat(sessionsResult.getValue().get(0)).isEqualTo(SESSION_ID); - - doAnswer(ans -> CommitResult.FAILURE) - .when(journalStorageSpy) - .commit(any(JournalMutation.class)); - - boolean clearSuccess = store.clearNonActionContent(); - assertThat(clearSuccess).isFalse(); - } - - @Test - public void clearStorage_journalStorage_failure_deleteJournal() { - JournalStorageDirect journalStorageSpy = spy(new DelegatingJournalStorage(mJournalStorage)); - PersistentFeedStore store = new PersistentFeedStore(Configuration.getDefaultInstance(), - mTimingUtils, mExtensionRegistry, mContentStorage, journalStorageSpy, - mFakeTaskQueue, mFakeThreadUtils, mFakeClock, new FeedStoreHelper(), - mBasicLoggingApi, mMainThreadRunner); - doAnswer(ans -> Result.failure()).when(journalStorageSpy).getAllJournals(); - - boolean clearSuccess = store.clearNonActionContent(); - assertThat(clearSuccess).isFalse(); - } - - @Test - public void clearStorage_allStorage() { - PersistentFeedStore store = (PersistentFeedStore) getStore(mMainThreadRunner); - - /* - SETUP - */ - - // Payload - CommitResult commitResult = store.editContent() - .add(CONTENT_ID, STREAM_PAYLOAD) - .add(CONTENT_ID_2, STREAM_PAYLOAD_2) - .commit(); - assertThat(commitResult).isEqualTo(CommitResult.SUCCESS); - - Result<List<PayloadWithId>> payloadsResult = - store.getPayloads(Arrays.asList(CONTENT_ID, CONTENT_ID_2)); - assertThat(payloadsResult.isSuccessful()).isTrue(); - assertThat(payloadsResult.getValue()).hasSize(2); - - // Semantic properties - commitResult = store.editSemanticProperties() - .add(CONTENT_ID, ByteString.copyFrom(SEMANTIC_PROPERTIES)) - .add(CONTENT_ID_2, ByteString.copyFrom(SEMANTIC_PROPERTIES_2)) - .commit(); - assertThat(commitResult).isEqualTo(CommitResult.SUCCESS); - - Result<List<SemanticPropertiesWithId>> semanticPropertiesResult = - store.getSemanticProperties(Arrays.asList(CONTENT_ID, CONTENT_ID_2)); - assertThat(semanticPropertiesResult.isSuccessful()).isTrue(); - assertThat(semanticPropertiesResult.getValue()).hasSize(2); - - // Shared State - commitResult = store.editContent() - .add(CONTENT_ID, STREAM_PAYLOAD_SHARED_STATE) - .add(CONTENT_ID_2, STREAM_PAYLOAD_SHARED_STATE_2) - .commit(); - assertThat(commitResult).isEqualTo(CommitResult.SUCCESS); - - Result<List<StreamSharedState>> sharedStatesResult = store.getSharedStates(); - assertThat(sharedStatesResult.isSuccessful()).isTrue(); - assertThat(sharedStatesResult.getValue()).hasSize(2); - - // Journal - boolean boolCommitResult = - store.editSession(SESSION_ID) - .add(StreamStructure.newBuilder().setContentId(CONTENT_ID).build()) - .commit(); - assertThat(boolCommitResult).isTrue(); - boolCommitResult = - store.editSession(SESSION_ID_2) - .add(StreamStructure.newBuilder().setContentId(CONTENT_ID_2).build()) - .commit(); - assertThat(boolCommitResult).isTrue(); - - Result<List<String>> sessionsResult = store.getAllSessions(); - assertThat(sessionsResult.isSuccessful()).isTrue(); - assertThat(sessionsResult.getValue()).hasSize(2); - - // Actions - commitResult = store.editLocalActions() - .add(ActionType.DISMISS, CONTENT_ID) - .add(ActionType.DISMISS, CONTENT_ID_2) - .commit(); - assertThat(commitResult).isEqualTo(CommitResult.SUCCESS); - - Result<List<StreamLocalAction>> dismissActionsResult = store.getAllDismissLocalActions(); - assertThat(dismissActionsResult.isSuccessful()).isTrue(); - assertThat(dismissActionsResult.getValue()).hasSize(2); - - commitResult = store.editUploadableActions() - .upsert(StreamUploadableAction.newBuilder() - .setFeatureContentId(CONTENT_ID) - .build(), - CONTENT_ID) - .upsert(StreamUploadableAction.newBuilder() - .setFeatureContentId(CONTENT_ID_2) - .build(), - CONTENT_ID_2) - .commit(); - assertThat(commitResult).isEqualTo(CommitResult.SUCCESS); - - Result<Set<StreamUploadableAction>> uploadableActionsResult = - store.getAllUploadableActions(); - assertThat(uploadableActionsResult.isSuccessful()).isTrue(); - assertThat(uploadableActionsResult.getValue()).hasSize(2); - - /* - CLEAR - */ - - assertThat(store.clearNonActionContent()).isTrue(); - - /* - VERIFICATION - */ - - // Payload - payloadsResult = store.getPayloads(Collections.singletonList(CONTENT_ID)); - assertThat(payloadsResult.isSuccessful()).isTrue(); - assertThat(payloadsResult.getValue()).hasSize(0); - - // Semantic properties (should not be cleared) - semanticPropertiesResult = - store.getSemanticProperties(Arrays.asList(CONTENT_ID, CONTENT_ID_2)); - assertThat(semanticPropertiesResult.isSuccessful()).isTrue(); - assertThat(semanticPropertiesResult.getValue()).hasSize(2); - assertThat(semanticPropertiesResult.getValue()) - .containsExactly(new SemanticPropertiesWithId(CONTENT_ID, SEMANTIC_PROPERTIES), - new SemanticPropertiesWithId(CONTENT_ID_2, SEMANTIC_PROPERTIES_2)); - - // Shared state - sharedStatesResult = store.getSharedStates(); - assertThat(sharedStatesResult.isSuccessful()).isTrue(); - assertThat(sharedStatesResult.getValue()).hasSize(0); - - // Journal - sessionsResult = store.getAllSessions(); - assertThat(sessionsResult.isSuccessful()).isTrue(); - assertThat(sessionsResult.getValue()).hasSize(0); - - // Actions (should not be cleared) - dismissActionsResult = store.getAllDismissLocalActions(); - assertThat(dismissActionsResult.isSuccessful()).isTrue(); - assertThat(dismissActionsResult.getValue()).hasSize(2); - assertThat(dismissActionsResult.getValue().get(0).getFeatureContentId()) - .isEqualTo(CONTENT_ID); - assertThat(dismissActionsResult.getValue().get(0).getAction()) - .isEqualTo(ActionType.DISMISS); - assertThat(dismissActionsResult.getValue().get(1).getFeatureContentId()) - .isEqualTo(CONTENT_ID_2); - assertThat(dismissActionsResult.getValue().get(1).getAction()) - .isEqualTo(ActionType.DISMISS); - - // UploadableActions (should be cleared) - uploadableActionsResult = store.getAllUploadableActions(); - assertThat(uploadableActionsResult.isSuccessful()).isTrue(); - assertThat(uploadableActionsResult.getValue()).isEmpty(); - } - - @Test - public void uploadActions_removedBeforeUpserted_stillUpserts() { - PersistentFeedStore store = (PersistentFeedStore) getStore(mMainThreadRunner); - - CommitResult commitResult = store.editUploadableActions() - .upsert(StreamUploadableAction.newBuilder() - .setFeatureContentId(CONTENT_ID) - .build(), - CONTENT_ID) - .upsert(StreamUploadableAction.newBuilder() - .setFeatureContentId(CONTENT_ID_2) - .build(), - CONTENT_ID_2) - .remove(StreamUploadableAction.newBuilder() - .setFeatureContentId(CONTENT_ID_2) - .build(), - CONTENT_ID_2) - .upsert(StreamUploadableAction.newBuilder() - .setFeatureContentId(CONTENT_ID_2) - .build(), - CONTENT_ID_2) - .commit(); - assertThat(commitResult).isEqualTo(CommitResult.SUCCESS); - - Result<Set<StreamUploadableAction>> uploadableActionsResult = - store.getAllUploadableActions(); - assertThat(uploadableActionsResult.isSuccessful()).isTrue(); - assertThat(uploadableActionsResult.getValue()).hasSize(2); - assertThat(uploadableActionsResult.getValue()) - .containsAtLeast( - StreamUploadableAction.newBuilder().setFeatureContentId(CONTENT_ID).build(), - StreamUploadableAction.newBuilder() - .setFeatureContentId(CONTENT_ID_2) - .build()); - } - - @Test - public void uploadActions_removedAfterCommittedUpsert_stillRemoves() { - PersistentFeedStore store = (PersistentFeedStore) getStore(mMainThreadRunner); - - CommitResult commitResult = store.editUploadableActions() - .upsert(StreamUploadableAction.newBuilder() - .setFeatureContentId(CONTENT_ID) - .build(), - CONTENT_ID) - .commit(); - - assertThat(commitResult).isEqualTo(CommitResult.SUCCESS); - Result<Set<StreamUploadableAction>> uploadableActionsResult = - store.getAllUploadableActions(); - assertThat(uploadableActionsResult.getValue()).hasSize(1); - assertThat(uploadableActionsResult.getValue()) - .contains(StreamUploadableAction.newBuilder() - .setFeatureContentId(CONTENT_ID) - .build()); - - commitResult = store.editUploadableActions() - .remove(StreamUploadableAction.newBuilder() - .setFeatureContentId(CONTENT_ID) - .build(), - CONTENT_ID) - .commit(); - assertThat(commitResult).isEqualTo(CommitResult.SUCCESS); - - uploadableActionsResult = store.getAllUploadableActions(); - assertThat(uploadableActionsResult.isSuccessful()).isTrue(); - assertThat(uploadableActionsResult.getValue()).isEmpty(); - } - - @Test - public void uploadActions_removedNonExistantAction_succeeds() { - PersistentFeedStore store = (PersistentFeedStore) getStore(mMainThreadRunner); - - CommitResult commitResult = store.editUploadableActions() - .remove(StreamUploadableAction.newBuilder() - .setFeatureContentId(CONTENT_ID) - .build(), - CONTENT_ID) - .commit(); - assertThat(commitResult).isEqualTo(CommitResult.SUCCESS); - - Result<Set<StreamUploadableAction>> uploadableActionsResult = - store.getAllUploadableActions(); - assertThat(uploadableActionsResult.isSuccessful()).isTrue(); - assertThat(uploadableActionsResult.getValue()).isEmpty(); - } - - @Test - public void getPayloads_noContent() { - Result<List<PayloadWithId>> result = - getStore(mMainThreadRunner).getPayloads(ImmutableList.of("foo")); - assertThat(result.isSuccessful()).isTrue(); - assertThat(result.getValue()).isEmpty(); - } - - @Test - public void getPayloads_withContent() { - StreamPayload streamPayload = StreamPayload.newBuilder() - .setStreamFeature(StreamFeature.getDefaultInstance()) - .build(); - mContentStorage.commit( - new ContentMutation.Builder().upsert("foo", streamPayload.toByteArray()).build()); - - Result<List<PayloadWithId>> result = - getStore(mMainThreadRunner).getPayloads(ImmutableList.of("foo")); - assertThat(result.isSuccessful()).isTrue(); - assertThat(result.getValue()).hasSize(1); - assertThat(result.getValue().get(0).payload).isEqualTo(streamPayload); - } - - @Test - public void getPayloads_cannotParse() { - mContentStorage.commit(new ContentMutation.Builder().upsert("foo", new byte[] {5}).build()); - - Result<List<PayloadWithId>> result = - getStore(mMainThreadRunner).getPayloads(ImmutableList.of("foo")); - assertThat(result.isSuccessful()).isTrue(); - assertThat(result.getValue()).isEmpty(); - assertThat(mBasicLoggingApi.lastInternalError).isEqualTo(InternalFeedError.ITEM_NOT_PARSED); - } - - @Test - public void getSharedStates_noContent() { - Result<List<StreamSharedState>> result = getStore(mMainThreadRunner).getSharedStates(); - assertThat(result.isSuccessful()).isTrue(); - assertThat(result.getValue()).isEmpty(); - } - - @Test - public void getSharedStates_withContent() { - StreamSharedState sharedState = StreamSharedState.newBuilder().setContentId("foo").build(); - mContentStorage.commit( - new ContentMutation.Builder() - .upsert(SHARED_STATE_PREFIX + "bar", sharedState.toByteArray()) - .build()); - - Result<List<StreamSharedState>> result = getStore(mMainThreadRunner).getSharedStates(); - assertThat(result.isSuccessful()).isTrue(); - assertThat(result.getValue()).containsExactly(sharedState); - } - - @Test - public void getSharedStates_cannotParse() { - mContentStorage.commit(new ContentMutation.Builder() - .upsert(SHARED_STATE_PREFIX + "bar", new byte[] {5}) - .build()); - - Result<List<StreamSharedState>> result = getStore(mMainThreadRunner).getSharedStates(); - assertThat(result.isSuccessful()).isFalse(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedstore/internal/StreamPayloadInternerTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedstore/internal/StreamPayloadInternerTest.java deleted file mode 100644 index 5761708..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedstore/internal/StreamPayloadInternerTest.java +++ /dev/null
@@ -1,86 +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. - -package org.chromium.chrome.browser.feed.library.feedstore.internal; - -import static com.google.common.truth.Truth.assertThat; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.common.intern.WeakPoolInterner; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamFeature; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamLegacyPayload; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamPayload; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamSharedState; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamToken; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests of the {@link StreamPayloadInterner} class. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class StreamPayloadInternerTest { - private final StreamPayloadInterner mInterner = - new StreamPayloadInterner(new WeakPoolInterner<>()); - - @Test - public void intern() { - StreamPayload first = - StreamPayload.newBuilder() - .setStreamFeature( - StreamFeature.newBuilder() - .setContentId(newString("foo")) - .setParentId(newString("bar")) - .setLegacyContent( - StreamLegacyPayload.newBuilder().setType("type"))) - .build(); - StreamPayload second = - StreamPayload.newBuilder() - .setStreamSharedState( - StreamSharedState.newBuilder().setContentId(newString("foo"))) - .build(); - StreamPayload third = StreamPayload.newBuilder() - .setStreamToken(StreamToken.newBuilder() - .setContentId(newString("bar")) - .setParentId(newString("foo"))) - .build(); - - // Sanity check for the newString correct working. - assertThat(first.getStreamFeature().getContentId()) - .isNotSameInstanceAs(second.getStreamSharedState().getContentId()); - assertThat(first.getStreamFeature().getContentId()) - .isEqualTo(second.getStreamSharedState().getContentId()); - - // Pool is empty so first is added/returned. - StreamPayload internedFirst = mInterner.intern(first); - assertThat(mInterner.size()).isEqualTo(2); // {foo, bar}. - assertThat(internedFirst).isSameInstanceAs(first); - - // Pool already has the "foo" content ID, which is reused. - StreamPayload internedSecond = mInterner.intern(second); - assertThat(internedSecond).isNotSameInstanceAs(second); - assertThat(internedSecond).isEqualTo(second); - // Content ID is the same as the one from first. - assertThat(mInterner.size()).isEqualTo(2); // {foo, bar}. - assertThat(internedSecond.getStreamSharedState().getContentId()) - .isSameInstanceAs(internedFirst.getStreamFeature().getContentId()); - - // Pool already has both "foo" and "bar" content IDs, which are reused. - StreamPayload internedThird = mInterner.intern(third); - assertThat(internedThird).isNotSameInstanceAs(third); - assertThat(internedThird).isEqualTo(third); - // Content IDs are both reused. - assertThat(mInterner.size()).isEqualTo(2); // {foo, bar}. - assertThat(internedThird.getStreamToken().getContentId()) - .isSameInstanceAs(internedFirst.getStreamFeature().getParentId()); - assertThat(internedThird.getStreamToken().getParentId()) - .isSameInstanceAs(internedFirst.getStreamFeature().getContentId()); - } - - // "new String()" below is called on purpose to generate different String objects. - private String newString(String input) { - return new String(input); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedstore/internal/StreamStructureInternerTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedstore/internal/StreamStructureInternerTest.java deleted file mode 100644 index 34b4adca..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedstore/internal/StreamStructureInternerTest.java +++ /dev/null
@@ -1,76 +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. - -package org.chromium.chrome.browser.feed.library.feedstore.internal; - -import static com.google.common.truth.Truth.assertThat; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.common.intern.WeakPoolInterner; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamStructure; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamStructure.Operation; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests of the {@link StreamStructureInterner} class. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class StreamStructureInternerTest { - private final StreamStructureInterner mInterner = - new StreamStructureInterner(new WeakPoolInterner<>()); - - @Test - public void intern() { - StreamStructure first = StreamStructure.newBuilder() - .setContentId(newString("foo")) - .setParentContentId(newString("bar")) - .setOperation(Operation.UPDATE_OR_APPEND) - .build(); - StreamStructure second = StreamStructure.newBuilder() - .setContentId(newString("foo")) - .setParentContentId(newString("baz")) - .setOperation(Operation.UPDATE_OR_APPEND) - .build(); - StreamStructure third = StreamStructure.newBuilder() - .setContentId(newString("bar")) - .setParentContentId(newString("foo")) - .setOperation(Operation.UPDATE_OR_APPEND) - .build(); - - // Sanity check for the newString correct working. - assertThat(first.getContentId()).isNotSameInstanceAs(second.getContentId()); - assertThat(first.getContentId()).isEqualTo(second.getContentId()); - - // Pool is empty so first is added/returned. - StreamStructure internedFirst = mInterner.intern(first); - assertThat(mInterner.size()).isEqualTo(2); // {foo, bar}. - assertThat(internedFirst).isSameInstanceAs(first); - - // Pool already has the "foo" content ID, which is reused. - StreamStructure internedSecond = mInterner.intern(second); - assertThat(internedSecond).isNotSameInstanceAs(second); - assertThat(internedSecond).isEqualTo(second); - // Content ID is the same as the one from first. - assertThat(mInterner.size()).isEqualTo(3); // {foo, bar, baz}. - assertThat(internedSecond.getContentId()).isSameInstanceAs(internedFirst.getContentId()); - - // Pool already has both "foo" and "bar" content IDs, which are reused. - StreamStructure internedThird = mInterner.intern(third); - assertThat(internedThird).isNotSameInstanceAs(third); - assertThat(internedThird).isEqualTo(third); - // Content IDs are both reused. - assertThat(mInterner.size()).isEqualTo(3); // {foo, bar, baz}. - assertThat(internedThird.getContentId()) - .isSameInstanceAs(internedFirst.getParentContentId()); - assertThat(internedThird.getParentContentId()) - .isSameInstanceAs(internedFirst.getContentId()); - } - - // "new String()" below is called on purpose to generate different String objects. - private String newString(String input) { - return new String(input); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/hostimpl/network/NetworkClientWrapperTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/hostimpl/network/NetworkClientWrapperTest.java deleted file mode 100644 index 55303a9..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/hostimpl/network/NetworkClientWrapperTest.java +++ /dev/null
@@ -1,81 +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. -package org.chromium.chrome.browser.feed.library.hostimpl.network; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.validateMockitoUsage; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import android.net.Uri; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.base.Consumer; -import org.chromium.chrome.browser.feed.library.api.host.network.HttpRequest; -import org.chromium.chrome.browser.feed.library.api.host.network.HttpRequest.HttpMethod; -import org.chromium.chrome.browser.feed.library.api.host.network.HttpResponse; -import org.chromium.chrome.browser.feed.library.api.host.network.NetworkClient; -import org.chromium.chrome.browser.feed.library.api.internal.common.ThreadUtils; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeMainThreadRunner; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.Collections; - -/** Tests of the {@link NetworkClientWrapper}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class NetworkClientWrapperTest { - @Mock - private ThreadUtils mThreadUtils; - @Mock - private NetworkClient mNetworkClient; - @Mock - private Consumer<HttpResponse> mResponseConsumer; - - private HttpRequest mRequest; - private final FakeMainThreadRunner mMainThreadRunner = FakeMainThreadRunner.queueAllTasks(); - - @Before - public void setup() { - mRequest = - new HttpRequest(Uri.EMPTY, HttpMethod.GET, Collections.emptyList(), new byte[] {}); - initMocks(this); - } - - @After - public void validate() { - validateMockitoUsage(); - } - - @Test - public void testSend_mainThread() { - when(mThreadUtils.isMainThread()).thenReturn(true); - NetworkClientWrapper wrapper = - new NetworkClientWrapper(mNetworkClient, mThreadUtils, mMainThreadRunner); - wrapper.send(mRequest, mResponseConsumer); - verify(mNetworkClient).send(mRequest, mResponseConsumer); - assertThat(mMainThreadRunner.hasTasks()).isFalse(); - } - - @Test - public void testSend_backgroundThread() { - when(mThreadUtils.isMainThread()).thenReturn(false); - NetworkClientWrapper wrapper = - new NetworkClientWrapper(mNetworkClient, mThreadUtils, mMainThreadRunner); - wrapper.send(mRequest, mResponseConsumer); - - assertThat(mMainThreadRunner.hasTasks()).isTrue(); - mMainThreadRunner.runAllTasks(); - - verify(mNetworkClient).send(mRequest, mResponseConsumer); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/hostimpl/scheduler/SchedulerApiWrapperTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/hostimpl/scheduler/SchedulerApiWrapperTest.java deleted file mode 100644 index 275b3aa..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/hostimpl/scheduler/SchedulerApiWrapperTest.java +++ /dev/null
@@ -1,110 +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. - -package org.chromium.chrome.browser.feed.library.hostimpl.scheduler; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.validateMockitoUsage; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.scheduler.SchedulerApi; -import org.chromium.chrome.browser.feed.library.api.host.scheduler.SchedulerApi.SessionState; -import org.chromium.chrome.browser.feed.library.api.internal.common.ThreadUtils; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeMainThreadRunner; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link SchedulerApiWrapper}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class SchedulerApiWrapperTest { - @Mock - private ThreadUtils mThreadUtils; - @Mock - private SchedulerApi mSchedulerApi; - private SessionState mSessionState; - - private final FakeMainThreadRunner mMainThreadRunner = - FakeMainThreadRunner.runTasksImmediately(); - - @Before - public void setup() { - mSessionState = new SessionState(false, 0L, false); - initMocks(this); - } - - @After - public void validate() { - validateMockitoUsage(); - } - - @Test - public void testShouldSessionRequestData_mainThread() { - when(mThreadUtils.isMainThread()).thenReturn(true); - SchedulerApiWrapper wrapper = - new SchedulerApiWrapper(mSchedulerApi, mThreadUtils, mMainThreadRunner); - wrapper.shouldSessionRequestData(mSessionState); - verify(mSchedulerApi).shouldSessionRequestData(mSessionState); - assertThat(mMainThreadRunner.hasTasks()).isFalse(); - } - - @Test - public void testShouldSessionRequestData_backgroundThread() { - when(mThreadUtils.isMainThread()).thenReturn(false); - SchedulerApiWrapper wrapper = - new SchedulerApiWrapper(mSchedulerApi, mThreadUtils, mMainThreadRunner); - wrapper.shouldSessionRequestData(mSessionState); - verify(mSchedulerApi).shouldSessionRequestData(mSessionState); - assertThat(mMainThreadRunner.getCompletedTaskCount()).isEqualTo(1); - } - - @Test - public void testOnReceiveNewContent_mainThread() { - when(mThreadUtils.isMainThread()).thenReturn(true); - SchedulerApiWrapper wrapper = - new SchedulerApiWrapper(mSchedulerApi, mThreadUtils, mMainThreadRunner); - wrapper.onReceiveNewContent(0); - verify(mSchedulerApi).onReceiveNewContent(0); - assertThat(mMainThreadRunner.hasTasks()).isFalse(); - } - - @Test - public void testOnReceiveNewContent_backgroundThread() { - when(mThreadUtils.isMainThread()).thenReturn(false); - SchedulerApiWrapper wrapper = - new SchedulerApiWrapper(mSchedulerApi, mThreadUtils, mMainThreadRunner); - wrapper.onReceiveNewContent(0); - verify(mSchedulerApi).onReceiveNewContent(0); - assertThat(mMainThreadRunner.getCompletedTaskCount()).isEqualTo(1); - } - - @Test - public void testOnRequestError_mainThread() { - when(mThreadUtils.isMainThread()).thenReturn(true); - SchedulerApiWrapper wrapper = - new SchedulerApiWrapper(mSchedulerApi, mThreadUtils, mMainThreadRunner); - wrapper.onRequestError(0); - verify(mSchedulerApi).onRequestError(0); - assertThat(mMainThreadRunner.hasTasks()).isFalse(); - } - - @Test - public void testOnRequestError_backgroundThread() { - when(mThreadUtils.isMainThread()).thenReturn(false); - SchedulerApiWrapper wrapper = - new SchedulerApiWrapper(mSchedulerApi, mThreadUtils, mMainThreadRunner); - wrapper.onRequestError(0); - verify(mSchedulerApi).onRequestError(0); - assertThat(mMainThreadRunner.getCompletedTaskCount()).isEqualTo(1); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/hostimpl/storage/PersistentContentStorageDirectTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/hostimpl/storage/PersistentContentStorageDirectTest.java deleted file mode 100644 index 78cd581..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/hostimpl/storage/PersistentContentStorageDirectTest.java +++ /dev/null
@@ -1,45 +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. - -package org.chromium.chrome.browser.feed.library.hostimpl.storage; - -import static org.mockito.MockitoAnnotations.initMocks; - -import android.content.Context; - -import androidx.test.core.app.ApplicationProvider; - -import com.google.common.util.concurrent.MoreExecutors; - -import org.junit.After; -import org.junit.Before; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.internal.common.ThreadUtils; -import org.chromium.chrome.browser.feed.library.testing.conformance.storage.ContentStorageDirectConformanceTest; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link PersistentContentStorage}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class PersistentContentStorageDirectTest extends ContentStorageDirectConformanceTest { - @Mock - private ThreadUtils mThreadUtils; - private Context mContext; - - @Before - public void setUp() { - initMocks(this); - mContext = ApplicationProvider.getApplicationContext(); - mStorage = new PersistentContentStorage( - mContext, MoreExecutors.newDirectExecutorService(), mThreadUtils); - } - - @After - public void tearDown() { - mContext.getFilesDir().delete(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/hostimpl/storage/PersistentContentStorageTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/hostimpl/storage/PersistentContentStorageTest.java deleted file mode 100644 index 94d3dd3..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/hostimpl/storage/PersistentContentStorageTest.java +++ /dev/null
@@ -1,45 +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. - -package org.chromium.chrome.browser.feed.library.hostimpl.storage; - -import static org.mockito.MockitoAnnotations.initMocks; - -import android.content.Context; - -import androidx.test.core.app.ApplicationProvider; - -import com.google.common.util.concurrent.MoreExecutors; - -import org.junit.After; -import org.junit.Before; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.internal.common.ThreadUtils; -import org.chromium.chrome.browser.feed.library.testing.conformance.storage.ContentStorageConformanceTest; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link PersistentContentStorage}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class PersistentContentStorageTest extends ContentStorageConformanceTest { - @Mock - private ThreadUtils mThreadUtils; - private Context mContext; - - @Before - public void setUp() { - initMocks(this); - mContext = ApplicationProvider.getApplicationContext(); - mStorage = new PersistentContentStorage( - mContext, MoreExecutors.newDirectExecutorService(), mThreadUtils); - } - - @After - public void tearDown() { - mContext.getFilesDir().delete(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/hostimpl/storage/PersistentJournalStorageDirectTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/hostimpl/storage/PersistentJournalStorageDirectTest.java deleted file mode 100644 index d6bd259..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/hostimpl/storage/PersistentJournalStorageDirectTest.java +++ /dev/null
@@ -1,60 +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. - -package org.chromium.chrome.browser.feed.library.hostimpl.storage; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.MockitoAnnotations.initMocks; - -import android.content.Context; - -import androidx.test.core.app.ApplicationProvider; - -import com.google.common.util.concurrent.MoreExecutors; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.internal.common.ThreadUtils; -import org.chromium.chrome.browser.feed.library.testing.conformance.storage.JournalStorageDirectConformanceTest; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link PersistentContentStorage}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class PersistentJournalStorageDirectTest extends JournalStorageDirectConformanceTest { - private Context mContext; - @Mock - private ThreadUtils mThreadUtils; - - @Before - public void setUp() throws Exception { - initMocks(this); - mContext = ApplicationProvider.getApplicationContext(); - mJournalStorage = new PersistentJournalStorage( - mContext, MoreExecutors.directExecutor(), mThreadUtils, null); - } - - @After - public void tearDown() { - mContext.getFilesDir().delete(); - } - - @Test - public void sanitize_and_desanitize() { - String[] reservedChars = {"|", "\\", "?", "*", "<", "\"", ":", ">"}; - for (String c : reservedChars) { - String test = "test" + c; - String sanitized = ((PersistentJournalStorage) mJournalStorage).sanitize(test); - assertThat(sanitized.contains(c)).isFalse(); - String unsanitized = ((PersistentJournalStorage) mJournalStorage).desanitize(sanitized); - assertThat(unsanitized).isEqualTo(test); - } - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/hostimpl/storage/PersistentJournalStorageTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/hostimpl/storage/PersistentJournalStorageTest.java deleted file mode 100644 index 8776096..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/hostimpl/storage/PersistentJournalStorageTest.java +++ /dev/null
@@ -1,60 +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. - -package org.chromium.chrome.browser.feed.library.hostimpl.storage; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.MockitoAnnotations.initMocks; - -import android.content.Context; - -import androidx.test.core.app.ApplicationProvider; - -import com.google.common.util.concurrent.MoreExecutors; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.internal.common.ThreadUtils; -import org.chromium.chrome.browser.feed.library.testing.conformance.storage.JournalStorageConformanceTest; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link PersistentContentStorage}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class PersistentJournalStorageTest extends JournalStorageConformanceTest { - private Context mContext; - @Mock - private ThreadUtils mThreadUtils; - - @Before - public void setUp() throws Exception { - initMocks(this); - mContext = ApplicationProvider.getApplicationContext(); - mJournalStorage = new PersistentJournalStorage( - mContext, MoreExecutors.directExecutor(), mThreadUtils, null); - } - - @After - public void tearDown() { - mContext.getFilesDir().delete(); - } - - @Test - public void sanitize_and_desanitize() { - String[] reservedChars = {"|", "\\", "?", "*", "<", "\"", ":", ">"}; - for (String c : reservedChars) { - String test = "test" + c; - String sanitized = ((PersistentJournalStorage) mJournalStorage).sanitize(test); - assertThat(sanitized.contains(c)).isFalse(); - String unsanitized = ((PersistentJournalStorage) mJournalStorage).desanitize(sanitized); - assertThat(unsanitized).isEqualTo(test); - } - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/hostimpl/storage/testing/InMemoryContentStorageDirectTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/hostimpl/storage/testing/InMemoryContentStorageDirectTest.java deleted file mode 100644 index 4c1f879..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/hostimpl/storage/testing/InMemoryContentStorageDirectTest.java +++ /dev/null
@@ -1,22 +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. - -package org.chromium.chrome.browser.feed.library.hostimpl.storage.testing; - -import org.junit.Before; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.testing.conformance.storage.ContentStorageDirectConformanceTest; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link InMemoryContentStorage}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class InMemoryContentStorageDirectTest extends ContentStorageDirectConformanceTest { - @Before - public void setUp() { - mStorage = new InMemoryContentStorage(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/hostimpl/storage/testing/InMemoryContentStorageTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/hostimpl/storage/testing/InMemoryContentStorageTest.java deleted file mode 100644 index e479a15..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/hostimpl/storage/testing/InMemoryContentStorageTest.java +++ /dev/null
@@ -1,23 +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. - -package org.chromium.chrome.browser.feed.library.hostimpl.storage.testing; - -import org.junit.Before; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.feedstore.testing.DelegatingContentStorage; -import org.chromium.chrome.browser.feed.library.testing.conformance.storage.ContentStorageConformanceTest; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link InMemoryContentStorage}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class InMemoryContentStorageTest extends ContentStorageConformanceTest { - @Before - public void setUp() { - mStorage = new DelegatingContentStorage(new InMemoryContentStorage()); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/hostimpl/storage/testing/InMemoryJournalStorageDirectTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/hostimpl/storage/testing/InMemoryJournalStorageDirectTest.java deleted file mode 100644 index 7eb2372..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/hostimpl/storage/testing/InMemoryJournalStorageDirectTest.java +++ /dev/null
@@ -1,22 +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. - -package org.chromium.chrome.browser.feed.library.hostimpl.storage.testing; - -import org.junit.Before; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.testing.conformance.storage.JournalStorageDirectConformanceTest; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link InMemoryJournalStorage}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class InMemoryJournalStorageDirectTest extends JournalStorageDirectConformanceTest { - @Before - public void setUp() { - mJournalStorage = new InMemoryJournalStorage(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/hostimpl/storage/testing/InMemoryJournalStorageTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/hostimpl/storage/testing/InMemoryJournalStorageTest.java deleted file mode 100644 index 4e60db2..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/hostimpl/storage/testing/InMemoryJournalStorageTest.java +++ /dev/null
@@ -1,26 +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. - -package org.chromium.chrome.browser.feed.library.hostimpl.storage.testing; - -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.feedstore.testing.DelegatingJournalStorage; -import org.chromium.chrome.browser.feed.library.testing.conformance.storage.JournalStorageConformanceTest; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link InMemoryJournalStorage}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class InMemoryJournalStorageTest extends JournalStorageConformanceTest { - @Before - public void setUp() { - initMocks(this); - mJournalStorage = new DelegatingJournalStorage(new InMemoryJournalStorage()); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/ClearAllTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/ClearAllTest.java deleted file mode 100644 index 313a8cb..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/ClearAllTest.java +++ /dev/null
@@ -1,108 +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. - -package org.chromium.chrome.browser.feed.library.infraintegration; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.client.lifecycle.AppLifecycleListener; -import org.chromium.chrome.browser.feed.library.api.client.requestmanager.RequestManager; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration.ConfigKey; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider.State; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProviderFactory; -import org.chromium.chrome.browser.feed.library.common.testing.InfraIntegrationScope; -import org.chromium.chrome.browser.feed.library.common.testing.ModelProviderValidator; -import org.chromium.chrome.browser.feed.library.common.testing.ResponseBuilder; -import org.chromium.chrome.browser.feed.library.testing.requestmanager.FakeFeedRequestManager; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.UiContext; -import org.chromium.components.feed.core.proto.wire.ContentIdProto.ContentId; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** This will test the behavior of clear all. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ClearAllTest { - private FakeFeedRequestManager mFakeFeedRequestManager; - private ModelProviderFactory mModelProviderFactory; - private ModelProviderValidator mModelValidator; - private AppLifecycleListener mAppLifecycleListener; - private RequestManager mRequestManager; - - @Before - public void setUp() { - initMocks(this); - Configuration configuration = - new Configuration.Builder().put(ConfigKey.LIMIT_PAGE_UPDATES, false).build(); - InfraIntegrationScope scope = - new InfraIntegrationScope.Builder().setConfiguration(configuration).build(); - mFakeFeedRequestManager = scope.getFakeFeedRequestManager(); - mRequestManager = scope.getRequestManager(); - mModelProviderFactory = scope.getModelProviderFactory(); - mAppLifecycleListener = scope.getAppLifecycleListener(); - mModelValidator = new ModelProviderValidator(scope.getProtocolAdapter()); - } - - /** - * This test creates two sessions/ModelProviders then will trigger the clear all. We then verify - * the expected behavior that the previously created ModelProviders are invalid. - */ - @Test - public void testClearAll() { - ContentId[] cards = new ContentId[] {ResponseBuilder.createFeatureContentId(1), - ResponseBuilder.createFeatureContentId(2), - ResponseBuilder.createFeatureContentId(3)}; - mFakeFeedRequestManager.queueResponse(ResponseBuilder.forClearAllWithCards(cards).build()); - mRequestManager.triggerScheduledRefresh(); - ModelProvider modelProvider1 = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - mModelValidator.assertCursorContents(modelProvider1, cards); - ModelProvider modelProvider2 = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - mModelValidator.assertCursorContents(modelProvider2, cards); - - mAppLifecycleListener.onClearAll(); - - assertThat(modelProvider1.getCurrentState()).isEqualTo(State.INVALIDATED); - assertThat(modelProvider2.getCurrentState()).isEqualTo(State.INVALIDATED); - } - - /** - * This test create a session/ModelProvider then calls clear all. It this validates validates - * creating a new empty ModelProvider and attempts to create the previously created - * ModelProvider. - */ - @Test - public void testPostClearAll() { - ContentId[] cards = new ContentId[] {ResponseBuilder.createFeatureContentId(1), - ResponseBuilder.createFeatureContentId(2), - ResponseBuilder.createFeatureContentId(3)}; - mFakeFeedRequestManager.queueResponse(ResponseBuilder.forClearAllWithCards(cards).build()); - mRequestManager.triggerScheduledRefresh(); - ModelProvider modelProvider = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - mModelValidator.assertCursorContents(modelProvider, cards); - String modelToken = modelProvider.getSessionId(); - mAppLifecycleListener.onClearAll(); - - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INVALIDATED); - - // create a new (Empty) ModelProvider - modelProvider = mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - assertThat(modelProvider.getRootFeature()).isNull(); - - // try to create the old existing ModelProvider - modelProvider = mModelProviderFactory.create(modelToken, UiContext.getDefaultInstance()); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INVALIDATED); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/ClientRequestManagerTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/ClientRequestManagerTest.java deleted file mode 100644 index 8fc696e9..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/ClientRequestManagerTest.java +++ /dev/null
@@ -1,59 +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. - -package org.chromium.chrome.browser.feed.library.infraintegration; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.client.requestmanager.RequestManager; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider; -import org.chromium.chrome.browser.feed.library.common.testing.InfraIntegrationScope; -import org.chromium.chrome.browser.feed.library.common.testing.ModelProviderValidator; -import org.chromium.chrome.browser.feed.library.common.testing.ResponseBuilder; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.UiContext; -import org.chromium.components.feed.core.proto.wire.ContentIdProto.ContentId; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** - * Integration test for {@link - * org.chromium.chrome.browser.feed.library.feedrequestmanager.RequestManagerImpl} - */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ClientRequestManagerTest { - private final InfraIntegrationScope mScope = new InfraIntegrationScope.Builder().build(); - private RequestManager mRequestManager; - private ModelProviderValidator mModelValidator; - - // Create a simple stream with a root and three features - private static final ContentId[] CARDS = new ContentId[] { - ResponseBuilder.createFeatureContentId(1), ResponseBuilder.createFeatureContentId(2), - ResponseBuilder.createFeatureContentId(3)}; - - @Before - public void setup() { - mRequestManager = mScope.getRequestManager(); - mModelValidator = new ModelProviderValidator(mScope.getProtocolAdapter()); - } - - @Test - public void testRequestManager() { - // Set up new response with 3 cards - mScope.getFakeFeedRequestManager().queueResponse( - ResponseBuilder.forClearAllWithCards(CARDS).build()); - - // Trigger refresh - mRequestManager.triggerScheduledRefresh(); - - // Create new session - ModelProvider modelProvider = - mScope.getModelProviderFactory().createNew(null, UiContext.getDefaultInstance()); - - // Model provider should now hold the cards - mModelValidator.assertCursorContents(modelProvider, CARDS); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/ContentRemoveTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/ContentRemoveTest.java deleted file mode 100644 index 8c3f1bf..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/ContentRemoveTest.java +++ /dev/null
@@ -1,112 +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. - -package org.chromium.chrome.browser.feed.library.infraintegration; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -import static org.chromium.chrome.browser.feed.library.common.testing.ResponseBuilder.ROOT_CONTENT_ID; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.client.requestmanager.RequestManager; -import org.chromium.chrome.browser.feed.library.api.common.MutationContext; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.FeatureChange; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.FeatureChangeObserver; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelCursor; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelFeature; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProviderFactory; -import org.chromium.chrome.browser.feed.library.api.internal.sessionmanager.FeedSessionManager; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeThreadUtils; -import org.chromium.chrome.browser.feed.library.common.testing.InfraIntegrationScope; -import org.chromium.chrome.browser.feed.library.common.testing.ModelProviderValidator; -import org.chromium.chrome.browser.feed.library.common.testing.ResponseBuilder; -import org.chromium.chrome.browser.feed.library.testing.requestmanager.FakeFeedRequestManager; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamToken; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.UiContext; -import org.chromium.components.feed.core.proto.wire.ConsistencyTokenProto.ConsistencyToken; -import org.chromium.components.feed.core.proto.wire.ContentIdProto.ContentId; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.List; - -/** Tests which remove content within an existing model. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ContentRemoveTest { - private final InfraIntegrationScope mScope = new InfraIntegrationScope.Builder().build(); - private final FakeFeedRequestManager mFakeFeedRequestManager = - mScope.getFakeFeedRequestManager(); - private final FakeThreadUtils mFakeThreadUtils = mScope.getFakeThreadUtils(); - private final FeedSessionManager mFeedSessionManager = mScope.getFeedSessionManager(); - private final ModelProviderFactory mModelProviderFactory = mScope.getModelProviderFactory(); - private final ModelProviderValidator mModelValidator = - new ModelProviderValidator(mScope.getProtocolAdapter()); - private final RequestManager mRequestManager = mScope.getRequestManager(); - - @Test - public void removeContent() { - // Create a simple stream with a root and four features - ContentId[] cards = new ContentId[] {ResponseBuilder.createFeatureContentId(1), - ResponseBuilder.createFeatureContentId(2), - ResponseBuilder.createFeatureContentId(3), - ResponseBuilder.createFeatureContentId(4)}; - mFakeFeedRequestManager.queueResponse(ResponseBuilder.forClearAllWithCards(cards).build()); - mRequestManager.triggerScheduledRefresh(); - - ModelProvider modelProvider = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - assertThat(modelProvider.getRootFeature()).isNotNull(); - ModelFeature rootFeature = modelProvider.getRootFeature(); - FeatureChangeObserver observer = mock(FeatureChangeObserver.class); - rootFeature.registerObserver(observer); - mModelValidator.assertCursorSize(rootFeature.getCursor(), cards.length); - - // Create cursor advanced to each spot in the list of children - ModelCursor advancedCursor0 = rootFeature.getCursor(); - ModelCursor advancedCursor1 = advanceCursor(rootFeature.getCursor(), 1); - ModelCursor advancedCursor2 = advanceCursor(rootFeature.getCursor(), 2); - ModelCursor advancedCursor3 = advanceCursor(rootFeature.getCursor(), 3); - ModelCursor advancedCursor4 = advanceCursor(rootFeature.getCursor(), 4); - - mFakeFeedRequestManager.queueResponse( - ResponseBuilder.builder().removeFeature(cards[1], ROOT_CONTENT_ID).build()); - // TODO: sessions reject removes without a CLEAR_ALL or paging with a different token. - mFakeThreadUtils.enforceMainThread(false); - mFakeFeedRequestManager.loadMore(StreamToken.getDefaultInstance(), - ConsistencyToken.getDefaultInstance(), - mFeedSessionManager.getUpdateConsumer(MutationContext.EMPTY_CONTEXT)); - - ArgumentCaptor<FeatureChange> capture = ArgumentCaptor.forClass(FeatureChange.class); - verify(observer).onChange(capture.capture()); - List<FeatureChange> featureChanges = capture.getAllValues(); - assertThat(featureChanges).hasSize(1); - FeatureChange change = featureChanges.get(0); - assertThat(change.getChildChanges().getRemovedChildren()).hasSize(1); - - mModelValidator.assertCursorContents(advancedCursor0, cards[0], cards[2], cards[3]); - mModelValidator.assertCursorContents(advancedCursor1, cards[2], cards[3]); - mModelValidator.assertCursorContents(advancedCursor2, cards[2], cards[3]); - mModelValidator.assertCursorContents(advancedCursor3, cards[3]); - mModelValidator.assertCursorContents(advancedCursor4); - - // create a cursor after the remove to verify $HEAD was modified - ModelCursor cursor = rootFeature.getCursor(); - mModelValidator.assertCursorContents(cursor, cards[0], cards[2], cards[3]); - } - - private ModelCursor advanceCursor(ModelCursor cursor, int count) { - for (int i = 0; i < count; i++) { - cursor.getNextItem(); - } - return cursor; - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/ContentUpdateTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/ContentUpdateTest.java deleted file mode 100644 index 6d12350..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/ContentUpdateTest.java +++ /dev/null
@@ -1,125 +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. - -package org.chromium.chrome.browser.feed.library.infraintegration; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.client.requestmanager.RequestManager; -import org.chromium.chrome.browser.feed.library.api.common.MutationContext; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.FeatureChange; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.FeatureChangeObserver; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelChild; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelCursor; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelFeature; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProviderFactory; -import org.chromium.chrome.browser.feed.library.api.internal.protocoladapter.ProtocolAdapter; -import org.chromium.chrome.browser.feed.library.api.internal.sessionmanager.FeedSessionManager; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeThreadUtils; -import org.chromium.chrome.browser.feed.library.common.testing.InfraIntegrationScope; -import org.chromium.chrome.browser.feed.library.common.testing.ModelProviderValidator; -import org.chromium.chrome.browser.feed.library.common.testing.ResponseBuilder; -import org.chromium.chrome.browser.feed.library.testing.requestmanager.FakeFeedRequestManager; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamToken; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.UiContext; -import org.chromium.components.feed.core.proto.wire.ConsistencyTokenProto.ConsistencyToken; -import org.chromium.components.feed.core.proto.wire.ContentIdProto.ContentId; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.ArrayList; -import java.util.List; - -/** Tests which update content within an existing model. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ContentUpdateTest { - private final InfraIntegrationScope mScope = new InfraIntegrationScope.Builder().build(); - private final FakeFeedRequestManager mFakeFeedRequestManager = - mScope.getFakeFeedRequestManager(); - private final FakeThreadUtils mFakeThreadUtils = mScope.getFakeThreadUtils(); - private final ModelProviderFactory mModelProviderFactory = mScope.getModelProviderFactory(); - private final ModelProviderValidator mModelValidator = - new ModelProviderValidator(mScope.getProtocolAdapter()); - private final ProtocolAdapter mProtocolAdapter = mScope.getProtocolAdapter(); - private final FeedSessionManager mFeedSessionManager = mScope.getFeedSessionManager(); - private final RequestManager mRequestManager = mScope.getRequestManager(); - - @Test - public void updateContent_observers() { - // Create a simple stream with a root and two features - ContentId[] cards = new ContentId[] {ResponseBuilder.createFeatureContentId(1), - ResponseBuilder.createFeatureContentId(2)}; - mFakeFeedRequestManager.queueResponse(ResponseBuilder.forClearAllWithCards(cards).build()); - mRequestManager.triggerScheduledRefresh(); - ModelProvider modelProvider = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - - ModelFeature root = modelProvider.getRootFeature(); - assertThat(root).isNotNull(); - ModelCursor cursor = root.getCursor(); - List<FeatureChangeObserver> observers = new ArrayList<>(); - List<FeatureChangeObserver> contentObservers = new ArrayList<>(); - for (ContentId contentId : cards) { - ModelChild child = cursor.getNextItem(); - assertThat(child).isNotNull(); - mModelValidator.assertStreamContentId( - child.getContentId(), mProtocolAdapter.getStreamContentId(contentId)); - mModelValidator.assertCardStructure(child); - // register observer on the card - ModelFeature feature = child.getModelFeature(); - FeatureChangeObserver observer = mock(FeatureChangeObserver.class); - observers.add(observer); - feature.registerObserver(observer); - - // register observer on the content of the card - FeatureChangeObserver contentObserver = mock(FeatureChangeObserver.class); - contentObservers.add(contentObserver); - ModelCursor cardCursor = feature.getCursor(); - ModelChild cardCursorNextItem = cardCursor.getNextItem(); - assertThat(cardCursorNextItem).isNotNull(); - cardCursorNextItem.getModelFeature().registerObserver(contentObserver); - } - assertThat(cursor.isAtEnd()).isTrue(); - - // Create an update response for the two content items - mFakeFeedRequestManager.queueResponse( - ResponseBuilder.builder().addCardsToRoot(cards).build()); - // TODO: sessions reject updates without a CLEAR_ALL or paging with a different token. - mFakeThreadUtils.enforceMainThread(false); - mFakeFeedRequestManager.loadMore(StreamToken.getDefaultInstance(), - ConsistencyToken.getDefaultInstance(), - mFeedSessionManager.getUpdateConsumer(MutationContext.EMPTY_CONTEXT)); - - int id = 0; - for (FeatureChangeObserver observer : observers) { - ArgumentCaptor<FeatureChange> capture = ArgumentCaptor.forClass(FeatureChange.class); - verify(observer).onChange(capture.capture()); - List<FeatureChange> featureChanges = capture.getAllValues(); - assertThat(featureChanges).hasSize(1); - FeatureChange change = featureChanges.get(0); - mModelValidator.assertStreamContentId( - change.getContentId(), mProtocolAdapter.getStreamContentId(cards[id])); - assertThat(change.isFeatureChanged()).isTrue(); - assertThat(change.getChildChanges().getAppendedChildren()).isEmpty(); - id++; - } - for (FeatureChangeObserver observer : contentObservers) { - ArgumentCaptor<FeatureChange> capture = ArgumentCaptor.forClass(FeatureChange.class); - verify(observer).onChange(capture.capture()); - List<FeatureChange> featureChanges = capture.getAllValues(); - assertThat(featureChanges).hasSize(1); - FeatureChange change = featureChanges.get(0); - assertThat(change.isFeatureChanged()).isTrue(); - } - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/DetachSessionTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/DetachSessionTest.java deleted file mode 100644 index 1ae0363e..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/DetachSessionTest.java +++ /dev/null
@@ -1,159 +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. - -package org.chromium.chrome.browser.feed.library.infraintegration; - -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.client.requestmanager.RequestManager; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration.ConfigKey; -import org.chromium.chrome.browser.feed.library.api.internal.common.testing.ContentIdGenerators; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelChild; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProviderFactory; -import org.chromium.chrome.browser.feed.library.common.testing.InfraIntegrationScope; -import org.chromium.chrome.browser.feed.library.common.testing.ModelProviderValidator; -import org.chromium.chrome.browser.feed.library.common.testing.PagingState; -import org.chromium.chrome.browser.feed.library.common.testing.ResponseBuilder; -import org.chromium.chrome.browser.feed.library.testing.requestmanager.FakeFeedRequestManager; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.UiContext; -import org.chromium.components.feed.core.proto.wire.ContentIdProto.ContentId; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** This will test detaching a session then updating it and reattaching to it */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class DetachSessionTest { - // Create a simple stream with a root and three features - private static final ContentId[] PAGE_1 = new ContentId[] { - ResponseBuilder.createFeatureContentId(1), ResponseBuilder.createFeatureContentId(2), - ResponseBuilder.createFeatureContentId(3)}; - private static final ContentId[] PAGE_2 = new ContentId[] { - ResponseBuilder.createFeatureContentId(4), ResponseBuilder.createFeatureContentId(5), - ResponseBuilder.createFeatureContentId(6)}; - - private FakeFeedRequestManager mFakeFeedRequestManager; - private ModelProviderFactory mModelProviderFactory; - private ModelProviderValidator mModelValidator; - private RequestManager mRequestManager; - - private final ContentIdGenerators mContentIdGenerators = new ContentIdGenerators(); - - @Before - public void setUp() { - initMocks(this); - Configuration configuration = - new Configuration.Builder().put(ConfigKey.LIMIT_PAGE_UPDATES, false).build(); - InfraIntegrationScope scope = - new InfraIntegrationScope.Builder().setConfiguration(configuration).build(); - mFakeFeedRequestManager = scope.getFakeFeedRequestManager(); - mRequestManager = scope.getRequestManager(); - mModelProviderFactory = scope.getModelProviderFactory(); - mModelValidator = new ModelProviderValidator(scope.getProtocolAdapter()); - } - - /** - * Steps in this test: - * - * <ul> - * <li>Create a sessionOne (ModelProvider) with a token - * <li>Create a sessionTwo matching sessionOne - * <li>Detach sessionOne - * <li>Create an existing session based upon sessionOne - * <li>page sessionTwo - * <li>Verify sessionTwo and the existingSession match - * </ul> - */ - @Test - public void testPagingDetachedSession() { - PagingState s1State = new PagingState(PAGE_1, PAGE_2, 1, mContentIdGenerators); - - mFakeFeedRequestManager.queueResponse(s1State.initialResponse); - mRequestManager.triggerScheduledRefresh(); - - // Create the sessionOne from page1 and a token - ModelProvider sessionOne = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - ModelChild tokenChild = mModelValidator.assertCursorContentsWithToken(sessionOne, PAGE_1); - - // Create the sessionTwo matching sessionOne - ModelProvider sessionTwo = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - mModelValidator.assertCursorContentsWithToken(sessionTwo, PAGE_1); - - // Detach sessionOne - String sessionId = sessionOne.getSessionId(); - sessionOne.detachModelProvider(); - - // recreate sessionOne as existingSession - ModelProvider existingSession = - mModelProviderFactory.create(sessionId, UiContext.getDefaultInstance()); - mModelValidator.assertCursorContentsWithToken(existingSession, PAGE_1); - - // page the sessionTwo - mFakeFeedRequestManager.queueResponse(s1State.pageResponse); - sessionTwo.handleToken(tokenChild.getModelToken()); - - // verify that existingSession and sessionTwo match - mModelValidator.assertCursorContents( - sessionTwo, PAGE_1[0], PAGE_1[1], PAGE_1[2], PAGE_2[0], PAGE_2[1], PAGE_2[2]); - mModelValidator.assertCursorContents( - existingSession, PAGE_1[0], PAGE_1[1], PAGE_1[2], PAGE_2[0], PAGE_2[1], PAGE_2[2]); - } - - /** - * This test differs from the previous test by paging sessionTwo while sessionOne is detached - * and then creating the existing session. These should still match. - * - * <ul> - * <li>Create a sessionOne (ModelProvider) with a token - * <li>Create a sessionTwo matching sessionOne - * <li>Detach sessionOne - * <li>page sessionTwo - * <li>Create an existing session based upon sessionOne - * <li>Verify sessionTwo and the existingSession match - * </ul> - */ - @Test - public void testPagingDetachedSession_pageWhileDetached() { - PagingState s1State = new PagingState(PAGE_1, PAGE_2, 1, mContentIdGenerators); - - mFakeFeedRequestManager.queueResponse(s1State.initialResponse); - mRequestManager.triggerScheduledRefresh(); - - // Create the sessionOne from page1 and a token - ModelProvider sessionOne = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - ModelChild tokenChild = mModelValidator.assertCursorContentsWithToken(sessionOne, PAGE_1); - - // Create the sessionTwo matching sessionOne - ModelProvider sessionTwo = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - mModelValidator.assertCursorContentsWithToken(sessionTwo, PAGE_1); - - // Detach sessionOne - String sessionId = sessionOne.getSessionId(); - sessionOne.detachModelProvider(); - - // page the sessionTwo - mFakeFeedRequestManager.queueResponse(s1State.pageResponse); - sessionTwo.handleToken(tokenChild.getModelToken()); - - // recreate sessionOne as existingSession - ModelProvider existingSession = - mModelProviderFactory.create(sessionId, UiContext.getDefaultInstance()); - - // verify that existingSession and sessionTwo match - mModelValidator.assertCursorContents( - sessionTwo, PAGE_1[0], PAGE_1[1], PAGE_1[2], PAGE_2[0], PAGE_2[1], PAGE_2[2]); - mModelValidator.assertCursorContents( - existingSession, PAGE_1[0], PAGE_1[1], PAGE_1[2], PAGE_2[0], PAGE_2[1], PAGE_2[2]); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/EmptyStreamTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/EmptyStreamTest.java deleted file mode 100644 index 71ee684..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/EmptyStreamTest.java +++ /dev/null
@@ -1,127 +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. - -package org.chromium.chrome.browser.feed.library.infraintegration; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.client.requestmanager.RequestManager; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider.State; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProviderFactory; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProviderObserver; -import org.chromium.chrome.browser.feed.library.common.concurrent.TaskQueue; -import org.chromium.chrome.browser.feed.library.common.testing.InfraIntegrationScope; -import org.chromium.chrome.browser.feed.library.common.testing.ResponseBuilder; -import org.chromium.chrome.browser.feed.library.common.testing.ResponseBuilder.WireProtocolInfo; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.testing.requestmanager.FakeFeedRequestManager; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.UiContext; -import org.chromium.components.feed.core.proto.libraries.testing.UiContextForTestProto.UiContextForTest; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Test which verifies the ModelProvider state for the empty stream cases. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class EmptyStreamTest { - private FakeClock mFakeClock; - private FakeFeedRequestManager mFakeFeedRequestManager; - private ModelProviderFactory mModelProviderFactory; - private RequestManager mRequestManager; - - @Before - public void setUp() { - initMocks(this); - InfraIntegrationScope scope = new InfraIntegrationScope.Builder().build(); - mFakeClock = scope.getFakeClock(); - mFakeFeedRequestManager = scope.getFakeFeedRequestManager(); - mModelProviderFactory = scope.getModelProviderFactory(); - mRequestManager = scope.getRequestManager(); - } - - @Test - public void emptyStream_observable() { - // ModelProvider will be initialized from empty $HEAD - ModelProvider modelProvider = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - assertThat(modelProvider.getRootFeature()).isNull(); - ModelProviderObserver observer = mock(ModelProviderObserver.class); - modelProvider.registerObserver(observer); - verify(observer).onSessionStart(UiContext.getDefaultInstance()); - } - - @Test - public void emptyStream_usesGivenUiContext() { - // ModelProvider will be initialized with the given UiContext. - UiContext uiContext = UiContext.newBuilder() - .setExtension(UiContextForTest.uiContextForTest, - UiContextForTest.newBuilder().setValue(2).build()) - .build(); - ModelProvider modelProvider = mModelProviderFactory.createNew(null, uiContext); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - assertThat(modelProvider.getRootFeature()).isNull(); - ModelProviderObserver observer = mock(ModelProviderObserver.class); - modelProvider.registerObserver(observer); - verify(observer).onSessionStart(uiContext); - } - - @Test - public void emptyStream_observableInvalidate() { - // Verify both ModelProviderObserver events are called - ModelProvider modelProvider = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - ModelProviderObserver observer = mock(ModelProviderObserver.class); - modelProvider.registerObserver(observer); - verify(observer).onSessionStart(UiContext.getDefaultInstance()); - modelProvider.invalidate(); - verify(observer).onSessionFinished(UiContext.getDefaultInstance()); - } - - @Test - public void emptyStream_unregisterObservable() { - // Verify unregister works, so the ModelProviderObserver is not called for invalidate - ModelProvider modelProvider = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - ModelProviderObserver observer = mock(ModelProviderObserver.class); - modelProvider.registerObserver(observer); - verify(observer).onSessionStart(UiContext.getDefaultInstance()); - modelProvider.unregisterObserver(observer); - modelProvider.invalidate(); - verify(observer, never()).onSessionFinished(UiContext.getDefaultInstance()); - } - - @Test - public void emptyStream_emptyResponse() { - // Create an empty stream through a response - ResponseBuilder responseBuilder = new ResponseBuilder(); - mFakeFeedRequestManager.queueResponse(responseBuilder.build()); - mRequestManager.triggerScheduledRefresh(); - - mFakeClock.advance(TaskQueue.STARVATION_TIMEOUT_MS); - ModelProvider modelProvider = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - - assertThat(modelProvider).isNotNull(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - assertThat(modelProvider.getRootFeature()).isNull(); - - WireProtocolInfo protocolInfo = responseBuilder.getWireProtocolInfo(); - // No features added - assertThat(protocolInfo.featuresAdded).hasSize(0); - assertThat(protocolInfo.hasClearOperation).isFalse(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/ExistingSessionTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/ExistingSessionTest.java deleted file mode 100644 index 45346221b..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/ExistingSessionTest.java +++ /dev/null
@@ -1,195 +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. - -package org.chromium.chrome.browser.feed.library.infraintegration; - -import static com.google.common.truth.Truth.assertThat; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.common.MutationContext; -import org.chromium.chrome.browser.feed.library.api.host.logging.RequestReason; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelCursor; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelFeature; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider.State; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProviderFactory; -import org.chromium.chrome.browser.feed.library.common.testing.InfraIntegrationScope; -import org.chromium.chrome.browser.feed.library.common.testing.ModelProviderValidator; -import org.chromium.chrome.browser.feed.library.common.testing.ResponseBuilder; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.UiContext; -import org.chromium.components.feed.core.proto.wire.ContentIdProto.ContentId; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests which verify creating a new Model Provider from an existing session. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ExistingSessionTest { - private static final ContentId[] CARDS = new ContentId[] { - ResponseBuilder.createFeatureContentId(1), ResponseBuilder.createFeatureContentId(2), - ResponseBuilder.createFeatureContentId(3)}; - - private final InfraIntegrationScope mScope = new InfraIntegrationScope.Builder().build(); - private final ModelProviderFactory mModelProviderFactory = mScope.getModelProviderFactory(); - private final ModelProviderValidator mModelValidator = - new ModelProviderValidator(mScope.getProtocolAdapter()); - - @Before - public void setUp() { - // Create a simple stream with a root and three features - mScope.getFakeFeedRequestManager() - .queueResponse(ResponseBuilder.forClearAllWithCards(CARDS).build()) - .triggerRefresh(RequestReason.OPEN_WITHOUT_CONTENT, - mScope.getFeedSessionManager().getUpdateConsumer( - MutationContext.EMPTY_CONTEXT)); - } - - @After - public void tearDown() { - assertThat(mScope.getTaskQueue().hasBacklog()).isFalse(); - assertThat(mScope.getFakeMainThreadRunner().hasPendingTasks()).isFalse(); - } - - @Test - public void createModelProvider() { - ModelProvider modelProvider = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - - ModelFeature initRoot = modelProvider.getRootFeature(); - assertThat(initRoot).isNotNull(); - ModelCursor initCursor = initRoot.getCursor(); - assertThat(initCursor).isNotNull(); - - String sessionId = modelProvider.getSessionId(); - assertThat(sessionId).isNotEmpty(); - - ModelProvider modelProvider2 = - mModelProviderFactory.create(sessionId, UiContext.getDefaultInstance()); - assertThat(modelProvider2).isNotNull(); - ModelFeature root2 = modelProvider2.getRootFeature(); - assertThat(root2).isNotNull(); - ModelCursor cursor2 = root2.getCursor(); - assertThat(cursor2).isNotNull(); - assertThat(modelProvider2.getSessionId()).isEqualTo(sessionId); - mModelValidator.assertCursorContents(cursor2, CARDS); - - // Creating the new session will invalidate the previous ModelProvider and Cursor - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INVALIDATED); - assertThat(initCursor.isAtEnd()).isTrue(); - } - - @Test - public void createModelProvider_restoreSession() { - ModelProvider modelProvider = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - String sessionId = modelProvider.getSessionId(); - modelProvider.detachModelProvider(); - - // Restore the session. - ModelProvider restoredModelProvider = - mModelProviderFactory.create(sessionId, UiContext.getDefaultInstance()); - assertThat(restoredModelProvider).isNotNull(); - assertThat(restoredModelProvider.getAllRootChildren()).hasSize(CARDS.length); - } - - @Test - public void createModelProvider_restoreSessionWithOutstandingRequest() { - ModelProvider modelProvider = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - String sessionId = modelProvider.getSessionId(); - modelProvider.detachModelProvider(); - - // Start a request. - mScope.getFakeFeedRequestManager() - .queueResponse( - ResponseBuilder.forClearAllWithCards(CARDS).build(), /* delayMs= */ 100) - .triggerRefresh(RequestReason.OPEN_WITHOUT_CONTENT, - mScope.getFeedSessionManager().getUpdateConsumer( - MutationContext.EMPTY_CONTEXT)); - - // Restore the session. - ModelProvider restoredModelProvider = - mModelProviderFactory.create(sessionId, UiContext.getDefaultInstance()); - assertThat(restoredModelProvider.getAllRootChildren()).hasSize(CARDS.length); - - // Advance the clock to process the outstanding request. - mScope.getFakeClock().advance(100); - } - - @Test - public void createModelProvider_unknownSession() { - ModelProvider modelProvider = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - - ModelFeature initRoot = modelProvider.getRootFeature(); - assertThat(initRoot).isNotNull(); - ModelCursor initCursor = initRoot.getCursor(); - assertThat(initCursor).isNotNull(); - - String sessionId = modelProvider.getSessionId(); - assertThat(sessionId).isNotEmpty(); - - // Create a second model provider using an unknown session token, this should return null - ModelProvider modelProvider2 = - mModelProviderFactory.create("unknown-session", UiContext.getDefaultInstance()); - assertThat(modelProvider2).isNotNull(); - assertThat(modelProvider2.getCurrentState()).isEqualTo(State.INVALIDATED); - - // Now create one from head - modelProvider2 = mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - assertThat(modelProvider2).isNotNull(); - ModelFeature root2 = modelProvider2.getRootFeature(); - assertThat(root2).isNotNull(); - ModelCursor cursor2 = root2.getCursor(); - assertThat(cursor2).isNotNull(); - mModelValidator.assertCursorContents(cursor2, CARDS); - - // two sessions against the same $HEAD instance - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - assertThat(modelProvider2.getCurrentState()).isEqualTo(State.READY); - } - - @Test - public void createModelProvider_invalidatedSession() { - ModelProvider modelProvider = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - assertThat(modelProvider).isNotNull(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - String sessionId = modelProvider.getSessionId(); - assertThat(sessionId).isNotEmpty(); - - modelProvider.invalidate(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INVALIDATED); - - // Attempt to connect with the session token we just invalidated. This will result in a - // INVALIDATED ModelProvider. - ModelProvider modelProvider2 = - mModelProviderFactory.create(sessionId, UiContext.getDefaultInstance()); - assertThat(modelProvider2).isNotNull(); - assertThat(modelProvider2.getCurrentState()).isEqualTo(State.INVALIDATED); - } - - @Test - public void createModelProvider_detachSession() { - ModelProvider modelProvider = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - assertThat(modelProvider).isNotNull(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - String sessionId = modelProvider.getSessionId(); - assertThat(sessionId).isNotEmpty(); - - modelProvider.detachModelProvider(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INVALIDATED); - - // Attempt to connect with the session token we just detached. This will work as expected. - ModelProvider modelProvider2 = - mModelProviderFactory.create(sessionId, UiContext.getDefaultInstance()); - assertThat(modelProvider2).isNotNull(); - assertThat(modelProvider2.getCurrentState()).isEqualTo(State.READY); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/FilterHeadTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/FilterHeadTest.java deleted file mode 100644 index c640165..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/FilterHeadTest.java +++ /dev/null
@@ -1,83 +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. - -package org.chromium.chrome.browser.feed.library.infraintegration; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.base.Consumer; -import org.chromium.base.Function; -import org.chromium.chrome.browser.feed.library.api.client.requestmanager.RequestManager; -import org.chromium.chrome.browser.feed.library.api.internal.sessionmanager.FeedSessionManager; -import org.chromium.chrome.browser.feed.library.common.testing.InfraIntegrationScope; -import org.chromium.chrome.browser.feed.library.common.testing.ResponseBuilder; -import org.chromium.chrome.browser.feed.library.testing.requestmanager.FakeFeedRequestManager; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamFeature; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamPayload; -import org.chromium.components.feed.core.proto.wire.ContentIdProto.ContentId; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests of the {@link FeedSessionManager#getStreamFeaturesFromHead(Function, Consumer)} method. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class FilterHeadTest { - private FakeFeedRequestManager mFakeFeedRequestManager; - - private FeedSessionManager mFeedSessionManager; - private RequestManager mRequestManager; - - @Before - public void setUp() { - initMocks(this); - InfraIntegrationScope scope = new InfraIntegrationScope.Builder().build(); - mFakeFeedRequestManager = scope.getFakeFeedRequestManager(); - mFeedSessionManager = scope.getFeedSessionManager(); - mRequestManager = scope.getRequestManager(); - } - - @Test - public void testFiltering() { - ContentId[] cards = new ContentId[] { - ResponseBuilder.createFeatureContentId(1), - ResponseBuilder.createFeatureContentId(2), - ResponseBuilder.createFeatureContentId(3), - ResponseBuilder.createFeatureContentId(4), - ResponseBuilder.createFeatureContentId(5), - }; - - mFakeFeedRequestManager.queueResponse(ResponseBuilder.forClearAllWithCards(cards).build()); - mRequestManager.triggerScheduledRefresh(); - - mFeedSessionManager.getStreamFeaturesFromHead(mTransformer, result -> { - assertThat(result.isSuccessful()).isTrue(); - assertThat(result.getValue()).hasSize(11); - }); - - // only return the contentId of the Content cards - mFeedSessionManager.getStreamFeaturesFromHead(mToContent, result -> { - assertThat(result.isSuccessful()).isTrue(); - assertThat(result.getValue()).hasSize(5); - }); - } - - // Return only StreamFeatures - private Function<StreamPayload, /*@Nullable*/ StreamFeature> mTransformer = streamPayload - -> streamPayload.hasStreamFeature() ? streamPayload.getStreamFeature() : null; - - // Return the contentId from a feature with a RenderableUnit type of CONTENT - private Function<StreamPayload, /*@Nullable*/ String> mToContent = streamPayload -> { - if (!streamPayload.hasStreamFeature()) { - return null; - } - StreamFeature streamFeature = streamPayload.getStreamFeature(); - return streamFeature.hasContent() ? streamFeature.getContentId() : null; - }; -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/GcTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/GcTest.java deleted file mode 100644 index 1a0cdcd..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/GcTest.java +++ /dev/null
@@ -1,207 +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. - -package org.chromium.chrome.browser.feed.library.infraintegration; - -import static com.google.common.truth.Truth.assertThat; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.common.MutationContext; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration.ConfigKey; -import org.chromium.chrome.browser.feed.library.api.host.logging.RequestReason; -import org.chromium.chrome.browser.feed.library.api.host.scheduler.SchedulerApi.RequestBehavior; -import org.chromium.chrome.browser.feed.library.api.internal.common.PayloadWithId; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeThreadUtils; -import org.chromium.chrome.browser.feed.library.common.testing.InfraIntegrationScope; -import org.chromium.chrome.browser.feed.library.common.testing.ResponseBuilder; -import org.chromium.chrome.browser.feed.library.testing.host.scheduler.FakeSchedulerApi; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamSharedState; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.UiContext; -import org.chromium.components.feed.core.proto.wire.ContentIdProto.ContentId; -import org.chromium.components.feed.core.proto.wire.ResponseProto.Response; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.time.Duration; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** Tests that assert the behavior of garbage collection. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public final class GcTest { - private static final ContentId PIET_SHARED_STATE_1 = - ContentId.newBuilder() - .setContentDomain("piet-shared-state") - .setId(1) - .setTable("feature") - .build(); - private static final ContentId PIET_SHARED_STATE_2 = - ContentId.newBuilder() - .setContentDomain("piet-shared-state") - .setId(2) - .setTable("feature") - .build(); - private static final ContentId[] REQUEST_1 = new ContentId[] { - ResponseBuilder.createFeatureContentId(1), ResponseBuilder.createFeatureContentId(2)}; - private static final ContentId[] REQUEST_2 = new ContentId[] { - ResponseBuilder.createFeatureContentId(3), ResponseBuilder.createFeatureContentId(4)}; - private static final long LIFETIME_MS = Duration.ofHours(1).toMillis(); - private static final long TIMEOUT_MS = Duration.ofSeconds(5).toMillis(); - - private final Configuration mConfiguration = - new Configuration.Builder().put(ConfigKey.SESSION_LIFETIME_MS, LIFETIME_MS).build(); - private final InfraIntegrationScope mScope = - new InfraIntegrationScope.Builder() - .setConfiguration(mConfiguration) - .withTimeoutSessionConfiguration(TIMEOUT_MS) - .build(); - - @Test - public void testGc_contentInLiveSessionRetained() { - mScope.getFakeFeedRequestManager() - .queueResponse(createResponse(REQUEST_1, PIET_SHARED_STATE_1)) - .triggerRefresh(RequestReason.OPEN_WITHOUT_CONTENT, - mScope.getFeedSessionManager().getUpdateConsumer( - MutationContext.EMPTY_CONTEXT)); - - // Create a new session based on this request. - mScope.getModelProviderFactory() - .createNew(/* viewDepthProvider= */ null, UiContext.getDefaultInstance()) - .detachModelProvider(); - assertPayloads(REQUEST_1, mScope, /* shouldExist= */ true); - - // Populate HEAD with new data. - mScope.getFakeFeedRequestManager() - .queueResponse(createResponse(REQUEST_2, PIET_SHARED_STATE_2)) - .triggerRefresh(RequestReason.OPEN_WITHOUT_CONTENT, - mScope.getFeedSessionManager().getUpdateConsumer( - MutationContext.EMPTY_CONTEXT)); - - // Advance the clock without expiring the first session. - mScope.getFakeClock().advance(LIFETIME_MS / 2); - InfraIntegrationScope secondScope = mScope.clone(); - assertPayloads(REQUEST_1, secondScope, /* shouldExist= */ true); - assertSharedStates( - new ContentId[] {PIET_SHARED_STATE_1}, secondScope, /* shouldExist= */ true); - assertPayloads(REQUEST_2, secondScope, /* shouldExist= */ true); - assertSharedStates( - new ContentId[] {PIET_SHARED_STATE_2}, secondScope, /* shouldExist= */ true); - } - - @Test - public void testGc_contentInExpiredSessionDeleted() { - mScope.getFakeFeedRequestManager() - .queueResponse(createResponse(REQUEST_1, PIET_SHARED_STATE_1)) - .triggerRefresh(RequestReason.OPEN_WITHOUT_CONTENT, - mScope.getFeedSessionManager().getUpdateConsumer( - MutationContext.EMPTY_CONTEXT)); - - // Create a new session based on this request. - mScope.getModelProviderFactory() - .createNew(/* viewDepthProvider= */ null, UiContext.getDefaultInstance()) - .detachModelProvider(); - assertPayloads(REQUEST_1, mScope, /* shouldExist= */ true); - - // Populate HEAD with new data. - mScope.getFakeFeedRequestManager() - .queueResponse(createResponse(REQUEST_2, PIET_SHARED_STATE_2)) - .triggerRefresh(RequestReason.OPEN_WITHOUT_CONTENT, - mScope.getFeedSessionManager().getUpdateConsumer( - MutationContext.EMPTY_CONTEXT)); - - // Advance the clock to expire the first session, create a new scope that will run - // initialization and delete content from the expired session. - mScope.getFakeClock().advance(LIFETIME_MS + 1L); - InfraIntegrationScope secondScope = mScope.clone(); - assertPayloads(REQUEST_1, secondScope, /* shouldExist= */ false); - assertSharedStates( - new ContentId[] {PIET_SHARED_STATE_1}, secondScope, /* shouldExist= */ false); - assertPayloads(REQUEST_2, secondScope, /* shouldExist= */ true); - assertSharedStates( - new ContentId[] {PIET_SHARED_STATE_2}, secondScope, /* shouldExist= */ true); - } - - @Test - public void testGc_contentBranchedMidInitializationRetained() { - InfraIntegrationScope scope = - new InfraIntegrationScope.Builder() - .setConfiguration(mConfiguration) - .setSchedulerApi( - new FakeSchedulerApi(FakeThreadUtils.withoutThreadChecks()) - .setRequestBehavior(RequestBehavior.REQUEST_WITH_CONTENT)) - .withQueuingTasks() - .withTimeoutSessionConfiguration(TIMEOUT_MS) - .build(); - - // Populate HEAD with REQUEST_1. - scope.getFakeFeedRequestManager() - .queueResponse(createResponse(REQUEST_1, PIET_SHARED_STATE_1)) - .triggerRefresh(RequestReason.OPEN_WITHOUT_CONTENT, - scope.getFeedSessionManager().getUpdateConsumer( - MutationContext.EMPTY_CONTEXT)); - scope.getFakeDirectExecutor().runAllTasks(); - - // Make a new scope and enqueue a request to be sent on the next new session. GC should run - // after the new session is created and branched off a HEAD containing REQUEST_1. - InfraIntegrationScope secondScope = scope.clone(); - secondScope.getFakeFeedRequestManager().queueResponse( - createResponse(REQUEST_2, PIET_SHARED_STATE_2)); - secondScope.getModelProviderFactory().createNew( - /* viewDepthProvider= */ null, UiContext.getDefaultInstance()); - secondScope.getFakeDirectExecutor().runAllTasks(); - assertThat(secondScope.getFakeDirectExecutor().hasTasks()).isFalse(); - assertPayloads(REQUEST_1, secondScope, /* shouldExist= */ true); - assertPayloads(REQUEST_2, secondScope, /* shouldExist= */ true); - } - - private static void assertPayloads( - ContentId[] contentIds, InfraIntegrationScope scope, boolean shouldExist) { - scope.getFakeThreadUtils().enforceMainThread(false); - for (ContentId contentId : contentIds) { - List<PayloadWithId> payloads = - scope.getStore() - .getPayloads(Arrays.asList(new String[] { - scope.getProtocolAdapter().getStreamContentId(contentId)})) - .getValue(); - if (shouldExist) { - assertThat(payloads).hasSize(1); - } else { - assertThat(payloads).isEmpty(); - } - } - } - - private static void assertSharedStates( - ContentId[] contentIds, InfraIntegrationScope scope, boolean shouldExist) { - scope.getFakeThreadUtils().enforceMainThread(false); - List<String> sharedStateContentIds = new ArrayList<>(); - for (StreamSharedState streamSharedState : scope.getStore().getSharedStates().getValue()) { - sharedStateContentIds.add(streamSharedState.getContentId()); - } - List<String> expectedContentIds = new ArrayList<>(contentIds.length); - for (ContentId contentId : contentIds) { - expectedContentIds.add(scope.getProtocolAdapter().getStreamContentId(contentId)); - } - - if (shouldExist) { - assertThat(sharedStateContentIds).containsAtLeastElementsIn(expectedContentIds); - } else { - assertThat(sharedStateContentIds).containsNoneIn(expectedContentIds); - } - } - - private static Response createResponse(ContentId[] cards, ContentId pietSharedStateContentId) { - return ResponseBuilder.builder() - .addClearOperation() - .addPietSharedState(pietSharedStateContentId) - .addRootFeature() - .addCardsToRoot(cards) - .build(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/LimitedPagingTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/LimitedPagingTest.java deleted file mode 100644 index d7aa84a..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/LimitedPagingTest.java +++ /dev/null
@@ -1,105 +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. - -package org.chromium.chrome.browser.feed.library.infraintegration; - -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.client.requestmanager.RequestManager; -import org.chromium.chrome.browser.feed.library.api.internal.common.testing.ContentIdGenerators; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelChild; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProviderFactory; -import org.chromium.chrome.browser.feed.library.common.testing.InfraIntegrationScope; -import org.chromium.chrome.browser.feed.library.common.testing.ModelProviderValidator; -import org.chromium.chrome.browser.feed.library.common.testing.PagingState; -import org.chromium.chrome.browser.feed.library.common.testing.ResponseBuilder; -import org.chromium.chrome.browser.feed.library.testing.requestmanager.FakeFeedRequestManager; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.UiContext; -import org.chromium.components.feed.core.proto.wire.ContentIdProto.ContentId; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Test which verifies that multiple session page correctly when limited paging is on. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class LimitedPagingTest { - // Create a simple stream with a root and three features - private static final ContentId[] PAGE_1 = new ContentId[] { - ResponseBuilder.createFeatureContentId(1), ResponseBuilder.createFeatureContentId(2), - ResponseBuilder.createFeatureContentId(3)}; - private static final ContentId[] PAGE_2 = new ContentId[] { - ResponseBuilder.createFeatureContentId(4), ResponseBuilder.createFeatureContentId(5), - ResponseBuilder.createFeatureContentId(6)}; - - private FakeFeedRequestManager mFakeFeedRequestManager; - private ModelProviderFactory mModelProviderFactory; - private ModelProviderValidator mModelValidator; - private RequestManager mRequestManager; - - private final ContentIdGenerators mContentIdGenerators = new ContentIdGenerators(); - - @Before - public void setUp() { - initMocks(this); - InfraIntegrationScope scope = new InfraIntegrationScope.Builder().build(); - mFakeFeedRequestManager = scope.getFakeFeedRequestManager(); - mModelProviderFactory = scope.getModelProviderFactory(); - mModelValidator = new ModelProviderValidator(scope.getProtocolAdapter()); - mRequestManager = scope.getRequestManager(); - } - - @Test - public void testPagingDetachedSession() { - PagingState s1State = new PagingState(PAGE_1, PAGE_2, 1, mContentIdGenerators); - mFakeFeedRequestManager.queueResponse(s1State.initialResponse); - mRequestManager.triggerScheduledRefresh(); - - // Create the sessionOne from page1 and a token - ModelProvider sessionOne = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - ModelChild tokenChild = mModelValidator.assertCursorContentsWithToken(sessionOne, PAGE_1); - - // Create the sessionTwo matching sessionOne - ModelProvider sessionTwo = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - mModelValidator.assertCursorContentsWithToken(sessionTwo, PAGE_1); - - // Now Page session one and verify both session are as expected, only session one will - // contain the paged content - mFakeFeedRequestManager.queueResponse(s1State.pageResponse); - sessionOne.handleToken(tokenChild.getModelToken()); - - // Create the sessionOne from page1 and a token - mModelValidator.assertCursorContents( - sessionOne, PAGE_1[0], PAGE_1[1], PAGE_1[2], PAGE_2[0], PAGE_2[1], PAGE_2[2]); - mModelValidator.assertCursorContentsWithToken(sessionTwo, PAGE_1); - - // Now create a new session from $HEAD to verify that the page response was added to $HEAD - ModelProvider sessionThree = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - mModelValidator.assertCursorContents( - sessionThree, PAGE_1[0], PAGE_1[1], PAGE_1[2], PAGE_2[0], PAGE_2[1], PAGE_2[2]); - - // Page session two, this should not change anything else - mFakeFeedRequestManager.queueResponse(s1State.pageResponse); - sessionTwo.handleToken(tokenChild.getModelToken()); - mModelValidator.assertCursorContents( - sessionOne, PAGE_1[0], PAGE_1[1], PAGE_1[2], PAGE_2[0], PAGE_2[1], PAGE_2[2]); - mModelValidator.assertCursorContents( - sessionTwo, PAGE_1[0], PAGE_1[1], PAGE_1[2], PAGE_2[0], PAGE_2[1], PAGE_2[2]); - mModelValidator.assertCursorContents( - sessionThree, PAGE_1[0], PAGE_1[1], PAGE_1[2], PAGE_2[0], PAGE_2[1], PAGE_2[2]); - - // Verify that paging session two did not update $HEAD - ModelProvider sessionFour = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - mModelValidator.assertCursorContents( - sessionFour, PAGE_1[0], PAGE_1[1], PAGE_1[2], PAGE_2[0], PAGE_2[1], PAGE_2[2]); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/MultiSessionPagingTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/MultiSessionPagingTest.java deleted file mode 100644 index f31b35c..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/MultiSessionPagingTest.java +++ /dev/null
@@ -1,154 +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. - -package org.chromium.chrome.browser.feed.library.infraintegration; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.MockitoAnnotations.initMocks; - -import com.google.protobuf.ByteString; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.client.requestmanager.RequestManager; -import org.chromium.chrome.browser.feed.library.api.common.MutationContext; -import org.chromium.chrome.browser.feed.library.api.host.logging.RequestReason; -import org.chromium.chrome.browser.feed.library.api.internal.common.testing.ContentIdGenerators; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelChild; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider.State; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProviderFactory; -import org.chromium.chrome.browser.feed.library.api.internal.sessionmanager.FeedSessionManager; -import org.chromium.chrome.browser.feed.library.common.testing.InfraIntegrationScope; -import org.chromium.chrome.browser.feed.library.common.testing.ModelProviderValidator; -import org.chromium.chrome.browser.feed.library.common.testing.PagingState; -import org.chromium.chrome.browser.feed.library.common.testing.ResponseBuilder; -import org.chromium.chrome.browser.feed.library.common.testing.ResponseBuilder.WireProtocolInfo; -import org.chromium.chrome.browser.feed.library.testing.requestmanager.FakeFeedRequestManager; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.UiContext; -import org.chromium.components.feed.core.proto.wire.ContentIdProto.ContentId; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.nio.charset.Charset; - -/** - * This test will create multiple sessions with different content in each. It will then page each - * session with different tokens to verify that paging sessions doesn't affect sessions without the - * paging token. - * - * <p>The test runs the following tasks: - * - * <ol> - * <li>Create the initial response and page response for Session 1 and 2, including tokens - * <li>Create Session 1 and $HEAD from Session 1 initial response - * <li>Create Session 2 from $HEAD (Session 1 initial response) - * <li>Refresh Session 2 (directly using the protocol adapter) using Session 2 initial response. - * This creates a new $HEAD and invalidates the Session 2 Model Provider - * <li>Create a new Session 2 against the new $HEAD - * <li>Validate that Session 1 and 2 have the expected content - * <li>Page Session 1 and validate that both sessions have expected content - * <li>Page Session 2 and validate that both sessions have expected content - * </ol> - */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class MultiSessionPagingTest { - private FakeFeedRequestManager mFakeFeedRequestManager; - private FeedSessionManager mFeedSessionManager; - private ModelProviderFactory mModelProviderFactory; - private ModelProviderValidator mModelValidator; - private ContentIdGenerators mContentIdGenerators = new ContentIdGenerators(); - private RequestManager mRequestManager; - - @Before - public void setUp() { - initMocks(this); - InfraIntegrationScope scope = new InfraIntegrationScope.Builder().build(); - mFakeFeedRequestManager = scope.getFakeFeedRequestManager(); - mFeedSessionManager = scope.getFeedSessionManager(); - mModelProviderFactory = scope.getModelProviderFactory(); - mModelValidator = new ModelProviderValidator(scope.getProtocolAdapter()); - mRequestManager = scope.getRequestManager(); - } - - @Test - public void testPaging() { - // Create session 1 content - ContentId[] s1Cards = new ContentId[] {ResponseBuilder.createFeatureContentId(1), - ResponseBuilder.createFeatureContentId(2)}; - ContentId[] s1PageCards = new ContentId[] {ResponseBuilder.createFeatureContentId(3), - ResponseBuilder.createFeatureContentId(4)}; - PagingState s1State = new PagingState(s1Cards, s1PageCards, 1, mContentIdGenerators); - ByteString token1 = ByteString.copyFrom("s1-page", Charset.defaultCharset()); - ResponseBuilder s1InitialResponse = getInitialResponse(s1Cards, token1); - - // Create session 2 content - ContentId[] s2Cards = new ContentId[] {ResponseBuilder.createFeatureContentId(101), - ResponseBuilder.createFeatureContentId(102)}; - ContentId[] s2PageCards = new ContentId[] {ResponseBuilder.createFeatureContentId(103), - ResponseBuilder.createFeatureContentId(104)}; - PagingState s2State = new PagingState(s2Cards, s2PageCards, 2, mContentIdGenerators); - - // Create an initial S1 $HEAD session - mFakeFeedRequestManager.queueResponse(s1State.initialResponse); - mRequestManager.triggerScheduledRefresh(); - - ModelProvider mp1 = mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - mModelValidator.assertRoot(mp1); - WireProtocolInfo protocolInfo = s1InitialResponse.getWireProtocolInfo(); - assertThat(protocolInfo.hasToken).isTrue(); - ModelChild mp1Token = mModelValidator.assertCursorContentsWithToken(mp1, s1Cards); - assertThat(mp1.getCurrentState()).isEqualTo(State.READY); - - // Create a second session against the S1 head. - ModelProvider mp2 = mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - assertThat(mp2.getCurrentState()).isEqualTo(State.READY); - mModelValidator.assertCursorContentsWithToken(mp2, s1Cards); - - // Refresh the Stream with the S2 initial response - mFakeFeedRequestManager.queueResponse(s2State.initialResponse); - mFakeFeedRequestManager.triggerRefresh(RequestReason.OPEN_WITHOUT_CONTENT, - mFeedSessionManager.getUpdateConsumer( - new MutationContext.Builder() - .setRequestingSessionId(mp2.getSessionId()) - .build())); - assertThat(mp1.getCurrentState()).isEqualTo(State.READY); - assertThat(mp2.getCurrentState()).isEqualTo(State.INVALIDATED); - - // Now create a ModelProvider against the new session. - mp2 = mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - mModelValidator.assertRoot(mp2); - protocolInfo = s1InitialResponse.getWireProtocolInfo(); - assertThat(protocolInfo.hasToken).isTrue(); - ModelChild mp2Token = mModelValidator.assertCursorContentsWithToken(mp2, s2Cards); - assertThat(mp2.getCurrentState()).isEqualTo(State.READY); - - // Verify that we didn't change the first session - mModelValidator.assertCursorContentsWithToken(mp1, s1Cards); - assertThat(mp1.getCurrentState()).isEqualTo(State.READY); - - // now page S1 - mFakeFeedRequestManager.queueResponse(s1State.pageResponse); - mp1.handleToken(mp1Token.getModelToken()); - mModelValidator.assertCursorContents( - mp1, s1Cards[0], s1Cards[1], s1PageCards[0], s1PageCards[1]); - mModelValidator.assertCursorContentsWithToken(mp2, s2Cards); - - // now page S2 - mFakeFeedRequestManager.queueResponse(s2State.pageResponse); - mp2.handleToken(mp2Token.getModelToken()); - mModelValidator.assertCursorContents( - mp1, s1Cards[0], s1Cards[1], s1PageCards[0], s1PageCards[1]); - mModelValidator.assertCursorContents( - mp2, s2Cards[0], s2Cards[1], s2PageCards[0], s2PageCards[1]); - } - - private ResponseBuilder getInitialResponse(ContentId[] cards, ByteString token) { - return ResponseBuilder.forClearAllWithCards(cards).addStreamToken(1, token); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/NoRequestWithContentTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/NoRequestWithContentTest.java deleted file mode 100644 index 8218702..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/NoRequestWithContentTest.java +++ /dev/null
@@ -1,82 +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. - -package org.chromium.chrome.browser.feed.library.infraintegration; - -import static com.google.common.truth.Truth.assertThat; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.scheduler.SchedulerApi.RequestBehavior; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider.State; -import org.chromium.chrome.browser.feed.library.common.testing.InfraIntegrationScope; -import org.chromium.chrome.browser.feed.library.common.testing.SessionTestUtils; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests the NO_REQUEST_WITH_CONTENT behavior for creating a new session. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public final class NoRequestWithContentTest { - private final SessionTestUtils mUtils = - new SessionTestUtils(RequestBehavior.NO_REQUEST_WITH_CONTENT); - private final InfraIntegrationScope mScope = mUtils.getScope(); - - @Before - public void setUp() { - mUtils.populateHead(); - } - - @After - public void tearDown() { - mUtils.assertWorkComplete(); - } - - @Test - public void test_hasContentWithRequest_shouldShowContentImmediatelyAndAppend() { - long delayMs = mUtils.startOutstandingRequest(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - mUtils.assertHeadContent(modelProvider.getAllRootChildren()); - - // REQUEST_2 items should be appended. - mScope.getFakeClock().advance(delayMs); - mUtils.assertAppendedContent(modelProvider.getAllRootChildren()); - } - - @Test - public void test_noContentWithRequest_shouldShowZeroState() { - mScope.getAppLifecycleListener().onClearAll(); - long delayMs = mUtils.startOutstandingRequest(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - assertThat(modelProvider.getAllRootChildren()).isEmpty(); - - // REQUEST_2 items should not be appended. - mScope.getFakeClock().advance(delayMs); - assertThat(modelProvider.getAllRootChildren()).isEmpty(); - } - - @Test - public void test_noContentNoRequest_shouldShowZeroState() { - mScope.getAppLifecycleListener().onClearAll(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - assertThat(modelProvider.getAllRootChildren()).isEmpty(); - } - - @Test - public void test_hasContentNoRequest_shouldShowContentImmediately() { - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - mUtils.assertHeadContent(modelProvider.getAllRootChildren()); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/NoRequestWithTimeoutTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/NoRequestWithTimeoutTest.java deleted file mode 100644 index 40cc64a..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/NoRequestWithTimeoutTest.java +++ /dev/null
@@ -1,167 +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. - -package org.chromium.chrome.browser.feed.library.infraintegration; - -import static com.google.common.truth.Truth.assertThat; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.scheduler.SchedulerApi.RequestBehavior; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider.State; -import org.chromium.chrome.browser.feed.library.common.testing.InfraIntegrationScope; -import org.chromium.chrome.browser.feed.library.common.testing.SessionTestUtils; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests the NO_REQUEST_WITH_TIMEOUT behavior for creating a new session. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public final class NoRequestWithTimeoutTest { - private final SessionTestUtils mUtils = - new SessionTestUtils(RequestBehavior.NO_REQUEST_WITH_TIMEOUT); - private final InfraIntegrationScope mScope = mUtils.getScope(); - - @Before - public void setUp() { - mUtils.populateHead(); - } - - @After - public void tearDown() { - mUtils.assertWorkComplete(); - } - - @Test - public void test_hasContentWithRequest_spinnerThenShowContent() { - long delayMs = mUtils.requestBeforeTimeout().startOutstandingRequest(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - mScope.getFakeClock().advance(delayMs); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - mUtils.assertNewContent(modelProvider.getAllRootChildren()); - } - - @Test - public void test_hasContentWithRequest_spinnerThenShowContentWithError() { - long delayMs = mUtils.requestBeforeTimeout().startOutstandingRequestWithError(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - mScope.getFakeClock().advance(delayMs); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - mUtils.assertHeadContent(modelProvider.getAllRootChildren()); - } - - @Test - public void test_hasContentWithRequest_spinnerThenShowContentOnTimeoutAndAppend() { - long delayMs = mUtils.startOutstandingRequest(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - mScope.getFakeClock().advance(SessionTestUtils.TIMEOUT_MS); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - mUtils.assertHeadContent(modelProvider.getAllRootChildren()); - - mScope.getFakeClock().advanceTo(delayMs); - mUtils.assertAppendedContent(modelProvider.getAllRootChildren()); - } - - @Test - public void test_hasContentWithRequest_spinnerThenShowContentOnTimeoutWithError() { - long delayMs = mUtils.startOutstandingRequestWithError(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - mScope.getFakeClock().advance(SessionTestUtils.TIMEOUT_MS); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - mUtils.assertHeadContent(modelProvider.getAllRootChildren()); - - mScope.getFakeClock().advanceTo(delayMs); - mUtils.assertHeadContent(modelProvider.getAllRootChildren()); - } - - @Test - public void test_noContentWithRequest_spinnerThenShowContent() { - mScope.getAppLifecycleListener().onClearAll(); - long delayMs = mUtils.requestBeforeTimeout().startOutstandingRequest(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - mScope.getFakeClock().advance(delayMs); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - mUtils.assertNewContent(modelProvider.getAllRootChildren()); - } - - @Test - public void test_noContentWithRequest_spinnerThenZeroStateWithError() { - mScope.getAppLifecycleListener().onClearAll(); - long delayMs = mUtils.requestBeforeTimeout().startOutstandingRequestWithError(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - mScope.getFakeClock().advance(delayMs); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - assertThat(modelProvider.getAllRootChildren()).isEmpty(); - } - - @Test - public void test_noContentWithRequest_spinnerThenZeroStateOnTimeout() { - mScope.getAppLifecycleListener().onClearAll(); - long delayMs = mUtils.startOutstandingRequest(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - mScope.getFakeClock().advance(SessionTestUtils.TIMEOUT_MS); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - assertThat(modelProvider.getAllRootChildren()).isEmpty(); - - mScope.getFakeClock().advanceTo(delayMs); - assertThat(modelProvider.getAllRootChildren()).isEmpty(); - } - - @Test - public void test_noContentWithRequest_spinnerThenZeroStateOnTimeoutWithError() { - mScope.getAppLifecycleListener().onClearAll(); - long delayMs = mUtils.startOutstandingRequestWithError(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - mScope.getFakeClock().advance(SessionTestUtils.TIMEOUT_MS); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - assertThat(modelProvider.getAllRootChildren()).isEmpty(); - - mScope.getFakeClock().advanceTo(delayMs); - assertThat(modelProvider.getAllRootChildren()).isEmpty(); - } - - @Test - public void test_noContentNoRequest_shouldShowZeroState() { - mScope.getAppLifecycleListener().onClearAll(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - assertThat(modelProvider.getAllRootChildren()).isEmpty(); - } - - @Test - public void test_hasContentNoRequest_shouldShowContentImmediately() { - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - mUtils.assertHeadContent(modelProvider.getAllRootChildren()); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/NoRequestWithWaitTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/NoRequestWithWaitTest.java deleted file mode 100644 index 663865d..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/NoRequestWithWaitTest.java +++ /dev/null
@@ -1,105 +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. - -package org.chromium.chrome.browser.feed.library.infraintegration; - -import static com.google.common.truth.Truth.assertThat; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.scheduler.SchedulerApi.RequestBehavior; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider.State; -import org.chromium.chrome.browser.feed.library.common.testing.InfraIntegrationScope; -import org.chromium.chrome.browser.feed.library.common.testing.SessionTestUtils; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests the NO_REQUEST_WITH_WAIT behavior for creating a new session. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public final class NoRequestWithWaitTest { - private final SessionTestUtils mUtils = - new SessionTestUtils(RequestBehavior.NO_REQUEST_WITH_WAIT); - private final InfraIntegrationScope mScope = mUtils.getScope(); - - @Before - public void setUp() { - mUtils.populateHead(); - } - - @After - public void tearDown() { - mUtils.assertWorkComplete(); - } - - @Test - public void test_hasContentWithRequest_spinnerThenShowContent() { - long delayMs = mUtils.startOutstandingRequest(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - mScope.getFakeClock().advance(delayMs); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - mUtils.assertNewContent(modelProvider.getAllRootChildren()); - } - - @Test - public void test_hasContentWithRequest_spinnerThenShowContentOnFailure() { - long delayMs = mUtils.startOutstandingRequestWithError(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - mScope.getFakeClock().advance(delayMs); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - mUtils.assertHeadContent(modelProvider.getAllRootChildren()); - } - - @Test - public void test_noContentWithRequest_spinnerThenShowContent() { - mScope.getAppLifecycleListener().onClearAll(); - long delayMs = mUtils.startOutstandingRequest(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - mScope.getFakeClock().advance(delayMs); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - mUtils.assertNewContent(modelProvider.getAllRootChildren()); - } - - @Test - public void test_noContentWithRequest_spinnerThenZeroStateOnFailure() { - mScope.getAppLifecycleListener().onClearAll(); - long delayMs = mUtils.startOutstandingRequestWithError(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - mScope.getFakeClock().advance(delayMs); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - assertThat(modelProvider.getAllRootChildren()).isEmpty(); - } - - @Test - public void test_noContentNoRequest_shouldShowZeroState() { - mScope.getAppLifecycleListener().onClearAll(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - assertThat(modelProvider.getAllRootChildren()).isEmpty(); - } - - @Test - public void test_hasContentNoRequest_shouldShowContentImmediately() { - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - mUtils.assertHeadContent(modelProvider.getAllRootChildren()); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/RemoveTrackingBehaviorTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/RemoveTrackingBehaviorTest.java deleted file mode 100644 index ac967e1..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/RemoveTrackingBehaviorTest.java +++ /dev/null
@@ -1,183 +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. - -package org.chromium.chrome.browser.feed.library.infraintegration; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.MockitoAnnotations.initMocks; - -import static org.chromium.chrome.browser.feed.library.common.testing.ResponseBuilder.ROOT_CONTENT_ID; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.base.Consumer; -import org.chromium.base.Function; -import org.chromium.chrome.browser.feed.library.api.client.requestmanager.RequestManager; -import org.chromium.chrome.browser.feed.library.api.common.MutationContext; -import org.chromium.chrome.browser.feed.library.api.internal.common.Model; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider.RemoveTrackingFactory; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProviderFactory; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.RemoveTracking; -import org.chromium.chrome.browser.feed.library.api.internal.protocoladapter.ProtocolAdapter; -import org.chromium.chrome.browser.feed.library.api.internal.sessionmanager.FeedSessionManager; -import org.chromium.chrome.browser.feed.library.common.Result; -import org.chromium.chrome.browser.feed.library.common.testing.InfraIntegrationScope; -import org.chromium.chrome.browser.feed.library.common.testing.ResponseBuilder; -import org.chromium.chrome.browser.feed.library.testing.requestmanager.FakeFeedRequestManager; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamDataOperation; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamFeature; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.UiContext; -import org.chromium.components.feed.core.proto.wire.ContentIdProto.ContentId; -import org.chromium.components.feed.core.proto.wire.ResponseProto.Response; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; - -/** Tests of the ModelProvider RemoveTracking behavior. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class RemoveTrackingBehaviorTest { - private static final ContentId[] CARDS = new ContentId[] { - ResponseBuilder.createFeatureContentId(1), - ResponseBuilder.createFeatureContentId(2), - ResponseBuilder.createFeatureContentId(3), - ResponseBuilder.createFeatureContentId(4), - ResponseBuilder.createFeatureContentId(5), - }; - - private FakeFeedRequestManager mFakeFeedRequestManager; - private FeedSessionManager mFeedSessionManager; - private ModelProviderFactory mModelProviderFactory; - private ProtocolAdapter mProtocolAdapter; - private RequestManager mRequestManager; - - @Before - public void setUp() { - initMocks(this); - InfraIntegrationScope scope = new InfraIntegrationScope.Builder().build(); - mFakeFeedRequestManager = scope.getFakeFeedRequestManager(); - mFeedSessionManager = scope.getFeedSessionManager(); - mModelProviderFactory = scope.getModelProviderFactory(); - mProtocolAdapter = scope.getProtocolAdapter(); - mRequestManager = scope.getRequestManager(); - } - - @Test - public void testBaseRemoveTracking() { - loadInitialData(); - - AtomicBoolean called = new AtomicBoolean(false); - ModelProvider modelProvider = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - modelProvider.enableRemoveTracking(getRemoveTrackingFactory((contentIds) -> { - assertThat(contentIds).hasSize(1); - called.set(true); - })); - ResponseBuilder responseBuilder = - ResponseBuilder.builder().removeFeature(CARDS[1], ROOT_CONTENT_ID); - List<StreamDataOperation> dataOperations = getDataOperations(responseBuilder); - MutationContext mutationContext = - new MutationContext.Builder().setUserInitiated(true).build(); - Consumer<Result<Model>> updateConsumer = - mFeedSessionManager.getUpdateConsumer(mutationContext); - updateConsumer.accept(Result.success(Model.of(dataOperations))); - assertThat(called.get()).isTrue(); - } - - @Test - public void testBaseRemoveTracking_multipleItems() { - loadInitialData(); - - AtomicBoolean called = new AtomicBoolean(false); - ModelProvider modelProvider = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - modelProvider.enableRemoveTracking(getRemoveTrackingFactory((contentIds) -> { - assertThat(contentIds).hasSize(2); - called.set(true); - })); - ResponseBuilder responseBuilder = ResponseBuilder.builder() - .removeFeature(CARDS[1], ROOT_CONTENT_ID) - .removeFeature(CARDS[3], ROOT_CONTENT_ID); - List<StreamDataOperation> dataOperations = getDataOperations(responseBuilder); - MutationContext mutationContext = - new MutationContext.Builder().setUserInitiated(true).build(); - Consumer<Result<Model>> updateConsumer = - mFeedSessionManager.getUpdateConsumer(mutationContext); - updateConsumer.accept(Result.success(Model.of(dataOperations))); - assertThat(called.get()).isTrue(); - } - - /** - * For non-user initiated mutations, the test is setup to return null from the factory. The - * result is the Consumer should not be called. - */ - @Test - public void testNonUserInitiated() { - loadInitialData(); - - AtomicBoolean called = new AtomicBoolean(false); - ModelProvider modelProvider = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - modelProvider.enableRemoveTracking(getRemoveTrackingFactory((contentIds) -> { - assertThat(contentIds).isEmpty(); - called.set(true); - })); - - ResponseBuilder responseBuilder = - ResponseBuilder.builder().removeFeature(CARDS[1], ROOT_CONTENT_ID); - List<StreamDataOperation> dataOperations = getDataOperations(responseBuilder); - MutationContext mutationContext = - new MutationContext.Builder().setUserInitiated(false).build(); - Consumer<Result<Model>> updateConsumer = - mFeedSessionManager.getUpdateConsumer(mutationContext); - updateConsumer.accept(Result.success(Model.of(dataOperations))); - assertThat(called.get()).isFalse(); - } - - private RemoveTrackingFactory<String> getRemoveTrackingFactory( - Consumer<List<String>> consumer) { - return new RemoveTrackingFactory<String>() { - @Override - public /*@Nullable*/ RemoveTracking<String> create(MutationContext mutationContext) { - // Only support RemoveTracking on user initiated removes - return mutationContext.isUserInitiated() ? getRemoveTracking( - (streamFeature) -> simpleTransform(streamFeature), consumer) - : null; - } - }; - } - - private RemoveTracking<String> getRemoveTracking( - Function<StreamFeature, String> transformer, Consumer<List<String>> consumer) { - return new RemoveTracking<>(transformer, consumer); - } - - @SuppressWarnings("unused") - private boolean alwaysTrue(String value) { - return true; - } - - private String simpleTransform(StreamFeature streamFeature) { - // only return the Content StreamFeatures. - return streamFeature.hasContent() ? streamFeature.getContentId() : null; - } - - private List<StreamDataOperation> getDataOperations(ResponseBuilder builder) { - Response response = builder.build(); - Result<Model> result = mProtocolAdapter.createModel(response); - assertThat(result.isSuccessful()).isTrue(); - return result.getValue().streamDataOperations; - } - - private void loadInitialData() { - mFakeFeedRequestManager.queueResponse(ResponseBuilder.forClearAllWithCards(CARDS).build()); - mRequestManager.triggerScheduledRefresh(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/RequestWithContentTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/RequestWithContentTest.java deleted file mode 100644 index 1746abb..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/RequestWithContentTest.java +++ /dev/null
@@ -1,93 +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. - -package org.chromium.chrome.browser.feed.library.infraintegration; - -import static com.google.common.truth.Truth.assertThat; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.scheduler.SchedulerApi.RequestBehavior; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider.State; -import org.chromium.chrome.browser.feed.library.common.testing.InfraIntegrationScope; -import org.chromium.chrome.browser.feed.library.common.testing.SessionTestUtils; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests the REQUEST_WITH_CONTENT behavior for creating a new session. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public final class RequestWithContentTest { - private final SessionTestUtils mUtils = - new SessionTestUtils(RequestBehavior.REQUEST_WITH_CONTENT); - private final InfraIntegrationScope mScope = mUtils.getScope(); - - @Before - public void setUp() { - mUtils.populateHead(); - } - - @After - public void tearDown() { - mUtils.assertWorkComplete(); - } - - @Test - public void test_hasContentWithRequest_shouldShowContentImmediatelyAndAppend() { - long delayMs = mUtils.startOutstandingRequest(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - mUtils.assertHeadContent(modelProvider.getAllRootChildren()); - - // REQUEST_2 items should be appended. - mScope.getFakeClock().advance(delayMs); - mUtils.assertAppendedContent(modelProvider.getAllRootChildren()); - } - - @Test - public void test_noContentWithRequest_shouldShowZeroState() { - mScope.getAppLifecycleListener().onClearAll(); - long delayMs = mUtils.startOutstandingRequest(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - assertThat(modelProvider.getAllRootChildren()).isEmpty(); - - // REQUEST_2 items should not be appended. - mScope.getFakeClock().advance(delayMs); - assertThat(modelProvider.getAllRootChildren()).isEmpty(); - } - - @Test - public void test_noContentNoRequest_shouldShowZeroState() { - mScope.getAppLifecycleListener().onClearAll(); - long delayMs = mUtils.queueRequest(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - assertThat(modelProvider.getAllRootChildren()).isEmpty(); - - // REQUEST_2 items should not be appended. - mScope.getFakeClock().advance(delayMs); - assertThat(modelProvider.getAllRootChildren()).isEmpty(); - } - - @Test - public void test_hasContentNoRequest_shouldShowContentImmediatelyAndAppend() { - long delayMs = mUtils.queueRequest(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - mUtils.assertHeadContent(modelProvider.getAllRootChildren()); - - // REQUEST_2 items should be appended. - mScope.getFakeClock().advance(delayMs); - mUtils.assertAppendedContent(modelProvider.getAllRootChildren()); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/RequestWithTimeoutTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/RequestWithTimeoutTest.java deleted file mode 100644 index 9a32aa0..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/RequestWithTimeoutTest.java +++ /dev/null
@@ -1,263 +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. - -package org.chromium.chrome.browser.feed.library.infraintegration; - -import static com.google.common.truth.Truth.assertThat; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.scheduler.SchedulerApi.RequestBehavior; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider.State; -import org.chromium.chrome.browser.feed.library.common.testing.InfraIntegrationScope; -import org.chromium.chrome.browser.feed.library.common.testing.SessionTestUtils; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests the REQUEST_WITH_TIMEOUT behavior for creating a new session. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public final class RequestWithTimeoutTest { - private final SessionTestUtils mUtils = - new SessionTestUtils(RequestBehavior.REQUEST_WITH_TIMEOUT); - private final InfraIntegrationScope mScope = mUtils.getScope(); - - @Before - public void setUp() { - mUtils.populateHead(); - } - - @After - public void tearDown() { - mUtils.assertWorkComplete(); - } - - @Test - public void test_hasContentWithRequest_spinnerThenShowContent() { - long delayMs = mUtils.requestBeforeTimeout().startOutstandingRequest(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - mScope.getFakeClock().advance(delayMs); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - mUtils.assertNewContent(modelProvider.getAllRootChildren()); - } - - @Test - public void test_hasContentWithRequest_spinnerThenShowContentWithError() { - long delayMs = mUtils.requestBeforeTimeout().startOutstandingRequestWithError(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - mScope.getFakeClock().advance(delayMs); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - mUtils.assertHeadContent(modelProvider.getAllRootChildren()); - } - - @Test - public void test_hasContentWithRequest_spinnerThenShowContentOnTimeoutAndAppend() { - long delayMs = mUtils.startOutstandingRequest(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - mScope.getFakeClock().advance(SessionTestUtils.TIMEOUT_MS); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - mUtils.assertHeadContent(modelProvider.getAllRootChildren()); - - mScope.getFakeClock().advanceTo(delayMs); - mUtils.assertAppendedContent(modelProvider.getAllRootChildren()); - } - - @Test - public void test_hasContentWithRequest_spinnerThenShowContentOnTimeoutWithError() { - long delayMs = mUtils.startOutstandingRequestWithError(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - mScope.getFakeClock().advance(SessionTestUtils.TIMEOUT_MS); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - mUtils.assertHeadContent(modelProvider.getAllRootChildren()); - - mScope.getFakeClock().advanceTo(delayMs); - mUtils.assertHeadContent(modelProvider.getAllRootChildren()); - } - - @Test - public void test_noContentWithRequest_spinnerThenShowContent() { - mScope.getAppLifecycleListener().onClearAll(); - long delayMs = mUtils.requestBeforeTimeout().startOutstandingRequest(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - mScope.getFakeClock().advance(delayMs); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - mUtils.assertNewContent(modelProvider.getAllRootChildren()); - } - - @Test - public void test_noContentWithRequest_spinnerThenZeroStateWithError() { - mScope.getAppLifecycleListener().onClearAll(); - long delayMs = mUtils.requestBeforeTimeout().startOutstandingRequestWithError(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - mScope.getFakeClock().advance(delayMs); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - assertThat(modelProvider.getAllRootChildren()).isEmpty(); - } - - @Test - public void test_noContentWithRequest_spinnerThenZeroStateOnTimeout() { - mScope.getAppLifecycleListener().onClearAll(); - long delayMs = mUtils.startOutstandingRequest(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - mScope.getFakeClock().advance(SessionTestUtils.TIMEOUT_MS); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - assertThat(modelProvider.getAllRootChildren()).isEmpty(); - - mScope.getFakeClock().advanceTo(delayMs); - assertThat(modelProvider.getAllRootChildren()).isEmpty(); - } - - @Test - public void test_noContentWithRequest_spinnerThenZeroStateOnTimeoutWithError() { - mScope.getAppLifecycleListener().onClearAll(); - long delayMs = mUtils.startOutstandingRequestWithError(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - mScope.getFakeClock().advance(SessionTestUtils.TIMEOUT_MS); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - assertThat(modelProvider.getAllRootChildren()).isEmpty(); - - mScope.getFakeClock().advanceTo(delayMs); - assertThat(modelProvider.getAllRootChildren()).isEmpty(); - } - - @Test - public void test_noContentNoRequest_spinnerThenShowContent() { - mScope.getAppLifecycleListener().onClearAll(); - long delayMs = mUtils.requestBeforeTimeout().queueRequest(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - mScope.getFakeClock().advance(delayMs); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - mUtils.assertNewContent(modelProvider.getAllRootChildren()); - } - - @Test - public void test_noContentNoRequest_spinnerThenZeroStateWithError() { - mScope.getAppLifecycleListener().onClearAll(); - long delayMs = mUtils.requestBeforeTimeout().queueError(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - mScope.getFakeClock().advance(delayMs); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - assertThat(modelProvider.getAllRootChildren()).isEmpty(); - } - - @Test - public void test_noContentNoRequest_spinnerThenZeroStateOnTimeout() { - mScope.getAppLifecycleListener().onClearAll(); - long delayMs = mUtils.queueRequest(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - mScope.getFakeClock().advance(SessionTestUtils.TIMEOUT_MS); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - assertThat(modelProvider.getAllRootChildren()).isEmpty(); - - mScope.getFakeClock().advanceTo(delayMs); - assertThat(modelProvider.getAllRootChildren()).isEmpty(); - } - - @Test - public void test_noContentNoRequest_spinnerThenZeroStateOnTimeoutWithError() { - mScope.getAppLifecycleListener().onClearAll(); - long delayMs = mUtils.queueError(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - mScope.getFakeClock().advance(SessionTestUtils.TIMEOUT_MS); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - assertThat(modelProvider.getAllRootChildren()).isEmpty(); - - mScope.getFakeClock().advanceTo(delayMs); - assertThat(modelProvider.getAllRootChildren()).isEmpty(); - } - - @Test - public void test_hasContentNoRequest_spinnerThenShowContent() { - long delayMs = mUtils.requestBeforeTimeout().queueRequest(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - mScope.getFakeClock().advance(delayMs); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - mUtils.assertNewContent(modelProvider.getAllRootChildren()); - } - - @Test - public void test_hasContentNoRequest_spinnerThenShowContentWithError() { - long delayMs = mUtils.requestBeforeTimeout().queueError(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - mScope.getFakeClock().advance(delayMs); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - mUtils.assertHeadContent(modelProvider.getAllRootChildren()); - } - - @Test - public void test_hasContentNoRequest_spinnerThenShowContentOnTimeoutAndAppend() { - long delayMs = mUtils.queueRequest(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - mScope.getFakeClock().advance(SessionTestUtils.TIMEOUT_MS); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - mUtils.assertHeadContent(modelProvider.getAllRootChildren()); - - mScope.getFakeClock().advanceTo(delayMs); - mUtils.assertAppendedContent(modelProvider.getAllRootChildren()); - } - - @Test - public void test_hasContentNoRequest_spinnerThenShowContentOnTimeoutWithError() { - long delayMs = mUtils.queueError(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - mScope.getFakeClock().advance(SessionTestUtils.TIMEOUT_MS); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - mUtils.assertHeadContent(modelProvider.getAllRootChildren()); - - mScope.getFakeClock().advanceTo(delayMs); - mUtils.assertHeadContent(modelProvider.getAllRootChildren()); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/RequestWithWaitTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/RequestWithWaitTest.java deleted file mode 100644 index 5a9d58f7..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/RequestWithWaitTest.java +++ /dev/null
@@ -1,137 +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. - -package org.chromium.chrome.browser.feed.library.infraintegration; - -import static com.google.common.truth.Truth.assertThat; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.scheduler.SchedulerApi.RequestBehavior; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider.State; -import org.chromium.chrome.browser.feed.library.common.testing.InfraIntegrationScope; -import org.chromium.chrome.browser.feed.library.common.testing.SessionTestUtils; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests the REQUEST_WITH_WAIT behavior for creating a new session. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public final class RequestWithWaitTest { - private final SessionTestUtils mUtils = new SessionTestUtils(RequestBehavior.REQUEST_WITH_WAIT); - private final InfraIntegrationScope mScope = mUtils.getScope(); - - @Before - public void setUp() { - mUtils.populateHead(); - } - - @After - public void tearDown() { - mUtils.assertWorkComplete(); - } - - @Test - public void test_hasContentWithRequest_spinnerThenShowContent() { - long delayMs = mUtils.startOutstandingRequest(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - mScope.getFakeClock().advance(delayMs); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - mUtils.assertNewContent(modelProvider.getAllRootChildren()); - } - - @Test - public void test_hasContentWithRequest_spinnerThenShowContentOnFailure() { - long delayMs = mUtils.startOutstandingRequestWithError(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - mScope.getFakeClock().advance(delayMs); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - mUtils.assertHeadContent(modelProvider.getAllRootChildren()); - } - - @Test - public void test_noContentWithRequest_spinnerThenShowContent() { - mScope.getAppLifecycleListener().onClearAll(); - long delayMs = mUtils.startOutstandingRequest(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - mScope.getFakeClock().advance(delayMs); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - mUtils.assertNewContent(modelProvider.getAllRootChildren()); - } - - @Test - public void test_noContentWithRequest_spinnerThenZeroStateOnFailure() { - mScope.getAppLifecycleListener().onClearAll(); - long delayMs = mUtils.startOutstandingRequestWithError(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - mScope.getFakeClock().advance(delayMs); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - assertThat(modelProvider.getAllRootChildren()).isEmpty(); - } - - @Test - public void test_noContentNoRequest_spinnerThenShowContent() { - mScope.getAppLifecycleListener().onClearAll(); - long delayMs = mUtils.queueRequest(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - mScope.getFakeClock().advance(delayMs); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - mUtils.assertNewContent(modelProvider.getAllRootChildren()); - } - - @Test - public void test_noContentNoRequest_spinnerThenZeroStateOnFailure() { - mScope.getAppLifecycleListener().onClearAll(); - long delayMs = mUtils.queueError(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - mScope.getFakeClock().advance(delayMs); - assertThat(modelProvider.getAllRootChildren()).isEmpty(); - } - - @Test - public void test_hasContentNoRequest_spinnerThenShowContent() { - long delayMs = mUtils.queueRequest(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - mScope.getFakeClock().advance(delayMs); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - mUtils.assertNewContent(modelProvider.getAllRootChildren()); - } - - @Test - public void test_hasContentNoRequest_spinnerThenShowContentOnFailure() { - long delayMs = mUtils.queueError(); - - ModelProvider modelProvider = mUtils.createNewSession(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.INITIALIZING); - - mScope.getFakeClock().advance(delayMs); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - mUtils.assertHeadContent(modelProvider.getAllRootChildren()); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/RootOnlyTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/RootOnlyTest.java deleted file mode 100644 index ee984905..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/RootOnlyTest.java +++ /dev/null
@@ -1,142 +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. - -package org.chromium.chrome.browser.feed.library.infraintegration; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.client.requestmanager.RequestManager; -import org.chromium.chrome.browser.feed.library.api.common.MutationContext; -import org.chromium.chrome.browser.feed.library.api.host.logging.RequestReason; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider.State; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProviderFactory; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProviderObserver; -import org.chromium.chrome.browser.feed.library.api.internal.sessionmanager.FeedSessionManager; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeThreadUtils; -import org.chromium.chrome.browser.feed.library.common.testing.InfraIntegrationScope; -import org.chromium.chrome.browser.feed.library.common.testing.ModelProviderValidator; -import org.chromium.chrome.browser.feed.library.common.testing.ResponseBuilder; -import org.chromium.chrome.browser.feed.library.common.testing.ResponseBuilder.WireProtocolInfo; -import org.chromium.chrome.browser.feed.library.testing.requestmanager.FakeFeedRequestManager; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamToken; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.UiContext; -import org.chromium.components.feed.core.proto.wire.ConsistencyTokenProto.ConsistencyToken; -import org.chromium.components.feed.core.proto.wire.ContentIdProto.ContentId; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests of a Stream with only a root. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class RootOnlyTest { - private final InfraIntegrationScope mScope = new InfraIntegrationScope.Builder().build(); - private final FakeFeedRequestManager mFakeFeedRequestManager = - mScope.getFakeFeedRequestManager(); - private final FakeThreadUtils mFakeThreadUtils = mScope.getFakeThreadUtils(); - private final ModelProviderFactory mModelProviderFactory = mScope.getModelProviderFactory(); - private final ModelProviderValidator mModelValidator = - new ModelProviderValidator(mScope.getProtocolAdapter()); - private final FeedSessionManager mFeedSessionManager = mScope.getFeedSessionManager(); - private final RequestManager mRequestManager = mScope.getRequestManager(); - - @Test - public void rootOnlyResponse_beforeSessionWithLifecycle() { - // ModelProvider is created from $HEAD containing content - ResponseBuilder responseBuilder = - new ResponseBuilder().addClearOperation().addRootFeature(); - mFakeFeedRequestManager.queueResponse(responseBuilder.build()); - mRequestManager.triggerScheduledRefresh(); - ModelProvider modelProvider = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - - ModelProviderObserver changeObserver = mock(ModelProviderObserver.class); - modelProvider.registerObserver(changeObserver); - verify(changeObserver).onSessionStart(UiContext.getDefaultInstance()); - verify(changeObserver, never()).onSessionFinished(any(UiContext.class)); - - assertThat(modelProvider).isNotNull(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - mModelValidator.assertRoot(modelProvider); - - WireProtocolInfo protocolInfo = responseBuilder.getWireProtocolInfo(); - // 1 root - assertThat(protocolInfo.featuresAdded).hasSize(1); - assertThat(protocolInfo.hasClearOperation).isTrue(); - - modelProvider.invalidate(); - verify(changeObserver).onSessionFinished(UiContext.getDefaultInstance()); - } - - @Test - public void rootOnlyResponse_afterSessionWithLifecycle() { - // ModelProvider created from empty $HEAD, followed by a response adding head - // Verify the observer lifecycle is correctly called - ModelProviderObserver changeObserver = mock(ModelProviderObserver.class); - ModelProvider modelProvider = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - modelProvider.registerObserver(changeObserver); - verify(changeObserver).onSessionStart(UiContext.getDefaultInstance()); - verify(changeObserver, never()).onSessionFinished(any(UiContext.class)); - - ResponseBuilder responseBuilder = new ResponseBuilder().addRootFeature(); - mFakeFeedRequestManager.queueResponse(responseBuilder.build()); - // TODO: sessions reject updates without a CLEAR_ALL or paging with a different token. - mFakeThreadUtils.enforceMainThread(false); - mFakeFeedRequestManager.loadMore(StreamToken.getDefaultInstance(), - ConsistencyToken.getDefaultInstance(), - mFeedSessionManager.getUpdateConsumer(MutationContext.EMPTY_CONTEXT)); - verify(changeObserver, never()).onSessionFinished(any(UiContext.class)); - - assertThat(modelProvider).isNotNull(); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - mModelValidator.assertRoot(modelProvider); - - WireProtocolInfo protocolInfo = responseBuilder.getWireProtocolInfo(); - // 1 root - assertThat(protocolInfo.featuresAdded).hasSize(1); - assertThat(protocolInfo.hasClearOperation).isFalse(); - - modelProvider.invalidate(); - verify(changeObserver).onSessionFinished(UiContext.getDefaultInstance()); - } - - @Test - public void rootOnlyResponse_setSecondRoot() { - // Set the root in two different responses, verify the lifecycle is called correctly - // and the root is replaced - ModelProviderObserver changeObserver = mock(ModelProviderObserver.class); - ResponseBuilder responseBuilder = - new ResponseBuilder().addClearOperation().addRootFeature(); - mFakeFeedRequestManager.queueResponse(responseBuilder.build()); - mFakeFeedRequestManager.triggerRefresh(RequestReason.OPEN_WITHOUT_CONTENT, - mFeedSessionManager.getUpdateConsumer(MutationContext.EMPTY_CONTEXT)); - ModelProvider modelProvider = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - modelProvider.registerObserver(changeObserver); - mModelValidator.assertRoot(modelProvider); - - ContentId anotherRoot = ContentId.newBuilder() - .setContentDomain("root-feature") - .setId(2) - .setTable("feature") - .build(); - responseBuilder = new ResponseBuilder().addRootFeature(anotherRoot); - mFakeFeedRequestManager.queueResponse(responseBuilder.build()); - // TODO: sessions reject updates without a CLEAR_ALL or paging with a different token. - mFakeThreadUtils.enforceMainThread(false); - mFakeFeedRequestManager.loadMore(StreamToken.getDefaultInstance(), - ConsistencyToken.getDefaultInstance(), - mFeedSessionManager.getUpdateConsumer(MutationContext.EMPTY_CONTEXT)); - verify(changeObserver).onSessionFinished(any(UiContext.class)); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/SemanticPropertiesTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/SemanticPropertiesTest.java deleted file mode 100644 index c8576d2..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/SemanticPropertiesTest.java +++ /dev/null
@@ -1,63 +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. - -package org.chromium.chrome.browser.feed.library.infraintegration; - -import static com.google.common.truth.Truth.assertThat; - -import com.google.protobuf.ByteString; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.client.requestmanager.RequestManager; -import org.chromium.chrome.browser.feed.library.api.internal.common.SemanticPropertiesWithId; -import org.chromium.chrome.browser.feed.library.api.internal.common.testing.ContentIdGenerators; -import org.chromium.chrome.browser.feed.library.api.internal.store.Store; -import org.chromium.chrome.browser.feed.library.common.Result; -import org.chromium.chrome.browser.feed.library.common.testing.InfraIntegrationScope; -import org.chromium.chrome.browser.feed.library.common.testing.ResponseBuilder; -import org.chromium.chrome.browser.feed.library.testing.requestmanager.FakeFeedRequestManager; -import org.chromium.components.feed.core.proto.wire.ContentIdProto.ContentId; -import org.chromium.components.feed.core.proto.wire.ResponseProto.Response; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.Collections; -import java.util.List; - -/** Tests around Semantic Properties */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class SemanticPropertiesTest { - private final InfraIntegrationScope mScope = new InfraIntegrationScope.Builder().build(); - private final FakeFeedRequestManager mFakeFeedRequestManager = - mScope.getFakeFeedRequestManager(); - private final RequestManager mRequestManager = mScope.getRequestManager(); - private final Store mStore = mScope.getStore(); - - @Test - public void persistingSemanticProperties() { - ContentId contentId = ResponseBuilder.createFeatureContentId(13); - ByteString semanticData = ByteString.copyFromUtf8("helloWorld"); - - Response response = new ResponseBuilder() - .addClearOperation() - .addCardWithSemanticData(contentId, semanticData) - .build(); - mFakeFeedRequestManager.queueResponse(response); - mRequestManager.triggerScheduledRefresh(); - - mScope.getFakeThreadUtils().enforceMainThread(false); - ContentIdGenerators idGenerators = new ContentIdGenerators(); - String contentIdString = idGenerators.createContentId(contentId); - Result<List<SemanticPropertiesWithId>> semanticPropertiesResult = - mStore.getSemanticProperties(Collections.singletonList(contentIdString)); - assertThat(semanticPropertiesResult.isSuccessful()).isTrue(); - List<SemanticPropertiesWithId> semanticProperties = semanticPropertiesResult.getValue(); - assertThat(semanticProperties).hasSize(1); - assertThat(semanticProperties.get(0).contentId).isEqualTo(contentIdString); - assertThat(semanticProperties.get(0).semanticData).isEqualTo(semanticData.toByteArray()); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/SharedStateTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/SharedStateTest.java deleted file mode 100644 index 79ed4ce..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/SharedStateTest.java +++ /dev/null
@@ -1,85 +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. - -package org.chromium.chrome.browser.feed.library.infraintegration; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.client.requestmanager.RequestManager; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProviderFactory; -import org.chromium.chrome.browser.feed.library.api.internal.protocoladapter.ProtocolAdapter; -import org.chromium.chrome.browser.feed.library.common.testing.InfraIntegrationScope; -import org.chromium.chrome.browser.feed.library.common.testing.ModelProviderValidator; -import org.chromium.chrome.browser.feed.library.common.testing.ResponseBuilder; -import org.chromium.chrome.browser.feed.library.testing.requestmanager.FakeFeedRequestManager; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamSharedState; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.UiContext; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests of accessing shared state. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class SharedStateTest { - private FakeFeedRequestManager mFakeFeedRequestManager; - private ProtocolAdapter mProtocolAdapter; - private ModelProviderFactory mModelProviderFactory; - private ModelProviderValidator mModelValidator; - private RequestManager mRequestManager; - - @Before - public void setUp() { - initMocks(this); - InfraIntegrationScope scope = new InfraIntegrationScope.Builder().build(); - mFakeFeedRequestManager = scope.getFakeFeedRequestManager(); - mModelProviderFactory = scope.getModelProviderFactory(); - mProtocolAdapter = scope.getProtocolAdapter(); - mModelValidator = new ModelProviderValidator(mProtocolAdapter); - mRequestManager = scope.getRequestManager(); - } - - @Test - public void sharedState_headBeforeModelProvider() { - // ModelProvider is created from $HEAD containing content, simple shared state added - ResponseBuilder responseBuilder = - new ResponseBuilder().addClearOperation().addPietSharedState().addRootFeature(); - mFakeFeedRequestManager.queueResponse(responseBuilder.build()); - mRequestManager.triggerScheduledRefresh(); - - ModelProvider modelProvider = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - StreamSharedState sharedState = - modelProvider.getSharedState(ResponseBuilder.PIET_SHARED_STATE); - assertThat(sharedState).isNotNull(); - mModelValidator.assertStreamContentId(sharedState.getContentId(), - mProtocolAdapter.getStreamContentId(ResponseBuilder.PIET_SHARED_STATE)); - } - - @Test - public void sharedState_headAfterModelProvider() { - // ModelProvider is created from empty $HEAD, simple shared state added - ModelProvider modelProvider = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - StreamSharedState sharedState = - modelProvider.getSharedState(ResponseBuilder.PIET_SHARED_STATE); - assertThat(sharedState).isNull(); - - ResponseBuilder responseBuilder = - new ResponseBuilder().addClearOperation().addPietSharedState().addRootFeature(); - mFakeFeedRequestManager.queueResponse(responseBuilder.build()); - mRequestManager.triggerScheduledRefresh(); - - sharedState = modelProvider.getSharedState(ResponseBuilder.PIET_SHARED_STATE); - assertThat(sharedState).isNotNull(); - mModelValidator.assertStreamContentId(sharedState.getContentId(), - mProtocolAdapter.getStreamContentId(ResponseBuilder.PIET_SHARED_STATE)); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/SimpleStreamTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/SimpleStreamTest.java deleted file mode 100644 index a8f8ce1..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/SimpleStreamTest.java +++ /dev/null
@@ -1,118 +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. - -package org.chromium.chrome.browser.feed.library.infraintegration; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.client.requestmanager.RequestManager; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelChild; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelCursor; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelFeature; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProviderFactory; -import org.chromium.chrome.browser.feed.library.api.internal.protocoladapter.ProtocolAdapter; -import org.chromium.chrome.browser.feed.library.common.testing.InfraIntegrationScope; -import org.chromium.chrome.browser.feed.library.common.testing.ModelProviderValidator; -import org.chromium.chrome.browser.feed.library.common.testing.ResponseBuilder; -import org.chromium.chrome.browser.feed.library.common.testing.ResponseBuilder.WireProtocolInfo; -import org.chromium.chrome.browser.feed.library.testing.requestmanager.FakeFeedRequestManager; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.UiContext; -import org.chromium.components.feed.core.proto.wire.ContentIdProto.ContentId; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Simple tests of a stream with multiple cards. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class SimpleStreamTest { - private FakeFeedRequestManager mFakeFeedRequestManager; - private ModelProviderFactory mModelProviderFactory; - private ModelProviderValidator mModelValidator; - private ProtocolAdapter mProtocolAdapter; - private RequestManager mRequestManager; - - @Before - public void setUp() { - initMocks(this); - InfraIntegrationScope scope = new InfraIntegrationScope.Builder().build(); - mFakeFeedRequestManager = scope.getFakeFeedRequestManager(); - mModelProviderFactory = scope.getModelProviderFactory(); - mProtocolAdapter = scope.getProtocolAdapter(); - mModelValidator = new ModelProviderValidator(mProtocolAdapter); - mRequestManager = scope.getRequestManager(); - } - - @Test - public void simpleStream_oneCard() { - // ModelProvider created after $HEAD has content, one root, and one Card - // A Card is two features, the Card and Content. - ResponseBuilder responseBuilder = ResponseBuilder.forClearAllWithCards( - new ContentId[] {ResponseBuilder.createFeatureContentId(1)}); - mFakeFeedRequestManager.queueResponse(responseBuilder.build()); - mRequestManager.triggerScheduledRefresh(); - ModelProvider modelProvider = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - mModelValidator.assertRoot(modelProvider); - - WireProtocolInfo protocolInfo = responseBuilder.getWireProtocolInfo(); - int expectedFeatureCount = 3; // 1 root, 1 Card (2 features) - assertThat(protocolInfo.featuresAdded).hasSize(expectedFeatureCount); - assertThat(protocolInfo.hasClearOperation).isTrue(); - mModelValidator.verifyContent(modelProvider, protocolInfo.featuresAdded); - - // Validate the cursors - ModelFeature root = modelProvider.getRootFeature(); - assertThat(root).isNotNull(); - ModelCursor cursor = root.getCursor(); - int cursorCount = 0; - while (cursor.getNextItem() != null) { - cursorCount++; - } - assertThat(cursorCount).isEqualTo(1); - - // Validate that the structure of the card - cursor = root.getCursor(); - ModelChild child = cursor.getNextItem(); - mModelValidator.assertCardStructure(child); - } - - @Test - public void simpleStream_twoCard() { - // ModelProvider created after $HEAD has content, one root, and two Cards - ContentId[] cards = new ContentId[] {ResponseBuilder.createFeatureContentId(1), - ResponseBuilder.createFeatureContentId(2)}; - ResponseBuilder responseBuilder = ResponseBuilder.forClearAllWithCards(cards); - mFakeFeedRequestManager.queueResponse(responseBuilder.build()); - mRequestManager.triggerScheduledRefresh(); - ModelProvider modelProvider = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - mModelValidator.assertRoot(modelProvider); - - WireProtocolInfo protocolInfo = responseBuilder.getWireProtocolInfo(); - int expectedFeatureCount = 5; // 1 root, 2 Card (* 2 features) - assertThat(protocolInfo.featuresAdded).hasSize(expectedFeatureCount); - assertThat(protocolInfo.hasClearOperation).isTrue(); - mModelValidator.verifyContent(modelProvider, protocolInfo.featuresAdded); - - // Validate the cursor, we should have one card for each added - ModelFeature root = modelProvider.getRootFeature(); - assertThat(root).isNotNull(); - ModelCursor cursor = root.getCursor(); - for (ContentId contentId : cards) { - ModelChild child = cursor.getNextItem(); - assertThat(child).isNotNull(); - mModelValidator.assertStreamContentId( - child.getContentId(), mProtocolAdapter.getStreamContentId(contentId)); - mModelValidator.assertCardStructure(child); - } - assertThat(cursor.isAtEnd()).isTrue(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/StreamPagingTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/StreamPagingTest.java deleted file mode 100644 index 6707965..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/StreamPagingTest.java +++ /dev/null
@@ -1,164 +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. - -package org.chromium.chrome.browser.feed.library.infraintegration; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.client.requestmanager.RequestManager; -import org.chromium.chrome.browser.feed.library.api.internal.common.testing.ContentIdGenerators; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelChild; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelCursor; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelFeature; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProviderFactory; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelToken; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.TokenCompleted; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.TokenCompletedObserver; -import org.chromium.chrome.browser.feed.library.common.testing.InfraIntegrationScope; -import org.chromium.chrome.browser.feed.library.common.testing.ModelProviderValidator; -import org.chromium.chrome.browser.feed.library.common.testing.PagingState; -import org.chromium.chrome.browser.feed.library.common.testing.ResponseBuilder; -import org.chromium.chrome.browser.feed.library.testing.requestmanager.FakeFeedRequestManager; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.UiContext; -import org.chromium.components.feed.core.proto.wire.ContentIdProto.ContentId; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Test of handling paging operations within the Stream. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class StreamPagingTest { - private FakeFeedRequestManager mFakeFeedRequestManager; - private ModelProviderFactory mModelProviderFactory; - private ModelProviderValidator mModelValidator; - private ContentIdGenerators mContentIdGenerators = new ContentIdGenerators(); - private RequestManager mRequestManager; - - @Before - public void setUp() { - initMocks(this); - InfraIntegrationScope scope = new InfraIntegrationScope.Builder().build(); - mFakeFeedRequestManager = scope.getFakeFeedRequestManager(); - mModelProviderFactory = scope.getModelProviderFactory(); - mModelValidator = new ModelProviderValidator(scope.getProtocolAdapter()); - mRequestManager = scope.getRequestManager(); - } - - /** - * This test will create a Session and page it. Fully validating the observer and results. - * - * <ol> - * <li>Setup the initial response and the paged response - * <li>Setup the paging handling for the FeedRequestManager - * <li>Create the Initial $HEAD from the initial response - * <li>Create a Session/ModelProvider - * <li>Setup the MutationContext and the ModelToken observer - * <li>ModelProvider.handleToken to cause the paging response to be loaded - * <li>Validate... - * </ol> - */ - @Test - public void testPaging() { - // ModelProvider created after $HEAD has content, one root, and two Cards and a token - ContentId[] cards = new ContentId[] {ResponseBuilder.createFeatureContentId(1), - ResponseBuilder.createFeatureContentId(2)}; - ContentId[] pageCards = new ContentId[] {ResponseBuilder.createFeatureContentId(3), - ResponseBuilder.createFeatureContentId(4)}; - PagingState state = new PagingState(cards, pageCards, 1, mContentIdGenerators); - mFakeFeedRequestManager.queueResponse(state.initialResponse); - mFakeFeedRequestManager.queueResponse(state.pageResponse); - - // Create an initial model - mRequestManager.triggerScheduledRefresh(); - ModelProvider modelProvider = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - mModelValidator.assertRoot(modelProvider); - - // Validate the structure of the stream after the initial response - ModelFeature rootFeature = modelProvider.getRootFeature(); - assertThat(rootFeature).isNotNull(); - ModelCursor cursor = rootFeature.getCursor(); - ModelChild tokenFeature = mModelValidator.assertCursorContentsWithToken(cursor, cards); - assertThat(tokenFeature).isNotNull(); - - // Add an observer to the Token to get an event when the response is processed - TokenCompletedObserver tokenCompletedObserver = mock(TokenCompletedObserver.class); - ModelToken modelToken = tokenFeature.getModelToken(); - assertThat(modelToken).isNotNull(); - - // Capture the event triggered once the paging operation is finished - modelToken.registerObserver(tokenCompletedObserver); - modelProvider.handleToken(modelToken); - ArgumentCaptor<TokenCompleted> completedArgumentCaptor = - ArgumentCaptor.forClass(TokenCompleted.class); - verify(tokenCompletedObserver).onTokenCompleted(completedArgumentCaptor.capture()); - ModelCursor pageCursor = completedArgumentCaptor.getValue().getCursor(); - assertThat(pageCursor).isNotNull(); - - // The event cursor will have only the new items added in the page - mModelValidator.assertCursorContents(pageCursor, pageCards); - - // The full cursor should now contain all the features - cursor = rootFeature.getCursor(); - mModelValidator.assertCursorContents( - cursor, cards[0], cards[1], pageCards[0], pageCards[1]); - } - - /** - * This test will create a session and page it. Then create a new session from $HEAD to verify - * that Head is correctly handling the token add/remove combination. - * - * <ul> - * <li>Setup the initial response and the paged response - * <li>Setup the paging handling for the FeedRequestManager - * <li>Create the Initial $HEAD from the initial response - * <li>Create a Session/ModelProvider - * <li>Page the Session/ModelProvider - * <li>Create a new Session from $HEAD - * <li>Validate that the PageToken are not in the cursor - * </ul> - */ - @Test - public void testPostPagingSessionCreation() { - ContentId[] cards = new ContentId[] {ResponseBuilder.createFeatureContentId(1), - ResponseBuilder.createFeatureContentId(2)}; - ContentId[] pageCards = new ContentId[] {ResponseBuilder.createFeatureContentId(3), - ResponseBuilder.createFeatureContentId(4)}; - PagingState state = new PagingState(cards, pageCards, 1, mContentIdGenerators); - mFakeFeedRequestManager.queueResponse(state.initialResponse); - mFakeFeedRequestManager.queueResponse(state.pageResponse); - - // Create an initial model - mRequestManager.triggerScheduledRefresh(); - ModelProvider modelProvider = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - ModelFeature rootFeature = modelProvider.getRootFeature(); - assertThat(rootFeature).isNotNull(); - ModelCursor cursor = rootFeature.getCursor(); - ModelChild tokenFeature = mModelValidator.assertCursorContentsWithToken(cursor, cards); - modelProvider.handleToken(tokenFeature.getModelToken()); - cursor = rootFeature.getCursor(); - mModelValidator.assertCursorContents( - cursor, cards[0], cards[1], pageCards[0], pageCards[1]); - - // Now create a second ModelProvider and verify the cursor. - ModelProvider session2 = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - rootFeature = session2.getRootFeature(); - assertThat(rootFeature).isNotNull(); - cursor = rootFeature.getCursor(); - mModelValidator.assertCursorContents( - cursor, cards[0], cards[1], pageCards[0], pageCards[1]); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/StructureUpdateTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/StructureUpdateTest.java deleted file mode 100644 index 2da2028d..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/StructureUpdateTest.java +++ /dev/null
@@ -1,137 +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. - -package org.chromium.chrome.browser.feed.library.infraintegration; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.client.requestmanager.RequestManager; -import org.chromium.chrome.browser.feed.library.api.common.MutationContext; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.FeatureChange; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.FeatureChangeObserver; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelChild; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelCursor; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelFeature; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProviderFactory; -import org.chromium.chrome.browser.feed.library.api.internal.protocoladapter.ProtocolAdapter; -import org.chromium.chrome.browser.feed.library.api.internal.sessionmanager.FeedSessionManager; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeThreadUtils; -import org.chromium.chrome.browser.feed.library.common.testing.InfraIntegrationScope; -import org.chromium.chrome.browser.feed.library.common.testing.ModelProviderValidator; -import org.chromium.chrome.browser.feed.library.common.testing.ResponseBuilder; -import org.chromium.chrome.browser.feed.library.testing.requestmanager.FakeFeedRequestManager; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamToken; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.UiContext; -import org.chromium.components.feed.core.proto.wire.ConsistencyTokenProto.ConsistencyToken; -import org.chromium.components.feed.core.proto.wire.ContentIdProto.ContentId; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.List; - -/** Tests which update (append) content to an existing model. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class StructureUpdateTest { - private final InfraIntegrationScope mScope = new InfraIntegrationScope.Builder().build(); - private final FakeFeedRequestManager mFakeFeedRequestManager = - mScope.getFakeFeedRequestManager(); - private final FakeThreadUtils mFakeThreadUtils = mScope.getFakeThreadUtils(); - private final ModelProviderFactory mModelProviderFactory = mScope.getModelProviderFactory(); - private final ModelProviderValidator mModelValidator = - new ModelProviderValidator(mScope.getProtocolAdapter()); - private final ProtocolAdapter mProtocolAdapter = mScope.getProtocolAdapter(); - private final FeedSessionManager mFeedSessionManager = mScope.getFeedSessionManager(); - private final RequestManager mRequestManager = mScope.getRequestManager(); - - @Test - public void appendChildren() { - // Create a simple stream with a root and two features - ContentId[] startingCards = new ContentId[] {ResponseBuilder.createFeatureContentId(1), - ResponseBuilder.createFeatureContentId(2)}; - // Define two features to be appended to the root - ContentId[] appendedCards = new ContentId[] {ResponseBuilder.createFeatureContentId(3), - ResponseBuilder.createFeatureContentId(4)}; - - mFakeFeedRequestManager.queueResponse( - ResponseBuilder.forClearAllWithCards(startingCards).build()); - mRequestManager.triggerScheduledRefresh(); - ModelProvider modelProvider = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - - ModelFeature root = modelProvider.getRootFeature(); - assertThat(root).isNotNull(); - FeatureChangeObserver rootObserver = mock(FeatureChangeObserver.class); - root.registerObserver(rootObserver); - mModelValidator.assertCursorSize(root.getCursor(), startingCards.length); - - // Append new children to root - mFakeFeedRequestManager.queueResponse( - ResponseBuilder.builder().addCardsToRoot(appendedCards).build()); - // TODO: sessions reject updates without a CLEAR_ALL or paging with a different token. - mFakeThreadUtils.enforceMainThread(false); - mFakeFeedRequestManager.loadMore(StreamToken.getDefaultInstance(), - ConsistencyToken.getDefaultInstance(), - mFeedSessionManager.getUpdateConsumer(MutationContext.EMPTY_CONTEXT)); - - // assert the new state of the stream - mModelValidator.assertCursorSize( - root.getCursor(), startingCards.length + appendedCards.length); - ArgumentCaptor<FeatureChange> capture = ArgumentCaptor.forClass(FeatureChange.class); - verify(rootObserver).onChange(capture.capture()); - List<FeatureChange> featureChanges = capture.getAllValues(); - assertThat(featureChanges).hasSize(1); - FeatureChange change = featureChanges.get(0); - assertThat(change.getChildChanges().getAppendedChildren()).hasSize(appendedCards.length); - assertThat(change.isFeatureChanged()).isFalse(); - int i = 0; - for (ModelChild appendedChild : change.getChildChanges().getAppendedChildren()) { - mModelValidator.assertStreamContentId(appendedChild.getContentId(), - mProtocolAdapter.getStreamContentId(appendedCards[i++])); - } - } - - @Test - public void appendChildren_concurrentModification() { - // Test which verifies the root can be updated while we advance a cursor (without - // a ConcurrentModificationException - // Create a simple stream with a root and two features - ContentId[] startingCards = new ContentId[] {ResponseBuilder.createFeatureContentId(1), - ResponseBuilder.createFeatureContentId(2)}; - // Define two features to be appended to the root - ContentId[] appendedCards = new ContentId[] {ResponseBuilder.createFeatureContentId(3), - ResponseBuilder.createFeatureContentId(4)}; - - mFakeFeedRequestManager.queueResponse( - ResponseBuilder.forClearAllWithCards(startingCards).build()); - mRequestManager.triggerScheduledRefresh(); - ModelProvider modelProvider = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - - ModelFeature root = modelProvider.getRootFeature(); - assertThat(root).isNotNull(); - FeatureChangeObserver rootObserver = mock(FeatureChangeObserver.class); - root.registerObserver(rootObserver); - ModelCursor cursor = root.getCursor(); - cursor.getNextItem(); - - // Now append additional children to the stream (and cursor) - mFakeFeedRequestManager.queueResponse( - ResponseBuilder.builder().addCardsToRoot(appendedCards).build()); - // TODO: sessions reject updates without a CLEAR_ALL or paging with a different token. - mFakeThreadUtils.enforceMainThread(false); - mFakeFeedRequestManager.loadMore(StreamToken.getDefaultInstance(), - ConsistencyToken.getDefaultInstance(), - mFeedSessionManager.getUpdateConsumer(MutationContext.EMPTY_CONTEXT)); - mModelValidator.assertCursorSize(cursor, 3); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/SyntheticTokensTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/SyntheticTokensTest.java deleted file mode 100644 index f86d3291..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/SyntheticTokensTest.java +++ /dev/null
@@ -1,492 +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. - -package org.chromium.chrome.browser.feed.library.infraintegration; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.MockitoAnnotations.initMocks; - -import static org.chromium.chrome.browser.feed.library.common.testing.ResponseBuilder.ROOT_CONTENT_ID; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.robolectric.annotation.Config; - -import org.chromium.base.Consumer; -import org.chromium.chrome.browser.feed.library.api.common.MutationContext; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration.ConfigKey; -import org.chromium.chrome.browser.feed.library.api.host.logging.RequestReason; -import org.chromium.chrome.browser.feed.library.api.internal.common.Model; -import org.chromium.chrome.browser.feed.library.api.internal.common.testing.ContentIdGenerators; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelChild; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelCursor; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelFeature; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider.State; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProviderFactory; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelToken; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.TokenCompleted; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.TokenCompletedObserver; -import org.chromium.chrome.browser.feed.library.api.internal.protocoladapter.ProtocolAdapter; -import org.chromium.chrome.browser.feed.library.api.internal.sessionmanager.FeedSessionManager; -import org.chromium.chrome.browser.feed.library.common.Result; -import org.chromium.chrome.browser.feed.library.common.concurrent.TaskQueue; -import org.chromium.chrome.browser.feed.library.common.testing.InfraIntegrationScope; -import org.chromium.chrome.browser.feed.library.common.testing.ModelProviderValidator; -import org.chromium.chrome.browser.feed.library.common.testing.PagingState; -import org.chromium.chrome.browser.feed.library.common.testing.ResponseBuilder; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.testing.requestmanager.FakeFeedRequestManager; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.UiContext; -import org.chromium.components.feed.core.proto.wire.ContentIdProto.ContentId; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.Arrays; - -/** Test Synthetic tokens. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class SyntheticTokensTest { - private static final int INITIAL_PAGE_SIZE = 4; - private static final int PAGE_SIZE = 4; - private static final int MIN_PAGE_SIZE = 2; - - private FakeClock mFakeClock; - private FakeFeedRequestManager mFakeFeedRequestManager; - private FeedSessionManager mFeedSessionManager; - private ModelProviderFactory mModelProviderFactory; - private ModelProviderValidator mModelValidator; - private ProtocolAdapter mProtocolAdapter; - private final ContentIdGenerators mContentIdGenerators = new ContentIdGenerators(); - - @Before - public void setUp() { - initMocks(this); - Configuration configuration = - new Configuration.Builder() - .put(ConfigKey.INITIAL_NON_CACHED_PAGE_SIZE, (long) INITIAL_PAGE_SIZE) - .put(ConfigKey.NON_CACHED_PAGE_SIZE, (long) PAGE_SIZE) - .put(ConfigKey.NON_CACHED_MIN_PAGE_SIZE, (long) MIN_PAGE_SIZE) - .build(); - InfraIntegrationScope scope = - new InfraIntegrationScope.Builder().setConfiguration(configuration).build(); - mFakeClock = scope.getFakeClock(); - mFakeFeedRequestManager = scope.getFakeFeedRequestManager(); - mFeedSessionManager = scope.getFeedSessionManager(); - mModelProviderFactory = scope.getModelProviderFactory(); - mProtocolAdapter = scope.getProtocolAdapter(); - mModelValidator = new ModelProviderValidator(scope.getProtocolAdapter()); - } - - /** - * This test will test the creation of synthetic tokens. - * - * <ol> - * <li>Create an initial $HEAD with 13 items - * <li>Clear the FeedSessionManager ContentCache to simulate non-cached mode - * <li>Create a new session which will have a synthetic token at INITIAL_PAGE_SIZE - * <li>FeedSessionManager.handleToken on the synthetic token, verify full cursor and partial - * page cursor - * <li>FeedSessionManager.handleToken on the next synthetic token, verify we get PAGE_SIZE + - * slop. Verify both the full cursor and the partial page cursor. No further tokens will - * be in the cursor. - * </ol> - */ - @Test - public void syntheticTokenPaging() { - ContentId[] cards = new ContentId[] {ResponseBuilder.createFeatureContentId(1), - ResponseBuilder.createFeatureContentId(2), - ResponseBuilder.createFeatureContentId(3), - ResponseBuilder.createFeatureContentId(4), - ResponseBuilder.createFeatureContentId(5), - ResponseBuilder.createFeatureContentId(6), - ResponseBuilder.createFeatureContentId(7), - ResponseBuilder.createFeatureContentId(9), - ResponseBuilder.createFeatureContentId(10), - ResponseBuilder.createFeatureContentId(11), - ResponseBuilder.createFeatureContentId(12), - ResponseBuilder.createFeatureContentId(13)}; - - // Create 13 cards (initial page size + page size + page size and slope of 1) - // Initial model will have all the cards - mFakeFeedRequestManager.queueResponse(ResponseBuilder.forClearAllWithCards(cards).build()); - mFakeFeedRequestManager.triggerRefresh(RequestReason.OPEN_WITHOUT_CONTENT, - mFeedSessionManager.getUpdateConsumer(MutationContext.EMPTY_CONTEXT)); - ModelProvider modelProvider = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - - ModelFeature root = modelProvider.getRootFeature(); - assertThat(root).isNotNull(); - ModelCursor cursor = root.getCursor(); - ModelChild token = mModelValidator.assertCursorContentsWithToken( - cursor, Arrays.copyOf(cards, INITIAL_PAGE_SIZE)); - assertThat(token.getModelToken().isSynthetic()).isTrue(); - - // clear the ContentCache - clearSessionManagerContentCache(); - - // Create a new ModelProvider and verify the first page size is INITIAL_PAGE_SIZE (4) - modelProvider = mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - - root = modelProvider.getRootFeature(); - assertThat(root).isNotNull(); - cursor = root.getCursor(); - token = mModelValidator.assertCursorContentsWithToken( - cursor, Arrays.copyOf(cards, INITIAL_PAGE_SIZE)); - - // Register observer, handle token, verify the full cursor and the observer's cursor - // This should be the second page (PAGE_SIZE) and there will still be a new synthetic token - TokenCompletedObserver tokenCompletedObserver = mock(TokenCompletedObserver.class); - token.getModelToken().registerObserver(tokenCompletedObserver); - modelProvider.handleToken(token.getModelToken()); - ArgumentCaptor<TokenCompleted> completedArgumentCaptor = - ArgumentCaptor.forClass(TokenCompleted.class); - verify(tokenCompletedObserver).onTokenCompleted(completedArgumentCaptor.capture()); - ModelCursor pageCursor = completedArgumentCaptor.getValue().getCursor(); - assertThat(pageCursor).isNotNull(); - mModelValidator.assertCursorContentsWithToken(cursor, - Arrays.copyOfRange(cards, INITIAL_PAGE_SIZE, INITIAL_PAGE_SIZE + PAGE_SIZE)); - cursor = root.getCursor(); - token = mModelValidator.assertCursorContentsWithToken( - cursor, Arrays.copyOf(cards, INITIAL_PAGE_SIZE + PAGE_SIZE)); - - // Register observer, handle token, verify that we pick up PAGE_SIZE + slop, verify - // observer cursor and full cursor, no further token will be in the cursor. - tokenCompletedObserver = mock(TokenCompletedObserver.class); - token.getModelToken().registerObserver(tokenCompletedObserver); - modelProvider.handleToken(token.getModelToken()); - completedArgumentCaptor = ArgumentCaptor.forClass(TokenCompleted.class); - verify(tokenCompletedObserver).onTokenCompleted(completedArgumentCaptor.capture()); - pageCursor = completedArgumentCaptor.getValue().getCursor(); - assertThat(pageCursor).isNotNull(); - mModelValidator.assertCursorContents( - pageCursor, Arrays.copyOfRange(cards, INITIAL_PAGE_SIZE + PAGE_SIZE, cards.length)); - modelProvider.handleToken(token.getModelToken()); - cursor = root.getCursor(); - mModelValidator.assertCursorContents(cursor, cards); - } - - /** - * This test will test the creation of synthetic tokens. - * - * <ol> - * <li>Create an initial $HEAD with 13 items - * <li>Clear the FeedSessionManager ContentCache to simulate non-cached mode - * <li>Create a new session which will have a synthetic token at INITIAL_PAGE_SIZE - * <li>FeedSessionManager.handleToken on the synthetic token, verify full cursor and partial - * page cursor - * <li>FeedSessionManager.handleToken on the next synthetic token, verify we get PAGE_SIZE + - * slop. Verify both the full cursor and the partial page cursor. No further tokens will - * be in the cursor. - * </ol> - */ - @Test - public void syntheticTokenPaging_withCache() { - ContentId[] cards = new ContentId[] {ResponseBuilder.createFeatureContentId(1), - ResponseBuilder.createFeatureContentId(2), - ResponseBuilder.createFeatureContentId(3), - ResponseBuilder.createFeatureContentId(4), - ResponseBuilder.createFeatureContentId(5), - ResponseBuilder.createFeatureContentId(6), - ResponseBuilder.createFeatureContentId(7), - ResponseBuilder.createFeatureContentId(9), - ResponseBuilder.createFeatureContentId(10), - ResponseBuilder.createFeatureContentId(11), - ResponseBuilder.createFeatureContentId(12), - ResponseBuilder.createFeatureContentId(13)}; - - // Create 13 cards (initial page size + page size + page size and slope of 1) - // Initial model will have all the cards - mFakeFeedRequestManager.queueResponse(ResponseBuilder.forClearAllWithCards(cards).build()); - mFakeFeedRequestManager.triggerRefresh(RequestReason.OPEN_WITHOUT_CONTENT, - mFeedSessionManager.getUpdateConsumer(MutationContext.EMPTY_CONTEXT)); - ModelProvider modelProvider = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - - ModelFeature root = modelProvider.getRootFeature(); - assertThat(root).isNotNull(); - ModelCursor cursor = root.getCursor(); - ModelChild token = mModelValidator.assertCursorContentsWithToken( - cursor, Arrays.copyOfRange(cards, 0, INITIAL_PAGE_SIZE)); - assertThat(token.getModelToken().isSynthetic()).isTrue(); - - // Create a new ModelProvider and verify the first page size is INITIAL_PAGE_SIZE (4) - modelProvider = mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - - root = modelProvider.getRootFeature(); - assertThat(root).isNotNull(); - cursor = root.getCursor(); - token = mModelValidator.assertCursorContentsWithToken( - cursor, Arrays.copyOf(cards, INITIAL_PAGE_SIZE)); - - // Register observer, handle token, verify the full cursor and the observer's cursor - // This should be the second page (PAGE_SIZE) and there will still be a new synthetic token - TokenCompletedObserver tokenCompletedObserver = mock(TokenCompletedObserver.class); - token.getModelToken().registerObserver(tokenCompletedObserver); - modelProvider.handleToken(token.getModelToken()); - ArgumentCaptor<TokenCompleted> completedArgumentCaptor = - ArgumentCaptor.forClass(TokenCompleted.class); - verify(tokenCompletedObserver).onTokenCompleted(completedArgumentCaptor.capture()); - ModelCursor pageCursor = completedArgumentCaptor.getValue().getCursor(); - assertThat(pageCursor).isNotNull(); - mModelValidator.assertCursorContentsWithToken(cursor, - Arrays.copyOfRange(cards, INITIAL_PAGE_SIZE, INITIAL_PAGE_SIZE + PAGE_SIZE)); - cursor = root.getCursor(); - token = mModelValidator.assertCursorContentsWithToken( - cursor, Arrays.copyOfRange(cards, 0, INITIAL_PAGE_SIZE + PAGE_SIZE)); - - // Register observer, handle token, verify that we pick up PAGE_SIZE + slop, verify - // observer cursor and full cursor, no further token will be in the cursor. - tokenCompletedObserver = mock(TokenCompletedObserver.class); - token.getModelToken().registerObserver(tokenCompletedObserver); - modelProvider.handleToken(token.getModelToken()); - completedArgumentCaptor = ArgumentCaptor.forClass(TokenCompleted.class); - verify(tokenCompletedObserver).onTokenCompleted(completedArgumentCaptor.capture()); - pageCursor = completedArgumentCaptor.getValue().getCursor(); - assertThat(pageCursor).isNotNull(); - mModelValidator.assertCursorContents( - pageCursor, Arrays.copyOfRange(cards, INITIAL_PAGE_SIZE + PAGE_SIZE, cards.length)); - modelProvider.handleToken(token.getModelToken()); - cursor = root.getCursor(); - mModelValidator.assertCursorContents(cursor, cards); - } - - /** - * Test Synthetic tokens on paged results. - * - * <ol> - * <li>Create an initial $HEAD with 4 items and a second page of 8 additional items - * <li>Create a new session and validate the expected cards and a real next page token. - * <li>Handle the token to bring in the second page of items - * <li>Validate that we have 8 total items, plus a synthetic token - * <li>Handle the synthetic token - * <li>Validate that we have all 12 total items with no token - * </ol> - */ - @Test - public void syntheticTokenPaging_paging() { - ContentId[] cards = new ContentId[] { - ResponseBuilder.createFeatureContentId(1), - ResponseBuilder.createFeatureContentId(2), - ResponseBuilder.createFeatureContentId(3), - ResponseBuilder.createFeatureContentId(4), - }; - ContentId[] pageCards = new ContentId[] {ResponseBuilder.createFeatureContentId(5), - ResponseBuilder.createFeatureContentId(6), - ResponseBuilder.createFeatureContentId(7), - ResponseBuilder.createFeatureContentId(8), - ResponseBuilder.createFeatureContentId(9), - ResponseBuilder.createFeatureContentId(10), - ResponseBuilder.createFeatureContentId(11), - ResponseBuilder.createFeatureContentId(12)}; - - PagingState state = new PagingState(cards, pageCards, 1, mContentIdGenerators); - mFakeFeedRequestManager.queueResponse(state.initialResponse); - mFakeFeedRequestManager.queueResponse(state.pageResponse); - mFakeFeedRequestManager.triggerRefresh(RequestReason.OPEN_WITHOUT_CONTENT, - mFeedSessionManager.getUpdateConsumer(MutationContext.EMPTY_CONTEXT)); - ModelProvider modelProvider = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - - ModelFeature root = modelProvider.getRootFeature(); - assertThat(root).isNotNull(); - ModelCursor cursor = root.getCursor(); - ModelChild tokenFeature = mModelValidator.assertCursorContentsWithToken(cursor, cards); - assertThat(tokenFeature).isNotNull(); - assertThat(tokenFeature.getModelToken().isSynthetic()).isFalse(); - - ModelToken modelToken = tokenFeature.getModelToken(); - modelProvider.handleToken(modelToken); - cursor = root.getCursor(); - tokenFeature = mModelValidator.assertCursorContentsWithToken( - cursor, getExpectedCards(cards, pageCards, 4)); - assertThat(tokenFeature).isNotNull(); - assertThat(tokenFeature.getModelToken().isSynthetic()).isTrue(); - - modelProvider.handleToken(tokenFeature.getModelToken()); - cursor = root.getCursor(); - tokenFeature = mModelValidator.assertCursorContentsWithToken( - cursor, getExpectedCards(cards, pageCards, -1)); - assertThat(tokenFeature).isNull(); - } - - /** - * Test Synthetic tokens on paged results when creating an existing session. - * - * <ol> - * <li>Create an initial $HEAD with 4 items and a second page of 8 additional items - * <li>Create a new session and validate the expected cards and a real next page token. - * <li>Handle the token to bring in the second page of items - * <li>Validate that we have 8 total items, plus a synthetic token - * <li>Recreate the session (invalidating the first version) - * <li>Validate that we have 4 cards and a synthetic token - * <li>Handle the synthetic token - * <li>Validate that we have 8 total items, plus a synthetic token - * <li>Handle the synthetic token - * <li>Validate that we have all 12 total items with no token - * </ol> - */ - @Test - public void syntheticTokenPaging_pagingRestoredSession() { - ContentId[] cards = new ContentId[] { - ResponseBuilder.createFeatureContentId(1), - ResponseBuilder.createFeatureContentId(2), - ResponseBuilder.createFeatureContentId(3), - ResponseBuilder.createFeatureContentId(4), - }; - ContentId[] pageCards = new ContentId[] {ResponseBuilder.createFeatureContentId(5), - ResponseBuilder.createFeatureContentId(6), - ResponseBuilder.createFeatureContentId(7), - ResponseBuilder.createFeatureContentId(8), - ResponseBuilder.createFeatureContentId(9), - ResponseBuilder.createFeatureContentId(10), - ResponseBuilder.createFeatureContentId(11), - ResponseBuilder.createFeatureContentId(12)}; - - PagingState state = new PagingState(cards, pageCards, 1, mContentIdGenerators); - mFakeFeedRequestManager.queueResponse(state.initialResponse); - mFakeFeedRequestManager.queueResponse(state.pageResponse); - mFakeFeedRequestManager.triggerRefresh(RequestReason.OPEN_WITHOUT_CONTENT, - mFeedSessionManager.getUpdateConsumer(MutationContext.EMPTY_CONTEXT)); - ModelProvider modelProvider = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - String sessionId = modelProvider.getSessionId(); - - ModelFeature root = modelProvider.getRootFeature(); - assertThat(root).isNotNull(); - ModelCursor cursor = root.getCursor(); - ModelChild tokenFeature = mModelValidator.assertCursorContentsWithToken(cursor, cards); - assertThat(tokenFeature).isNotNull(); - assertThat(tokenFeature.getModelToken().isSynthetic()).isFalse(); - - ModelToken modelToken = tokenFeature.getModelToken(); - modelProvider.handleToken(modelToken); - cursor = root.getCursor(); - tokenFeature = mModelValidator.assertCursorContentsWithToken( - cursor, getExpectedCards(cards, pageCards, 4)); - assertThat(tokenFeature).isNotNull(); - assertThat(tokenFeature.getModelToken().isSynthetic()).isTrue(); - - // now restore the session and see what we have - modelProvider = mModelProviderFactory.create(sessionId, UiContext.getDefaultInstance()); - root = modelProvider.getRootFeature(); - assertThat(root).isNotNull(); - cursor = root.getCursor(); - tokenFeature = mModelValidator.assertCursorContentsWithToken(cursor, cards); - assertThat(tokenFeature).isNotNull(); - assertThat(tokenFeature.getModelToken().isSynthetic()).isTrue(); - - modelProvider.handleToken(tokenFeature.getModelToken()); - cursor = root.getCursor(); - tokenFeature = mModelValidator.assertCursorContentsWithToken( - cursor, getExpectedCards(cards, pageCards, 4)); - assertThat(tokenFeature).isNotNull(); - assertThat(tokenFeature.getModelToken().isSynthetic()).isTrue(); - - modelProvider.handleToken(tokenFeature.getModelToken()); - cursor = root.getCursor(); - tokenFeature = mModelValidator.assertCursorContentsWithToken( - cursor, getExpectedCards(cards, pageCards, -1)); - assertThat(tokenFeature).isNull(); - } - - /** - * This will tests synthetic tokens in the context of an empty ModelProvider, see [INTERNAL - * LINK]. This test is written directly against the session manager instead of the request - * manager. - * - * <p> - * <li>Create an initial Model provider with a single content item under the root - * <li>Remove that item, creating an empty Root - * <li>Added a new page of items with enough to cause a synthetic token to be added - */ - @Test - public void testEmptyFeed() { - ContentId[] cards = new ContentId[] { - ResponseBuilder.createFeatureContentId(1), - }; - ContentId[] cardsTwo = new ContentId[] { - ResponseBuilder.createFeatureContentId(2), - ResponseBuilder.createFeatureContentId(3), - ResponseBuilder.createFeatureContentId(4), - ResponseBuilder.createFeatureContentId(5), - ResponseBuilder.createFeatureContentId(6), - ResponseBuilder.createFeatureContentId(7), - ResponseBuilder.createFeatureContentId(8), - }; - - // Create an initial root with a single item in it. - mFakeFeedRequestManager.queueResponse(ResponseBuilder.forClearAllWithCards(cards).build()); - mFakeFeedRequestManager.triggerRefresh(RequestReason.OPEN_WITHOUT_CONTENT, - mFeedSessionManager.getUpdateConsumer(MutationContext.EMPTY_CONTEXT)); - ModelProvider modelProvider = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - assertThat(modelProvider.getCurrentState()).isEqualTo(State.READY); - - // Prep for sending modifications to the model provider - MutationContext context = new MutationContext.Builder() - .setRequestingSessionId(modelProvider.getSessionId()) - .build(); - - // Remove the single item under the root to create the empty state. - Result<Model> result = mProtocolAdapter.createModel( - ResponseBuilder.builder().removeFeature(cards[0], ROOT_CONTENT_ID).build()); - assertThat(result.isSuccessful()).isTrue(); - Consumer<Result<Model>> updateConsumer = mFeedSessionManager.getUpdateConsumer(context); - updateConsumer.accept(result); - - // Verify the empty state - ModelFeature root = modelProvider.getRootFeature(); - assertThat(root).isNotNull(); - ModelCursor cursor = root.getCursor(); - assertThat(cursor.isAtEnd()).isTrue(); - - // Create a next page response with enough new cards to ensure a synthetic token is added - result = mProtocolAdapter.createModel( - ResponseBuilder.builder().addCardsToRoot(cardsTwo).build()); - assertThat(result.isSuccessful()).isTrue(); - updateConsumer = mFeedSessionManager.getUpdateConsumer(context); - updateConsumer.accept(result); - - // Validate the current model - root = modelProvider.getRootFeature(); - assertThat(root).isNotNull(); - cursor = root.getCursor(); - ModelChild tokenFeature = mModelValidator.assertCursorContentsWithToken( - cursor, Arrays.copyOf(cardsTwo, INITIAL_PAGE_SIZE)); - assertThat(tokenFeature).isNotNull(); - assertThat(tokenFeature.getModelToken().isSynthetic()).isTrue(); - } - - private ContentId[] getExpectedCards(ContentId[] first, ContentId[] second, int length) { - if (length == -1) { - length = second.length; - } - ContentId[] results = new ContentId[first.length + length]; - System.arraycopy(first, 0, results, 0, first.length); - System.arraycopy(second, 0, results, first.length, length); - return results; - } - - private void clearSessionManagerContentCache() { - // This is a bit of hack, which will clear the content cache and indicate to the - // FeedSessionManager that we are in the non-cached mode. - mFakeFeedRequestManager.queueResponse(new ResponseBuilder().build()); - mFakeFeedRequestManager.triggerRefresh(RequestReason.OPEN_WITHOUT_CONTENT, - mFeedSessionManager.getUpdateConsumer(MutationContext.EMPTY_CONTEXT)); - mFakeClock.advance(TaskQueue.STARVATION_TIMEOUT_MS); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/TimeoutSessionBaseTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/TimeoutSessionBaseTest.java deleted file mode 100644 index b1e4a537..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/TimeoutSessionBaseTest.java +++ /dev/null
@@ -1,155 +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. - -package org.chromium.chrome.browser.feed.library.infraintegration; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.scheduler.SchedulerApi.RequestBehavior; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelError; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProviderFactory; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProviderObserver; -import org.chromium.chrome.browser.feed.library.api.internal.sessionmanager.FeedSessionManager; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeThreadUtils; -import org.chromium.chrome.browser.feed.library.common.testing.InfraIntegrationScope; -import org.chromium.chrome.browser.feed.library.common.testing.ModelProviderValidator; -import org.chromium.chrome.browser.feed.library.common.testing.ResponseBuilder; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.feedsessionmanager.FeedSessionManagerImpl; -import org.chromium.chrome.browser.feed.library.testing.host.scheduler.FakeSchedulerApi; -import org.chromium.chrome.browser.feed.library.testing.requestmanager.FakeFeedRequestManager; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.UiContext; -import org.chromium.components.feed.core.proto.wire.ContentIdProto.ContentId; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * This is a TimeoutSession test which verifies the REQUEST_WITH_WAIT. - * - * <p>NOTE: This test has multiple threads running. There is a single threaded executor created in - * addition to the main thread. The Test will throw a TimeoutException in in production in the event - * of a deadlock. The DEBUG boolean controls the behavior to allow debugging. - */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class TimeoutSessionBaseTest { - // This flag will should be flipped to debug the test. It will disable TimeoutExceptions. - private static final boolean DEBUG = false; - - private final FakeSchedulerApi mFakeSchedulerApi = - new FakeSchedulerApi(FakeThreadUtils.withoutThreadChecks()); - - private FakeClock mFakeClock; - private FakeFeedRequestManager mFakeFeedRequestManager; - private FeedSessionManager mFeedSessionManager; - private ModelProviderFactory mModelProviderFactory; - private ModelProviderValidator mModelValidator; - private long mTimeoutDeadline; - - @Before - public void setUp() { - initMocks(this); - InfraIntegrationScope scope = new InfraIntegrationScope.Builder() - .setSchedulerApi(mFakeSchedulerApi) - .withTimeoutSessionConfiguration(2L) - .build(); - mFakeClock = scope.getFakeClock(); - mFakeFeedRequestManager = scope.getFakeFeedRequestManager(); - mFeedSessionManager = scope.getFeedSessionManager(); - mModelProviderFactory = scope.getModelProviderFactory(); - mModelValidator = new ModelProviderValidator(scope.getProtocolAdapter()); - } - - /** - * Test steps: - * - * <ol> - * <li>Create the initial ModelProvider from $HEAD with a REQUEST_WITH_WAIT which makes the - * request before the session is populated. - * <li>Create a second ModelProvider using NO_REQUEST_WITH_CONTENT which should duplidate the - * session created with the initial request. - * </ol> - */ - @Test - public void testRequestWithWait() throws TimeoutException { - ContentId[] requestOne = new ContentId[] {ResponseBuilder.createFeatureContentId(1), - ResponseBuilder.createFeatureContentId(2), - ResponseBuilder.createFeatureContentId(3)}; - - // Load up the initial request - mFakeFeedRequestManager.queueResponse( - ResponseBuilder.forClearAllWithCards(requestOne).build(), /* delayMs= */ 100); - - // Wait for the request to complete (REQUEST_WITH_WAIT). This will trigger the request and - // wait for it to complete to populate the new session. - mFakeSchedulerApi.setRequestBehavior(RequestBehavior.REQUEST_WITH_WAIT); - ModelProvider modelProvider = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - - // This will wait for the session to be created and validate the root cursor - AtomicBoolean finished = new AtomicBoolean(false); - assertSessionCreation(modelProvider, finished, requestOne); - long startTimeMs = mFakeClock.currentTimeMillis(); - while (!finished.get()) { - // Loop through the tasks and wait for the assertSessionCreation to set finished to true - mFakeClock.tick(); - if (mTimeoutDeadline > 0 && mFakeClock.currentTimeMillis() > mTimeoutDeadline) { - throw new TimeoutException(); - } - } - assertThat(mFakeClock.currentTimeMillis() - startTimeMs).isAtLeast(100L); - - // Create a new ModelProvider from HEAD (NO_REQUEST_WITH_CONTENT) - mFakeSchedulerApi.setRequestBehavior(RequestBehavior.NO_REQUEST_WITH_CONTENT); - // This will wait for the session to be created and validate the root cursor - modelProvider = mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - assertSessionCreation(modelProvider, finished, requestOne); - startTimeMs = mFakeClock.currentTimeMillis(); - while (!finished.get()) { - // Loop through the tasks and wait for the assertSessionCreation to set finished to true - mFakeClock.tick(); - if (mTimeoutDeadline > 0 && mFakeClock.currentTimeMillis() > mTimeoutDeadline) { - throw new TimeoutException(); - } - } - assertThat(mFakeClock.currentTimeMillis() - startTimeMs).isEqualTo(0); - } - - private void assertSessionCreation( - ModelProvider modelProvider, AtomicBoolean finished, ContentId... cards) { - finished.set(false); - mTimeoutDeadline = DEBUG - ? InfraIntegrationScope.TIMEOUT_TEST_TIMEOUT + mFakeClock.currentTimeMillis() - : 0; - modelProvider.registerObserver(new ModelProviderObserver() { - @Override - public void onSessionStart(UiContext uiContext) { - System.out.println("onSessionStart"); - finished.set(true); - mModelValidator.assertCursorContents(modelProvider, cards); - assertThat(((FeedSessionManagerImpl) mFeedSessionManager).isDelayed()).isFalse(); - } - - @Override - public void onSessionFinished(UiContext uiContext) { - System.out.println("onSessionFinished"); - } - - @Override - public void onError(ModelError modelError) { - System.out.println("onError"); - } - }); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/TimeoutSessionWithContentTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/TimeoutSessionWithContentTest.java deleted file mode 100644 index 0c9177c2..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/TimeoutSessionWithContentTest.java +++ /dev/null
@@ -1,203 +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. - -package org.chromium.chrome.browser.feed.library.infraintegration; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.MockitoAnnotations.initMocks; - -import static org.chromium.chrome.browser.feed.library.common.testing.ResponseBuilder.ROOT_CONTENT_ID; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.scheduler.SchedulerApi.RequestBehavior; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.FeatureChange.ChildChanges; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelError; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelFeature; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProviderFactory; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProviderObserver; -import org.chromium.chrome.browser.feed.library.api.internal.protocoladapter.ProtocolAdapter; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeThreadUtils; -import org.chromium.chrome.browser.feed.library.common.testing.InfraIntegrationScope; -import org.chromium.chrome.browser.feed.library.common.testing.ModelProviderValidator; -import org.chromium.chrome.browser.feed.library.common.testing.ResponseBuilder; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.testing.host.scheduler.FakeSchedulerApi; -import org.chromium.chrome.browser.feed.library.testing.requestmanager.FakeFeedRequestManager; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.UiContext; -import org.chromium.components.feed.core.proto.wire.ContentIdProto.ContentId; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * This is a TimeoutSession test which verifies REQUEST_WITH_CONTENT - * - * <p>NOTE: This test has multiple threads running. There is a single threaded executor created in - * addition to the main thread. The Test will throw a TimeoutException in in production in the event - * of a deadlock. The DEBUG boolean controls the behavior to allow debugging. - */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class TimeoutSessionWithContentTest { - // This flag will should be flipped to debug the test. It will disable TimeoutExceptions. - private static final boolean DEBUG = false; - private static final ContentId[] REQUEST_ONE = new ContentId[] { - ResponseBuilder.createFeatureContentId(1), ResponseBuilder.createFeatureContentId(2), - ResponseBuilder.createFeatureContentId(3)}; - private static final ContentId[] REQUEST_TWO = new ContentId[] { - ResponseBuilder.createFeatureContentId(4), ResponseBuilder.createFeatureContentId(3), - ResponseBuilder.createFeatureContentId(5)}; - - private final FakeSchedulerApi mFakeSchedulerApi = - new FakeSchedulerApi(FakeThreadUtils.withoutThreadChecks()); - - private FakeClock mFakeClock; - private FakeFeedRequestManager mFakeFeedRequestManager; - private ModelProviderFactory mModelProviderFactory; - private ProtocolAdapter mProtocolAdapter; - private ModelProviderValidator mModelValidator; - private long mTimeoutDeadline; - - @Before - public void setUp() { - initMocks(this); - InfraIntegrationScope scope = new InfraIntegrationScope.Builder() - .setSchedulerApi(mFakeSchedulerApi) - .withTimeoutSessionConfiguration(2L) - .build(); - mFakeClock = scope.getFakeClock(); - mFakeFeedRequestManager = scope.getFakeFeedRequestManager(); - mModelProviderFactory = scope.getModelProviderFactory(); - mProtocolAdapter = scope.getProtocolAdapter(); - mModelValidator = new ModelProviderValidator(scope.getProtocolAdapter()); - } - - /** - * Test steps: - * - * <ol> - * <li>Create the initial ModelProvider from $HEAD with a REQUEST_WITH_WAIT which makes the - * request before the session is populated. - * <li>Load the second request into the FeedRequestManager - * <li>Create a second ModelProvider using REQUEST_WITH_CONTENT which displays the initial - * $HEAD but makes a request. The second request will be appended to and update the - * ModelProvider. - * </ol> - */ - @Test - public void testRequestWithWait() throws TimeoutException { - // Load up the initial request - mFakeFeedRequestManager.queueResponse( - ResponseBuilder.forClearAllWithCards(REQUEST_ONE).build(), /* delayMs= */ 100); - - // Wait for the request to complete (REQUEST_WITH_CONTENT). This will trigger the request - // and wait for it to complete to populate the new session. - mFakeSchedulerApi.setRequestBehavior(RequestBehavior.REQUEST_WITH_WAIT); - ModelProvider modelProvider = - mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - - // This will wait for the session to be created and validate the root cursor - AtomicBoolean finished = new AtomicBoolean(false); - assertSessionCreation(modelProvider, finished); - long startTimeMs = mFakeClock.currentTimeMillis(); - while (!finished.get()) { - // Loop through the tasks and wait for the assertSessionCreation to set finished to true - mFakeClock.tick(); - if (mTimeoutDeadline > 0 && mFakeClock.currentTimeMillis() > mTimeoutDeadline) { - throw new TimeoutException(); - } - } - assertThat(mFakeClock.currentTimeMillis() - startTimeMs).isAtLeast(100L); - - // Create a new ModelProvider from HEAD (REQUEST_WITH_CONTENT) - mFakeFeedRequestManager.queueResponse( - ResponseBuilder.forClearAllWithCards(REQUEST_TWO).build(), /* delayMs= */ 100); - mFakeSchedulerApi.setRequestBehavior(RequestBehavior.REQUEST_WITH_CONTENT); - // This will wait for the session to be created and validate the root cursor - modelProvider = mModelProviderFactory.createNew(null, UiContext.getDefaultInstance()); - assertSessionCreationWithRequest(modelProvider, finished); - startTimeMs = mFakeClock.currentTimeMillis(); - while (!finished.get()) { - // Loop through the tasks and wait for the assertSessionCreation to set finished to true - mFakeClock.tick(); - if (mTimeoutDeadline > 0 && mFakeClock.currentTimeMillis() > mTimeoutDeadline) { - throw new TimeoutException(); - } - } - assertThat(mFakeClock.currentTimeMillis() - startTimeMs).isAtLeast(100L); - } - - // Verifies the initial session. - private void assertSessionCreation(ModelProvider modelProvider, AtomicBoolean finished) { - finished.set(false); - mTimeoutDeadline = DEBUG - ? InfraIntegrationScope.TIMEOUT_TEST_TIMEOUT + mFakeClock.currentTimeMillis() - : 0; - modelProvider.registerObserver(new ModelProviderObserver() { - @Override - public void onSessionStart(UiContext uiContext) { - System.out.println("onSessionStart"); - finished.set(true); - mModelValidator.assertCursorContents(modelProvider, REQUEST_ONE); - } - - @Override - public void onSessionFinished(UiContext uiContext) { - System.out.println("onSessionFinished"); - } - - @Override - public void onError(ModelError modelError) { - System.out.println("onError"); - } - }); - } - - // Verifies the second session. There are two observers verified, the ModelProvider READ - // and a change listener on the root for the second request. - private void assertSessionCreationWithRequest( - ModelProvider modelProvider, AtomicBoolean finished) { - finished.set(false); - mTimeoutDeadline = DEBUG - ? InfraIntegrationScope.TIMEOUT_TEST_TIMEOUT + mFakeClock.currentTimeMillis() - : 0; - modelProvider.registerObserver(new ModelProviderObserver() { - @Override - public void onSessionStart(UiContext uiContext) { - System.out.println("onSessionStart"); - ModelFeature feature = modelProvider.getRootFeature(); - // The second request will cause an change on the root - assertThat(feature).isNotNull(); - feature.registerObserver(change -> { - System.out.println("root.onChange"); - finished.set(true); - mModelValidator.assertCursorContents(modelProvider, REQUEST_ONE[0], - REQUEST_ONE[1], REQUEST_ONE[2], REQUEST_TWO[0], REQUEST_TWO[2]); - assertThat(change.getContentId()) - .isEqualTo(mProtocolAdapter.getStreamContentId(ROOT_CONTENT_ID)); - ChildChanges childChanges = change.getChildChanges(); - assertThat(childChanges.getAppendedChildren().size()).isEqualTo(2); - }); - mModelValidator.assertCursorContents(modelProvider, REQUEST_ONE); - } - - @Override - public void onSessionFinished(UiContext uiContext) { - System.out.println("onSessionFinished"); - } - - @Override - public void onError(ModelError modelError) { - System.out.println("onError"); - } - }); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/ViewDepthProviderTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/ViewDepthProviderTest.java deleted file mode 100644 index 81c22b2..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/infraintegration/ViewDepthProviderTest.java +++ /dev/null
@@ -1,152 +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. - -package org.chromium.chrome.browser.feed.library.infraintegration; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.client.requestmanager.RequestManager; -import org.chromium.chrome.browser.feed.library.api.common.MutationContext; -import org.chromium.chrome.browser.feed.library.api.host.scheduler.SchedulerApi; -import org.chromium.chrome.browser.feed.library.api.host.scheduler.SchedulerApi.RequestBehavior; -import org.chromium.chrome.browser.feed.library.api.host.scheduler.SchedulerApi.SessionState; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider.ViewDepthProvider; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProviderFactory; -import org.chromium.chrome.browser.feed.library.api.internal.protocoladapter.ProtocolAdapter; -import org.chromium.chrome.browser.feed.library.api.internal.sessionmanager.FeedSessionManager; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeThreadUtils; -import org.chromium.chrome.browser.feed.library.common.testing.InfraIntegrationScope; -import org.chromium.chrome.browser.feed.library.common.testing.ModelProviderValidator; -import org.chromium.chrome.browser.feed.library.common.testing.ResponseBuilder; -import org.chromium.chrome.browser.feed.library.testing.modelprovider.FakeViewDepthProvider; -import org.chromium.chrome.browser.feed.library.testing.requestmanager.FakeFeedRequestManager; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamToken; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.UiContext; -import org.chromium.components.feed.core.proto.wire.ConsistencyTokenProto.ConsistencyToken; -import org.chromium.components.feed.core.proto.wire.ContentIdProto.ContentId; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** - * Tests of the ViewDepthProvider. The ViewDepthProvider indicates the depth of the Stream the user - * has seen. For some types of SchedulerApi {@link RequestBehavior} values this will prune the - * Stream beyond that depth. - */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ViewDepthProviderTest { - private static final ContentId[] REQUEST_ONE = new ContentId[] { - ResponseBuilder.createFeatureContentId(1), ResponseBuilder.createFeatureContentId(2), - ResponseBuilder.createFeatureContentId(3), ResponseBuilder.createFeatureContentId(4)}; - private static final ContentId[] REQUEST_TWO = new ContentId[] { - ResponseBuilder.createFeatureContentId(5), ResponseBuilder.createFeatureContentId(6), - ResponseBuilder.createFeatureContentId(7)}; - private static final ContentId[] REQUEST_TWO_WITH_DUPLICATES = new ContentId[] { - ResponseBuilder.createFeatureContentId(5), ResponseBuilder.createFeatureContentId(6), - ResponseBuilder.createFeatureContentId(4)}; - private static final ContentId[] REQUEST_TWO_WITH_DUPLICATES_PAGE = new ContentId[] { - ResponseBuilder.createFeatureContentId(5), ResponseBuilder.createFeatureContentId(4), - ResponseBuilder.createFeatureContentId(7)}; - - @Mock - private SchedulerApi mSchedulerApi; - - private FakeFeedRequestManager mFakeFeedRequestManager; - private FakeThreadUtils mFakeThreadUtils; - private ModelProviderFactory mModelProviderFactory; - private ModelProviderValidator mModelValidator; - private FeedSessionManager mFeedSessionManager; - private ViewDepthProvider mViewDepthProvider; - private RequestManager mRequestManager; - - @Before - public void setUp() { - initMocks(this); - InfraIntegrationScope scope = new InfraIntegrationScope.Builder() - .setSchedulerApi(mSchedulerApi) - .withTimeoutSessionConfiguration(2L) - .build(); - mFakeThreadUtils = scope.getFakeThreadUtils(); - mFakeFeedRequestManager = scope.getFakeFeedRequestManager(); - mModelProviderFactory = scope.getModelProviderFactory(); - ProtocolAdapter protocolAdapter = scope.getProtocolAdapter(); - mModelValidator = new ModelProviderValidator(protocolAdapter); - mFeedSessionManager = scope.getFeedSessionManager(); - mViewDepthProvider = new FakeViewDepthProvider().setChildViewDepth( - protocolAdapter.getStreamContentId(REQUEST_ONE[1])); - mRequestManager = scope.getRequestManager(); - } - - @Test - public void baseDepthProviderTest() { - // Load up the initial request - mFakeFeedRequestManager.queueResponse( - ResponseBuilder.forClearAllWithCards(REQUEST_ONE).build()); - - // The REQUEST_ONE content will be added to head, this is then used to create the initial - // session. - mRequestManager.triggerScheduledRefresh(); - - // The REQUEST_TWO content acts as a second request on the server, it is triggered by - // REQUEST_WITH_CONTENT - when(mSchedulerApi.shouldSessionRequestData(any(SessionState.class))) - .thenReturn(RequestBehavior.REQUEST_WITH_CONTENT); - mFakeFeedRequestManager.queueResponse( - ResponseBuilder.forClearAllWithCards(REQUEST_TWO).build()); - ModelProvider modelProvider = - mModelProviderFactory.createNew(mViewDepthProvider, UiContext.getDefaultInstance()); - - // The second request will be added after the first request, the ViewDepthProvider indicates - // we only saw [0] and [1] from the first request, so [2] and [3] will be removed. - mModelValidator.assertCursorContents(modelProvider, REQUEST_ONE[0], REQUEST_ONE[1], - REQUEST_TWO[0], REQUEST_TWO[1], REQUEST_TWO[2]); - } - - @Test - public void testDuplicateEntries() { - // Load up the initial request - mFakeFeedRequestManager.queueResponse( - ResponseBuilder.forClearAllWithCards(REQUEST_ONE).build()); - - // The REQUEST_ONE content will be added to head, this is then used to create the initial - // session. - mRequestManager.triggerScheduledRefresh(); - - // The REQUEST_TWO content acts as a second request on the server, it is triggered by - // REQUEST_WITH_CONTENT - when(mSchedulerApi.shouldSessionRequestData(any(SessionState.class))) - .thenReturn(RequestBehavior.REQUEST_WITH_CONTENT); - mFakeFeedRequestManager.queueResponse( - ResponseBuilder.forClearAllWithCards(REQUEST_TWO_WITH_DUPLICATES).build()); - ModelProvider modelProvider = - mModelProviderFactory.createNew(mViewDepthProvider, UiContext.getDefaultInstance()); - - // The second request will be added after the first request, the ViewDepthProvider indicates - // we only saw [0] and [1] from the first request, so [2] and [3] will be removed. - mModelValidator.assertCursorContents(modelProvider, REQUEST_ONE[0], REQUEST_ONE[1], - REQUEST_TWO_WITH_DUPLICATES[0], REQUEST_TWO_WITH_DUPLICATES[1], - REQUEST_TWO_WITH_DUPLICATES[2]); - - // Now page in the same content, this should all be updates - mFakeFeedRequestManager.queueResponse( - ResponseBuilder.builder().addCardsToRoot(REQUEST_TWO_WITH_DUPLICATES_PAGE).build()); - // TODO: sessions reject updates without a CLEAR_ALL or paging with a different token. - mFakeThreadUtils.enforceMainThread(false); - mFakeFeedRequestManager.loadMore(StreamToken.getDefaultInstance(), - ConsistencyToken.getDefaultInstance(), - mFeedSessionManager.getUpdateConsumer(MutationContext.EMPTY_CONTEXT)); - - mModelValidator.assertCursorContents(modelProvider, REQUEST_ONE[0], REQUEST_ONE[1], - REQUEST_TWO_WITH_DUPLICATES[0], REQUEST_TWO_WITH_DUPLICATES[1], - REQUEST_TWO_WITH_DUPLICATES[2], REQUEST_TWO_WITH_DUPLICATES_PAGE[2]); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/mocknetworkclient/MockServerNetworkClientTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/mocknetworkclient/MockServerNetworkClientTest.java deleted file mode 100644 index c753fcc..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/mocknetworkclient/MockServerNetworkClientTest.java +++ /dev/null
@@ -1,262 +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. - -package org.chromium.chrome.browser.feed.library.mocknetworkclient; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import android.app.Activity; -import android.content.Context; -import android.net.Uri; - -import com.google.protobuf.ByteString; -import com.google.protobuf.CodedInputStream; - -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestRule; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.base.Consumer; -import org.chromium.base.test.util.JniMocker; -import org.chromium.chrome.browser.feed.library.api.host.config.ApplicationInfo; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration; -import org.chromium.chrome.browser.feed.library.api.host.network.HttpRequest; -import org.chromium.chrome.browser.feed.library.api.host.network.HttpRequest.HttpMethod; -import org.chromium.chrome.browser.feed.library.api.host.network.HttpResponse; -import org.chromium.chrome.browser.feed.library.api.host.scheduler.SchedulerApi; -import org.chromium.chrome.browser.feed.library.api.host.stream.TooltipSupportedApi; -import org.chromium.chrome.browser.feed.library.api.internal.actionmanager.ActionReader; -import org.chromium.chrome.browser.feed.library.api.internal.common.Model; -import org.chromium.chrome.browser.feed.library.api.internal.protocoladapter.ProtocolAdapter; -import org.chromium.chrome.browser.feed.library.common.Result; -import org.chromium.chrome.browser.feed.library.common.concurrent.MainThreadRunner; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeMainThreadRunner; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeTaskQueue; -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeThreadUtils; -import org.chromium.chrome.browser.feed.library.common.protoextensions.FeedExtensionRegistry; -import org.chromium.chrome.browser.feed.library.common.time.TimingUtils; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.feedrequestmanager.FeedRequestManagerImpl; -import org.chromium.chrome.browser.feed.library.testing.conformance.network.NetworkClientConformanceTest; -import org.chromium.chrome.browser.feed.library.testing.host.logging.FakeBasicLoggingApi; -import org.chromium.chrome.browser.flags.ChromeFeatureList; -import org.chromium.chrome.browser.profiles.Profile; -import org.chromium.chrome.browser.signin.services.IdentityServicesProvider; -import org.chromium.chrome.browser.signin.services.IdentityServicesProviderJni; -import org.chromium.chrome.test.util.browser.Features; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamToken; -import org.chromium.components.feed.core.proto.wire.ConsistencyTokenProto.ConsistencyToken; -import org.chromium.components.feed.core.proto.wire.ResponseProto.Response; -import org.chromium.components.feed.core.proto.wire.ResponseProto.Response.ResponseVersion; -import org.chromium.components.feed.core.proto.wire.mockserver.MockServerProto.ConditionalResponse; -import org.chromium.components.feed.core.proto.wire.mockserver.MockServerProto.MockServer; -import org.chromium.components.signin.identitymanager.IdentityManager; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; - -/** Tests of the {@link MockServerNetworkClient} class. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -@Features.EnableFeatures(ChromeFeatureList.INTEREST_FEED_CONTENT_SUGGESTIONS) -@Features. -DisableFeatures({ChromeFeatureList.REPORT_FEED_USER_ACTIONS, ChromeFeatureList.INTEREST_FEED_V2}) -public class MockServerNetworkClientTest extends NetworkClientConformanceTest { - private final Configuration mConfiguration = new Configuration.Builder().build(); - private final FakeClock mFakeClock = new FakeClock(); - private final FakeThreadUtils mFakeThreadUtils = FakeThreadUtils.withThreadChecks(); - private final FeedExtensionRegistry mExtensionRegistry = - new FeedExtensionRegistry(ArrayList::new); - private final TimingUtils mTimingUtils = new TimingUtils(); - - @Mock - private ActionReader mActionReader; - @Mock - private ProtocolAdapter mProtocolAdapter; - @Mock - private SchedulerApi mScheduler; - @Mock - private TooltipSupportedApi mTooltipSupportedApi; - @Mock - private IdentityServicesProvider.Natives mIdentityServicesProviderJniMock; - @Mock - private Profile mProfileMock; - @Mock - private IdentityManager mIdentifiyManagerMock; - @Captor - private ArgumentCaptor<Response> mResponseCaptor; - private ApplicationInfo mApplicationInfo; - private Context mContext; - private FakeBasicLoggingApi mBasicLoggingApi; - private MainThreadRunner mMainThreadRunner; - - @Rule - public JniMocker jniMocker = new JniMocker(); - - @Rule - public TestRule mFeaturesProcessorRule = new Features.JUnitProcessor(); - - @Override - protected Uri getValidUri(@HttpMethod String method) { - // The URI does not matter - mockNetworkClient will default to an empty response - return new Uri.Builder().path("foo").appendPath(method).build(); - } - - @Before - public void setUp() throws Exception { - initMocks(this); - mContext = Robolectric.buildActivity(Activity.class).get(); - mApplicationInfo = new ApplicationInfo.Builder(mContext).setVersionString("0").build(); - mMainThreadRunner = FakeMainThreadRunner.runTasksImmediately(); - - MockServer mockServer = MockServer.getDefaultInstance(); - mNetworkClient = - new MockServerNetworkClient(mContext, mockServer, /* responseDelayMillis= */ 0L); - - when(mActionReader.getDismissActionsWithSemanticProperties()) - .thenReturn(Result.success(Collections.emptyList())); - - mBasicLoggingApi = new FakeBasicLoggingApi(); - - Profile.setLastUsedProfileForTesting(mProfileMock); - jniMocker.mock(IdentityServicesProviderJni.TEST_HOOKS, mIdentityServicesProviderJniMock); - when(mIdentityServicesProviderJniMock.getIdentityManager(mProfileMock)) - .thenReturn(mIdentifiyManagerMock); - } - - @After - public void tearDown() { - Profile.setLastUsedProfileForTesting(null); - } - - @Test - public void testSend() { - MockServer.Builder mockServerBuilder = MockServer.newBuilder(); - Response initialResponse = - Response.newBuilder().setResponseVersion(ResponseVersion.FEED_RESPONSE).build(); - mockServerBuilder.setInitialResponse(initialResponse); - MockServerNetworkClient networkClient = new MockServerNetworkClient( - mContext, mockServerBuilder.build(), /* responseDelayMillis= */ 0L); - Consumer<HttpResponse> responseConsumer = input -> { - try { - CodedInputStream inputStream = - CodedInputStream.newInstance(input.getResponseBody()); - int length = inputStream.readRawVarint32(); - assertThat(inputStream.readRawBytes(length)) - .isEqualTo(initialResponse.toByteArray()); - assertThat(input.getResponseCode()).isEqualTo(200); - } catch (IOException e) { - throw new RuntimeException(e); - } - }; - networkClient.send( - new HttpRequest(Uri.EMPTY, HttpMethod.POST, Collections.emptyList(), new byte[] {}), - responseConsumer); - } - - @Test - public void testSend_oneTimeResponse() { - MockServer.Builder mockServerBuilder = MockServer.newBuilder(); - Response initialResponse = - Response.newBuilder().setResponseVersion(ResponseVersion.FEED_RESPONSE).build(); - mockServerBuilder.setInitialResponse(initialResponse); - MockServerNetworkClient networkClient = new MockServerNetworkClient( - mContext, mockServerBuilder.build(), /* responseDelayMillis= */ 0L); - Consumer<HttpResponse> responseConsumer = input -> { - try { - CodedInputStream inputStream = - CodedInputStream.newInstance(input.getResponseBody()); - int length = inputStream.readRawVarint32(); - assertThat(inputStream.readRawBytes(length)) - .isEqualTo(initialResponse.toByteArray()); - assertThat(input.getResponseCode()).isEqualTo(200); - } catch (IOException e) { - throw new RuntimeException(e); - } - }; - networkClient.send( - new HttpRequest(Uri.EMPTY, HttpMethod.POST, Collections.emptyList(), new byte[] {}), - responseConsumer); - } - - @Test - public void testPaging() { - MockServer.Builder mockServerBuilder = MockServer.newBuilder(); - Response response = - Response.newBuilder().setResponseVersion(ResponseVersion.FEED_RESPONSE).build(); - ByteString token = ByteString.copyFromUtf8("fooToken"); - StreamToken streamToken = StreamToken.newBuilder().setNextPageToken(token).build(); - ConditionalResponse.Builder conditionalResponseBuilder = ConditionalResponse.newBuilder(); - conditionalResponseBuilder.setContinuationToken(token).setResponse(response); - mockServerBuilder.addConditionalResponses(conditionalResponseBuilder.build()); - MockServerNetworkClient networkClient = new MockServerNetworkClient( - mContext, mockServerBuilder.build(), /* responseDelayMillis= */ 0L); - FeedRequestManagerImpl feedRequestManager = new FeedRequestManagerImpl(mConfiguration, - networkClient, mProtocolAdapter, mExtensionRegistry, mScheduler, getTaskQueue(), - mTimingUtils, mFakeThreadUtils, mActionReader, mContext, mApplicationInfo, - mMainThreadRunner, mBasicLoggingApi, mTooltipSupportedApi); - when(mProtocolAdapter.createModel(any(Response.class))) - .thenReturn(Result.success(Model.empty())); - - mFakeThreadUtils.enforceMainThread(false); - feedRequestManager.loadMore(streamToken, ConsistencyToken.getDefaultInstance(), result -> { - assertThat(result.isSuccessful()).isTrue(); - assertThat(result.getValue().streamDataOperations).hasSize(0); - }); - - verify(mProtocolAdapter).createModel(mResponseCaptor.capture()); - assertThat(mResponseCaptor.getValue()).isEqualTo(response); - } - - @Test - public void testPaging_noMatch() { - MockServer.Builder mockServerBuilder = MockServer.newBuilder(); - Response response = - Response.newBuilder().setResponseVersion(ResponseVersion.FEED_RESPONSE).build(); - // Create a MockServerConfig without a matching token. - ConditionalResponse.Builder conditionalResponseBuilder = ConditionalResponse.newBuilder(); - conditionalResponseBuilder.setResponse(response); - mockServerBuilder.addConditionalResponses(conditionalResponseBuilder.build()); - MockServerNetworkClient networkClient = new MockServerNetworkClient( - mContext, mockServerBuilder.build(), /* responseDelayMillis= */ 0L); - FeedRequestManagerImpl feedRequestManager = new FeedRequestManagerImpl(mConfiguration, - networkClient, mProtocolAdapter, mExtensionRegistry, mScheduler, getTaskQueue(), - mTimingUtils, mFakeThreadUtils, mActionReader, mContext, mApplicationInfo, - mMainThreadRunner, mBasicLoggingApi, mTooltipSupportedApi); - when(mProtocolAdapter.createModel(any(Response.class))) - .thenReturn(Result.success(Model.empty())); - - mFakeThreadUtils.enforceMainThread(false); - ByteString token = ByteString.copyFromUtf8("fooToken"); - StreamToken streamToken = StreamToken.newBuilder().setNextPageToken(token).build(); - feedRequestManager.loadMore(streamToken, ConsistencyToken.getDefaultInstance(), result -> { - assertThat(result.isSuccessful()).isTrue(); - assertThat(result.getValue().streamDataOperations).hasSize(0); - }); - - verify(mProtocolAdapter).createModel(mResponseCaptor.capture()); - assertThat(mResponseCaptor.getValue()).isEqualTo(Response.getDefaultInstance()); - } - - private FakeTaskQueue getTaskQueue() { - FakeTaskQueue taskQueue = new FakeTaskQueue(mFakeClock, mFakeThreadUtils); - taskQueue.initialize(() -> {}); - return taskQueue; - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ChunkedTextElementAdapterTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ChunkedTextElementAdapterTest.java deleted file mode 100644 index 16e38e2..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ChunkedTextElementAdapterTest.java +++ /dev/null
@@ -1,892 +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. - -package org.chromium.chrome.browser.feed.library.piet; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import static org.chromium.chrome.browser.feed.library.api.host.imageloader.ImageLoaderApi.DIMENSION_UNKNOWN; -import static org.chromium.chrome.browser.feed.library.common.testing.RunnableSubject.assertThatRunnable; -import static org.chromium.chrome.browser.feed.library.piet.ChunkedTextElementAdapter.SINGLE_LAYER_ID; -import static org.chromium.components.feed.core.proto.ui.piet.ErrorsProto.ErrorCode.ERR_MISSING_BINDING_VALUE; -import static org.chromium.components.feed.core.proto.ui.piet.ErrorsProto.ErrorCode.ERR_MISSING_OR_UNHANDLED_CONTENT; - -import android.app.Activity; -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Color; -import android.graphics.PorterDuff.Mode; -import android.graphics.PorterDuffColorFilter; -import android.graphics.Rect; -import android.graphics.Typeface; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.ColorDrawable; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.LayerDrawable; -import android.text.SpannableStringBuilder; -import android.text.SpannedString; -import android.text.style.AbsoluteSizeSpan; -import android.text.style.ForegroundColorSpan; -import android.text.style.ImageSpan; -import android.text.style.StyleSpan; -import android.view.MotionEvent; -import android.view.View; -import android.widget.TextView; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.Shadows; -import org.robolectric.annotation.Config; -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; -import org.robolectric.shadows.ShadowTextView; - -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.common.ui.LayoutUtils; -import org.chromium.chrome.browser.feed.library.piet.AdapterFactory.SingletonKeySupplier; -import org.chromium.chrome.browser.feed.library.piet.ChunkedTextElementAdapter.ActionsClickableSpan; -import org.chromium.chrome.browser.feed.library.piet.ChunkedTextElementAdapter.ImageSpanDrawableCallback; -import org.chromium.chrome.browser.feed.library.piet.ChunkedTextElementAdapterTest.ShadowTextViewWithHeight; -import org.chromium.chrome.browser.feed.library.piet.DebugLogger.MessageType; -import org.chromium.chrome.browser.feed.library.piet.host.ActionHandler; -import org.chromium.chrome.browser.feed.library.piet.host.ActionHandler.ActionType; -import org.chromium.chrome.browser.feed.library.piet.host.AssetProvider; -import org.chromium.components.feed.core.proto.ui.piet.ActionsProto.Action; -import org.chromium.components.feed.core.proto.ui.piet.ActionsProto.Actions; -import org.chromium.components.feed.core.proto.ui.piet.BindingRefsProto.ActionsBindingRef; -import org.chromium.components.feed.core.proto.ui.piet.BindingRefsProto.ChunkedTextBindingRef; -import org.chromium.components.feed.core.proto.ui.piet.BindingRefsProto.ImageBindingRef; -import org.chromium.components.feed.core.proto.ui.piet.BindingRefsProto.ParameterizedTextBindingRef; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.BindingValue; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.Element; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.TextElement; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.Visibility; -import org.chromium.components.feed.core.proto.ui.piet.ErrorsProto.ErrorCode; -import org.chromium.components.feed.core.proto.ui.piet.ImagesProto.Image; -import org.chromium.components.feed.core.proto.ui.piet.ImagesProto.ImageSource; -import org.chromium.components.feed.core.proto.ui.piet.LogDataProto.LogData; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.Frame; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.EdgeWidths; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.Font; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.Style; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.StyleIdsStack; -import org.chromium.components.feed.core.proto.ui.piet.TextProto.Chunk; -import org.chromium.components.feed.core.proto.ui.piet.TextProto.ChunkedText; -import org.chromium.components.feed.core.proto.ui.piet.TextProto.ParameterizedText; -import org.chromium.components.feed.core.proto.ui.piet.TextProto.StyledImageChunk; -import org.chromium.components.feed.core.proto.ui.piet.TextProto.StyledTextChunk; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests of the {@link ChunkedTextElementAdapter}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE, shadows = ShadowTextViewWithHeight.class) -public class ChunkedTextElementAdapterTest { - private static final StyleIdsStack CHUNK_STYLE = - StyleIdsStack.newBuilder().addStyleIds("roasted").build(); - private static final String CHUNKY_TEXT = "Skippy"; - private static final String PROCESSED_TEXT = "smooth"; - private static final ParameterizedText PARAMETERIZED_CHUNK_TEXT = - ParameterizedText.newBuilder().setText(CHUNKY_TEXT).build(); - private static final Chunk TEXT_CHUNK = - Chunk.newBuilder() - .setTextChunk(StyledTextChunk.newBuilder() - .setParameterizedText(PARAMETERIZED_CHUNK_TEXT) - .setStyleReferences(CHUNK_STYLE)) - .build(); - private static final ChunkedText CHUNKED_TEXT_TEXT = - ChunkedText.newBuilder().addChunks(TEXT_CHUNK).build(); - private static final String CHUNKY_URL = "pb.com/jif"; - private static final Image IMAGE_CHUNK_IMAGE = - Image.newBuilder().addSources(ImageSource.newBuilder().setUrl(CHUNKY_URL)).build(); - private static final Chunk IMAGE_CHUNK = - Chunk.newBuilder() - .setImageChunk(StyledImageChunk.newBuilder() - .setImage(IMAGE_CHUNK_IMAGE) - .setStyleReferences(CHUNK_STYLE)) - .build(); - private static final String BINDING_ID = "PB"; - private static final ChunkedTextBindingRef CHUNKED_TEXT_BINDING_REF = - ChunkedTextBindingRef.newBuilder().setBindingId(BINDING_ID).build(); - - private static final int STYLE_HEIGHT_PX = 6; - private static final int STYLE_ASPECT_RATIO = 2; - private static final int STYLE_WIDTH_PX = STYLE_HEIGHT_PX * STYLE_ASPECT_RATIO; - - private static final int HEIGHT_DP = 6; - private static final int WIDTH_DP = HEIGHT_DP * STYLE_ASPECT_RATIO; - - private static final int IMAGE_HEIGHT_PX = 60; - private static final int IMAGE_ASPECT_RATIO = 3; - private static final int IMAGE_WIDTH_PX = IMAGE_HEIGHT_PX * IMAGE_ASPECT_RATIO; - - private static final int TEXT_HEIGHT = 12; - - @Mock - private FrameContext mFrameContext; - @Mock - private StyleProvider mMockStyleProvider; - @Mock - private ParameterizedTextEvaluator mMockTextEvaluator; - @Mock - private AssetProvider mMockAssetProvider; - @Mock - private ActionHandler mMockActionHandler; - @Mock - private HostProviders mHostProviders; - - private Drawable mDrawable; - private SpannableStringBuilder mSpannable; - - private Context mContext; - private TextView mTextView; - - private AdapterParameters mAdapterParameters; - - private ChunkedTextElementAdapter mAdapter; - - @Before - public void setUp() throws Exception { - initMocks(this); - mContext = Robolectric.buildActivity(Activity.class).get(); - - mDrawable = new BitmapDrawable( - Bitmap.createBitmap(IMAGE_WIDTH_PX, IMAGE_HEIGHT_PX, Bitmap.Config.ARGB_8888)); - Shadows.shadowOf(mDrawable).setIntrinsicHeight(IMAGE_HEIGHT_PX); - Shadows.shadowOf(mDrawable).setIntrinsicWidth(IMAGE_WIDTH_PX); - mSpannable = new SpannableStringBuilder(); - - mTextView = new TextView(mContext); - - when(mMockTextEvaluator.evaluate(mMockAssetProvider, - ParameterizedText.newBuilder().setText(CHUNKY_TEXT).build())) - .thenReturn(PROCESSED_TEXT); - when(mFrameContext.makeStyleFor(CHUNK_STYLE)).thenReturn(mMockStyleProvider); - when(mFrameContext.filterImageSourcesByMediaQueryCondition(any(Image.class))) - .thenAnswer(invocation -> invocation.getArguments()[0]); - when(mFrameContext.reportMessage(anyInt(), any(), anyString())) - .thenAnswer(invocation -> invocation.getArguments()[2]); - when(mHostProviders.getAssetProvider()).thenReturn(mMockAssetProvider); - when(mMockAssetProvider.isRtL()).thenReturn(false); - when(mFrameContext.getActionHandler()).thenReturn(mMockActionHandler); - when(mMockStyleProvider.getFont()).thenReturn(Font.getDefaultInstance()); - when(mMockStyleProvider.getMargins()).thenReturn(EdgeWidths.getDefaultInstance()); - when(mMockStyleProvider.getWidthSpecPx(mContext)).thenReturn(DIMENSION_UNKNOWN); - when(mMockStyleProvider.getHeightSpecPx(mContext)).thenReturn(DIMENSION_UNKNOWN); - - mAdapterParameters = new AdapterParameters( - null, null, mHostProviders, mMockTextEvaluator, null, null, new FakeClock()); - - when(mFrameContext.makeStyleFor(StyleIdsStack.getDefaultInstance())) - .thenReturn(mAdapterParameters.mDefaultStyleProvider); - - mAdapter = new ChunkedTextElementAdapter.KeySupplier().getAdapter( - mContext, mAdapterParameters); - } - - @Test - public void testCreate() { - assertThat(mAdapter).isNotNull(); - } - - @Test - public void testBind_chunkedText() { - TextElement chunkedTextElement = - TextElement.newBuilder().setChunkedText(CHUNKED_TEXT_TEXT).build(); - - mAdapter.createAdapter(asElement(chunkedTextElement), mFrameContext); - mAdapter.bindModel(asElement(chunkedTextElement), mFrameContext); - - assertThat(mAdapter.getBaseView().getText().toString()).isEqualTo(PROCESSED_TEXT); - } - - @Test - public void testBind_chunkedTextBinding() { - TextElement chunkedTextBindingElement = - TextElement.newBuilder().setChunkedTextBinding(CHUNKED_TEXT_BINDING_REF).build(); - - when(mFrameContext.getChunkedTextBindingValue(CHUNKED_TEXT_BINDING_REF)) - .thenReturn(BindingValue.newBuilder().setChunkedText(CHUNKED_TEXT_TEXT).build()); - - mAdapter.createAdapter(asElement(chunkedTextBindingElement), mFrameContext); - mAdapter.bindModel(asElement(chunkedTextBindingElement), mFrameContext); - - verify(mFrameContext).getChunkedTextBindingValue(CHUNKED_TEXT_BINDING_REF); - assertThat(mAdapter.getBaseView().getText().toString()).isEqualTo(PROCESSED_TEXT); - } - - @Test - public void testBind_chunkedTextWithBoundText() { - ParameterizedTextBindingRef textBinding = - ParameterizedTextBindingRef.newBuilder().setBindingId("sometext").build(); - TextElement chunkedTextElement = - TextElement.newBuilder() - .setChunkedText( - ChunkedText.newBuilder().addChunks(Chunk.newBuilder().setTextChunk( - StyledTextChunk.newBuilder().setParameterizedTextBinding( - textBinding)))) - .build(); - when(mFrameContext.getParameterizedTextBindingValue(textBinding)) - .thenReturn(BindingValue.newBuilder() - .setParameterizedText(PARAMETERIZED_CHUNK_TEXT) - .build()); - - mAdapter.createAdapter(asElement(chunkedTextElement), mFrameContext); - mAdapter.bindModel(asElement(chunkedTextElement), mFrameContext); - - assertThat(mAdapter.getBaseView().getText().toString()).isEqualTo(PROCESSED_TEXT); - } - - @Test - public void testBind_chunkedTextWithBoundImage() { - ImageBindingRef imageBinding = - ImageBindingRef.newBuilder().setBindingId("image-binding-id").build(); - TextElement chunkedTextElement = - TextElement.newBuilder() - .setChunkedText( - ChunkedText.newBuilder().addChunks(Chunk.newBuilder().setImageChunk( - StyledImageChunk.newBuilder().setImageBinding( - imageBinding)))) - .build(); - when(mFrameContext.getImageBindingValue(imageBinding)) - .thenReturn(BindingValue.newBuilder().setImage(IMAGE_CHUNK_IMAGE).build()); - - mAdapter.createAdapter(asElement(chunkedTextElement), mFrameContext); - mAdapter.bindModel(asElement(chunkedTextElement), mFrameContext); - - assertThat(mAdapter.getBaseView().getText().toString()).isEqualTo(" "); - ImageSpan[] imageSpans = - ((SpannedString) mAdapter.getBaseView().getText()).getSpans(0, 1, ImageSpan.class); - assertThat(imageSpans).hasLength(1); - - LayerDrawable containerDrawable = (LayerDrawable) imageSpans[0].getDrawable(); - - ArgumentCaptor<ImageSpanDrawableCallback> imageCallbackCaptor = - ArgumentCaptor.forClass(ImageSpanDrawableCallback.class); - - verify(mMockAssetProvider) - .getImage(eq(IMAGE_CHUNK_IMAGE), eq(DIMENSION_UNKNOWN), eq(DIMENSION_UNKNOWN), - imageCallbackCaptor.capture()); - - // Activate the image loading callback - Drawable imageDrawable = new ColorDrawable(123); - imageCallbackCaptor.getValue().accept(imageDrawable); - - // Assert that we set the image on the span - assertThat(containerDrawable.getDrawable(SINGLE_LAYER_ID)).isSameInstanceAs(imageDrawable); - } - - @Test - public void testBind_styledTextChunkWithNoContent() { - TextElement chunkedTextElement = - TextElement.newBuilder() - .setChunkedText( - ChunkedText.newBuilder().addChunks(Chunk.newBuilder().setTextChunk( - StyledTextChunk.getDefaultInstance()))) - .build(); - when(mMockTextEvaluator.evaluate( - mMockAssetProvider, ParameterizedText.getDefaultInstance())) - .thenReturn(""); - - mAdapter.createAdapter(asElement(chunkedTextElement), mFrameContext); - mAdapter.bindModel(asElement(chunkedTextElement), mFrameContext); - - assertThat(mAdapter.getBaseView().getText().toString()).isEmpty(); - verify(mFrameContext) - .reportMessage(MessageType.ERROR, ERR_MISSING_OR_UNHANDLED_CONTENT, - "StyledTextChunk missing ParameterizedText content; has CONTENT_NOT_SET"); - } - - @Test - public void testBind_chunkedTextWithOptionalBindingNoImage() { - ImageBindingRef imageBinding = ImageBindingRef.newBuilder() - .setBindingId("image-binding-id") - .setIsOptional(true) - .build(); - TextElement chunkedTextElement = - TextElement.newBuilder() - .setChunkedText( - ChunkedText.newBuilder().addChunks(Chunk.newBuilder().setImageChunk( - StyledImageChunk.newBuilder().setImageBinding( - imageBinding)))) - .build(); - when(mFrameContext.getImageBindingValue(imageBinding)) - .thenReturn(BindingValue.getDefaultInstance()); - - mAdapter.createAdapter(asElement(chunkedTextElement), mFrameContext); - mAdapter.bindModel(asElement(chunkedTextElement), mFrameContext); - - assertThat(mAdapter.getBaseView().getText().toString()).isEmpty(); - ImageSpan[] imageSpans = - ((SpannedString) mAdapter.getBaseView().getText()).getSpans(0, 1, ImageSpan.class); - assertThat(imageSpans).hasLength(0); - verify(mFrameContext, never()).reportMessage(anyInt(), any(ErrorCode.class), anyString()); - } - - @Test - public void testBind_chunkedTextWithNoImage() { - ImageBindingRef imageBinding = - ImageBindingRef.newBuilder().setBindingId("image-binding-id").build(); - TextElement chunkedTextElement = - TextElement.newBuilder() - .setChunkedText( - ChunkedText.newBuilder().addChunks(Chunk.newBuilder().setImageChunk( - StyledImageChunk.newBuilder().setImageBinding( - imageBinding)))) - .build(); - when(mFrameContext.getImageBindingValue(imageBinding)) - .thenReturn(BindingValue.getDefaultInstance()); - - mAdapter.createAdapter(asElement(chunkedTextElement), mFrameContext); - mAdapter.bindModel(asElement(chunkedTextElement), mFrameContext); - - assertThat(mAdapter.getBaseView().getText().toString()).isEmpty(); - verify(mFrameContext) - .reportMessage(MessageType.ERROR, ERR_MISSING_BINDING_VALUE, - "No image found for binding id: image-binding-id"); - } - - @Test - public void testBind_styledImageChunkWithNoContent() { - TextElement chunkedTextElement = - TextElement.newBuilder() - .setChunkedText( - ChunkedText.newBuilder().addChunks(Chunk.newBuilder().setImageChunk( - StyledImageChunk.getDefaultInstance()))) - .build(); - when(mMockTextEvaluator.evaluate( - mMockAssetProvider, ParameterizedText.getDefaultInstance())) - .thenReturn(""); - - mAdapter.createAdapter(asElement(chunkedTextElement), mFrameContext); - mAdapter.bindModel(asElement(chunkedTextElement), mFrameContext); - - assertThat(mAdapter.getBaseView().getText().toString()).isEmpty(); - ImageSpan[] imageSpans = - ((SpannedString) mAdapter.getBaseView().getText()).getSpans(0, 1, ImageSpan.class); - assertThat(imageSpans).hasLength(0); - - verify(mFrameContext) - .reportMessage(MessageType.ERROR, ERR_MISSING_OR_UNHANDLED_CONTENT, - "StyledImageChunk missing Image content; has CONTENT_NOT_SET"); - } - - @Test - public void testBind_wrongContent_fails() { - TextElement elementWithWrongContent = - TextElement.newBuilder() - .setParameterizedText(ParameterizedText.getDefaultInstance()) - .build(); - - mAdapter.createAdapter(asElement(elementWithWrongContent), mFrameContext); - - assertThatRunnable( - () -> mAdapter.bindModel(asElement(elementWithWrongContent), mFrameContext)) - .throwsAnExceptionOfType(IllegalArgumentException.class) - .that() - .hasMessageThat() - .contains("Unhandled type of TextElement"); - } - - @Test - public void testBind_missingContent_fails() { - TextElement emptyElement = TextElement.getDefaultInstance(); - - assertThatRunnable(() -> mAdapter.bindModel(asElement(emptyElement), mFrameContext)) - .throwsAnExceptionOfType(IllegalArgumentException.class) - .that() - .hasMessageThat() - .contains("Unhandled type of TextElement"); - } - - @Test - public void testBind_textChunk() { - TextElement chunkedTextElement = - TextElement.newBuilder().setChunkedText(CHUNKED_TEXT_TEXT).build(); - - mAdapter.createAdapter(asElement(chunkedTextElement), mFrameContext); - mAdapter.bindModel(asElement(chunkedTextElement), mFrameContext); - - assertThat(mAdapter.getBaseView().getText().toString()).isEqualTo(PROCESSED_TEXT); - } - - @Test - public void testBind_imageChunk() { - TextElement chunkedImageElement = - TextElement.newBuilder() - .setChunkedText(ChunkedText.newBuilder().addChunks(IMAGE_CHUNK)) - .build(); - - mAdapter.createAdapter(asElement(chunkedImageElement), mFrameContext); - mAdapter.bindModel(asElement(chunkedImageElement), mFrameContext); - - assertThat(mAdapter.getBaseView().getText().toString()).isEqualTo(" "); - assertThat( - ((SpannedString) mAdapter.getBaseView().getText()).getSpans(0, 1, ImageSpan.class)) - .hasLength(1); - assertThat(((SpannedString) mAdapter.getBaseView().getText()) - .getSpans(0, 1, ImageSpan.class)[0] - .getVerticalAlignment()) - .isEqualTo(ImageSpan.ALIGN_BASELINE); - } - - @Test - public void testBind_emptyChunk_fails() { - TextElement elementWithEmptyChunk = - TextElement.newBuilder() - .setChunkedText( - ChunkedText.newBuilder().addChunks(Chunk.getDefaultInstance())) - .build(); - - mAdapter.createAdapter(asElement(elementWithEmptyChunk), mFrameContext); - - assertThatRunnable( - () -> mAdapter.bindModel(asElement(elementWithEmptyChunk), mFrameContext)) - .throwsAnExceptionOfType(IllegalArgumentException.class) - .that() - .hasMessageThat() - .contains("Unhandled type of ChunkedText Chunk"); - } - - @Test - public void testSetTextOnView_optionalAbsent() { - TextElement chunkedTextBindingElement = - TextElement.newBuilder().setChunkedTextBinding(CHUNKED_TEXT_BINDING_REF).build(); - when(mFrameContext.getChunkedTextBindingValue(CHUNKED_TEXT_BINDING_REF)) - .thenReturn(BindingValue.newBuilder().setChunkedText(CHUNKED_TEXT_TEXT).build()); - mAdapter.createAdapter(asElement(chunkedTextBindingElement), mFrameContext); - - ChunkedTextBindingRef optionalBindingRef = - CHUNKED_TEXT_BINDING_REF.toBuilder().setIsOptional(true).build(); - TextElement chunkedTextBindingElementOptional = - TextElement.newBuilder().setChunkedTextBinding(optionalBindingRef).build(); - when(mFrameContext.getChunkedTextBindingValue(optionalBindingRef)) - .thenReturn(BindingValue.getDefaultInstance()); - - mAdapter.setTextOnView(mFrameContext, chunkedTextBindingElementOptional); - assertThat(mAdapter.getBaseView().getText().toString()).isEmpty(); - assertThat(mAdapter.getView().getVisibility()).isEqualTo(View.GONE); - } - - @Test - public void testSetTextOnView_noContent() { - TextElement chunkedTextBindingElement = - TextElement.newBuilder().setChunkedTextBinding(CHUNKED_TEXT_BINDING_REF).build(); - mAdapter.createAdapter( - asElement(TextElement.newBuilder().setChunkedText(CHUNKED_TEXT_TEXT).build()), - mFrameContext); - - when(mFrameContext.getChunkedTextBindingValue(CHUNKED_TEXT_BINDING_REF)) - .thenReturn(BindingValue.newBuilder() - .setBindingId(BINDING_ID) - .setVisibility(Visibility.INVISIBLE) - .build()); - - assertThatRunnable(() -> mAdapter.setTextOnView(mFrameContext, chunkedTextBindingElement)) - .throwsAnExceptionOfType(IllegalArgumentException.class) - .that() - .hasMessageThat() - .contains("Chunked text binding PB had no content"); - } - - @Test - public void testAddTextChunk_setsTextAfterEvaluatingParameterizedText() { - mAdapter.addTextChunk(mFrameContext, mSpannable, TEXT_CHUNK); - - verify(mMockTextEvaluator) - .evaluate(mMockAssetProvider, TEXT_CHUNK.getTextChunk().getParameterizedText()); - - assertThat(mSpannable.toString()).isEqualTo(PROCESSED_TEXT); - } - - @Test - public void testAddTextChunk_setsStyles() { - int color = 314159; - mContext.getResources().getDisplayMetrics().scaledDensity = 1.5f; - Font font = Font.newBuilder().setItalic(true).setSize(20).build(); - // The text scales with accessibility settings: size (20) x scaledDensity (1.5) = final size - // 30 - int expectedTextSize = 30; - - when(mMockStyleProvider.hasColor()).thenReturn(true); - when(mMockStyleProvider.getColor()).thenReturn(color); - when(mMockStyleProvider.getFont()).thenReturn(font); - - mAdapter.addTextChunk(mFrameContext, mSpannable, TEXT_CHUNK); - - assertThat(mSpannable.getSpans(0, PROCESSED_TEXT.length(), Object.class)).hasLength(3); - - ForegroundColorSpan[] colorSpans = - mSpannable.getSpans(0, PROCESSED_TEXT.length(), ForegroundColorSpan.class); - assertThat(colorSpans[0].getForegroundColor()).isEqualTo(color); - - AbsoluteSizeSpan[] sizeSpans = - mSpannable.getSpans(0, PROCESSED_TEXT.length(), AbsoluteSizeSpan.class); - assertThat(sizeSpans[0].getSize()).isEqualTo(expectedTextSize); - - StyleSpan[] styleSpans = mSpannable.getSpans(0, PROCESSED_TEXT.length(), StyleSpan.class); - assertThat(styleSpans[0].getStyle()).isEqualTo(Typeface.ITALIC); - } - - @Test - public void testAddTextChunk_addsMargins() { - when(mMockStyleProvider.hasWidth()).thenReturn(true); - when(mMockStyleProvider.getWidthSpecPx(mContext)).thenReturn(STYLE_WIDTH_PX); - when(mMockStyleProvider.hasHeight()).thenReturn(true); - when(mMockStyleProvider.getHeightSpecPx(mContext)).thenReturn(STYLE_HEIGHT_PX); - - when(mMockStyleProvider.getMargins()) - .thenReturn(EdgeWidths.newBuilder().setStart(11).setEnd(22).build()); - - // Required to set up the local frameContext member var. - mAdapter.createAdapter(asElement(TextElement.getDefaultInstance()), mFrameContext); - - mAdapter.addTextChunk(mFrameContext, mSpannable, TEXT_CHUNK); - - assertThat(mSpannable.toString()).isEqualTo(" smooth "); - - ImageSpan[] imageSpans = mSpannable.getSpans(0, 8, ImageSpan.class); - - Drawable leftMarginDrawable = imageSpans[0].getDrawable(); - assertThat(leftMarginDrawable.getBounds().left).isEqualTo(0); - assertThat(leftMarginDrawable.getBounds().right).isEqualTo(11); - - Drawable rightMarginDrawable = imageSpans[1].getDrawable(); - assertThat(leftMarginDrawable.getBounds().left).isEqualTo(0); - assertThat(rightMarginDrawable.getBounds().right).isEqualTo(22); - } - - @Test - public void testAddImageChunk_setsImageAndDims() { - when(mMockStyleProvider.hasWidth()).thenReturn(true); - when(mMockStyleProvider.getWidthSpecPx(mContext)).thenReturn(STYLE_WIDTH_PX); - when(mMockStyleProvider.hasHeight()).thenReturn(true); - when(mMockStyleProvider.getHeightSpecPx(mContext)).thenReturn(STYLE_HEIGHT_PX); - when(mMockStyleProvider.hasPreLoadFill()).thenReturn(true); - Drawable preLoadFill = new ColorDrawable(Color.CYAN); - when(mMockStyleProvider.createPreLoadFill()).thenReturn(preLoadFill); - - // Required to set up the local frameContext member var. - mAdapter.createAdapter(asElement(TextElement.getDefaultInstance()), mFrameContext); - - mAdapter.addImageChunk(mFrameContext, mTextView, mSpannable, IMAGE_CHUNK); - - assertThat(mSpannable.toString()).isEqualTo(" "); - - ImageSpan[] imageSpans = mSpannable.getSpans(0, 1, ImageSpan.class); - LayerDrawable containerDrawable = (LayerDrawable) imageSpans[0].getDrawable(); - - ArgumentCaptor<ImageSpanDrawableCallback> imageCallbackCaptor = - ArgumentCaptor.forClass(ImageSpanDrawableCallback.class); - verify(mMockAssetProvider) - .getImage(eq(IMAGE_CHUNK_IMAGE), eq(STYLE_WIDTH_PX), eq(STYLE_HEIGHT_PX), - imageCallbackCaptor.capture()); - - // Check for the pre-load fill - assertThat(containerDrawable.getDrawable(0)).isSameInstanceAs(preLoadFill); - - // Activate the image loading callback - Drawable imageDrawable = new ColorDrawable(123); - imageCallbackCaptor.getValue().accept(imageDrawable); - - // Assert that we set the image on the span - assertThat(containerDrawable.getDrawable(0)).isSameInstanceAs(imageDrawable); - - assertThat(imageDrawable.getBounds()) - .isEqualTo(new Rect(0, 0, STYLE_WIDTH_PX, STYLE_HEIGHT_PX)); - assertThat(containerDrawable.getBounds()) - .isEqualTo(new Rect(0, 0, STYLE_WIDTH_PX, STYLE_HEIGHT_PX)); - } - - @Test - public void testAddImageChunk_setsImageAndDimsWidthNotSpecified() { - when(mMockStyleProvider.hasWidth()).thenReturn(true); - when(mMockStyleProvider.getWidthSpecPx(mContext)).thenReturn(-1); - when(mMockStyleProvider.hasHeight()).thenReturn(true); - when(mMockStyleProvider.getHeightSpecPx(mContext)).thenReturn(STYLE_HEIGHT_PX); - when(mMockStyleProvider.hasPreLoadFill()).thenReturn(true); - Drawable preLoadFill = new ColorDrawable(Color.CYAN); - when(mMockStyleProvider.createPreLoadFill()).thenReturn(preLoadFill); - - // Required to set up the local mFrameContext member var. - mAdapter.createAdapter(asElement(TextElement.getDefaultInstance()), mFrameContext); - - mAdapter.addImageChunk(mFrameContext, mTextView, mSpannable, IMAGE_CHUNK); - - ImageSpan[] imageSpans = mSpannable.getSpans(0, 1, ImageSpan.class); - LayerDrawable containerDrawable = (LayerDrawable) imageSpans[0].getDrawable(); - - ArgumentCaptor<ImageSpanDrawableCallback> imageCallbackCaptor = - ArgumentCaptor.forClass(ImageSpanDrawableCallback.class); - verify(mMockAssetProvider) - .getImage(eq(IMAGE_CHUNK_IMAGE), eq(-1), eq(STYLE_HEIGHT_PX), - imageCallbackCaptor.capture()); - - int aspectRatio = 4; - Drawable imageDrawable = new ColorDrawable(123) { - @Override - public int getIntrinsicWidth() { - return 11 * aspectRatio; - } - - @Override - public int getIntrinsicHeight() { - return 11; - } - }; - - // Activate the image loading callback - imageCallbackCaptor.getValue().accept(imageDrawable); - - // Assert that we set the image on the span - assertThat(containerDrawable.getDrawable(0)).isSameInstanceAs(imageDrawable); - - assertThat(imageDrawable.getBounds()) - .isEqualTo(new Rect(0, 0, STYLE_HEIGHT_PX * 4, STYLE_HEIGHT_PX)); - assertThat(containerDrawable.getBounds()) - .isEqualTo(new Rect(0, 0, STYLE_HEIGHT_PX * 4, STYLE_HEIGHT_PX)); - } - - @Test - public void testAddImageChunk_addsMargins() { - when(mMockStyleProvider.hasWidth()).thenReturn(true); - when(mMockStyleProvider.getWidthSpecPx(mContext)).thenReturn(STYLE_WIDTH_PX); - when(mMockStyleProvider.hasHeight()).thenReturn(true); - when(mMockStyleProvider.getHeightSpecPx(mContext)).thenReturn(STYLE_HEIGHT_PX); - - when(mMockStyleProvider.getMargins()) - .thenReturn(EdgeWidths.newBuilder().setStart(11).setEnd(22).build()); - - // Required to set up the local frameContext member var. - mAdapter.createAdapter(asElement(TextElement.getDefaultInstance()), mFrameContext); - - mAdapter.addImageChunk(mFrameContext, mTextView, mSpannable, IMAGE_CHUNK); - - assertThat(mSpannable.toString()).isEqualTo(" "); - - ImageSpan[] imageSpans = mSpannable.getSpans(0, 3, ImageSpan.class); - - Drawable leftMarginDrawable = imageSpans[0].getDrawable(); - assertThat(leftMarginDrawable.getBounds().left).isEqualTo(0); - assertThat(leftMarginDrawable.getBounds().right).isEqualTo(11); - - Drawable rightMarginDrawable = imageSpans[2].getDrawable(); - assertThat(leftMarginDrawable.getBounds().left).isEqualTo(0); - assertThat(rightMarginDrawable.getBounds().right).isEqualTo(22); - } - - @Test - public void testAddImageChunk_tintColor() { - // Required to set up the local frameContext member var. - mAdapter.createAdapter(asElement(TextElement.getDefaultInstance()), mFrameContext); - - StyleProvider tintStyleProvider = new StyleProvider( - Style.newBuilder().setStyleId("tint").setColor(0xFEEDFACE).build(), - mMockAssetProvider); - StyleIdsStack tintStyle = StyleIdsStack.newBuilder().addStyleIds("tint").build(); - when(mFrameContext.makeStyleFor(tintStyle)).thenReturn(tintStyleProvider); - - Chunk imageChunk = Chunk.newBuilder() - .setImageChunk(StyledImageChunk.newBuilder() - .setImage(IMAGE_CHUNK_IMAGE) - .setStyleReferences(tintStyle)) - .build(); - - mAdapter.addImageChunk(mFrameContext, mTextView, mSpannable, imageChunk); - - ImageSpan[] imageSpans = mSpannable.getSpans(0, 1, ImageSpan.class); - LayerDrawable containerDrawable = (LayerDrawable) imageSpans[0].getDrawable(); - - ArgumentCaptor<ImageSpanDrawableCallback> imageCallbackCaptor = - ArgumentCaptor.forClass(ImageSpanDrawableCallback.class); - verify(mMockAssetProvider) - .getImage(eq(IMAGE_CHUNK_IMAGE), anyInt(), anyInt(), imageCallbackCaptor.capture()); - - // Activate the image loading callback - imageCallbackCaptor.getValue().accept(mDrawable); - - // Assert that we set the image on the span - assertThat(containerDrawable.getDrawable(0).getColorFilter()) - .isEqualTo(new PorterDuffColorFilter(0xFEEDFACE, Mode.SRC_IN)); - } - - @Test - public void testBindSetsActions_inline() { - TextElement imageChunkWithActions = - TextElement.newBuilder() - .setChunkedText(ChunkedText.newBuilder().addChunks( - IMAGE_CHUNK.toBuilder().setActions( - Actions.newBuilder().setOnClickAction( - Action.getDefaultInstance())))) - .build(); - when(mFrameContext.getFrame()).thenReturn(Frame.getDefaultInstance()); - - mAdapter.createAdapter(asElement(imageChunkWithActions), mFrameContext); - mAdapter.bindModel(asElement(imageChunkWithActions), mFrameContext); - - assertThat(((SpannedString) mAdapter.getBaseView().getText()) - .getSpans(0, 1, ActionsClickableSpan.class)) - .hasLength(1); - MotionEvent motionEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, 0, 0, 0); - mAdapter.getBaseView().dispatchTouchEvent(motionEvent); - verify(mMockActionHandler) - .handleAction(Action.getDefaultInstance(), ActionType.CLICK, - Frame.getDefaultInstance(), mAdapter.getBaseView(), - LogData.getDefaultInstance()); - } - - @Test - public void testBindSetsActions_bind() { - String bindingId = "ACTION"; - ActionsBindingRef binding = ActionsBindingRef.newBuilder().setBindingId(bindingId).build(); - TextElement imageChunkWithActions = - TextElement.newBuilder() - .setChunkedText(ChunkedText.newBuilder().addChunks( - IMAGE_CHUNK.toBuilder().setActionsBinding(binding))) - .build(); - when(mFrameContext.getActionsFromBinding(binding)) - .thenReturn( - Actions.newBuilder().setOnClickAction(Action.getDefaultInstance()).build()); - when(mFrameContext.getFrame()).thenReturn(Frame.getDefaultInstance()); - - mAdapter.createAdapter(asElement(imageChunkWithActions), mFrameContext); - mAdapter.bindModel(asElement(imageChunkWithActions), mFrameContext); - - assertThat(((SpannedString) mAdapter.getBaseView().getText()) - .getSpans(0, 1, ActionsClickableSpan.class)) - .hasLength(1); - MotionEvent motionEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, 0, 0, 0); - mAdapter.getBaseView().dispatchTouchEvent(motionEvent); - verify(mMockActionHandler) - .handleAction(Action.getDefaultInstance(), ActionType.CLICK, - Frame.getDefaultInstance(), mAdapter.getBaseView(), - LogData.getDefaultInstance()); - } - - @Test - public void testBindSetsActions_bindingNotFound() { - String bindingId = "ACTION"; - ActionsBindingRef binding = ActionsBindingRef.newBuilder().setBindingId(bindingId).build(); - TextElement imageChunkWithActions = - TextElement.newBuilder() - .setChunkedText(ChunkedText.newBuilder().addChunks( - IMAGE_CHUNK.toBuilder().setActionsBinding(binding))) - .build(); - when(mFrameContext.getActionsFromBinding(binding)).thenReturn(Actions.getDefaultInstance()); - when(mFrameContext.getFrame()).thenReturn(Frame.getDefaultInstance()); - - mAdapter.createAdapter(asElement(imageChunkWithActions), mFrameContext); - mAdapter.bindModel(asElement(imageChunkWithActions), mFrameContext); - - // Completes successfully, but doesn't add the clickable span. - assertThat(((SpannedString) mAdapter.getBaseView().getText()) - .getSpans(0, 1, ActionsClickableSpan.class)) - .isEmpty(); - } - - @Test - public void testUnbind_cancelsCallbacks() { - mAdapter.createAdapter(asElement(TextElement.getDefaultInstance()), mFrameContext); - mAdapter.addImageChunk(mFrameContext, mTextView, mSpannable, IMAGE_CHUNK); - - ImageSpan[] imageSpans = mSpannable.getSpans(0, 1, ImageSpan.class); - LayerDrawable containerDrawable = (LayerDrawable) imageSpans[0].getDrawable(); - ArgumentCaptor<ImageSpanDrawableCallback> imageCallbackCaptor = - ArgumentCaptor.forClass(ImageSpanDrawableCallback.class); - verify(mMockAssetProvider) - .getImage(eq(IMAGE_CHUNK_IMAGE), eq(DIMENSION_UNKNOWN), eq(DIMENSION_UNKNOWN), - imageCallbackCaptor.capture()); - - // Unbind the model - mAdapter.unbindModel(); - - // Activate the image loading callback - Drawable imageDrawable = new ColorDrawable(Color.RED); - imageCallbackCaptor.getValue().accept(imageDrawable); - - // Assert that we did NOT set the image on the span - assertThat(containerDrawable.getDrawable(SINGLE_LAYER_ID)) - .isNotSameInstanceAs(imageDrawable); - } - - @Test - public void testKeySupplier() { - ChunkedTextElementAdapter.KeySupplier keySupplier = - new ChunkedTextElementAdapter.KeySupplier(); - assertThat(keySupplier.getAdapterTag()).isEqualTo("ChunkedTextElementAdapter"); - assertThat(keySupplier.getAdapter(mContext, mAdapterParameters)).isNotNull(); - assertThat(keySupplier).isNotInstanceOf(SingletonKeySupplier.class); - } - - @Test - public void testSetBounds_heightAndWidth_setsBoth() { - int widthDp = 123; - int heightDp = 456; - mAdapter.setBounds(mDrawable, - new StyleProvider(Style.newBuilder().setHeight(heightDp).setWidth(widthDp).build(), - mMockAssetProvider), - mTextView); - - int widthPx = (int) LayoutUtils.dpToPx(widthDp, mContext); - int heightPx = (int) LayoutUtils.dpToPx(heightDp, mContext); - assertThat(mDrawable.getBounds()).isEqualTo(new Rect(0, 0, widthPx, heightPx)); - } - - @Test - public void testSetBounds_heightOnly_aspectRatioScaled() { - mAdapter.setBounds(mDrawable, - new StyleProvider( - Style.newBuilder().setHeight(HEIGHT_DP).build(), mMockAssetProvider), - mTextView); - - int heightPx = (int) LayoutUtils.dpToPx(HEIGHT_DP, mContext); - assertThat(mDrawable.getBounds()) - .isEqualTo(new Rect(0, 0, heightPx * IMAGE_ASPECT_RATIO, heightPx)); - } - - @Test - public void testSetBounds_widthOnly_aspectRatioScaled() { - mAdapter.setBounds(mDrawable, - new StyleProvider( - Style.newBuilder().setWidth(WIDTH_DP).build(), mMockAssetProvider), - mTextView); - - int widthPx = (int) LayoutUtils.dpToPx(WIDTH_DP, mContext); - assertThat(mDrawable.getBounds()) - .isEqualTo(new Rect(0, 0, widthPx, widthPx / IMAGE_ASPECT_RATIO)); - } - - @Test - public void testSetBounds_noHeightOrWidth_defaultsToTextHeight() { - mAdapter.setBounds(mDrawable, - new StyleProvider(Style.getDefaultInstance(), mMockAssetProvider), mTextView); - - assertThat(mDrawable.getBounds()) - .isEqualTo(new Rect(0, 0, TEXT_HEIGHT * IMAGE_ASPECT_RATIO, TEXT_HEIGHT)); - } - - @Implements(TextView.class) - public static class ShadowTextViewWithHeight extends ShadowTextView { - @Implementation - public int getLineHeight() { - return TEXT_HEIGHT; - } - } - - private static Element asElement(TextElement textElement) { - return Element.newBuilder().setTextElement(textElement).build(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/CustomElementAdapterTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/CustomElementAdapterTest.java deleted file mode 100644 index 50cda0b..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/CustomElementAdapterTest.java +++ /dev/null
@@ -1,238 +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. - -package org.chromium.chrome.browser.feed.library.piet; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import static org.chromium.chrome.browser.feed.library.common.testing.RunnableSubject.assertThatRunnable; - -import android.app.Activity; -import android.content.Context; -import android.view.View; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.common.functional.Suppliers; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.piet.CustomElementAdapter.KeySupplier; -import org.chromium.chrome.browser.feed.library.piet.host.AssetProvider; -import org.chromium.chrome.browser.feed.library.piet.host.CustomElementProvider; -import org.chromium.components.feed.core.proto.ui.piet.BindingRefsProto.CustomBindingRef; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.BindingValue; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.CustomElement; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.CustomElementData; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.Element; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.TextElement; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.StyleIdsStack; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests of the {@link CustomElementAdapter}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class CustomElementAdapterTest { - private static final CustomElementData DUMMY_DATA = CustomElementData.getDefaultInstance(); - private static final Element DEFAULT_MODEL = - asElement(CustomElement.newBuilder().setCustomElementData(DUMMY_DATA).build()); - - @Mock - private FrameContext mFrameContext; - @Mock - private CustomElementProvider mCustomElementProvider; - @Mock - private HostProviders mHostProviders; - @Mock - private AssetProvider mAssetProvider; - - private Context mContext; - private View mCustomView; - private CustomElementAdapter mAdapter; - private AdapterParameters mAdapterParameters; - - @Before - public void setUp() throws Exception { - initMocks(this); - mContext = Robolectric.buildActivity(Activity.class).get(); - mCustomView = new View(mContext); - - when(mHostProviders.getCustomElementProvider()).thenReturn(mCustomElementProvider); - when(mHostProviders.getAssetProvider()).thenReturn(mAssetProvider); - when(mAssetProvider.isRtL()).thenReturn(false); - when(mCustomElementProvider.createCustomElement(DUMMY_DATA)).thenReturn(mCustomView); - when(mFrameContext.reportMessage(anyInt(), any(), anyString())) - .thenAnswer(invocation -> invocation.getArguments()[2]); - - mAdapterParameters = new AdapterParameters( - mContext, Suppliers.of(null), mHostProviders, new FakeClock(), false, false); - - when(mFrameContext.makeStyleFor(any(StyleIdsStack.class))) - .thenReturn(mAdapterParameters.mDefaultStyleProvider); - - mAdapter = new KeySupplier().getAdapter(mContext, mAdapterParameters); - } - - @Test - public void testCreate() { - assertThat(mAdapter).isNotNull(); - } - - @Test - public void testCreateAdapter_initializes() { - mAdapter.createAdapter(DEFAULT_MODEL, mFrameContext); - - assertThat(mAdapter.getView()).isNotNull(); - assertThat(mAdapter.getKey()).isNotNull(); - } - - @Test - public void testCreateAdapter_ignoresSubsequentCalls() { - mAdapter.createAdapter(DEFAULT_MODEL, mFrameContext); - View adapterView = mAdapter.getView(); - RecyclerKey adapterKey = mAdapter.getKey(); - - mAdapter.createAdapter(DEFAULT_MODEL, mFrameContext); - - assertThat(mAdapter.getView()).isSameInstanceAs(adapterView); - assertThat(mAdapter.getKey()).isSameInstanceAs(adapterKey); - } - - @Test - public void testBindModel_data() { - mAdapter.createAdapter(DEFAULT_MODEL, mFrameContext); - mAdapter.bindModel(DEFAULT_MODEL, mFrameContext); - - assertThat(mAdapter.getBaseView().getChildAt(0)).isEqualTo(mCustomView); - } - - @Test - public void testBindModel_binding() { - CustomBindingRef bindingRef = CustomBindingRef.newBuilder().setBindingId("CUSTOM!").build(); - when(mFrameContext.getCustomElementBindingValue(bindingRef)) - .thenReturn(BindingValue.newBuilder().setCustomElementData(DUMMY_DATA).build()); - - Element model = asElement(CustomElement.newBuilder().setCustomBinding(bindingRef).build()); - - mAdapter.createAdapter(model, mFrameContext); - mAdapter.bindModel(model, mFrameContext); - - assertThat(mAdapter.getBaseView().getChildAt(0)).isEqualTo(mCustomView); - } - - @Test - public void testBindModel_noContent() { - mAdapter.createAdapter(DEFAULT_MODEL, mFrameContext); - mAdapter.bindModel(asElement(CustomElement.getDefaultInstance()), mFrameContext); - - verifyZeroInteractions(mCustomElementProvider); - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(0); - } - - @Test - public void testBindModel_optionalAbsent() { - CustomBindingRef bindingRef = - CustomBindingRef.newBuilder().setBindingId("CUSTOM!").setIsOptional(true).build(); - when(mFrameContext.getCustomElementBindingValue(bindingRef)) - .thenReturn(BindingValue.getDefaultInstance()); - Element model = asElement(CustomElement.newBuilder().setCustomBinding(bindingRef).build()); - mAdapter.createAdapter(model, mFrameContext); - - // This should not fail. - mAdapter.bindModel(model, mFrameContext); - assertThat(mAdapter.getView().getVisibility()).isEqualTo(View.GONE); - } - - @Test - public void testBindModel_noContentInBinding() { - CustomBindingRef bindingRef = CustomBindingRef.newBuilder().setBindingId("CUSTOM").build(); - when(mFrameContext.getCustomElementBindingValue(bindingRef)) - .thenReturn(BindingValue.newBuilder().setBindingId("CUSTOM").build()); - Element model = asElement(CustomElement.newBuilder().setCustomBinding(bindingRef).build()); - mAdapter.createAdapter(model, mFrameContext); - - assertThatRunnable(() -> mAdapter.bindModel(model, mFrameContext)) - .throwsAnExceptionOfType(PietFatalException.class) - .that() - .hasMessageThat() - .contains("Custom element binding CUSTOM had no content"); - } - - @Test - public void testUnbindModel() { - mAdapter.createAdapter(DEFAULT_MODEL, mFrameContext); - mAdapter.bindModel(DEFAULT_MODEL, mFrameContext); - - mAdapter.unbindModel(); - - verify(mCustomElementProvider).releaseCustomView(mCustomView, DUMMY_DATA); - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(0); - } - - @Test - public void testUnbindModel_noChildren() { - mAdapter.createAdapter(DEFAULT_MODEL, mFrameContext); - - mAdapter.unbindModel(); - - verifyZeroInteractions(mCustomElementProvider); - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(0); - } - - @Test - public void testUnbindModel_multipleChildren() { - View customView2 = new View(mContext); - when(mCustomElementProvider.createCustomElement(DUMMY_DATA)) - .thenReturn(mCustomView) - .thenReturn(customView2); - - mAdapter.createAdapter(DEFAULT_MODEL, mFrameContext); - mAdapter.bindModel(DEFAULT_MODEL, mFrameContext); - mAdapter.bindModel(DEFAULT_MODEL, mFrameContext); - - mAdapter.unbindModel(); - - verify(mCustomElementProvider).releaseCustomView(mCustomView, DUMMY_DATA); - verify(mCustomElementProvider).releaseCustomView(customView2, DUMMY_DATA); - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(0); - } - - @Test - public void testGetModelFromElement() { - CustomElement model = CustomElement.newBuilder().build(); - - Element elementWithModel = Element.newBuilder().setCustomElement(model).build(); - assertThat(mAdapter.getModelFromElement(elementWithModel)).isSameInstanceAs(model); - - Element elementWithWrongModel = - Element.newBuilder().setTextElement(TextElement.getDefaultInstance()).build(); - assertThatRunnable(() -> mAdapter.getModelFromElement(elementWithWrongModel)) - .throwsAnExceptionOfType(PietFatalException.class) - .that() - .hasMessageThat() - .contains("Missing CustomElement"); - - Element emptyElement = Element.getDefaultInstance(); - assertThatRunnable(() -> mAdapter.getModelFromElement(emptyElement)) - .throwsAnExceptionOfType(PietFatalException.class) - .that() - .hasMessageThat() - .contains("Missing CustomElement"); - } - - private static Element asElement(CustomElement customElement) { - return Element.newBuilder().setCustomElement(customElement).build(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/DebugLoggerTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/DebugLoggerTest.java deleted file mode 100644 index 8af68ec..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/DebugLoggerTest.java +++ /dev/null
@@ -1,155 +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. - -package org.chromium.chrome.browser.feed.library.piet; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.MockitoAnnotations.initMocks; - -import android.app.Activity; -import android.content.Context; -import android.widget.LinearLayout; -import android.widget.LinearLayout.LayoutParams; -import android.widget.TextView; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.common.ui.LayoutUtils; -import org.chromium.chrome.browser.feed.library.piet.DebugLogger.ErrorCodeAndMessage; -import org.chromium.chrome.browser.feed.library.piet.DebugLogger.MessageType; -import org.chromium.components.feed.core.proto.ui.piet.ErrorsProto.ErrorCode; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests of the {@link DebugLogger}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class DebugLoggerTest { - private static final String ERROR_TEXT_1 = "Interdimensional rift formation."; - private static final String ERROR_TEXT_2 = "Exotic particle containment breach."; - private static final String WARNING_TEXT = "Noncompliant meson entanglement."; - - private Context mContext; - - private DebugLogger mDebugLogger; - - @Before - public void setUp() throws Exception { - initMocks(this); - mContext = Robolectric.buildActivity(Activity.class).get(); - mDebugLogger = new DebugLogger(); - } - - @Test - public void testGetReportView_singleError() { - mDebugLogger.recordMessage(MessageType.ERROR, ERROR_TEXT_1); - - LinearLayout reportView = - (LinearLayout) mDebugLogger.getReportView(MessageType.ERROR, mContext); - - assertThat(reportView.getOrientation()).isEqualTo(LinearLayout.VERTICAL); - assertThat(reportView.getLayoutParams().width).isEqualTo(LayoutParams.MATCH_PARENT); - assertThat(reportView.getLayoutParams().height).isEqualTo(LayoutParams.WRAP_CONTENT); - - assertThat(reportView.getChildCount()).isEqualTo(2); - - // Check the divider - assertThat(reportView.getChildAt(0).getLayoutParams().width) - .isEqualTo(LayoutParams.MATCH_PARENT); - assertThat(reportView.getChildAt(0).getLayoutParams().height) - .isEqualTo((int) LayoutUtils.dpToPx(DebugLogger.ERROR_DIVIDER_WIDTH_DP, mContext)); - - // Check the error box - assertThat(reportView.getChildAt(1)).isInstanceOf(TextView.class); - TextView textErrorView = (TextView) reportView.getChildAt(1); - assertThat(textErrorView.getText().toString()).isEqualTo(ERROR_TEXT_1); - - // Check that padding has been set (but don't check specific values) - assertThat(textErrorView.getPaddingBottom()).isNotEqualTo(0); - assertThat(textErrorView.getPaddingTop()).isNotEqualTo(0); - assertThat(textErrorView.getPaddingStart()).isNotEqualTo(0); - assertThat(textErrorView.getPaddingEnd()).isNotEqualTo(0); - } - - @Test - public void testGetReportView_multipleErrors() { - mDebugLogger.recordMessage(MessageType.ERROR, ERROR_TEXT_1); - mDebugLogger.recordMessage(MessageType.ERROR, ERROR_TEXT_2); - - LinearLayout reportView = - (LinearLayout) mDebugLogger.getReportView(MessageType.ERROR, mContext); - - assertThat(reportView.getChildCount()).isEqualTo(3); - - assertThat(((TextView) reportView.getChildAt(1)).getText().toString()) - .isEqualTo(ERROR_TEXT_1); - assertThat(((TextView) reportView.getChildAt(2)).getText().toString()) - .isEqualTo(ERROR_TEXT_2); - } - - @Test - public void testGetReportView_zeroErrors() { - LinearLayout errorView = - (LinearLayout) mDebugLogger.getReportView(MessageType.ERROR, mContext); - - assertThat(errorView).isNull(); - } - - @Test - public void testGetMessageTypes() { - assertThat(mDebugLogger.getMessages(MessageType.ERROR)).isEmpty(); - assertThat(mDebugLogger.getMessages(MessageType.WARNING)).isEmpty(); - - mDebugLogger.recordMessage(MessageType.WARNING, WARNING_TEXT); - assertThat(mDebugLogger.getMessages(MessageType.ERROR)).isEmpty(); - assertThat(mDebugLogger.getMessages(MessageType.WARNING)) - .containsExactly(new ErrorCodeAndMessage(ErrorCode.ERR_UNSPECIFIED, WARNING_TEXT)); - - mDebugLogger.recordMessage(MessageType.ERROR, ErrorCode.ERR_PROTO_TOO_LARGE, ERROR_TEXT_1); - assertThat(mDebugLogger.getMessages(MessageType.ERROR)) - .containsExactly( - new ErrorCodeAndMessage(ErrorCode.ERR_PROTO_TOO_LARGE, ERROR_TEXT_1)); - assertThat(mDebugLogger.getMessages(MessageType.WARNING)) - .containsExactly(new ErrorCodeAndMessage(ErrorCode.ERR_UNSPECIFIED, WARNING_TEXT)); - } - - @Test - public void testGetReportView_byType() { - mDebugLogger.recordMessage(MessageType.ERROR, ERROR_TEXT_1); - mDebugLogger.recordMessage(MessageType.WARNING, WARNING_TEXT); - - LinearLayout errorView = - (LinearLayout) mDebugLogger.getReportView(MessageType.ERROR, mContext); - - assertThat(errorView.getChildCount()).isEqualTo(2); - assertThat(((TextView) errorView.getChildAt(1)).getText().toString()) - .isEqualTo(ERROR_TEXT_1); - - LinearLayout warningView = - (LinearLayout) mDebugLogger.getReportView(MessageType.WARNING, mContext); - - assertThat(warningView.getChildCount()).isEqualTo(2); - assertThat(((TextView) warningView.getChildAt(1)).getText().toString()) - .isEqualTo(WARNING_TEXT); - } - - @Test - public void testGetErrorCodes() { - mDebugLogger.recordMessage(MessageType.ERROR, ErrorCode.ERR_MISSING_FONTS, ERROR_TEXT_1); - mDebugLogger.recordMessage(MessageType.ERROR, ErrorCode.ERR_MISSING_FONTS, ERROR_TEXT_2); - mDebugLogger.recordMessage(MessageType.ERROR, ErrorCode.ERR_DUPLICATE_STYLE, ERROR_TEXT_1); - mDebugLogger.recordMessage(MessageType.WARNING, ErrorCode.ERR_MISSING_FONTS, WARNING_TEXT); - mDebugLogger.recordMessage( - MessageType.WARNING, ErrorCode.ERR_DUPLICATE_TEMPLATE, WARNING_TEXT); - - assertThat(mDebugLogger.getErrorCodes()) - .containsExactly(ErrorCode.ERR_MISSING_FONTS, ErrorCode.ERR_MISSING_FONTS, - ErrorCode.ERR_DUPLICATE_STYLE, ErrorCode.ERR_MISSING_FONTS, - ErrorCode.ERR_DUPLICATE_TEMPLATE); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ElementAdapterFactoryTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ElementAdapterFactoryTest.java deleted file mode 100644 index a57ebcd3..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ElementAdapterFactoryTest.java +++ /dev/null
@@ -1,334 +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. - -package org.chromium.chrome.browser.feed.library.piet; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import static org.chromium.chrome.browser.feed.library.common.testing.RunnableSubject.assertThatRunnable; - -import android.view.View; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.piet.TemplateBinder.TemplateKey; -import org.chromium.components.feed.core.proto.ui.piet.BindingRefsProto.ChunkedTextBindingRef; -import org.chromium.components.feed.core.proto.ui.piet.BindingRefsProto.ParameterizedTextBindingRef; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.CustomElement; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.Element; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.ElementList; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.ElementStack; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.GridRow; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.ImageElement; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.TextElement; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.PietSharedState; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.Template; -import org.chromium.components.feed.core.proto.ui.piet.TextProto.ChunkedText; -import org.chromium.components.feed.core.proto.ui.piet.TextProto.ParameterizedText; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** Tests for the ElementAdapterFactory. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ElementAdapterFactoryTest { - @Mock - private FrameContext mFrameContext; - - @Mock - private CustomElementAdapter mCustomElementAdapter; - @Mock - private ChunkedTextElementAdapter mChunkedTextElementAdapter; - @Mock - private ParameterizedTextElementAdapter mParameterizedTextElementAdapter; - @Mock - private ImageElementAdapter mImageElementAdapter; - @Mock - private GridRowAdapter mGridRowAdapter; - @Mock - private ElementListAdapter mElementListAdapter; - @Mock - private ElementAdapter<? extends View, ?> mTemplateAdapter; - @Mock - private ElementStackAdapter mElementStackAdapter; - - @Mock - private AdapterFactory<CustomElementAdapter, CustomElement> mCustomElementFactory; - - @Mock - private AdapterFactory<ChunkedTextElementAdapter, Element> mChunkedTextElementFactory; - - @Mock - private AdapterFactory<ParameterizedTextElementAdapter, Element> - mParameterizedTextElementFactory; - - @Mock - private AdapterFactory<ImageElementAdapter, ImageElement> mImageElementFactory; - - @Mock - private AdapterFactory<GridRowAdapter, GridRow> mGridRowFactory; - - @Mock - private AdapterFactory<ElementListAdapter, ElementList> mElementListFactory; - - @Mock - private AdapterFactory<ElementStackAdapter, ElementStack> mElementStackFactory; - - @Mock - private KeyedRecyclerPool<ElementAdapter<? extends View, ?>> mTemplateRecyclerPool; - - private final List<AdapterFactory<?, ?>> mAdapterFactories = new ArrayList<>(); - - private ElementAdapterFactory mAdapterFactory; - - @Before - public void setUp() { - initMocks(this); - when(mFrameContext.reportMessage(anyInt(), any(), anyString())) - .thenAnswer(invocation -> invocation.getArguments()[2]); - mAdapterFactory = new ElementAdapterFactory(mCustomElementFactory, - mChunkedTextElementFactory, mParameterizedTextElementFactory, mImageElementFactory, - mGridRowFactory, mElementListFactory, mElementStackFactory, mTemplateRecyclerPool); - when(mCustomElementFactory.get(any(CustomElement.class), eq(mFrameContext))) - .thenReturn(mCustomElementAdapter); - when(mChunkedTextElementFactory.get(any(Element.class), eq(mFrameContext))) - .thenReturn(mChunkedTextElementAdapter); - when(mParameterizedTextElementFactory.get(any(Element.class), eq(mFrameContext))) - .thenReturn(mParameterizedTextElementAdapter); - when(mImageElementFactory.get(any(ImageElement.class), eq(mFrameContext))) - .thenReturn(mImageElementAdapter); - when(mGridRowFactory.get(any(GridRow.class), eq(mFrameContext))) - .thenReturn(mGridRowAdapter); - when(mElementListFactory.get(any(ElementList.class), eq(mFrameContext))) - .thenReturn(mElementListAdapter); - when(mElementStackFactory.get(any(ElementStack.class), eq(mFrameContext))) - .thenReturn(mElementStackAdapter); - mAdapterFactories.add(mCustomElementFactory); - mAdapterFactories.add(mChunkedTextElementFactory); - mAdapterFactories.add(mParameterizedTextElementFactory); - mAdapterFactories.add(mImageElementFactory); - mAdapterFactories.add(mGridRowFactory); - mAdapterFactories.add(mElementListFactory); - mAdapterFactories.add(mElementStackFactory); - } - - @Test - public void testCreateAdapterForElement_customElement() { - CustomElement model = CustomElement.getDefaultInstance(); - Element element = Element.newBuilder().setCustomElement(model).build(); - assertThat(mAdapterFactory.createAdapterForElement(element, mFrameContext)) - .isSameInstanceAs(mCustomElementAdapter); - verify(mCustomElementFactory).get(model, mFrameContext); - } - - @Test - public void testCreateAdapterForElement_chunkedTextElement() { - TextElement model = - TextElement.newBuilder().setChunkedText(ChunkedText.getDefaultInstance()).build(); - Element element = Element.newBuilder().setTextElement(model).build(); - assertThat(mAdapterFactory.createAdapterForElement(element, mFrameContext)) - .isSameInstanceAs(mChunkedTextElementAdapter); - verify(mChunkedTextElementFactory).get(element, mFrameContext); - } - - @Test - public void testCreateAdapterForElement_chunkedTextBindingElement() { - TextElement model = - TextElement.newBuilder() - .setChunkedTextBinding(ChunkedTextBindingRef.getDefaultInstance()) - .build(); - Element element = Element.newBuilder().setTextElement(model).build(); - assertThat(mAdapterFactory.createAdapterForElement(element, mFrameContext)) - .isSameInstanceAs(mChunkedTextElementAdapter); - verify(mChunkedTextElementFactory).get(element, mFrameContext); - } - - @Test - public void testCreateAdapterForElement_parameterizedTextElement() { - TextElement model = TextElement.newBuilder() - .setParameterizedText(ParameterizedText.getDefaultInstance()) - .build(); - Element element = Element.newBuilder().setTextElement(model).build(); - assertThat(mAdapterFactory.createAdapterForElement(element, mFrameContext)) - .isSameInstanceAs(mParameterizedTextElementAdapter); - verify(mParameterizedTextElementFactory).get(element, mFrameContext); - } - - @Test - public void testCreateAdapterForElement_parameterizedTextBindingElement() { - TextElement model = TextElement.newBuilder() - .setParameterizedTextBinding( - ParameterizedTextBindingRef.getDefaultInstance()) - .build(); - Element element = Element.newBuilder().setTextElement(model).build(); - assertThat(mAdapterFactory.createAdapterForElement(element, mFrameContext)) - .isSameInstanceAs(mParameterizedTextElementAdapter); - verify(mParameterizedTextElementFactory).get(element, mFrameContext); - } - - @Test - public void testCreateAdapterForElement_invalidTextElement() { - TextElement model = TextElement.getDefaultInstance(); - Element element = Element.newBuilder().setTextElement(model).build(); - - assertThatRunnable(() -> mAdapterFactory.createAdapterForElement(element, mFrameContext)) - .throwsAnExceptionOfType(PietFatalException.class) - .that() - .hasMessageThat() - .contains("Unsupported TextElement type"); - } - - @Test - public void testCreateAdapterForElement_imageElement() { - ImageElement model = ImageElement.getDefaultInstance(); - Element element = Element.newBuilder().setImageElement(model).build(); - assertThat(mAdapterFactory.createAdapterForElement(element, mFrameContext)) - .isSameInstanceAs(mImageElementAdapter); - verify(mImageElementFactory).get(model, mFrameContext); - } - - @Test - public void testCreateAdapterForElement_gridRow() { - GridRow model = GridRow.getDefaultInstance(); - Element element = Element.newBuilder().setGridRow(model).build(); - assertThat(mAdapterFactory.createAdapterForElement(element, mFrameContext)) - .isSameInstanceAs(mGridRowAdapter); - verify(mGridRowFactory).get(model, mFrameContext); - } - - @Test - public void testCreateAdapterForElement_elementList() { - ElementList model = ElementList.getDefaultInstance(); - Element element = Element.newBuilder().setElementList(model).build(); - assertThat(mAdapterFactory.createAdapterForElement(element, mFrameContext)) - .isSameInstanceAs(mElementListAdapter); - verify(mElementListFactory).get(model, mFrameContext); - } - - @Test - public void testCreateAdapterForElement_unsupported() { - assertThatRunnable(() - -> mAdapterFactory.createAdapterForElement( - Element.getDefaultInstance(), mFrameContext)) - .throwsAnExceptionOfType(PietFatalException.class) - .that() - .hasMessageThat() - .contains("Unsupported Element type"); - } - - @Test - public void testReleaseAdapter_template() { - TemplateKey templateKey = new TemplateKey(Template.getDefaultInstance(), null, null); - when(mTemplateAdapter.getKey()).thenReturn(templateKey); - - mAdapterFactory.releaseAdapter(mTemplateAdapter); - - // We unbind the adapter but do not release it so it can be created quickly again. - verify(mTemplateAdapter).unbindModel(); - verify(mTemplateAdapter, never()).releaseAdapter(); - verify(mTemplateRecyclerPool).put(templateKey, mTemplateAdapter); - } - - @Test - public void testReleaseAdapter_custom() { - mAdapterFactory.releaseAdapter(mCustomElementAdapter); - verify(mCustomElementFactory).release(mCustomElementAdapter); - testNoOtherFactoryInteractions(); - } - - @Test - public void testReleaseAdapter_chunkedText() { - mAdapterFactory.releaseAdapter(mChunkedTextElementAdapter); - verify(mChunkedTextElementFactory).release(mChunkedTextElementAdapter); - testNoOtherFactoryInteractions(); - } - - @Test - public void testReleaseAdapter_parameterizedText() { - mAdapterFactory.releaseAdapter(mParameterizedTextElementAdapter); - verify(mParameterizedTextElementFactory).release(mParameterizedTextElementAdapter); - testNoOtherFactoryInteractions(); - } - - @Test - public void testReleaseAdapter_imageElement() { - mAdapterFactory.releaseAdapter(mImageElementAdapter); - verify(mImageElementFactory).release(mImageElementAdapter); - testNoOtherFactoryInteractions(); - } - - @Test - public void testReleaseAdapter_gridRow() { - mAdapterFactory.releaseAdapter(mGridRowAdapter); - verify(mGridRowFactory).release(mGridRowAdapter); - testNoOtherFactoryInteractions(); - } - - @Test - public void testReleaseAdapter_list() { - mAdapterFactory.releaseAdapter(mElementListAdapter); - verify(mElementListFactory).release(mElementListAdapter); - testNoOtherFactoryInteractions(); - } - - @Test - public void testReleaseAdapter_stacked() { - mAdapterFactory.releaseAdapter(mElementStackAdapter); - verify(mElementStackFactory).release(mElementStackAdapter); - testNoOtherFactoryInteractions(); - } - - @Test - public void testPurgeRecyclerPools() { - mAdapterFactory.purgeRecyclerPools(); - for (AdapterFactory<?, ?> adapterFactory : mAdapterFactories) { - verify(adapterFactory).purgeRecyclerPool(); - } - } - - @Test - public void testPurgeTemplateRecyclerPool() { - Template template = Template.newBuilder() - .setTemplateId("template") - .setElement(Element.newBuilder().setElementList( - ElementList.getDefaultInstance())) - .build(); - List<PietSharedState> sharedStates = Collections.emptyList(); - when(mTemplateAdapter.getKey()).thenReturn(new TemplateKey(template, sharedStates, null)); - when(mFrameContext.getPietSharedStates()).thenReturn(sharedStates); - - // Release adapter to populate the recycler pool - mAdapterFactory.releaseAdapter(mTemplateAdapter); - - verify(mTemplateRecyclerPool).put(mTemplateAdapter.getKey(), mTemplateAdapter); - - // Purge the recycler pools. - mAdapterFactory.purgeRecyclerPools(); - - verify(mTemplateRecyclerPool).clear(); - } - - private void testNoOtherFactoryInteractions() { - for (AdapterFactory<?, ?> adapterFactory : mAdapterFactories) { - verifyNoMoreInteractions(adapterFactory); - } - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ElementAdapterTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ElementAdapterTest.java deleted file mode 100644 index b63a85e..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ElementAdapterTest.java +++ /dev/null
@@ -1,1160 +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. - -package org.chromium.chrome.browser.feed.library.piet; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import static org.chromium.chrome.browser.feed.library.piet.StyleProvider.DIMENSION_NOT_SET; - -import android.app.Activity; -import android.content.Context; -import android.view.Gravity; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewGroup.LayoutParams; -import android.view.accessibility.AccessibilityNodeInfo; -import android.widget.FrameLayout; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; -import org.robolectric.shadow.api.Shadow; - -import org.chromium.chrome.browser.feed.library.common.functional.Suppliers; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.piet.host.ActionHandler; -import org.chromium.chrome.browser.feed.library.piet.host.ActionHandler.ActionType; -import org.chromium.chrome.browser.feed.library.piet.host.LogDataCallback; -import org.chromium.chrome.browser.feed.library.piet.ui.RoundedCornerMaskCache; -import org.chromium.chrome.browser.feed.library.piet.ui.RoundedCornerWrapperView; -import org.chromium.chrome.browser.feed.library.testing.shadows.ExtendedShadowView; -import org.chromium.components.feed.core.proto.ui.piet.AccessibilityProto.Accessibility; -import org.chromium.components.feed.core.proto.ui.piet.AccessibilityProto.AccessibilityRole; -import org.chromium.components.feed.core.proto.ui.piet.ActionsProto.Action; -import org.chromium.components.feed.core.proto.ui.piet.ActionsProto.Actions; -import org.chromium.components.feed.core.proto.ui.piet.ActionsProto.VisibilityAction; -import org.chromium.components.feed.core.proto.ui.piet.BindingRefsProto.ActionsBindingRef; -import org.chromium.components.feed.core.proto.ui.piet.BindingRefsProto.LogDataBindingRef; -import org.chromium.components.feed.core.proto.ui.piet.BindingRefsProto.ParameterizedTextBindingRef; -import org.chromium.components.feed.core.proto.ui.piet.BindingRefsProto.VisibilityBindingRef; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.BindingValue; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.Element; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.Visibility; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.VisibilityState; -import org.chromium.components.feed.core.proto.ui.piet.LogDataProto.LogData; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.Frame; -import org.chromium.components.feed.core.proto.ui.piet.RoundedCornersProto.RoundedCorners; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.Borders; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.StyleIdsStack; -import org.chromium.components.feed.core.proto.ui.piet.TextProto.ParameterizedText; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests of the {@link ElementAdapter}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ElementAdapterTest { - private static final int WIDTH = 123; - private static final int HEIGHT = 456; - private static final boolean LEGACY_CORNERS_FLAG = false; - private static final boolean OUTLINE_CORNERS_FLAG = false; - - private final LogData mLogDataTest = LogData.newBuilder().build(); - - @Mock - private FrameContext mFrameContext; - @Mock - private HostProviders mHostProviders; - @Mock - private ActionHandler mActionHandler; - @Mock - private StyleProvider mStyleProvider; - - private Context mContext; - private AdapterParameters mParameters; - private View mView; - private RoundedCornerMaskCache mMaskCache; - - private TestElementAdapter mAdapter; - private boolean mCallbackBound; - private boolean mCallbackUnbound; - - @Before - public void setUp() { - initMocks(this); - mContext = Robolectric.buildActivity(Activity.class).get(); - LogDataCallback logDataCallback = new LogDataCallback() { - @Override - public void onBind(LogData logData, View view) { - assertThat(mLogDataTest).isEqualTo(logData); - mCallbackBound = true; - } - - @Override - public void onUnbind(LogData logData, View view) { - assertThat(mLogDataTest).isEqualTo(logData); - mCallbackUnbound = true; - } - }; - mParameters = new AdapterParameters(mContext, Suppliers.of((ViewGroup) null), - mHostProviders, new FakeClock(), LEGACY_CORNERS_FLAG, OUTLINE_CORNERS_FLAG); - mMaskCache = mParameters.mRoundedCornerMaskCache; - when(mHostProviders.getLogDataCallback()).thenReturn(logDataCallback); - when(mFrameContext.makeStyleFor(any(StyleIdsStack.class))).thenReturn(mStyleProvider); - when(mFrameContext.getActionHandler()).thenReturn(mActionHandler); - when(mStyleProvider.hasRoundedCorners()).thenReturn(false); - when(mStyleProvider.getRoundedCorners()).thenReturn(RoundedCorners.getDefaultInstance()); - when(mStyleProvider.createWrapperView( - mContext, mMaskCache, LEGACY_CORNERS_FLAG, OUTLINE_CORNERS_FLAG)) - .thenReturn(new FrameLayout(mContext)); - - mView = new View(mContext); - mAdapter = new TestElementAdapter(mContext, mParameters, mView); - } - - @Test - public void testGetters() { - // Pre-creation - assertThat(mAdapter.getHorizontalGravity(Gravity.CLIP_HORIZONTAL)) - .isEqualTo(Gravity.CLIP_HORIZONTAL); - assertThat(mAdapter.getVerticalGravity(Gravity.CLIP_VERTICAL)) - .isEqualTo(Gravity.CLIP_VERTICAL); - assertThat(mAdapter.getGravity(Gravity.AXIS_Y_SHIFT)).isEqualTo(Gravity.AXIS_Y_SHIFT); - - Element defaultElement = Element.newBuilder().build(); - Frame frame = Frame.newBuilder().setTag("FRAME").build(); - when(mFrameContext.getFrame()).thenReturn(frame); - when(mStyleProvider.getGravityHorizontal(Gravity.CLIP_HORIZONTAL)) - .thenReturn(Gravity.CENTER_HORIZONTAL); - when(mStyleProvider.hasGravityHorizontal()).thenReturn(true); - when(mStyleProvider.hasGravityVertical()).thenReturn(true); - when(mStyleProvider.getGravityHorizontal(anyInt())).thenReturn(Gravity.CENTER_HORIZONTAL); - when(mStyleProvider.getGravityVertical(anyInt())).thenReturn(Gravity.CENTER_VERTICAL); - // This should typically be CENTER_HORIZONTAL | CENTER_VERTICAL but I want to make sure that - // ElementAdapter is calling this method instead of OR'ing the H/V gravities itself. - when(mStyleProvider.getGravity(anyInt())).thenReturn(Gravity.FILL); - - mAdapter.createAdapter(defaultElement, defaultElement, mFrameContext); - - assertThat(mAdapter.getContext()).isSameInstanceAs(mContext); - assertThat(mAdapter.getModel()).isSameInstanceAs(defaultElement); - assertThat(mAdapter.getRawModel()).isSameInstanceAs(defaultElement); - assertThat(mAdapter.getHorizontalGravity(Gravity.CLIP_HORIZONTAL)) - .isEqualTo(Gravity.CENTER_HORIZONTAL); - assertThat(mAdapter.getParameters()).isSameInstanceAs(mParameters); - assertThat(mAdapter.getTemplatedStringEvaluator()) - .isSameInstanceAs(mParameters.mTemplatedStringEvaluator); - assertThat(mAdapter.getElementStyle()).isSameInstanceAs(mStyleProvider); - assertThat(mAdapter.getElementStyleIdsStack()) - .isEqualTo(StyleIdsStack.getDefaultInstance()); - - assertThat(mAdapter.getHorizontalGravity(Gravity.CLIP_VERTICAL)) - .isEqualTo(Gravity.CENTER_HORIZONTAL); - assertThat(mAdapter.getVerticalGravity(Gravity.CLIP_HORIZONTAL)) - .isEqualTo(Gravity.CENTER_VERTICAL); - assertThat(mAdapter.getGravity(Gravity.CLIP_VERTICAL)).isEqualTo(Gravity.FILL); - } - - @Test - public void setLayoutParams() { - mAdapter.setLayoutParams(new LayoutParams(WIDTH, HEIGHT)); - - assertThat(mView.getLayoutParams().width).isEqualTo(WIDTH); - assertThat(mView.getLayoutParams().height).isEqualTo(HEIGHT); - } - - @Test - public void testGetComputedDimensions_defaults() { - assertThat(mAdapter.getComputedWidthPx()).isEqualTo(DIMENSION_NOT_SET); - assertThat(mAdapter.getComputedHeightPx()).isEqualTo(DIMENSION_NOT_SET); - } - - @Test - public void getComputedDimensions_explicit() { - mAdapter.setDims(WIDTH, HEIGHT); - - assertThat(mAdapter.getComputedWidthPx()).isEqualTo(WIDTH); - assertThat(mAdapter.getComputedHeightPx()).isEqualTo(HEIGHT); - } - - @Test - public void createAdapter_callsOnCreateAdapter() { - Element defaultElement = Element.getDefaultInstance(); - - mAdapter.createAdapter(defaultElement, defaultElement, mFrameContext); - - assertThat(mAdapter.mTestAdapterCreated).isTrue(); - } - - @Test - public void createAdapter_extractsModelFromElement() { - Element element = Element.getDefaultInstance(); - - mAdapter.createAdapter(element, mFrameContext); - - assertThat(mAdapter.getModel()).isEqualTo(TestElementAdapter.DEFAULT_MODEL); - } - - @Test - public void testCreateAdapter_addsBorders() { - when(mStyleProvider.hasBorders()).thenReturn(true); - - mAdapter.createAdapter( - Element.getDefaultInstance(), Element.getDefaultInstance(), mFrameContext); - - verify(mStyleProvider) - .addBordersWithoutRoundedCorners((FrameLayout) mAdapter.getView(), mContext); - } - - @Test - public void createAdapter_appliesVisibility() { - Element defaultElement = - Element.newBuilder() - .setVisibilityState(VisibilityState.newBuilder().setDefaultVisibility( - Visibility.INVISIBLE)) - .build(); - - mAdapter.createAdapter(defaultElement, mFrameContext); - - assertThat(mAdapter.getView().getVisibility()).isEqualTo(View.INVISIBLE); - } - - @Test - public void createAdapter_doesNothingWithVisibilityGone() { - Element defaultElement = - Element.newBuilder() - .setVisibilityState( - VisibilityState.newBuilder().setDefaultVisibility(Visibility.GONE)) - .build(); - - mAdapter.createAdapter(defaultElement, mFrameContext); - - assertThat(mAdapter.mTestAdapterCreated).isFalse(); - assertThat(mAdapter.getView().getVisibility()).isEqualTo(View.GONE); - } - - @Test - public void createAdapter_ignoresBoundVisibility() { - String visibilityBindingId = "invisible"; - VisibilityBindingRef visibilityBinding = - VisibilityBindingRef.newBuilder().setBindingId(visibilityBindingId).build(); - Element defaultElement = - Element.newBuilder() - .setVisibilityState( - VisibilityState.newBuilder() - .setDefaultVisibility(Visibility.VISIBLE) - .setOverridingBoundVisibility(visibilityBinding)) - .build(); - when(mFrameContext.getVisibilityFromBinding(visibilityBinding)).thenReturn(Visibility.GONE); - - mAdapter.createAdapter(defaultElement, mFrameContext); - - assertThat(mAdapter.mTestAdapterCreated).isTrue(); - assertThat(mAdapter.getView().getVisibility()).isEqualTo(View.VISIBLE); - } - - @Test - public void createAdapter_setsDimensions() { - int width = 10; - int height = 20; - - when(mStyleProvider.hasWidth()).thenReturn(true); - when(mStyleProvider.hasHeight()).thenReturn(true); - when(mStyleProvider.getWidthSpecPx(mContext)).thenReturn(width); - when(mStyleProvider.getHeightSpecPx(mContext)).thenReturn(height); - - mAdapter.createAdapter(Element.getDefaultInstance(), mFrameContext); - - assertThat(mAdapter.getComputedWidthPx()).isEqualTo(width); - assertThat(mAdapter.getComputedHeightPx()).isEqualTo(height); - } - - @Test - public void createAdapter_resetsUnsetDimensions() { - // Set some dimensions first - int width = 10; - int height = 20; - - when(mStyleProvider.hasWidth()).thenReturn(true); - when(mStyleProvider.hasHeight()).thenReturn(true); - when(mStyleProvider.getWidthSpecPx(mContext)).thenReturn(width); - when(mStyleProvider.getHeightSpecPx(mContext)).thenReturn(height); - - mAdapter.createAdapter(Element.getDefaultInstance(), mFrameContext); - mAdapter.releaseAdapter(); - - // Recreate with new style that unsets the dimensions - when(mStyleProvider.hasWidth()).thenReturn(false); - when(mStyleProvider.hasHeight()).thenReturn(false); - when(mStyleProvider.getWidthSpecPx(mContext)).thenReturn(DIMENSION_NOT_SET); - when(mStyleProvider.getHeightSpecPx(mContext)).thenReturn(DIMENSION_NOT_SET); - - mAdapter.createAdapter(Element.getDefaultInstance(), mFrameContext); - - assertThat(mAdapter.getComputedWidthPx()).isEqualTo(DIMENSION_NOT_SET); - assertThat(mAdapter.getComputedHeightPx()).isEqualTo(DIMENSION_NOT_SET); - } - - @Test - public void createAdapter_dimensionsDontOverrideSubclass() { - int width = 10; - int height = 20; - - final int subclassWidth = 30; - final int subclassHeight = 40; - - mAdapter = new TestElementAdapter(mContext, mParameters, mView) { - @Override - protected void onCreateAdapter( - Object model, Element baseElement, FrameContext frameContext) { - mWidthPx = subclassWidth; - mHeightPx = subclassHeight; - } - }; - - when(mStyleProvider.hasWidth()).thenReturn(true); - when(mStyleProvider.hasHeight()).thenReturn(true); - when(mStyleProvider.getWidthSpecPx(mContext)).thenReturn(width); - when(mStyleProvider.getHeightSpecPx(mContext)).thenReturn(height); - - mAdapter.createAdapter(Element.getDefaultInstance(), mFrameContext); - - assertThat(mAdapter.getComputedWidthPx()).isEqualTo(subclassWidth); - assertThat(mAdapter.getComputedHeightPx()).isEqualTo(subclassHeight); - } - - @Test - public void bindModel_callsOnBindModel() { - Element defaultElement = Element.getDefaultInstance(); - - mAdapter.bindModel(defaultElement, defaultElement, mFrameContext); - - assertThat(mAdapter.mTestAdapterBound).isTrue(); - } - - @Test - public void testBindModel_callsOnBindLogDataCallback() { - Element defaultElement = Element.newBuilder().setLogData(mLogDataTest).build(); - - mAdapter.bindModel(defaultElement, defaultElement, mFrameContext); - - assertThat(mCallbackBound).isTrue(); - } - - @Test - public void testBindModel_callsOnBindLogDataCallback_bindingRef() { - LogDataBindingRef logDataBinding = - LogDataBindingRef.newBuilder().setBindingId("LogData!").build(); - Element defaultElement = Element.newBuilder().setLogDataRef(logDataBinding).build(); - when(mFrameContext.getLogDataFromBinding(logDataBinding)).thenReturn(mLogDataTest); - mAdapter.bindModel(defaultElement, defaultElement, mFrameContext); - - assertThat(mCallbackBound).isTrue(); - } - - @Test - public void bindModel_extractsModelFromElement() { - Element element = Element.getDefaultInstance(); - - mAdapter.bindModel(element, mFrameContext); - - assertThat(mAdapter.getModel()).isEqualTo(TestElementAdapter.DEFAULT_MODEL); - } - - @Test - public void testBindModel_setsActions() { - Actions actions = - Actions.newBuilder().setOnClickAction(Action.getDefaultInstance()).build(); - Element elementWithActions = Element.newBuilder().setActions(actions).build(); - - mAdapter.bindModel(elementWithActions, elementWithActions, mFrameContext); - assertThat(mAdapter.getView().hasOnClickListeners()).isTrue(); - assertThat(mAdapter.mActions).isSameInstanceAs(actions); - } - - @Test - public void bindModel_setsActionsOnBaseView() { - Actions actions = - Actions.newBuilder().setOnClickAction(Action.getDefaultInstance()).build(); - Element elementWithActions = Element.newBuilder().setActions(actions).build(); - when(mStyleProvider.hasBorders()).thenReturn(true); - - mAdapter.createAdapter(elementWithActions, elementWithActions, mFrameContext); - mAdapter.bindModel(elementWithActions, elementWithActions, mFrameContext); - assertThat(mAdapter.getView().hasOnClickListeners()).isFalse(); - assertThat(mAdapter.getBaseView().hasOnClickListeners()).isTrue(); - assertThat(mAdapter.mActions).isSameInstanceAs(actions); - } - - @Test - public void bindModel_setsActionsWithBinding() { - Actions actions = - Actions.newBuilder().setOnClickAction(Action.getDefaultInstance()).build(); - ActionsBindingRef actionsBinding = - ActionsBindingRef.newBuilder().setBindingId("ACTION!").build(); - Element elementWithActions = Element.newBuilder().setActionsBinding(actionsBinding).build(); - when(mFrameContext.getActionsFromBinding(actionsBinding)).thenReturn(actions); - - mAdapter.bindModel(elementWithActions, elementWithActions, mFrameContext); - assertThat(mAdapter.getView().hasOnClickListeners()).isTrue(); - assertThat(mAdapter.mActions).isSameInstanceAs(actions); - } - - @Test - public void bindModel_unsetsActions() { - Actions actions = - Actions.newBuilder().setOnClickAction(Action.getDefaultInstance()).build(); - Element elementWithActions = Element.newBuilder().setActions(actions).build(); - Element elementWithoutActions = Element.getDefaultInstance(); - - mAdapter.bindModel(elementWithActions, elementWithActions, mFrameContext); - assertThat(mAdapter.getView().hasOnClickListeners()).isTrue(); - assertThat(mAdapter.mActions).isSameInstanceAs(actions); - - mAdapter.bindModel(elementWithoutActions, elementWithoutActions, mFrameContext); - assertThat(mAdapter.getView().hasOnClickListeners()).isFalse(); - assertThat(mAdapter.mActions).isSameInstanceAs(Actions.getDefaultInstance()); - } - - @Test - public void bindModel_unsetsActionsOnBaseView() { - Actions actions = - Actions.newBuilder().setOnClickAction(Action.getDefaultInstance()).build(); - Element elementWithActions = Element.newBuilder().setActions(actions).build(); - Element elementWithoutActions = elementWithActions.toBuilder().clearActions().build(); - - when(mStyleProvider.hasBorders()).thenReturn(true); - mAdapter.createAdapter(elementWithActions, elementWithActions, mFrameContext); - mAdapter.bindModel(elementWithActions, elementWithActions, mFrameContext); - assertThat(mAdapter.getView().hasOnClickListeners()).isFalse(); - assertThat(mAdapter.getBaseView().hasOnClickListeners()).isTrue(); - assertThat(mAdapter.mActions).isSameInstanceAs(actions); - - mAdapter.unbindModel(); - - when(mStyleProvider.hasBorders()).thenReturn(false); - mAdapter.bindModel(elementWithoutActions, elementWithoutActions, mFrameContext); - assertThat(mAdapter.getView().hasOnClickListeners()).isFalse(); - assertThat(mAdapter.getBaseView().hasOnClickListeners()).isFalse(); - assertThat(mAdapter.mActions).isSameInstanceAs(Actions.getDefaultInstance()); - } - - @Test - public void testBindModel_setsVisibility() { - Element visibleElement = - Element.newBuilder() - .setVisibilityState(VisibilityState.newBuilder().setDefaultVisibility( - Visibility.VISIBLE)) - .build(); - mAdapter.createAdapter(visibleElement, mFrameContext); - Element invisibleElement = - Element.newBuilder() - .setVisibilityState(VisibilityState.newBuilder().setDefaultVisibility( - Visibility.INVISIBLE)) - .build(); - - mAdapter.bindModel(invisibleElement, mFrameContext); - - assertThat(mAdapter.mTestAdapterBound).isTrue(); - assertThat(mAdapter.getView().getVisibility()).isEqualTo(View.INVISIBLE); - } - - @Test - public void bindModel_doesNothingWhenVisibilityIsGone() { - Element visibleElement = - Element.newBuilder() - .setVisibilityState(VisibilityState.newBuilder().setDefaultVisibility( - Visibility.VISIBLE)) - .build(); - mAdapter.createAdapter(visibleElement, mFrameContext); - Element goneElement = - Element.newBuilder() - .setVisibilityState( - VisibilityState.newBuilder().setDefaultVisibility(Visibility.GONE)) - .build(); - - mAdapter.bindModel(goneElement, mFrameContext); - - assertThat(mAdapter.mTestAdapterBound).isFalse(); - assertThat(mAdapter.getView().getVisibility()).isEqualTo(View.GONE); - } - - @Test - public void bindModel_recreatesWhenVisibilityWasGone() { - Element goneElement = - Element.newBuilder() - .setVisibilityState( - VisibilityState.newBuilder().setDefaultVisibility(Visibility.GONE)) - .build(); - mAdapter.createAdapter(goneElement, mFrameContext); - Element invisibleElement = - Element.newBuilder() - .setVisibilityState(VisibilityState.newBuilder().setDefaultVisibility( - Visibility.INVISIBLE)) - .build(); - - mAdapter.bindModel(invisibleElement, mFrameContext); - - assertThat(mAdapter.mTestAdapterCreated).isTrue(); - assertThat(mAdapter.mTestAdapterBound).isTrue(); - assertThat(mAdapter.getView().getVisibility()).isEqualTo(View.INVISIBLE); - } - - @Test - public void bindModel_recreatesWhenVisibilityWasGone_bound() { - VisibilityBindingRef visibilityBinding = - VisibilityBindingRef.newBuilder().setBindingId("camo").build(); - Element elementWithVisibilityBinding = - Element.newBuilder() - .setVisibilityState( - VisibilityState.newBuilder() - .setDefaultVisibility(Visibility.GONE) - .setOverridingBoundVisibility(visibilityBinding)) - .build(); - - // When adapter is created, the Element is GONE - when(mFrameContext.getVisibilityFromBinding(visibilityBinding)).thenReturn(Visibility.GONE); - - mAdapter.createAdapter(elementWithVisibilityBinding, mFrameContext); - - assertThat(mAdapter.mTestAdapterCreated).isFalse(); - assertThat(mAdapter.getView().getVisibility()).isEqualTo(View.GONE); - - // Now on binding, the Element is VISIBLE - when(mFrameContext.getVisibilityFromBinding(visibilityBinding)) - .thenReturn(Visibility.VISIBLE); - - mAdapter.bindModel(elementWithVisibilityBinding, mFrameContext); - - assertThat(mAdapter.mTestAdapterCreated).isTrue(); - assertThat(mAdapter.mTestAdapterBound).isTrue(); - assertThat(mAdapter.getView().getVisibility()).isEqualTo(View.VISIBLE); - } - - @Test - public void bindModel_doesntRecreateWhenWasCreatedButVisibilityGone() { - // Create a real adapter for a visible element. - Element visibileElement = - Element.newBuilder() - .setVisibilityState(VisibilityState.newBuilder().setDefaultVisibility( - Visibility.VISIBLE)) - .build(); - mAdapter.createAdapter(visibileElement, mFrameContext); - - // Bind a gone element, and unbind it so the visibility is GONE. - Element goneElement = - Element.newBuilder() - .setVisibilityState( - VisibilityState.newBuilder().setDefaultVisibility(Visibility.GONE)) - .build(); - mAdapter.bindModel(goneElement, mFrameContext); - mAdapter.unbindModel(); - - assertThat(mAdapter.mTestAdapterCreated).isTrue(); - mAdapter.mTestAdapterCreated = - false; // set this so we can test that it doesn't get recreated - - // Bind a real element, and ensure that the adapter is not recreated. - Element invisibleElement = - Element.newBuilder() - .setVisibilityState(VisibilityState.newBuilder().setDefaultVisibility( - Visibility.INVISIBLE)) - .build(); - - mAdapter.bindModel(invisibleElement, mFrameContext); - - assertThat(mAdapter.mTestAdapterCreated).isFalse(); - assertThat(mAdapter.mTestAdapterBound).isTrue(); - assertThat(mAdapter.getView().getVisibility()).isEqualTo(View.INVISIBLE); - } - - @Test - public void bindModel_accessibility() { - Element accessibilityElement = - Element.newBuilder() - .setAccessibility( - Accessibility.newBuilder() - .addRoles(AccessibilityRole.HEADER) - .setDescription(ParameterizedText.newBuilder().setText( - "Accessible!"))) - .build(); - - mAdapter.bindModel(accessibilityElement, mFrameContext); - assertThat(mAdapter.getView().getContentDescription().toString()).isEqualTo("Accessible!"); - final AccessibilityNodeInfo nodeInfo = AccessibilityNodeInfo.obtain(); - mAdapter.getView().onInitializeAccessibilityNodeInfo(nodeInfo); - assertThat(nodeInfo.isHeading()).isTrue(); - } - - @Test - public void bindModel_accessibilityBinding() { - ParameterizedTextBindingRef textBinding = - ParameterizedTextBindingRef.newBuilder().setBindingId("binding").build(); - Element accessibilityElement = - Element.newBuilder() - .setAccessibility( - Accessibility.newBuilder().setDescriptionBinding(textBinding)) - .build(); - when(mFrameContext.getParameterizedTextBindingValue(textBinding)) - .thenReturn(BindingValue.newBuilder() - .setParameterizedText( - ParameterizedText.newBuilder().setText("Accessible!")) - .build()); - - mAdapter.bindModel(accessibilityElement, mFrameContext); - - assertThat(mAdapter.getView().getContentDescription().toString()).isEqualTo("Accessible!"); - } - - @Test - public void bindModel_accessibilityReset() { - mAdapter.getView().setContentDescription("OLD CONTENT DESCRIPTION"); - - mAdapter.bindModel(Element.getDefaultInstance(), mFrameContext); - - assertThat(mAdapter.getView().getContentDescription()).isNull(); - } - - @Test - public void unbindModel_callsOnUnbindModel() { - Element defaultElement = Element.getDefaultInstance(); - - mAdapter.createAdapter(defaultElement, defaultElement, mFrameContext); - mAdapter.bindModel(defaultElement, defaultElement, mFrameContext); - assertThat(mAdapter.mTestAdapterBound).isTrue(); - - mAdapter.unbindModel(); - assertThat(mAdapter.mTestAdapterBound).isFalse(); - } - - @Test - public void testUnbindModel_callsOnBindLogDataCallback() { - Element defaultElement = Element.newBuilder().setLogData(mLogDataTest).build(); - - mAdapter.bindModel(defaultElement, defaultElement, mFrameContext); - mAdapter.unbindModel(); - assertThat(mCallbackUnbound).isTrue(); - } - - @Test - public void testUnbindModel_callsOnBindLogDataCallback_bindingRef() { - LogDataBindingRef logDataBinding = - LogDataBindingRef.newBuilder().setBindingId("LogData!").build(); - Element defaultElement = Element.newBuilder().setLogDataRef(logDataBinding).build(); - when(mFrameContext.getLogDataFromBinding(logDataBinding)).thenReturn(mLogDataTest); - - mAdapter.bindModel(defaultElement, defaultElement, mFrameContext); - mAdapter.unbindModel(); - assertThat(mCallbackUnbound).isTrue(); - } - - @Test - public void unbindModel_unsetsModel() { - Element element = Element.getDefaultInstance(); - - mAdapter.createAdapter(element, element, mFrameContext); - mAdapter.bindModel(element, element, mFrameContext); - assertThat(mAdapter.getModel()).isEqualTo(element); - - mAdapter.unbindModel(); - assertThat(mAdapter.getRawModel()).isNull(); - } - - // If onBindModel was never called, onUnbindModel should not be called. - @Test - public void unbindModel_visibilityWasGone() { - Element goneElement = - Element.newBuilder() - .setVisibilityState( - VisibilityState.newBuilder().setDefaultVisibility(Visibility.GONE)) - .build(); - mAdapter.createAdapter(goneElement, mFrameContext); - mAdapter.bindModel(goneElement, mFrameContext); - - assertThat(mAdapter.mTestAdapterCreated).isFalse(); - assertThat(mAdapter.mTestAdapterBound).isFalse(); - - // Set this to something else so we can check if onUnbindModel gets called - it should not. - mAdapter.mTestAdapterBound = true; - - mAdapter.unbindModel(); - - // onUnbindModel was not called so this is still true. - assertThat(mAdapter.mTestAdapterBound).isTrue(); - assertThat(mAdapter.mTestAdapterCreated).isFalse(); - } - - @Test - public void unbindModel_unsetsActions() { - Element elementWithWrapperAndActions = - Element.newBuilder() - .setActions( - Actions.newBuilder().setOnClickAction(Action.getDefaultInstance())) - .build(); - - when(mStyleProvider.hasBorders()).thenReturn(true); - - mAdapter.createAdapter( - elementWithWrapperAndActions, elementWithWrapperAndActions, mFrameContext); - mAdapter.bindModel( - elementWithWrapperAndActions, elementWithWrapperAndActions, mFrameContext); - View adapterView = mAdapter.getBaseView(); - View wrapperView = mAdapter.getView(); - - mAdapter.unbindModel(); - - assertThat(adapterView.hasOnClickListeners()).isFalse(); - assertThat(wrapperView.hasOnClickListeners()).isFalse(); - } - - @Test - public void testUnbindModel_affectsVisibilityCalculations() { - VisibilityBindingRef visibilityBinding = - VisibilityBindingRef.newBuilder().setBindingId("vis").build(); - Element element = Element.newBuilder() - .setVisibilityState( - VisibilityState.newBuilder() - .setDefaultVisibility(Visibility.INVISIBLE) - .setOverridingBoundVisibility(visibilityBinding)) - .build(); - when(mFrameContext.getVisibilityFromBinding(visibilityBinding)) - .thenReturn(Visibility.VISIBLE); - - mAdapter.createAdapter(element, element, mFrameContext); - assertThat(mAdapter.getVisibilityForElement(element, mFrameContext)) - .isEqualTo(Visibility.INVISIBLE); - - mAdapter.bindModel(element, element, mFrameContext); - assertThat(mAdapter.getVisibilityForElement(element, mFrameContext)) - .isEqualTo(Visibility.VISIBLE); - - mAdapter.unbindModel(); - assertThat(mAdapter.getVisibilityForElement(element, mFrameContext)) - .isEqualTo(Visibility.INVISIBLE); - } - - @Test - public void releaseAdapter_callsOnReleaseAdapter() { - Element defaultElement = Element.getDefaultInstance(); - - mAdapter.createAdapter(defaultElement, defaultElement, mFrameContext); - assertThat(mAdapter.mTestAdapterCreated).isTrue(); - - mAdapter.releaseAdapter(); - assertThat(mAdapter.mTestAdapterCreated).isFalse(); - } - - @Test - public void testReleaseAdapter_resetsVisibility() { - Element defaultElement = Element.getDefaultInstance(); - - mAdapter.createAdapter(defaultElement, defaultElement, mFrameContext); - mAdapter.setVisibilityOnView(Visibility.INVISIBLE); - assertThat(mAdapter.getBaseView().getVisibility()).isEqualTo(View.INVISIBLE); - - mAdapter.releaseAdapter(); - assertThat(mAdapter.getBaseView().getVisibility()).isEqualTo(View.VISIBLE); - } - - @Test - public void releaseAdapter_resetsDimensions() { - Element defaultElement = Element.getDefaultInstance(); - - mAdapter.createAdapter(defaultElement, defaultElement, mFrameContext); - mAdapter.setDims(123, 456); - - mAdapter.releaseAdapter(); - - assertThat(mAdapter.getComputedWidthPx()).isEqualTo(DIMENSION_NOT_SET); - assertThat(mAdapter.getComputedHeightPx()).isEqualTo(DIMENSION_NOT_SET); - } - - @Test - public void setVisibility() { - mAdapter.createAdapter( - Element.getDefaultInstance(), Element.getDefaultInstance(), mFrameContext); - mAdapter.getBaseView().setVisibility(View.GONE); - mAdapter.setVisibilityOnView(Visibility.VISIBLE); - assertThat(mAdapter.getBaseView().getVisibility()).isEqualTo(View.VISIBLE); - mAdapter.setVisibilityOnView(Visibility.INVISIBLE); - assertThat(mAdapter.getBaseView().getVisibility()).isEqualTo(View.INVISIBLE); - mAdapter.setVisibilityOnView(Visibility.GONE); - assertThat(mAdapter.getBaseView().getVisibility()).isEqualTo(View.GONE); - mAdapter.setVisibilityOnView(Visibility.VISIBILITY_UNSPECIFIED); - assertThat(mAdapter.getBaseView().getVisibility()).isEqualTo(View.VISIBLE); - } - - @Test - public void getVisibilityForElement() { - VisibilityBindingRef bindingRef = - VisibilityBindingRef.newBuilder().setBindingId("binding").build(); - Element elementWithDefaultVisibility = - Element.newBuilder() - .setVisibilityState(VisibilityState.newBuilder().setDefaultVisibility( - Visibility.INVISIBLE)) - .build(); - Element elementWithVisibilityOverride = - Element.newBuilder() - .setVisibilityState(VisibilityState.newBuilder() - .setDefaultVisibility(Visibility.INVISIBLE) - .setOverridingBoundVisibility(bindingRef)) - .build(); - - // Default visibility; no override - assertThat(mAdapter.getVisibilityForElement(elementWithDefaultVisibility, mFrameContext)) - .isEqualTo(Visibility.INVISIBLE); - - // Don't look up override when not binding - when(mFrameContext.getVisibilityFromBinding(bindingRef)).thenReturn(Visibility.GONE); - assertThat(mAdapter.getVisibilityForElement(elementWithVisibilityOverride, mFrameContext)) - .isEqualTo(Visibility.INVISIBLE); - - mAdapter.bindModel(Element.getDefaultInstance(), mFrameContext); - - // Look up override successfully - when(mFrameContext.getVisibilityFromBinding(bindingRef)).thenReturn(Visibility.GONE); - assertThat(mAdapter.getVisibilityForElement(elementWithVisibilityOverride, mFrameContext)) - .isEqualTo(Visibility.GONE); - - // Override not found; use default - when(mFrameContext.getVisibilityFromBinding(bindingRef)).thenReturn(null); - assertThat(mAdapter.getVisibilityForElement(elementWithVisibilityOverride, mFrameContext)) - .isEqualTo(Visibility.INVISIBLE); - } - - @Config(shadows = {ExtendedShadowView.class}) - @Test - public void getOnFullViewActions() { - Frame frame = Frame.newBuilder().setTag("FRAME").build(); - when(mFrameContext.getFrame()).thenReturn(frame); - View viewport = new View(mContext); - - // No actions defined - mAdapter.createAdapter(Element.getDefaultInstance(), mFrameContext); - mAdapter.bindModel(Element.getDefaultInstance(), mFrameContext); - mAdapter.triggerViewActions(viewport, mFrameContext); - verifyZeroInteractions(mActionHandler); - mAdapter.releaseAdapter(); - - // Actions defined, but not fullview actions - Element elementWithNoViewActions = - Element.newBuilder() - .setActions( - Actions.newBuilder().setOnClickAction(Action.newBuilder().build())) - .build(); - mAdapter.createAdapter(elementWithNoViewActions, mFrameContext); - mAdapter.bindModel(elementWithNoViewActions, mFrameContext); - mAdapter.triggerViewActions(viewport, mFrameContext); - verifyZeroInteractions(mActionHandler); - mAdapter.unbindModel(); - mAdapter.releaseAdapter(); - - // Actions defined, but not fully visible - ExtendedShadowView viewShadow = Shadow.extract(mAdapter.getView()); - viewShadow.setAttachedToWindow(false); - Actions fullViewActions = Actions.newBuilder() - .addOnViewActions(VisibilityAction.newBuilder().setAction( - Action.newBuilder().build())) - .build(); - Element elementWithActions = Element.newBuilder().setActions(fullViewActions).build(); - mAdapter.createAdapter(elementWithActions, mFrameContext); - mAdapter.bindModel(elementWithActions, mFrameContext); - mAdapter.triggerViewActions(viewport, mFrameContext); - verifyZeroInteractions(mActionHandler); - mAdapter.unbindModel(); - mAdapter.releaseAdapter(); - - // Actions defined, and fully visible - ExtendedShadowView viewportShadow = Shadow.extract(viewport); - viewportShadow.setLocationInWindow(0, 0); - viewportShadow.setHeight(100); - viewportShadow.setWidth(100); - viewShadow.setLocationInWindow(10, 10); - viewShadow.setHeight(50); - viewShadow.setWidth(50); - viewShadow.setAttachedToWindow(true); - - mAdapter.createAdapter(elementWithActions, mFrameContext); - mAdapter.bindModel(elementWithActions, mFrameContext); - mAdapter.triggerViewActions(viewport, mFrameContext); - verify(mActionHandler) - .handleAction(same(fullViewActions.getOnViewActions(0).getAction()), - eq(ActionType.VIEW), eq(frame), eq(mView), - eq(LogData.getDefaultInstance())); - } - - @Config(shadows = {ExtendedShadowView.class}) - @Test - public void getOnPartialViewActions() { - Frame frame = Frame.newBuilder().setTag("FRAME").build(); - when(mFrameContext.getFrame()).thenReturn(frame); - View viewport = new View(mContext); - - // No actions defined - mAdapter.createAdapter(Element.getDefaultInstance(), mFrameContext); - mAdapter.bindModel(Element.getDefaultInstance(), mFrameContext); - mAdapter.triggerViewActions(viewport, mFrameContext); - verifyZeroInteractions(mActionHandler); - mAdapter.releaseAdapter(); - - // Actions defined, but not partial view actions - Element elementWithNoViewActions = - Element.newBuilder() - .setActions( - Actions.newBuilder().setOnClickAction(Action.newBuilder().build())) - .build(); - mAdapter.createAdapter(elementWithNoViewActions, mFrameContext); - mAdapter.bindModel(elementWithNoViewActions, mFrameContext); - mAdapter.triggerViewActions(viewport, mFrameContext); - verifyZeroInteractions(mActionHandler); - mAdapter.unbindModel(); - mAdapter.releaseAdapter(); - - // Actions defined, but not attached to window - ExtendedShadowView viewShadow = Shadow.extract(mAdapter.getView()); - viewShadow.setAttachedToWindow(false); - Actions partialViewActions = - Actions.newBuilder() - .addOnViewActions(VisibilityAction.newBuilder() - .setAction(Action.newBuilder().build()) - .setProportionVisible(0.01f)) - .build(); - Element elementWithActions = Element.newBuilder().setActions(partialViewActions).build(); - mAdapter.createAdapter(elementWithActions, mFrameContext); - mAdapter.bindModel(elementWithActions, mFrameContext); - mAdapter.triggerViewActions(viewport, mFrameContext); - verifyZeroInteractions(mActionHandler); - mAdapter.unbindModel(); - mAdapter.releaseAdapter(); - - // Actions defined, and partially visible - ExtendedShadowView viewportShadow = Shadow.extract(viewport); - viewportShadow.setLocationInWindow(0, 0); - viewportShadow.setHeight(100); - viewportShadow.setWidth(100); - viewShadow.setLocationInWindow(10, 10); - viewShadow.setHeight(200); - viewShadow.setWidth(200); - viewShadow.setAttachedToWindow(true); - - mAdapter.createAdapter(elementWithActions, mFrameContext); - mAdapter.bindModel(elementWithActions, mFrameContext); - mAdapter.triggerViewActions(viewport, mFrameContext); - verify(mActionHandler) - .handleAction(same(partialViewActions.getOnViewActions(0).getAction()), - eq(ActionType.VIEW), eq(frame), eq(mView), - eq(LogData.getDefaultInstance())); - - // Actions defined, and fully visible - viewShadow.setHeight(50); - viewShadow.setWidth(50); - - mAdapter.createAdapter(elementWithActions, mFrameContext); - mAdapter.bindModel(elementWithActions, mFrameContext); - mAdapter.triggerViewActions(viewport, mFrameContext); - verify(mActionHandler, times(2)) - .handleAction(same(partialViewActions.getOnViewActions(0).getAction()), - eq(ActionType.VIEW), eq(frame), eq(mView), - eq(LogData.getDefaultInstance())); - } - - @Config(shadows = {ExtendedShadowView.class}) - @Test - public void triggerHideActions() { - Frame frame = Frame.newBuilder().setTag("FRAME").build(); - when(mFrameContext.getFrame()).thenReturn(frame); - View viewport = new View(mContext); - - // No actions defined - mAdapter.createAdapter(Element.getDefaultInstance(), mFrameContext); - mAdapter.bindModel(Element.getDefaultInstance(), mFrameContext); - mAdapter.triggerHideActions(mFrameContext); - verifyZeroInteractions(mActionHandler); - mAdapter.releaseAdapter(); - - // Actions defined, but not hide actions - Element elementWithNoViewActions = - Element.newBuilder() - .setActions( - Actions.newBuilder().setOnClickAction(Action.getDefaultInstance())) - .build(); - mAdapter.createAdapter(elementWithNoViewActions, mFrameContext); - mAdapter.bindModel(elementWithNoViewActions, mFrameContext); - mAdapter.triggerHideActions(mFrameContext); - verifyZeroInteractions(mActionHandler); - mAdapter.unbindModel(); - mAdapter.releaseAdapter(); - - // Trigger hide actions on the fully-visible view to make hide actions not active. - Action hideAction = Action.newBuilder().build(); - Actions hideActions = - Actions.newBuilder() - .addOnHideActions(VisibilityAction.newBuilder().setAction(hideAction)) - .build(); - Element elementWithActions = Element.newBuilder().setActions(hideActions).build(); - ExtendedShadowView viewShadow = Shadow.extract(mAdapter.getView()); - ExtendedShadowView viewportShadow = Shadow.extract(viewport); - viewportShadow.setLocationInWindow(0, 0); - viewportShadow.setHeight(100); - viewportShadow.setWidth(100); - viewShadow.setLocationInWindow(10, 10); - viewShadow.setHeight(50); - viewShadow.setWidth(50); - viewShadow.setAttachedToWindow(true); - - mAdapter.createAdapter(elementWithActions, mFrameContext); - mAdapter.bindModel(elementWithActions, mFrameContext); - mAdapter.triggerViewActions(viewport, mFrameContext); - verifyZeroInteractions(mActionHandler); - - // Trigger hide actions - mAdapter.triggerHideActions(mFrameContext); - - verify(mActionHandler) - .handleAction(same(hideAction), eq(ActionType.VIEW), eq(frame), eq(mView), - eq(LogData.getDefaultInstance())); - - // Ensure actions do not trigger again - mAdapter.triggerHideActions(mFrameContext); - - verify(mActionHandler) // Only once, not twice - .handleAction(same(hideAction), eq(ActionType.VIEW), eq(frame), eq(mView), - eq(LogData.getDefaultInstance())); - } - - @Test - public void createRoundedCorners() { - RoundedCorners roundedCorners = RoundedCorners.newBuilder().setRadiusDp(10).build(); - RoundedCornerWrapperView roundedCornerWrapperView = new RoundedCornerWrapperView(mContext, - roundedCorners, mMaskCache, Suppliers.of(false), - /*radiusOverride= */ 0, Borders.getDefaultInstance(), LEGACY_CORNERS_FLAG, - OUTLINE_CORNERS_FLAG); - when(mStyleProvider.hasRoundedCorners()).thenReturn(true); - when(mStyleProvider.createWrapperView( - mContext, mMaskCache, LEGACY_CORNERS_FLAG, OUTLINE_CORNERS_FLAG)) - .thenReturn(roundedCornerWrapperView); - - mAdapter.createAdapter(Element.getDefaultInstance(), mFrameContext); - - assertThat(mAdapter.getView()).isSameInstanceAs(roundedCornerWrapperView); - } - - @Test - public void setVisibilityWithRoundedCorners() { - RoundedCorners roundedCorners = RoundedCorners.newBuilder().setRadiusDp(10).build(); - RoundedCornerWrapperView roundedCornerWrapperView = new RoundedCornerWrapperView(mContext, - roundedCorners, mMaskCache, Suppliers.of(false), - /*radiusOverride= */ 0, Borders.getDefaultInstance(), LEGACY_CORNERS_FLAG, - OUTLINE_CORNERS_FLAG); - when(mStyleProvider.hasRoundedCorners()).thenReturn(true); - when(mStyleProvider.createWrapperView( - mContext, mMaskCache, LEGACY_CORNERS_FLAG, OUTLINE_CORNERS_FLAG)) - .thenReturn(roundedCornerWrapperView); - - VisibilityBindingRef visibilityBinding = - VisibilityBindingRef.newBuilder().setBindingId("visibility").build(); - when(mFrameContext.getVisibilityFromBinding(visibilityBinding)) - .thenReturn(Visibility.VISIBLE); - - Element element = Element.newBuilder() - .setVisibilityState( - VisibilityState.newBuilder() - .setDefaultVisibility(Visibility.GONE) - .setOverridingBoundVisibility(visibilityBinding)) - .build(); - - mAdapter.createAdapter(element, mFrameContext); - - FrameLayout parentView = new FrameLayout(mContext); - parentView.addView(mAdapter.getView()); - - mAdapter.bindModel(element, mFrameContext); - - assertThat(mAdapter.getView()).isSameInstanceAs(roundedCornerWrapperView); - assertThat(mAdapter.getView().getVisibility()).isEqualTo(View.VISIBLE); - - // Try setting visibility back to GONE and ensure that RCWV is GONE - when(mFrameContext.getVisibilityFromBinding(visibilityBinding)).thenReturn(Visibility.GONE); - mAdapter.unbindModel(); - mAdapter.bindModel(element, mFrameContext); - assertThat(mAdapter.getView()).isSameInstanceAs(roundedCornerWrapperView); - assertThat(mAdapter.getView().getVisibility()).isEqualTo(View.GONE); - } - - @Test - public void getStyleIdsStack() { - StyleIdsStack style = StyleIdsStack.newBuilder().addStyleIds("style").build(); - Element elementWithStyle = Element.newBuilder().setStyleReferences(style).build(); - - mAdapter.createAdapter(elementWithStyle, mFrameContext); - - assertThat(mAdapter.getElementStyleIdsStack()).isSameInstanceAs(style); - - Element elementWithNoStyle = Element.getDefaultInstance(); - - mAdapter.createAdapter(elementWithNoStyle, mFrameContext); - - assertThat(mAdapter.getElementStyleIdsStack()) - .isEqualTo(StyleIdsStack.getDefaultInstance()); - } - - // Dummy implementation - static class TestElementAdapter extends ElementAdapter<View, Object> { - static final String DEFAULT_MODEL = "MODEL"; - - boolean mTestAdapterCreated; - boolean mTestAdapterBound; - - View mAdapterView; - - TestElementAdapter(Context context, AdapterParameters parameters, View adapterView) { - super(context, parameters, adapterView); - this.mAdapterView = adapterView; - } - - @Override - protected Object getModelFromElement(Element baseElement) { - return DEFAULT_MODEL; - } - - @Override - protected void onCreateAdapter( - Object model, Element baseElement, FrameContext frameContext) { - mTestAdapterCreated = true; - } - - @Override - protected void onBindModel(Object model, Element baseElement, FrameContext frameContext) { - mTestAdapterBound = true; - } - - @Override - protected void onUnbindModel() { - mTestAdapterBound = false; - } - - @Override - protected void onReleaseAdapter() { - mTestAdapterCreated = false; - } - - public void setDims(int width, int height) { - mWidthPx = width; - mHeightPx = height; - } - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ElementContainerAdapterTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ElementContainerAdapterTest.java deleted file mode 100644 index ced051f..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ElementContainerAdapterTest.java +++ /dev/null
@@ -1,648 +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. - -package org.chromium.chrome.browser.feed.library.piet; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import static org.chromium.chrome.browser.feed.library.common.testing.RunnableSubject.assertThatRunnable; - -import android.app.Activity; -import android.content.Context; -import android.view.View; -import android.widget.LinearLayout; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.common.functional.Suppliers; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.piet.host.AssetProvider; -import org.chromium.components.feed.core.proto.ui.piet.BindingRefsProto.ElementBindingRef; -import org.chromium.components.feed.core.proto.ui.piet.BindingRefsProto.TemplateBindingRef; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.BindingContext; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.BindingValue; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.Content; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.Element; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.ElementList; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.GridRow; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.ImageElement; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.TemplateInvocation; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.TextElement; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.Visibility; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.VisibilityState; -import org.chromium.components.feed.core.proto.ui.piet.ImagesProto.Image; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.Template; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.StyleIdsStack; -import org.chromium.components.feed.core.proto.ui.piet.TextProto.ParameterizedText; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** Tests of the {@link ElementContainerAdapter}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ElementContainerAdapterTest { - private static final Element DUMMY_BASE_ELEMENT = Element.getDefaultInstance(); - private static final Element DEFAULT_ELEMENT = - Element.newBuilder().setElementList(ElementList.newBuilder().build()).build(); - - private static final Element DEFAULT_BOUND_ELEMENT = - Element.newBuilder().setGridRow(GridRow.getDefaultInstance()).build(); - private static final String DEFAULT_ELEMENT_BINDING_ID = "bound-grid-element"; - private static final ElementBindingRef DEFAULT_ELEMENT_BINDING = - ElementBindingRef.newBuilder().setBindingId(DEFAULT_ELEMENT_BINDING_ID).build(); - private static final BindingValue DEFAULT_ELEMENT_BINDING_VALUE = - BindingValue.newBuilder() - .setBindingId(DEFAULT_ELEMENT_BINDING_ID) - .setElement(DEFAULT_BOUND_ELEMENT) - .build(); - - private static final String DEFAULT_TEMPLATE_ID = "inline-text-template"; - private static final Template DEFAULT_TEMPLATE = - Template.newBuilder() - .setTemplateId(DEFAULT_TEMPLATE_ID) - .setElement(Element.newBuilder().setTextElement( - TextElement.newBuilder().setParameterizedText( - ParameterizedText.getDefaultInstance()))) - .build(); - private static final TemplateInvocation DEFAULT_TEMPLATE_INVOCATION = - TemplateInvocation.newBuilder() - .setTemplateId(DEFAULT_TEMPLATE_ID) - .addBindingContexts(BindingContext.newBuilder().addBindingValues( - BindingValue.newBuilder().setBindingId("T1"))) - .addBindingContexts(BindingContext.newBuilder().addBindingValues( - BindingValue.newBuilder().setBindingId("T2"))) - .build(); - - private static final String DEFAULT_BOUND_TEMPLATE_ID = "bound-image-template"; - private static final Template DEFAULT_BOUND_TEMPLATE = - Template.newBuilder() - .setTemplateId(DEFAULT_BOUND_TEMPLATE_ID) - .setElement(Element.newBuilder().setImageElement( - ImageElement.newBuilder().setImage(Image.getDefaultInstance()))) - .build(); - private static final TemplateInvocation DEFAULT_BOUND_TEMPLATE_INVOCATION = - TemplateInvocation.newBuilder() - .setTemplateId(DEFAULT_BOUND_TEMPLATE_ID) - .addBindingContexts(BindingContext.newBuilder().addBindingValues( - BindingValue.newBuilder().setBindingId("BT1"))) - .addBindingContexts(BindingContext.newBuilder().addBindingValues( - BindingValue.newBuilder().setBindingId("BT2"))) - .addBindingContexts(BindingContext.newBuilder().addBindingValues( - BindingValue.newBuilder().setBindingId("BT3"))) - .build(); - private static final String DEFAULT_TEMPLATE_BINDING_ID = "bind-the-bound-image-template"; - private static final TemplateBindingRef DEFAULT_TEMPLATE_BINDING = - TemplateBindingRef.newBuilder().setBindingId(DEFAULT_TEMPLATE_BINDING_ID).build(); - private static final BindingValue TEMPLATE_BINDING_VALUE = - BindingValue.newBuilder() - .setBindingId(DEFAULT_TEMPLATE_BINDING_ID) - .setTemplateInvocation(DEFAULT_BOUND_TEMPLATE_INVOCATION) - .build(); - - @Mock - private FrameContext mFrameContext; - @Mock - private HostProviders mHostProviders; - @Mock - private AssetProvider mAssetProvider; - - private Context mContext; - - private TestElementContainerAdapter mAdapter; - - @Before - public void setUp() { - initMocks(this); - mContext = Robolectric.buildActivity(Activity.class).get(); - - when(mHostProviders.getAssetProvider()).thenReturn(mAssetProvider); - AdapterParameters adapterParameters = new AdapterParameters( - mContext, Suppliers.of(null), mHostProviders, new FakeClock(), false, false); - - when(mFrameContext.createTemplateContext(eq(DEFAULT_TEMPLATE), any(BindingContext.class))) - .thenReturn(mFrameContext); - when(mFrameContext.createTemplateContext( - eq(DEFAULT_BOUND_TEMPLATE), any(BindingContext.class))) - .thenReturn(mFrameContext); - when(mFrameContext.makeStyleFor(any(StyleIdsStack.class))) - .thenReturn(adapterParameters.mDefaultStyleProvider); - when(mFrameContext.filterImageSourcesByMediaQueryCondition(any(Image.class))) - .thenAnswer(invocation -> invocation.getArguments()[0]); - - // Default no-errors behavior - when(mFrameContext.getTemplateInvocationBindingValue(DEFAULT_TEMPLATE_BINDING)) - .thenReturn(TEMPLATE_BINDING_VALUE); - when(mFrameContext.getTemplate(DEFAULT_TEMPLATE_ID)).thenReturn(DEFAULT_TEMPLATE); - when(mFrameContext.getTemplate(DEFAULT_BOUND_TEMPLATE_ID)) - .thenReturn(DEFAULT_BOUND_TEMPLATE); - when(mFrameContext.getElementBindingValue(DEFAULT_ELEMENT_BINDING)) - .thenReturn(DEFAULT_ELEMENT_BINDING_VALUE); - - LinearLayout view = new LinearLayout(mContext); - - mAdapter = new TestElementContainerAdapter(mContext, adapterParameters, view); - } - - @Test - public void testCreateChildAdapters_elementCreatesOneAdapter() { - mAdapter.createAdapter( - Collections.singletonList(Content.newBuilder().setElement(DEFAULT_ELEMENT).build()), - DUMMY_BASE_ELEMENT, mFrameContext); - - // A single adapter created from the Element. - assertThat(mAdapter.mChildAdapters).hasSize(1); - assertThat(mAdapter.mChildAdapters.get(0)).isInstanceOf(ElementListAdapter.class); - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(1); - assertThat(mAdapter.getBaseView().getChildAt(0)) - .isSameInstanceAs(mAdapter.mChildAdapters.get(0).getView()); - assertThat(mAdapter.mAdaptersPerContent).isEqualTo(new int[] {1}); - } - - @Test - public void testCreateChildAdapters_templateCreatesMultipleAdapters() { - mAdapter.createAdapter(Collections.singletonList( - Content.newBuilder() - .setTemplateInvocation(DEFAULT_TEMPLATE_INVOCATION) - .build()), - DUMMY_BASE_ELEMENT, mFrameContext); - - // One TemplateInstanceAdapter for each BindingContext in the TemplateInvocation. - assertThat(DEFAULT_TEMPLATE_INVOCATION.getBindingContextsCount()).isEqualTo(2); - assertThat(mAdapter.mChildAdapters).hasSize(2); - assertThat(mAdapter.mChildAdapters.get(0)).isInstanceOf(TextElementAdapter.class); - assertThat(mAdapter.mChildAdapters.get(1)).isInstanceOf(TextElementAdapter.class); - verify(mFrameContext) - .createTemplateContext( - DEFAULT_TEMPLATE, DEFAULT_TEMPLATE_INVOCATION.getBindingContexts(0)); - verify(mFrameContext) - .createTemplateContext( - DEFAULT_TEMPLATE, DEFAULT_TEMPLATE_INVOCATION.getBindingContexts(1)); - - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(2); - assertThat(mAdapter.getBaseView().getChildAt(0)) - .isSameInstanceAs(mAdapter.mChildAdapters.get(0).getView()); - assertThat(mAdapter.getBaseView().getChildAt(1)) - .isSameInstanceAs(mAdapter.mChildAdapters.get(1).getView()); - assertThat(mAdapter.mAdaptersPerContent).isEqualTo(new int[] {2}); - } - - @Test - public void testCreateChildAdapters_templateNotFound() { - when(mFrameContext.getTemplate(DEFAULT_TEMPLATE_ID)).thenReturn(null); - - mAdapter.createAdapter(Collections.singletonList( - Content.newBuilder() - .setTemplateInvocation(DEFAULT_TEMPLATE_INVOCATION) - .build()), - DUMMY_BASE_ELEMENT, mFrameContext); - - // No child adapters are created. - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(0); - assertThat(mAdapter.mChildAdapters).isEmpty(); - assertThat(mAdapter.mAdaptersPerContent).isEqualTo(new int[] {0}); - } - - @Test - public void testCreateChildAdapters_boundElement_doesNothing() { - mAdapter.createAdapter( - Collections.singletonList( - Content.newBuilder().setBoundElement(DEFAULT_ELEMENT_BINDING).build()), - DUMMY_BASE_ELEMENT, mFrameContext); - - // No child adapters are created. - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(0); - assertThat(mAdapter.mChildAdapters).isEmpty(); - assertThat(mAdapter.mAdaptersPerContent).isEqualTo(new int[] {0}); - } - - @Test - public void testCreateChildAdapters_boundElementNotFound_doesNothing() { - when(mFrameContext.getElementBindingValue(DEFAULT_ELEMENT_BINDING)) - .thenReturn(BindingValue.getDefaultInstance()); - - mAdapter.createAdapter( - Collections.singletonList( - Content.newBuilder().setBoundElement(DEFAULT_ELEMENT_BINDING).build()), - DUMMY_BASE_ELEMENT, mFrameContext); - - // No child adapters are created. - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(0); - assertThat(mAdapter.mChildAdapters).isEmpty(); - assertThat(mAdapter.mAdaptersPerContent).isEqualTo(new int[] {0}); - } - - @Test - public void testCreateChildAdapters_boundTemplate_doesNothing() { - mAdapter.createAdapter( - Collections.singletonList( - Content.newBuilder().setTemplateBinding(DEFAULT_TEMPLATE_BINDING).build()), - DUMMY_BASE_ELEMENT, mFrameContext); - - // No child adapters are created. - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(0); - assertThat(mAdapter.mChildAdapters).isEmpty(); - assertThat(mAdapter.mAdaptersPerContent).isEqualTo(new int[] {0}); - } - - @Test - public void testCreateChildAdapters_boundTemplateNotFound_doesNothing() { - when(mFrameContext.getTemplateInvocationBindingValue(DEFAULT_TEMPLATE_BINDING)) - .thenReturn(BindingValue.getDefaultInstance()); - - mAdapter.createAdapter( - Collections.singletonList( - Content.newBuilder().setTemplateBinding(DEFAULT_TEMPLATE_BINDING).build()), - DUMMY_BASE_ELEMENT, mFrameContext); - - // No child adapters are created. - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(0); - assertThat(mAdapter.mChildAdapters).isEmpty(); - assertThat(mAdapter.mAdaptersPerContent).isEqualTo(new int[] {0}); - } - - @Test - public void testCreateChildAdapters_boundTemplateBetweenInlineContents() { - List<Content> contents = new ArrayList<>(); - contents.add( - Content.newBuilder().setTemplateInvocation(DEFAULT_TEMPLATE_INVOCATION).build()); - contents.add(Content.newBuilder().setTemplateBinding(DEFAULT_TEMPLATE_BINDING).build()); - contents.add(Content.newBuilder().setElement(DEFAULT_ELEMENT).build()); - - mAdapter.createAdapter(contents, DUMMY_BASE_ELEMENT, mFrameContext); - - // Adapters created: 2 templates, (nothing for the binding), 1 element list - assertThat(mAdapter.mChildAdapters).hasSize(3); - assertThat(mAdapter.mChildAdapters.get(0)).isInstanceOf(TextElementAdapter.class); - assertThat(mAdapter.mChildAdapters.get(1)).isInstanceOf(TextElementAdapter.class); - - assertThat(mAdapter.mChildAdapters.get(2)).isInstanceOf(ElementListAdapter.class); - - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(3); - for (int i = 0; i < 3; i++) { - assertThat(mAdapter.getBaseView().getChildAt(i)) - .isSameInstanceAs(mAdapter.mChildAdapters.get(i).getView()); - } - - assertThat(mAdapter.mAdaptersPerContent).isEqualTo(new int[] {2, 0, 1}); - } - - @Test - public void testCreateChildAdapters_failsIfAdapterNotReleased() { - mAdapter.createAdapter( - Collections.singletonList(Content.newBuilder().setElement(DEFAULT_ELEMENT).build()), - DUMMY_BASE_ELEMENT, mFrameContext); - - assertThatRunnable( - () - -> mAdapter.createAdapter( - Collections.singletonList( - Content.newBuilder().setElement(DEFAULT_ELEMENT).build()), - DUMMY_BASE_ELEMENT, mFrameContext)) - .throwsAnExceptionOfType(IllegalStateException.class) - .that() - .hasMessageThat() - .contains("release adapter before creating"); - } - - @Test - public void testBindChildAdapters_createsAdapterIfNotAlreadyCreated() { - mAdapter.bindModel( - Collections.singletonList(Content.newBuilder().setElement(DEFAULT_ELEMENT).build()), - DUMMY_BASE_ELEMENT, mFrameContext); - - assertThat(mAdapter.mChildAdapters).hasSize(1); - assertThat(mAdapter.mChildAdapters.get(0)).isInstanceOf(ElementListAdapter.class); - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(1); - } - - @Test - public void testBindChildAdapters_element() { - List<Content> contents = - Collections.singletonList(Content.newBuilder().setElement(DEFAULT_ELEMENT).build()); - mAdapter.createAdapter(contents, DUMMY_BASE_ELEMENT, mFrameContext); - ElementAdapter<? extends View, ?> mockChildAdapter = mock(ElementListAdapter.class); - mAdapter.mChildAdapters.set(0, mockChildAdapter); - - mAdapter.bindModel(contents, DUMMY_BASE_ELEMENT, mFrameContext); - - verify(mockChildAdapter).bindModel(DEFAULT_ELEMENT, mFrameContext); - } - - @Test - public void testBindChildAdapters_template() { - List<Content> contents = Collections.singletonList( - Content.newBuilder().setTemplateInvocation(DEFAULT_TEMPLATE_INVOCATION).build()); - mAdapter.createAdapter(contents, DUMMY_BASE_ELEMENT, mFrameContext); - RecyclerKey key1 = mAdapter.mChildAdapters.get(0).getKey(); - RecyclerKey key2 = mAdapter.mChildAdapters.get(1).getKey(); - TextElementAdapter mockChildAdapter1 = mock(TextElementAdapter.class); - TextElementAdapter mockChildAdapter2 = mock(TextElementAdapter.class); - when(mockChildAdapter1.getKey()).thenReturn(key1); - when(mockChildAdapter2.getKey()).thenReturn(key2); - mAdapter.mChildAdapters.set(0, mockChildAdapter1); - mAdapter.mChildAdapters.set(1, mockChildAdapter2); - - FrameContext templateContext1 = mock(FrameContext.class); - FrameContext templateContext2 = mock(FrameContext.class); - when(mFrameContext.createTemplateContext( - DEFAULT_TEMPLATE, DEFAULT_TEMPLATE_INVOCATION.getBindingContexts(0))) - .thenReturn(templateContext1); - when(mFrameContext.createTemplateContext( - DEFAULT_TEMPLATE, DEFAULT_TEMPLATE_INVOCATION.getBindingContexts(1))) - .thenReturn(templateContext2); - - mAdapter.bindModel(contents, DUMMY_BASE_ELEMENT, mFrameContext); - - verify(mockChildAdapter1).bindModel(DEFAULT_TEMPLATE.getElement(), templateContext1); - verify(mockChildAdapter2).bindModel(DEFAULT_TEMPLATE.getElement(), templateContext2); - } - - @Test - public void testBindChildAdapters_templateNotFound() { - when(mFrameContext.getTemplate(DEFAULT_TEMPLATE_ID)).thenReturn(null); - - List<Content> contents = Collections.singletonList( - Content.newBuilder().setTemplateInvocation(DEFAULT_TEMPLATE_INVOCATION).build()); - mAdapter.createAdapter(contents, DUMMY_BASE_ELEMENT, mFrameContext); - - mAdapter.bindModel(contents, DUMMY_BASE_ELEMENT, mFrameContext); - - // No child adapters are created; binding does nothing. - assertThat(mAdapter.mChildAdapters).isEmpty(); - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(0); - assertThat(mAdapter.mAdaptersPerContent).isEqualTo(new int[] {0}); - } - - @Test - public void testBindChildAdapters_boundElement() { - List<Content> contents = Collections.singletonList( - Content.newBuilder().setBoundElement(DEFAULT_ELEMENT_BINDING).build()); - mAdapter.createAdapter(contents, DUMMY_BASE_ELEMENT, mFrameContext); - - mAdapter.bindModel(contents, DUMMY_BASE_ELEMENT, mFrameContext); - - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(1); - assertThat(mAdapter.getBaseView().getChildAt(0)) - .isSameInstanceAs(mAdapter.mChildAdapters.get(0).getView()); - - assertThat(mAdapter.mAdaptersPerContent).isEqualTo(new int[] {1}); - } - - @Test - public void testBindChildAdapters_boundTemplate() { - List<Content> contents = Collections.singletonList( - Content.newBuilder().setTemplateBinding(DEFAULT_TEMPLATE_BINDING).build()); - mAdapter.createAdapter(contents, DUMMY_BASE_ELEMENT, mFrameContext); - - mAdapter.bindModel(contents, DUMMY_BASE_ELEMENT, mFrameContext); - - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(3); - assertThat(mAdapter.getBaseView().getChildAt(0)) - .isSameInstanceAs(mAdapter.mChildAdapters.get(0).getView()); - assertThat(mAdapter.getBaseView().getChildAt(1)) - .isSameInstanceAs(mAdapter.mChildAdapters.get(1).getView()); - assertThat(mAdapter.getBaseView().getChildAt(2)) - .isSameInstanceAs(mAdapter.mChildAdapters.get(2).getView()); - - assertThat(mAdapter.mAdaptersPerContent).isEqualTo(new int[] {3}); - } - - @Test - public void testBindChildAdapters_boundTemplateNotFound_doesNothing() { - when(mFrameContext.getTemplate(DEFAULT_BOUND_TEMPLATE_ID)).thenReturn(null); - - List<Content> contents = Collections.singletonList( - Content.newBuilder().setTemplateBinding(DEFAULT_TEMPLATE_BINDING).build()); - mAdapter.createAdapter(contents, DUMMY_BASE_ELEMENT, mFrameContext); - - mAdapter.bindModel(contents, DUMMY_BASE_ELEMENT, mFrameContext); - - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(0); - assertThat(mAdapter.mAdaptersPerContent).isEqualTo(new int[] {0}); - } - - @Test - public void testBindChildAdapters_boundTemplateBindingNotFound_doesNothing() { - when(mFrameContext.getTemplateInvocationBindingValue(DEFAULT_TEMPLATE_BINDING)) - .thenReturn(BindingValue.getDefaultInstance()); - - List<Content> contents = Collections.singletonList( - Content.newBuilder().setTemplateBinding(DEFAULT_TEMPLATE_BINDING).build()); - mAdapter.createAdapter(contents, DUMMY_BASE_ELEMENT, mFrameContext); - - mAdapter.bindModel(contents, DUMMY_BASE_ELEMENT, mFrameContext); - - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(0); - assertThat(mAdapter.mAdaptersPerContent).isEqualTo(new int[] {0}); - } - - @Test - public void testBindChildAdapters_boundTemplateBetweenInlineContents() { - List<Content> contents = new ArrayList<>(); - contents.add( - Content.newBuilder().setTemplateInvocation(DEFAULT_TEMPLATE_INVOCATION).build()); - contents.add(Content.newBuilder().setTemplateBinding(DEFAULT_TEMPLATE_BINDING).build()); - contents.add(Content.newBuilder().setElement(DEFAULT_ELEMENT).build()); - - mAdapter.createAdapter(contents, DUMMY_BASE_ELEMENT, mFrameContext); - mAdapter.bindModel(contents, DUMMY_BASE_ELEMENT, mFrameContext); - - // 2 templates, 3 templates, 1 element list - assertThat(mAdapter.mChildAdapters).hasSize(6); - - assertThat(mAdapter.mChildAdapters.get(0)).isInstanceOf(TextElementAdapter.class); - assertThat(mAdapter.mChildAdapters.get(1)).isInstanceOf(TextElementAdapter.class); - - assertThat(mAdapter.mChildAdapters.get(2)).isInstanceOf(ImageElementAdapter.class); - assertThat(mAdapter.mChildAdapters.get(3)).isInstanceOf(ImageElementAdapter.class); - assertThat(mAdapter.mChildAdapters.get(4)).isInstanceOf(ImageElementAdapter.class); - - assertThat(mAdapter.mChildAdapters.get(5)).isInstanceOf(ElementListAdapter.class); - - // Each of these occur 2 times; once for create and once for bind. - verify(mFrameContext, times(2)) - .createTemplateContext( - DEFAULT_TEMPLATE, DEFAULT_TEMPLATE_INVOCATION.getBindingContexts(0)); - verify(mFrameContext, times(2)) - .createTemplateContext( - DEFAULT_TEMPLATE, DEFAULT_TEMPLATE_INVOCATION.getBindingContexts(1)); - - // These only occur once because we do create and bind at the same time. - verify(mFrameContext) - .createTemplateContext(DEFAULT_BOUND_TEMPLATE, - DEFAULT_BOUND_TEMPLATE_INVOCATION.getBindingContexts(0)); - verify(mFrameContext) - .createTemplateContext(DEFAULT_BOUND_TEMPLATE, - DEFAULT_BOUND_TEMPLATE_INVOCATION.getBindingContexts(1)); - verify(mFrameContext) - .createTemplateContext(DEFAULT_BOUND_TEMPLATE, - DEFAULT_BOUND_TEMPLATE_INVOCATION.getBindingContexts(2)); - - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(6); - for (int i = 0; i < 6; i++) { - assertThat(mAdapter.getBaseView().getChildAt(i)) - .isSameInstanceAs(mAdapter.mChildAdapters.get(i).getView()); - } - - assertThat(mAdapter.mAdaptersPerContent).isEqualTo(new int[] {2, 3, 1}); - } - - @Test - public void testUnbindChildAdapters_inline() { - List<Content> contents = new ArrayList<>(); - contents.add( - Content.newBuilder().setTemplateInvocation(DEFAULT_TEMPLATE_INVOCATION).build()); - contents.add(Content.newBuilder().setElement(DEFAULT_ELEMENT).build()); - - mAdapter.createAdapter(contents, DUMMY_BASE_ELEMENT, mFrameContext); - mAdapter.bindModel(contents, DUMMY_BASE_ELEMENT, mFrameContext); - - mAdapter.unbindModel(); - - // 2 templates, 1 element list - assertThat(mAdapter.mChildAdapters).hasSize(3); - assertThat(mAdapter.mChildAdapters.get(0)).isInstanceOf(TextElementAdapter.class); - assertThat(mAdapter.mChildAdapters.get(1)).isInstanceOf(TextElementAdapter.class); - assertThat(mAdapter.mChildAdapters.get(2)).isInstanceOf(ElementListAdapter.class); - - assertThat(mAdapter.mChildAdapters.get(0).getRawModel()).isNull(); - assertThat(mAdapter.mChildAdapters.get(1).getRawModel()).isNull(); - assertThat(mAdapter.mChildAdapters.get(2).getRawModel()).isNull(); - - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(3); - for (int i = 0; i < 3; i++) { - assertThat(mAdapter.getBaseView().getChildAt(i)) - .isSameInstanceAs(mAdapter.mChildAdapters.get(i).getView()); - } - - assertThat(mAdapter.mAdaptersPerContent).isEqualTo(new int[] {2, 1}); - } - - @Test - public void testUnbindChildAdapters_boundElement() { - List<Content> contents = Collections.singletonList( - Content.newBuilder().setBoundElement(DEFAULT_ELEMENT_BINDING).build()); - mAdapter.createAdapter(contents, DUMMY_BASE_ELEMENT, mFrameContext); - mAdapter.bindModel(contents, DUMMY_BASE_ELEMENT, mFrameContext); - - mAdapter.unbindModel(); - - // All (bound) adapters and views have been destroyed - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(0); - assertThat(mAdapter.mChildAdapters).isEmpty(); - assertThat(mAdapter.mAdaptersPerContent).isEqualTo(new int[] {0}); - } - - @Test - public void testUnbindChildAdapters_boundTemplate() { - List<Content> contents = Collections.singletonList( - Content.newBuilder().setTemplateBinding(DEFAULT_TEMPLATE_BINDING).build()); - mAdapter.createAdapter(contents, DUMMY_BASE_ELEMENT, mFrameContext); - mAdapter.bindModel(contents, DUMMY_BASE_ELEMENT, mFrameContext); - - mAdapter.unbindModel(); - - // All (bound) adapters and views have been destroyed - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(0); - assertThat(mAdapter.mChildAdapters).isEmpty(); - assertThat(mAdapter.mAdaptersPerContent).isEqualTo(new int[] {0}); - } - - @Test - public void testUnbindChildAdapters_boundContentBetweenInlineContents() { - List<Content> contents = new ArrayList<>(); - contents.add( - Content.newBuilder().setTemplateInvocation(DEFAULT_TEMPLATE_INVOCATION).build()); - contents.add(Content.newBuilder().setTemplateBinding(DEFAULT_TEMPLATE_BINDING).build()); - contents.add(Content.newBuilder().setElement(DEFAULT_ELEMENT).build()); - - mAdapter.createAdapter(contents, DUMMY_BASE_ELEMENT, mFrameContext); - mAdapter.bindModel(contents, DUMMY_BASE_ELEMENT, mFrameContext); - - assertThat(mAdapter.mChildAdapters).hasSize(6); - ImageElementAdapter mockTemplateAdapter = mock(ImageElementAdapter.class); - mAdapter.mChildAdapters.set(3, mockTemplateAdapter); - - mAdapter.unbindModel(); - - // The inline adapters have been unbound; the bound adapters have been destroyed. - assertThat(mAdapter.mChildAdapters).hasSize(3); - assertThat(mAdapter.mChildAdapters.get(0).getRawModel()).isNull(); - assertThat(mAdapter.mChildAdapters.get(1).getRawModel()).isNull(); - assertThat(mAdapter.mChildAdapters.get(2).getRawModel()).isNull(); - - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(3); - for (int i = 0; i < 3; i++) { - assertThat(mAdapter.getBaseView().getChildAt(i)) - .isSameInstanceAs(mAdapter.mChildAdapters.get(i).getView()); - } - - assertThat(mAdapter.mAdaptersPerContent).isEqualTo(new int[] {2, 0, 1}); - - verify(mockTemplateAdapter).unbindModel(); - verify(mockTemplateAdapter).releaseAdapter(); - } - - @Test - public void testUnbind_visibilityWasGone() { - List<Content> contents = new ArrayList<>(); - contents.add( - Content.newBuilder().setTemplateInvocation(DEFAULT_TEMPLATE_INVOCATION).build()); - contents.add(Content.newBuilder().setElement(DEFAULT_ELEMENT).build()); - - Element goneElement = - Element.newBuilder() - .setVisibilityState( - VisibilityState.newBuilder().setDefaultVisibility(Visibility.GONE)) - .build(); - - mAdapter.createAdapter(contents, goneElement, mFrameContext); - mAdapter.bindModel(contents, goneElement, mFrameContext); - - // Nothing was created because the visibility was GONE - assertThat(mAdapter.mChildAdapters).isEmpty(); - assertThat(mAdapter.mAdaptersPerContent).isEmpty(); - - mAdapter.unbindModel(); - - // Nothing crashes, and the adapter is still uncreated. - assertThat(mAdapter.mChildAdapters).isEmpty(); - assertThat(mAdapter.mAdaptersPerContent).isEmpty(); - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(0); - } - - private static class TestElementContainerAdapter - extends ElementContainerAdapter<LinearLayout, List<Content>> { - TestElementContainerAdapter( - Context context, AdapterParameters adapterParameters, LinearLayout view) { - super(context, adapterParameters, view); - } - - @Override - List<Content> getContentsFromModel(List<Content> model) { - return model; - } - - @Override - List<Content> getModelFromElement(Element baseElement) { - throw new UnsupportedOperationException("Not used in this test"); - } - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ElementListAdapterTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ElementListAdapterTest.java deleted file mode 100644 index 86569ea..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ElementListAdapterTest.java +++ /dev/null
@@ -1,534 +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. - -package org.chromium.chrome.browser.feed.library.piet; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import static org.chromium.chrome.browser.feed.library.common.testing.RunnableSubject.assertThatRunnable; - -import android.app.Activity; -import android.content.Context; -import android.view.Gravity; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewGroup.MarginLayoutParams; -import android.widget.LinearLayout; -import android.widget.LinearLayout.LayoutParams; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; -import org.robolectric.shadow.api.Shadow; - -import org.chromium.chrome.browser.feed.library.common.functional.Suppliers; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.piet.ElementListAdapter.KeySupplier; -import org.chromium.chrome.browser.feed.library.piet.host.ActionHandler; -import org.chromium.chrome.browser.feed.library.piet.host.AssetProvider; -import org.chromium.chrome.browser.feed.library.testing.shadows.ExtendedShadowLinearLayout; -import org.chromium.components.feed.core.proto.ui.piet.BindingRefsProto.ElementBindingRef; -import org.chromium.components.feed.core.proto.ui.piet.BindingRefsProto.StyleBindingRef; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.BindingValue; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.Content; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.CustomElement; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.Element; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.ElementList; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.ElementStack; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.ImageElement; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.Visibility; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.Frame; -import org.chromium.components.feed.core.proto.ui.piet.RoundedCornersProto.RoundedCorners; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.EdgeWidths; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.StyleIdsStack; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests of the {@link ElementListAdapter}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ElementListAdapterTest { - private static final String LIST_STYLE_ID = "manycats"; - private static final StyleIdsStack LIST_STYLES = - StyleIdsStack.newBuilder().addStyleIds(LIST_STYLE_ID).build(); - - private static final Element DEFAULT_ELEMENT = - Element.newBuilder().setElementStack(ElementStack.getDefaultInstance()).build(); - private static final Content DEFAULT_CONTENT = - Content.newBuilder().setElement(DEFAULT_ELEMENT).build(); - private static final Element IMAGE_ELEMENT = - Element.newBuilder().setImageElement(ImageElement.getDefaultInstance()).build(); - private static final ElementList DEFAULT_LIST = - ElementList.newBuilder().addContents(DEFAULT_CONTENT).build(); - - private static final ElementBindingRef ELEMENT_BINDING_REF = - ElementBindingRef.newBuilder().setBindingId("shopping").build(); - private static final Element LIST_WITH_BOUND_LIST = asElement( - ElementList.newBuilder() - .addContents(Content.newBuilder().setBoundElement(ELEMENT_BINDING_REF)) - .build()); - - @Mock - private ActionHandler mActionHandler; - @Mock - private FrameContext mFrameContext; - @Mock - private StyleProvider mStyleProvider; - @Mock - private HostProviders mHostProviders; - @Mock - private AssetProvider mAssetProvider; - - private Context mContext; - private AdapterParameters mAdapterParameters; - - private ElementListAdapter mAdapter; - - @Before - public void setUp() { - initMocks(this); - mContext = Robolectric.buildActivity(Activity.class).get(); - - when(mFrameContext.makeStyleFor(LIST_STYLES)).thenReturn(mStyleProvider); - when(mStyleProvider.getPadding()).thenReturn(EdgeWidths.getDefaultInstance()); - when(mFrameContext.getActionHandler()).thenReturn(mActionHandler); - when(mHostProviders.getAssetProvider()).thenReturn(mAssetProvider); - when(mAssetProvider.isRtL()).thenReturn(false); - when(mStyleProvider.getRoundedCorners()).thenReturn(RoundedCorners.getDefaultInstance()); - - mAdapterParameters = new AdapterParameters( - mContext, Suppliers.of(null), mHostProviders, new FakeClock(), false, false); - - when(mFrameContext.makeStyleFor(StyleIdsStack.getDefaultInstance())) - .thenReturn(mAdapterParameters.mDefaultStyleProvider); - - mAdapter = new KeySupplier().getAdapter(mContext, mAdapterParameters); - } - - @Test - public void testViewDoesNotClip() { - assertThat(mAdapter.getBaseView().getClipToPadding()).isFalse(); - } - - @Test - public void testOnCreateAdapter_makesList() { - ElementList listWithStyles = ElementList.newBuilder() - .addContents(DEFAULT_CONTENT) - .addContents(DEFAULT_CONTENT) - .addContents(DEFAULT_CONTENT) - .build(); - - mAdapter.createAdapter(asElementWithDefaultStyle(listWithStyles), mFrameContext); - - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(3); - assertThat(mAdapter.getBaseView().getOrientation()).isEqualTo(LinearLayout.VERTICAL); - } - - @Test - public void testOnCreateAdapter_setsStyles() { - ElementList listWithStyles = ElementList.newBuilder().addContents(DEFAULT_CONTENT).build(); - - mAdapter.createAdapter(asElementWithDefaultStyle(listWithStyles), mFrameContext); - - verify(mStyleProvider).applyElementStyles(mAdapter); - } - - @Config(shadows = {ExtendedShadowLinearLayout.class}) - @Test - public void testTriggerActions_triggersChildren() { - Frame frame = Frame.newBuilder().setTag("Frame").build(); - when(mFrameContext.getFrame()).thenReturn(frame); - Element baseElement = - Element.newBuilder() - .setElementList(ElementList.newBuilder().addContents( - Content.newBuilder().setElement(Element.newBuilder().setElementList( - ElementList.getDefaultInstance())))) - .build(); - mAdapter.createAdapter(baseElement, mFrameContext); - mAdapter.bindModel(baseElement, mFrameContext); - - // Replace the child adapter so we can verify on it - ElementAdapter<?, ?> mockChildAdapter = mock(ElementAdapter.class); - mAdapter.mChildAdapters.set(0, mockChildAdapter); - - ExtendedShadowLinearLayout shadowView = Shadow.extract(mAdapter.getView()); - mAdapter.getView().setVisibility(View.VISIBLE); - shadowView.setAttachedToWindow(true); - - View viewport = new View(mContext); - - mAdapter.triggerViewActions(viewport, mFrameContext); - - verify(mockChildAdapter).triggerViewActions(viewport, mFrameContext); - } - - @Test - public void testOnBindModel_setsStylesOnlyIfBindingIsDefined() { - ElementList list = ElementList.newBuilder().addContents(DEFAULT_CONTENT).build(); - - mAdapter.createAdapter(asElement(list, LIST_STYLES), mFrameContext); - verify(mFrameContext).makeStyleFor(LIST_STYLES); - - // Binding an element with a different style will not apply the new style - StyleIdsStack otherStyles = StyleIdsStack.newBuilder().addStyleIds("bobcat").build(); - - mAdapter.bindModel(asElement(list, otherStyles), mFrameContext); - verify(mFrameContext, never()).makeStyleFor(otherStyles); - - // But binding an element with a style binding will re-apply the style - StyleIdsStack otherStylesWithBinding = - StyleIdsStack.newBuilder() - .addStyleIds("bobcat") - .setStyleBinding(StyleBindingRef.newBuilder().setBindingId("lynx")) - .build(); - when(mFrameContext.makeStyleFor(otherStylesWithBinding)).thenReturn(mStyleProvider); - - mAdapter.bindModel(asElement(list, otherStylesWithBinding), mFrameContext); - verify(mFrameContext).makeStyleFor(otherStylesWithBinding); - } - - @Test - public void testOnBindModel_failsWithIncompatibleModel() { - ElementList listWithThreeElements = ElementList.newBuilder() - .addContents(DEFAULT_CONTENT) - .addContents(DEFAULT_CONTENT) - .addContents(DEFAULT_CONTENT) - .build(); - - mAdapter.createAdapter(asElementWithDefaultStyle(listWithThreeElements), mFrameContext); - mAdapter.bindModel(asElementWithDefaultStyle(listWithThreeElements), mFrameContext); - mAdapter.unbindModel(); - - ElementList listWithTwoElements = ElementList.newBuilder() - .addContents(DEFAULT_CONTENT) - .addContents(DEFAULT_CONTENT) - .build(); - - assertThatRunnable( - () - -> mAdapter.bindModel( - asElementWithDefaultStyle(listWithTwoElements), mFrameContext)) - .throwsAnExceptionOfType(IllegalStateException.class) - .that() - .hasMessageThat() - .contains("Internal error in adapters per content"); - } - - @Test - public void testOnBindModel_elementListBindingRecreatesAdapter() { - Element listWithOneItem = - Element.newBuilder() - .setElementList(ElementList.newBuilder().addContents(DEFAULT_CONTENT)) - .build(); - Element listWithTwoItems = Element.newBuilder() - .setElementList(ElementList.newBuilder() - .addContents(DEFAULT_CONTENT) - .addContents(DEFAULT_CONTENT)) - .build(); - - when(mFrameContext.getElementBindingValue(ELEMENT_BINDING_REF)) - .thenReturn(BindingValue.newBuilder().setElement(listWithOneItem).build()); - mAdapter.createAdapter(LIST_WITH_BOUND_LIST, mFrameContext); - // No child adapters have been created yet. - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(0); - assertThat(mAdapter.mChildAdapters).isEmpty(); - - when(mFrameContext.getElementBindingValue(ELEMENT_BINDING_REF)) - .thenReturn(BindingValue.newBuilder().setElement(listWithTwoItems).build()); - mAdapter.bindModel(LIST_WITH_BOUND_LIST, mFrameContext); - // The list adapter creates its one view on bind. - assertThat(((LinearLayout) mAdapter.getBaseView().getChildAt(0)).getChildCount()) - .isEqualTo(2); - - mAdapter.unbindModel(); - // The list adapter has been released. - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(0); - assertThat(mAdapter.mChildAdapters).isEmpty(); - - when(mFrameContext.getElementBindingValue(ELEMENT_BINDING_REF)) - .thenReturn(BindingValue.newBuilder().setElement(listWithOneItem).build()); - mAdapter.bindModel(LIST_WITH_BOUND_LIST, mFrameContext); - // The list adapter can bind to a different model. - assertThat(((LinearLayout) mAdapter.getBaseView().getChildAt(0)).getChildCount()) - .isEqualTo(1); - } - - @Test - public void testOnBindModel_bindingWithVisibilityGone() { - when(mFrameContext.getElementBindingValue(ELEMENT_BINDING_REF)) - .thenReturn(BindingValue.newBuilder() - .setBindingId(ELEMENT_BINDING_REF.getBindingId()) - .setElement(Element.newBuilder().setElementList(DEFAULT_LIST)) - .build()); - mAdapter.createAdapter(LIST_WITH_BOUND_LIST, mFrameContext); - when(mFrameContext.getElementBindingValue(ELEMENT_BINDING_REF)) - .thenReturn(BindingValue.newBuilder() - .setBindingId(ELEMENT_BINDING_REF.getBindingId()) - .setVisibility(Visibility.GONE) - .build()); - - mAdapter.bindModel(LIST_WITH_BOUND_LIST, mFrameContext); - - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(0); - assertThat(mAdapter.mChildAdapters).isEmpty(); - } - - @Test - public void testOnBindModel_bindingWithNoContent() { - when(mFrameContext.getElementBindingValue(ELEMENT_BINDING_REF)) - .thenReturn(BindingValue.newBuilder() - .setBindingId(ELEMENT_BINDING_REF.getBindingId()) - .setElement(DEFAULT_ELEMENT) - .build()); - mAdapter.createAdapter(LIST_WITH_BOUND_LIST, mFrameContext); - when(mFrameContext.getElementBindingValue(ELEMENT_BINDING_REF)) - .thenReturn(BindingValue.newBuilder() - .setBindingId(ELEMENT_BINDING_REF.getBindingId()) - .build()); - - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(0); - assertThat(mAdapter.mChildAdapters).isEmpty(); - } - - @Test - public void testOnBindModel_bindingWithOptionalAbsent() { - when(mFrameContext.getElementBindingValue(ELEMENT_BINDING_REF)) - .thenReturn(BindingValue.newBuilder() - .setBindingId(ELEMENT_BINDING_REF.getBindingId()) - .setElement(DEFAULT_ELEMENT) - .build()); - mAdapter.createAdapter(LIST_WITH_BOUND_LIST, mFrameContext); - - ElementBindingRef optionalBinding = - ELEMENT_BINDING_REF.toBuilder().setIsOptional(true).build(); - ElementList optionalBindingList = - ElementList.newBuilder() - .addContents(Content.newBuilder().setBoundElement(optionalBinding)) - .build(); - when(mFrameContext.getElementBindingValue(optionalBinding)) - .thenReturn(BindingValue.newBuilder() - .setBindingId(optionalBinding.getBindingId()) - .build()); - - mAdapter.bindModel(asElement(optionalBindingList), mFrameContext); - - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(0); - assertThat(mAdapter.mChildAdapters).isEmpty(); - } - - @Test - public void testOnBindModel_setsLayoutParamsOnChild() { - ElementList list = - ElementList.newBuilder() - .addContents(Content.newBuilder().setElement( - DEFAULT_ELEMENT.toBuilder().setStyleReferences(LIST_STYLES))) - .build(); - when(mStyleProvider.getGravityHorizontal(anyInt())).thenReturn(Gravity.CENTER_HORIZONTAL); - - mAdapter.createAdapter(asElement(list), mFrameContext); - - mAdapter.mChildAdapters.get(0).mWidthPx = 123; - mAdapter.mChildAdapters.get(0).mHeightPx = 456; - - mAdapter.bindModel(asElement(list), mFrameContext); - - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(1); - assertThat(mAdapter.getBaseView().getChildAt(0).getLayoutParams()) - .isInstanceOf(LinearLayout.LayoutParams.class); - assertThat(((LayoutParams) mAdapter.getBaseView().getChildAt(0).getLayoutParams()).gravity) - .isEqualTo(Gravity.CENTER_HORIZONTAL); - assertThat(((LayoutParams) mAdapter.getBaseView().getChildAt(0).getLayoutParams()).width) - .isEqualTo(123); - assertThat(((LayoutParams) mAdapter.getBaseView().getChildAt(0).getLayoutParams()).height) - .isEqualTo(456); - } - - @Test - public void testOnBindModel_setsMargins() { - String marginsStyleId = "spacecat"; - StyleIdsStack marginsStyles = - StyleIdsStack.newBuilder().addStyleIds(marginsStyleId).build(); - Element elementWithMargins = Element.newBuilder() - .setStyleReferences(marginsStyles) - .setElementStack(ElementStack.getDefaultInstance()) - .build(); - ElementList list = ElementList.newBuilder() - .addContents(Content.newBuilder().setElement(elementWithMargins)) - .build(); - when(mFrameContext.makeStyleFor(marginsStyles)).thenReturn(mStyleProvider); - - mAdapter.createAdapter(asElement(list), mFrameContext); - mAdapter.bindModel(asElement(list), mFrameContext); - - // Assert that applyMargins is called on the child's layout params - ArgumentCaptor<MarginLayoutParams> capturedLayoutParams = - ArgumentCaptor.forClass(MarginLayoutParams.class); - verify(mStyleProvider).applyMargins(eq(mContext), capturedLayoutParams.capture()); - - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(1); - assertThat(mAdapter.getBaseView().getChildAt(0).getLayoutParams()) - .isInstanceOf(MarginLayoutParams.class); - assertThat(mAdapter.getBaseView().getChildAt(0).getLayoutParams()) - .isSameInstanceAs(capturedLayoutParams.getValue()); - } - - @Test - public void testReleaseAdapter() { - ElementList listWithStyles = ElementList.newBuilder() - .addContents(DEFAULT_CONTENT) - .addContents(DEFAULT_CONTENT) - .addContents(DEFAULT_CONTENT) - .build(); - - mAdapter.createAdapter(asElementWithDefaultStyle(listWithStyles), mFrameContext); - mAdapter.bindModel(asElementWithDefaultStyle(listWithStyles), mFrameContext); - - mAdapter.releaseAdapter(); - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(0); - assertThat(mAdapter.mChildAdapters).isEmpty(); - } - - @Test - public void testGetVerticalGravity_noModel() { - assertThat(mAdapter.getVerticalGravity(Gravity.CLIP_VERTICAL)) - .isEqualTo(Gravity.CLIP_VERTICAL); - } - - @Test - public void testGetStyleIdsStack() { - ElementList listWithStyles = ElementList.newBuilder().addContents(DEFAULT_CONTENT).build(); - - mAdapter.createAdapter(asElement(listWithStyles, LIST_STYLES), mFrameContext); - - assertThat(mAdapter.getElementStyleIdsStack()).isEqualTo(LIST_STYLES); - } - - @Test - public void testGetModelFromElement() { - ElementList model = ElementList.newBuilder().addContents(DEFAULT_CONTENT).build(); - - Element elementWithModel = Element.newBuilder().setElementList(model).build(); - assertThat(mAdapter.getModelFromElement(elementWithModel)).isSameInstanceAs(model); - - Element elementWithWrongModel = - Element.newBuilder().setCustomElement(CustomElement.getDefaultInstance()).build(); - assertThatRunnable(() -> mAdapter.getModelFromElement(elementWithWrongModel)) - .throwsAnExceptionOfType(PietFatalException.class) - .that() - .hasMessageThat() - .contains("Missing ElementList"); - - Element emptyElement = Element.getDefaultInstance(); - assertThatRunnable(() -> mAdapter.getModelFromElement(emptyElement)) - .throwsAnExceptionOfType(PietFatalException.class) - .that() - .hasMessageThat() - .contains("Missing ElementList"); - } - - @Test - public void testSetLayoutParamsOnChild() { - ElementList list = - ElementList.newBuilder() - .addContents(Content.newBuilder().setElement( - DEFAULT_ELEMENT.toBuilder().setStyleReferences(LIST_STYLES))) - .build(); - when(mStyleProvider.getWidthSpecPx(mContext)).thenReturn(123); - when(mStyleProvider.getHeightSpecPx(mContext)).thenReturn(456); - when(mStyleProvider.getGravityHorizontal(anyInt())).thenReturn(Gravity.CENTER_HORIZONTAL); - - mAdapter.createAdapter(asElement(list), mFrameContext); - - LayoutParams layoutParams = new LayoutParams( - ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); - mAdapter.setLayoutParams(layoutParams); - - assertThat(((LayoutParams) mAdapter.getBaseView().getChildAt(0).getLayoutParams()).gravity) - .isEqualTo(Gravity.CENTER_HORIZONTAL); - assertThat(((LayoutParams) mAdapter.getBaseView().getChildAt(0).getLayoutParams()).width) - .isEqualTo(123); - assertThat(((LayoutParams) mAdapter.getBaseView().getChildAt(0).getLayoutParams()).height) - .isEqualTo(456); - } - - @Test - public void testSetLayoutParams_childWidthSet() { - int childWidth = 5; - - ElementList list = ElementList.newBuilder() - .addContents(Content.newBuilder().setElement(IMAGE_ELEMENT)) - .build(); - - mAdapter.createAdapter(asElement(list), mFrameContext); - StyleProvider childStyleProvider = mock(StyleProvider.class); - ImageElementAdapter mockChildAdapter = mock(ImageElementAdapter.class); - when(mockChildAdapter.getComputedWidthPx()).thenReturn(childWidth); - when(mockChildAdapter.getElementStyle()).thenReturn(childStyleProvider); - when(mockChildAdapter.getHorizontalGravity(anyInt())).thenReturn(Gravity.CENTER_HORIZONTAL); - when(mockChildAdapter.getElementStyle().hasGravityHorizontal()).thenReturn(true); - mAdapter.mChildAdapters.set(0, mockChildAdapter); - - LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( - ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); - mAdapter.setLayoutParams(params); - - ArgumentCaptor<LinearLayout.LayoutParams> childLayoutParamsCaptor = - ArgumentCaptor.forClass(LinearLayout.LayoutParams.class); - verify(mockChildAdapter).setLayoutParams(childLayoutParamsCaptor.capture()); - - LinearLayout.LayoutParams childLayoutParams = childLayoutParamsCaptor.getValue(); - assertThat(childLayoutParams.width).isEqualTo(childWidth); - assertThat(childLayoutParams.gravity).isEqualTo(Gravity.CENTER_HORIZONTAL); - - verify(childStyleProvider).applyMargins(mContext, childLayoutParams); - } - - @Test - public void testSetLayoutParams_widthSetOnList() { - ElementList list = ElementList.newBuilder() - .addContents(Content.newBuilder().setElement(IMAGE_ELEMENT)) - .build(); - - mAdapter.createAdapter(asElement(list), mFrameContext); - - LinearLayout.LayoutParams params = - new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT); - params.weight = 1; - mAdapter.setLayoutParams(params); - - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(1); - assertThat(mAdapter.getBaseView().getChildAt(0).getLayoutParams()) - .isInstanceOf(LinearLayout.LayoutParams.class); - assertThat(((LayoutParams) mAdapter.getBaseView().getChildAt(0).getLayoutParams()).width) - .isEqualTo(ViewGroup.LayoutParams.MATCH_PARENT); - assertThat(((LayoutParams) mAdapter.getBaseView().getChildAt(0).getLayoutParams()).height) - .isEqualTo(ViewGroup.LayoutParams.WRAP_CONTENT); - } - - private static Element asElement(ElementList elementList) { - return Element.newBuilder().setElementList(elementList).build(); - } - - private static Element asElement(ElementList elementList, StyleIdsStack styles) { - return Element.newBuilder().setStyleReferences(styles).setElementList(elementList).build(); - } - - private static Element asElementWithDefaultStyle(ElementList elementList) { - return Element.newBuilder() - .setStyleReferences(LIST_STYLES) - .setElementList(elementList) - .build(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ElementStackAdapterTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ElementStackAdapterTest.java deleted file mode 100644 index be4180a..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ElementStackAdapterTest.java +++ /dev/null
@@ -1,222 +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. - -package org.chromium.chrome.browser.feed.library.piet; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import static java.util.Arrays.asList; - -import android.app.Activity; -import android.content.Context; -import android.view.ViewGroup.LayoutParams; -import android.view.ViewGroup.MarginLayoutParams; -import android.widget.ImageView; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.common.functional.Suppliers; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.piet.host.AssetProvider; -import org.chromium.components.feed.core.proto.ui.piet.BindingRefsProto.ElementBindingRef; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.BindingValue; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.Content; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.Element; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.ElementList; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.ElementStack; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.GridRow; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.ImageElement; -import org.chromium.components.feed.core.proto.ui.piet.ImagesProto.Image; -import org.chromium.components.feed.core.proto.ui.piet.RoundedCornersProto.RoundedCorners; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.Collections; -import java.util.List; - -/** Tests of the {@link ElementStackAdapter} */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ElementStackAdapterTest { - private static final Content INLINE_CONTENT = - Content.newBuilder() - .setElement( - Element.newBuilder().setElementList(ElementList.getDefaultInstance())) - .build(); - private static final Element BOUND_ELEMENT = - Element.newBuilder().setGridRow(GridRow.getDefaultInstance()).build(); - private static final String ELEMENT_BINDING_ID = "RowBinding"; - private static final ElementBindingRef ELEMENT_BINDING = - ElementBindingRef.newBuilder().setBindingId(ELEMENT_BINDING_ID).build(); - private static final BindingValue ELEMENT_BINDING_VALUE = - BindingValue.newBuilder() - .setBindingId(ELEMENT_BINDING_ID) - .setElement(BOUND_ELEMENT) - .build(); - private static final Content BOUND_CONTENT = - Content.newBuilder().setBoundElement(ELEMENT_BINDING).build(); - - @Mock - private FrameContext mFrameContext; - @Mock - private AssetProvider mAssetProvider; - @Mock - private StyleProvider mMockStyleProvider; - @Mock - private HostProviders mMockHostProviders; - - private Context mContext; - private AdapterParameters mAdapterParameters; - - private ElementStackAdapter mAdapter; - - @Before - public void setUp() throws Exception { - initMocks(this); - mContext = Robolectric.buildActivity(Activity.class).get(); - - when(mFrameContext.getElementBindingValue(ELEMENT_BINDING)) - .thenReturn(ELEMENT_BINDING_VALUE); - when(mFrameContext.makeStyleFor(any())).thenReturn(mMockStyleProvider); - when(mFrameContext.filterImageSourcesByMediaQueryCondition(any(Image.class))) - .thenAnswer(invocation -> invocation.getArguments()[0]); - when(mMockHostProviders.getAssetProvider()).thenReturn(mAssetProvider); - when(mMockStyleProvider.getRoundedCorners()) - .thenReturn(RoundedCorners.getDefaultInstance()); - - mAdapterParameters = new AdapterParameters( - mContext, Suppliers.of(null), mMockHostProviders, new FakeClock(), false, false); - - mAdapter = new ElementStackAdapter.KeySupplier().getAdapter(mContext, mAdapterParameters); - } - - @Test - public void testCreatesInlineAdaptersInOnCreate() { - Element element = asElement(asList(INLINE_CONTENT, BOUND_CONTENT)); - - mAdapter.createAdapter(element, mFrameContext); - - assertThat(mAdapter.mChildAdapters).hasSize(1); - assertThat(mAdapter.mChildAdapters.get(0)).isInstanceOf(ElementListAdapter.class); - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(1); - assertThat(mAdapter.getBaseView().getChildAt(0)) - .isSameInstanceAs(mAdapter.mChildAdapters.get(0).getView()); - } - - @Test - public void testCreatesBoundAdaptersInOnBind() { - Element element = asElement(asList(INLINE_CONTENT, BOUND_CONTENT)); - - mAdapter.createAdapter(element, mFrameContext); - mAdapter.bindModel(element, mFrameContext); - - assertThat(mAdapter.mChildAdapters).hasSize(2); - assertThat(mAdapter.mChildAdapters.get(0)).isInstanceOf(ElementListAdapter.class); - assertThat(mAdapter.mChildAdapters.get(1)).isInstanceOf(GridRowAdapter.class); - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(2); - assertThat(mAdapter.getBaseView().getChildAt(0)) - .isSameInstanceAs(mAdapter.mChildAdapters.get(0).getView()); - assertThat(mAdapter.getBaseView().getChildAt(1)) - .isSameInstanceAs(mAdapter.mChildAdapters.get(1).getView()); - } - - @Test - public void testSetsLayoutParamsOnChildForInlineAdapters() { - Content imageContent = - Content.newBuilder() - .setElement(Element.newBuilder().setImageElement( - ImageElement.newBuilder().setImage(Image.getDefaultInstance()))) - .build(); - Element element = asElement(Collections.singletonList(imageContent)); - - when(mMockStyleProvider.hasWidth()).thenReturn(true); - when(mMockStyleProvider.hasHeight()).thenReturn(true); - when(mMockStyleProvider.getWidthSpecPx(mContext)).thenReturn(123); - when(mMockStyleProvider.getHeightSpecPx(mContext)).thenReturn(456); - when(mMockStyleProvider.getScaleType()).thenReturn(ImageView.ScaleType.CENTER_CROP); - - mAdapter.createAdapter(element, mFrameContext); - mAdapter.bindModel(element, mFrameContext); - - LayoutParams inlineAdapterLayoutParams = - mAdapter.mChildAdapters.get(0).getView().getLayoutParams(); - - assertThat(inlineAdapterLayoutParams.width).isEqualTo(123); - assertThat(inlineAdapterLayoutParams.height).isEqualTo(456); - } - - @Test - public void testSetsLayoutParamsOnChildForBoundAdapters() { - ElementBindingRef imageBinding = - ElementBindingRef.newBuilder().setBindingId("image").build(); - BindingValue imageBindingValue = - BindingValue.newBuilder() - .setElement(Element.newBuilder().setImageElement( - ImageElement.newBuilder().setImage(Image.getDefaultInstance()))) - .build(); - when(mFrameContext.getElementBindingValue(imageBinding)).thenReturn(imageBindingValue); - Element element = asElement(Collections.singletonList( - Content.newBuilder().setBoundElement(imageBinding).build())); - - when(mMockStyleProvider.hasWidth()).thenReturn(true); - when(mMockStyleProvider.hasHeight()).thenReturn(true); - when(mMockStyleProvider.getWidthSpecPx(mContext)).thenReturn(123); - when(mMockStyleProvider.getHeightSpecPx(mContext)).thenReturn(456); - when(mMockStyleProvider.getScaleType()).thenReturn(ImageView.ScaleType.CENTER_CROP); - - mAdapter.createAdapter(element, mFrameContext); - mAdapter.bindModel(element, mFrameContext); - - LayoutParams boundAdapterLayoutParams = - mAdapter.mChildAdapters.get(0).getView().getLayoutParams(); - - assertThat(boundAdapterLayoutParams.width).isEqualTo(123); - assertThat(boundAdapterLayoutParams.height).isEqualTo(456); - } - - @Test - public void testSetsMarginsOnChild() { - Element element = asElement(Collections.singletonList(INLINE_CONTENT)); - - mAdapter.createAdapter(element, mFrameContext); - mAdapter.bindModel(element, mFrameContext); - - MarginLayoutParams childAdapterLayoutParams = - (MarginLayoutParams) mAdapter.mChildAdapters.get(0).getView().getLayoutParams(); - - verify(mMockStyleProvider).applyMargins(mContext, childAdapterLayoutParams); - } - - @Test - public void testGetContentsFromModel() { - ElementStack model = ElementStack.newBuilder() - .addAllContents(asList(INLINE_CONTENT, BOUND_CONTENT)) - .build(); - - assertThat(mAdapter.getContentsFromModel(model)).isSameInstanceAs(model.getContentsList()); - } - - @Test - public void testGetModelFromElement() { - Element element = asElement(asList(INLINE_CONTENT, BOUND_CONTENT)); - - assertThat(mAdapter.getModelFromElement(element)) - .isSameInstanceAs(element.getElementStack()); - } - - private Element asElement(List<Content> contents) { - return Element.newBuilder() - .setElementStack(ElementStack.newBuilder().addAllContents(contents)) - .build(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/FrameAdapterImplTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/FrameAdapterImplTest.java deleted file mode 100644 index 3500da2..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/FrameAdapterImplTest.java +++ /dev/null
@@ -1,853 +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. - -package org.chromium.chrome.browser.feed.library.piet; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import android.app.Activity; -import android.content.Context; -import android.graphics.drawable.ColorDrawable; -import android.view.Gravity; -import android.view.View; -import android.view.ViewGroup.LayoutParams; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.LinearLayout; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.config.DebugBehavior; -import org.chromium.chrome.browser.feed.library.common.functional.Suppliers; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.piet.DebugLogger.MessageType; -import org.chromium.chrome.browser.feed.library.piet.PietStylesHelper.PietStylesHelperFactory; -import org.chromium.chrome.browser.feed.library.piet.TemplateBinder.TemplateAdapterModel; -import org.chromium.chrome.browser.feed.library.piet.host.ActionHandler; -import org.chromium.chrome.browser.feed.library.piet.host.ActionHandler.ActionType; -import org.chromium.chrome.browser.feed.library.piet.host.AssetProvider; -import org.chromium.chrome.browser.feed.library.piet.host.CustomElementProvider; -import org.chromium.chrome.browser.feed.library.piet.host.EventLogger; -import org.chromium.chrome.browser.feed.library.piet.host.HostBindingProvider; -import org.chromium.chrome.browser.feed.library.piet.host.LogDataCallback; -import org.chromium.chrome.browser.feed.library.piet.ui.RoundedCornerMaskCache; -import org.chromium.components.feed.core.proto.ui.piet.ActionsProto.Action; -import org.chromium.components.feed.core.proto.ui.piet.ActionsProto.Actions; -import org.chromium.components.feed.core.proto.ui.piet.ActionsProto.VisibilityAction; -import org.chromium.components.feed.core.proto.ui.piet.BindingRefsProto.ActionsBindingRef; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.BindingContext; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.BindingValue; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.Content; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.Element; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.ElementList; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.ElementStack; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.GridRow; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.ImageElement; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.TemplateInvocation; -import org.chromium.components.feed.core.proto.ui.piet.ErrorsProto.ErrorCode; -import org.chromium.components.feed.core.proto.ui.piet.GradientsProto.Fill; -import org.chromium.components.feed.core.proto.ui.piet.ImagesProto.Image; -import org.chromium.components.feed.core.proto.ui.piet.LogDataProto.LogData; -import org.chromium.components.feed.core.proto.ui.piet.PietAndroidSupport.ShardingControl; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.Frame; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.PietSharedState; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.Stylesheet; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.Stylesheets; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.Template; -import org.chromium.components.feed.core.proto.ui.piet.RoundedCornersProto.RoundedCorners; -import org.chromium.components.feed.core.proto.ui.piet.ShadowsProto.ElevationShadow; -import org.chromium.components.feed.core.proto.ui.piet.ShadowsProto.Shadow; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.EdgeWidths; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.GravityHorizontal; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.GravityVertical; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.Style; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.StyleIdsStack; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** Tests of the {@link FrameAdapterImpl}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class FrameAdapterImplTest { - private static final Content DEFAULT_CONTENT = - Content.newBuilder() - .setElement(Element.newBuilder().setElementList( - ElementList.newBuilder().addContents( - Content.newBuilder().setElement(Element.getDefaultInstance())))) - .build(); - private static final int FRAME_WIDTH = 321; - private final LogData mLogDataTest = LogData.getDefaultInstance(); - - @Mock - private AssetProvider mAssetProvider; - @Mock - private ElementAdapterFactory mAdapterFactory; - @Mock - private TemplateBinder mTemplateBinder; - @Mock - private FrameContext mFrameContext; - @Mock - private DebugBehavior mDebugBehavior; - @Mock - private DebugLogger mDebugLogger; - @Mock - private StyleProvider mStyleProvider; - @Mock - private ElementAdapter<? extends View, ?> mElementAdapter; - @Mock - private ElementAdapter<? extends View, ?> mTemplateAdapter; - @Mock - private CustomElementProvider mCustomElementProvider; - @Mock - private ActionHandler mActionHandler; - @Mock - private HostProviders mHostProviders; - @Mock - private EventLogger mEventLogger; - @Mock - private PietStylesHelperFactory mStylesHelpers; - @Mock - private RoundedCornerMaskCache mMaskCache; - - @Captor - private ArgumentCaptor<LayoutParams> mLayoutParamsCaptor; - - private Context mContext; - private List<PietSharedState> mPietSharedStates; - private AdapterParameters mAdapterParameters; - private boolean mCallbackBound; - private boolean mCallbackUnbound; - private FrameAdapterImpl mFrameAdapter; - - @Before - public void setUp() throws Exception { - initMocks(this); - mContext = Robolectric.buildActivity(Activity.class).get(); - LogDataCallback logDataCallback = new LogDataCallback() { - @Override - public void onBind(LogData logData, View view) { - assertThat(mLogDataTest).isEqualTo(logData); - mCallbackBound = true; - } - - @Override - public void onUnbind(LogData logData, View view) { - assertThat(mLogDataTest).isEqualTo(logData); - mCallbackUnbound = true; - } - }; - mAdapterParameters = new AdapterParameters(null, Suppliers.of(new FrameLayout(mContext)), - mHostProviders, new ParameterizedTextEvaluator(new FakeClock()), mAdapterFactory, - mTemplateBinder, new FakeClock(), mStylesHelpers, mMaskCache, false, false); - when(mElementAdapter.getView()).thenReturn(new LinearLayout(mContext)); - when(mTemplateAdapter.getView()).thenReturn(new LinearLayout(mContext)); - doReturn(mElementAdapter) - .when(mAdapterFactory) - .createAdapterForElement(any(Element.class), eq(mFrameContext)); - doReturn(mTemplateAdapter) - .when(mTemplateBinder) - .createAndBindTemplateAdapter(any(TemplateAdapterModel.class), eq(mFrameContext)); - when(mElementAdapter.getHorizontalGravity(anyInt())).thenReturn(Gravity.CENTER_HORIZONTAL); - when(mElementAdapter.getVerticalGravity(anyInt())).thenReturn(Gravity.BOTTOM); - when(mTemplateAdapter.getHorizontalGravity(anyInt())).thenReturn(Gravity.CENTER_HORIZONTAL); - when(mTemplateAdapter.getVerticalGravity(anyInt())).thenReturn(Gravity.BOTTOM); - when(mHostProviders.getAssetProvider()).thenReturn(mAssetProvider); - when(mHostProviders.getLogDataCallback()).thenReturn(logDataCallback); - when(mAssetProvider.isRtLSupplier()).thenReturn(Suppliers.of(false)); - when(mFrameContext.reportMessage(eq(MessageType.ERROR), anyString())) - .thenAnswer(invocationOnMock -> { - throw new RuntimeException((String) invocationOnMock.getArguments()[1]); - }); - when(mFrameContext.getDebugLogger()).thenReturn(mDebugLogger); - when(mFrameContext.getDebugBehavior()).thenReturn(DebugBehavior.VERBOSE); - when(mFrameContext.makeStyleFor(any(StyleIdsStack.class))).thenReturn(mStyleProvider); - when(mFrameContext.getFrame()).thenReturn(Frame.getDefaultInstance()); - when(mElementAdapter.getElementStyle()).thenReturn(mStyleProvider); - when(mTemplateAdapter.getElementStyle()).thenReturn(mStyleProvider); - - mPietSharedStates = new ArrayList<>(); - mFrameAdapter = new FrameAdapterImpl( - mContext, mAdapterParameters, mActionHandler, mEventLogger, mDebugBehavior) { - @Override - FrameContext createFrameContext(Frame frame, int frameWidthPx, - List<PietSharedState> pietSharedStates, View view) { - return mFrameContext; - } - }; - } - - @Test - public void testCreate() { - LinearLayout linearLayout = mFrameAdapter.getFrameContainer(); - assertThat(linearLayout).isNotNull(); - LayoutParams layoutParams = linearLayout.getLayoutParams(); - assertThat(layoutParams).isNotNull(); - assertThat(layoutParams.width).isEqualTo(LayoutParams.MATCH_PARENT); - assertThat(layoutParams.height).isEqualTo(LayoutParams.WRAP_CONTENT); - } - - @Test - public void testGetBoundAdaptersForContent() { - Content content = DEFAULT_CONTENT; - - String templateId = "loaf"; - when(mFrameContext.getTemplate(templateId)).thenReturn(Template.getDefaultInstance()); - List<ElementAdapter<?, ?>> viewAdapters = - mFrameAdapter.getBoundAdaptersForContent(content, mFrameContext); - assertThat(viewAdapters).containsExactly(mElementAdapter); - - content = Content.newBuilder() - .setTemplateInvocation( - TemplateInvocation.newBuilder().setTemplateId(templateId)) - .build(); - viewAdapters = mFrameAdapter.getBoundAdaptersForContent(content, mFrameContext); - assertThat(viewAdapters).isEmpty(); - - content = Content.newBuilder() - .setTemplateInvocation( - TemplateInvocation.newBuilder() - .setTemplateId(templateId) - .addBindingContexts(BindingContext.getDefaultInstance())) - .build(); - viewAdapters = mFrameAdapter.getBoundAdaptersForContent(content, mFrameContext); - assertThat(viewAdapters).containsExactly(mTemplateAdapter); - - content = Content.newBuilder() - .setTemplateInvocation( - TemplateInvocation.newBuilder() - .setTemplateId(templateId) - .addBindingContexts( - BindingContext.newBuilder().addBindingValues( - BindingValue.newBuilder().setBindingId( - "1"))) - .addBindingContexts( - BindingContext.newBuilder().addBindingValues( - BindingValue.newBuilder().setBindingId( - "2"))) - .addBindingContexts( - BindingContext.newBuilder().addBindingValues( - BindingValue.newBuilder().setBindingId( - "3")))) - .build(); - viewAdapters = mFrameAdapter.getBoundAdaptersForContent(content, mFrameContext); - assertThat(viewAdapters) - .containsExactly(mTemplateAdapter, mTemplateAdapter, mTemplateAdapter); - verify(mTemplateBinder) - .createAndBindTemplateAdapter( - new TemplateAdapterModel(Template.getDefaultInstance(), - content.getTemplateInvocation().getBindingContexts(0)), - mFrameContext); - verify(mTemplateBinder) - .createAndBindTemplateAdapter( - new TemplateAdapterModel(Template.getDefaultInstance(), - content.getTemplateInvocation().getBindingContexts(1)), - mFrameContext); - verify(mTemplateBinder) - .createAndBindTemplateAdapter( - new TemplateAdapterModel(Template.getDefaultInstance(), - content.getTemplateInvocation().getBindingContexts(2)), - mFrameContext); - - verify(mFrameContext, never()).reportMessage(anyInt(), anyString()); - } - - /** - * This test sets up all real objects to ensure that real adapters are bound and unbound, etc. - */ - @Test - public void testBindAndUnbind_respectsAdapterLifecycle() { - String templateId = "template"; - ElementList defaultList = - ElementList.newBuilder() - .addContents( - Content.newBuilder().setElement(Element.newBuilder().setElementList( - ElementList.getDefaultInstance()))) - .addContents(Content.newBuilder().setElement( - Element.newBuilder().setGridRow(GridRow.getDefaultInstance()))) - .build(); - AdapterParameters adapterParameters = - new AdapterParameters(mContext, Suppliers.of(new LinearLayout(mContext)), - mHostProviders, new FakeClock(), false, false); - PietSharedState pietSharedState = - PietSharedState.newBuilder() - .addTemplates(Template.newBuilder() - .setTemplateId(templateId) - .setElement(Element.newBuilder().setElementList( - defaultList))) - .build(); - mPietSharedStates.add(pietSharedState); - MediaQueryHelper mediaQueryHelper = new MediaQueryHelper( - FRAME_WIDTH, adapterParameters.mHostProviders.getAssetProvider(), mContext); - PietStylesHelper stylesHelper = - adapterParameters.mPietStylesHelperFactory.get(mPietSharedStates, mediaQueryHelper); - FrameContext frameContext = FrameContext.createFrameContext( - Frame.newBuilder().setStylesheets(Stylesheets.getDefaultInstance()).build(), - mPietSharedStates, stylesHelper, mDebugBehavior, new DebugLogger(), mActionHandler, - new HostProviders( - mAssetProvider, mCustomElementProvider, new HostBindingProvider(), null), - new FrameLayout(mContext)); - - mFrameAdapter = new FrameAdapterImpl( - mContext, adapterParameters, mActionHandler, mEventLogger, mDebugBehavior); - - Content content = Content.newBuilder() - .setElement(Element.newBuilder().setElementList(defaultList)) - .build(); - - List<ElementAdapter<?, ?>> viewAdapters = - mFrameAdapter.getBoundAdaptersForContent(content, frameContext); - assertThat(viewAdapters).hasSize(1); - ElementAdapter<?, ?> viewAdapter = viewAdapters.get(0); - assertThat(viewAdapter.getModel()).isEqualTo(content.getElement().getElementList()); - mFrameAdapter.bindModel(Frame.newBuilder().addContents(content).build(), FRAME_WIDTH, null, - mPietSharedStates); - assertThat(frameContext.getDebugLogger().getMessages(MessageType.ERROR)).isEmpty(); - mFrameAdapter.unbindModel(); - - content = Content.newBuilder() - .setTemplateInvocation( - TemplateInvocation.newBuilder() - .setTemplateId(templateId) - .addBindingContexts(BindingContext.getDefaultInstance())) - .build(); - viewAdapters = mFrameAdapter.getBoundAdaptersForContent(content, frameContext); - assertThat(viewAdapters).hasSize(1); - viewAdapter = viewAdapters.get(0); - assertThat(viewAdapter.getModel()).isEqualTo(defaultList); - mFrameAdapter.bindModel(Frame.newBuilder().addContents(content).build(), FRAME_WIDTH, null, - mPietSharedStates); - assertThat(frameContext.getDebugLogger().getMessages(MessageType.ERROR)).isEmpty(); - mFrameAdapter.unbindModel(); - } - - /** - * This test sets up all real objects to ensure that real adapters are bound and unbound, etc. - */ - @Test - public void testBindAndUnbind_resetsStylesWhenWrapperViewIsAdded() { - AdapterParameters adapterParameters = - new AdapterParameters(mContext, Suppliers.of(new LinearLayout(mContext)), - mHostProviders, new FakeClock(), false, false); - PietSharedState pietSharedState = - PietSharedState.newBuilder() - .addStylesheets( - Stylesheet.newBuilder() - .setStylesheetId("stylesheet") - // clang-format off - .addStyles( - Style.newBuilder() - .setStyleId("style1") - .setBackground(Fill.newBuilder().setColor( - 0x11111111)) - .setPadding(EdgeWidths.newBuilder() - .setStart(1) - .setTop(1)) - .setMargins(EdgeWidths.newBuilder() - .setStart(1) - .setTop(1)) - .setColor(0x11111111) - .setHeight(1) - .setWidth(1) - .setShadow( - Shadow.newBuilder() - .setElevationShadow( - ElevationShadow - .newBuilder() - .setElevation( - 1))) - .setOpacity(0.5f) - .setGravityHorizontal( - GravityHorizontal.GRAVITY_START) - .setGravityVertical( - GravityVertical.GRAVITY_BOTTOM)) - .addStyles( - Style.newBuilder() - .setStyleId("style2") - .setBackground(Fill.newBuilder().setColor( - 0x22222222)) - .setPadding(EdgeWidths.newBuilder() - .setEnd(2) - .setTop(2)) - .setMargins(EdgeWidths.newBuilder() - .setEnd(2) - .setTop(2)) - .setColor(0x222222) - .setHeight(2) - .setWidth(2) - .setShadow( - Shadow.newBuilder() - .setElevationShadow( - ElevationShadow - .newBuilder() - .setElevation( - 2))) - .setOpacity(0.25f) - // Rounded corners will introduce an - // overlay. - .setRoundedCorners( - RoundedCorners.newBuilder() - .setRadiusDp(2) - .setBitmask(2)) - .setGravityHorizontal( - GravityHorizontal.GRAVITY_END))) - // clang-format on - .build(); - mPietSharedStates.add(pietSharedState); - - mFrameAdapter = new FrameAdapterImpl( - mContext, adapterParameters, mActionHandler, mEventLogger, mDebugBehavior); - - ImageElement defaultImage = - ImageElement.newBuilder().setImage(Image.getDefaultInstance()).build(); - Content content1 = - Content.newBuilder() - .setElement(Element.newBuilder().setElementList( - ElementList.newBuilder().addContents( - Content.newBuilder().setElement( - Element.newBuilder() - .setStyleReferences( - StyleIdsStack.newBuilder() - .addStyleIds("style1")) - .setImageElement(defaultImage))))) - .build(); - Content content2 = - Content.newBuilder() - .setElement(Element.newBuilder().setElementList( - ElementList.newBuilder().addContents( - Content.newBuilder().setElement( - Element.newBuilder() - .setStyleReferences( - StyleIdsStack.newBuilder() - .addStyleIds("style2")) - .setImageElement(defaultImage))))) - .build(); - - // Bind to a Frame with no wrapper view - mFrameAdapter.bindModel( - Frame.newBuilder() - .setStylesheets(Stylesheets.newBuilder().addStylesheetIds("stylesheet")) - .addContents(content1) - .build(), - 0, null, mPietSharedStates); - - ImageView imageView = - (ImageView) ((LinearLayout) mFrameAdapter.getView().getChildAt(0)).getChildAt(0); - LinearLayout.LayoutParams imageViewParams = - (LinearLayout.LayoutParams) imageView.getLayoutParams(); - assertThat(imageViewParams.leftMargin).isEqualTo(1); - assertThat(imageViewParams.topMargin).isEqualTo(1); - assertThat(imageViewParams.rightMargin).isEqualTo(0); - assertThat(imageViewParams.bottomMargin).isEqualTo(0); - assertThat(imageView.getPaddingStart()).isEqualTo(1); - assertThat(imageView.getPaddingTop()).isEqualTo(1); - assertThat(imageView.getPaddingEnd()).isEqualTo(0); - assertThat(imageView.getPaddingBottom()).isEqualTo(0); - assertThat(imageViewParams.height).isEqualTo(1); - assertThat(imageViewParams.width).isEqualTo(1); - assertThat(imageView.getElevation()).isWithin(0.1f).of(1); - assertThat(imageView.getAlpha()).isWithin(0.1f).of(0.5f); - - mFrameAdapter.unbindModel(); - - // Re-bind to a Frame with a wrapper view - // This will recycle the ImageView, but it will be within a wrapper view. - // Ensure that the properties on the ImageView get unset correctly. - mFrameAdapter.bindModel( - Frame.newBuilder() - .setStylesheets(Stylesheets.newBuilder().addStylesheetIds("stylesheet")) - .addContents(content2) - .build(), - 0, null, Collections.singletonList(pietSharedState)); - - FrameLayout wrapperView = - (FrameLayout) ((LinearLayout) mFrameAdapter.getView().getChildAt(0)).getChildAt(0); - LinearLayout.LayoutParams wrapperViewParams = - (LinearLayout.LayoutParams) wrapperView.getLayoutParams(); - - // Exactly one of the wrapper view and the image view have the specified params set. - assertThat(wrapperViewParams.leftMargin).isEqualTo(0); - assertThat(wrapperViewParams.topMargin).isEqualTo(2); - assertThat(wrapperViewParams.rightMargin).isEqualTo(2); - assertThat(wrapperViewParams.bottomMargin).isEqualTo(0); - assertThat(wrapperView.getPaddingStart()).isEqualTo(0); - assertThat(wrapperView.getPaddingTop()).isEqualTo(0); - assertThat(wrapperView.getPaddingEnd()).isEqualTo(0); - assertThat(wrapperView.getPaddingBottom()).isEqualTo(0); - assertThat(wrapperViewParams.height).isEqualTo(2); - assertThat(wrapperViewParams.width).isEqualTo(2); - assertThat(wrapperView.getElevation()).isWithin(0.1f).of(2); - assertThat(wrapperView.getAlpha()).isWithin(0.1f).of(1.0f); - - assertThat(wrapperView.getChildAt(0)).isSameInstanceAs(imageView); - FrameLayout.LayoutParams newImageViewParams = - (FrameLayout.LayoutParams) imageView.getLayoutParams(); - assertThat(newImageViewParams.leftMargin).isEqualTo(0); - assertThat(newImageViewParams.topMargin).isEqualTo(0); - assertThat(newImageViewParams.rightMargin).isEqualTo(0); - assertThat(newImageViewParams.bottomMargin).isEqualTo(0); - assertThat(imageView.getPaddingStart()).isEqualTo(0); - assertThat(imageView.getPaddingTop()).isEqualTo(2); - assertThat(imageView.getPaddingEnd()).isEqualTo(2); - assertThat(imageView.getPaddingBottom()).isEqualTo(0); - assertThat(newImageViewParams.height).isEqualTo(LayoutParams.MATCH_PARENT); - assertThat(newImageViewParams.width).isEqualTo(LayoutParams.MATCH_PARENT); - assertThat(imageView.getElevation()).isWithin(0.1f).of(0); - assertThat(imageView.getAlpha()).isWithin(0.1f).of(0.25f); - } - - @Test - public void testBindModel_defaultDimensions() { - Frame frame = Frame.newBuilder().addContents(DEFAULT_CONTENT).build(); - when(mElementAdapter.getComputedWidthPx()).thenReturn(StyleProvider.DIMENSION_NOT_SET); - when(mElementAdapter.getComputedHeightPx()).thenReturn(StyleProvider.DIMENSION_NOT_SET); - - mFrameAdapter.bindModel(frame, FRAME_WIDTH, (ShardingControl) null, mPietSharedStates); - - assertThat(mFrameAdapter.getView().getChildCount()).isEqualTo(1); - - verify(mElementAdapter).setLayoutParams(mLayoutParamsCaptor.capture()); - assertThat(mLayoutParamsCaptor.getValue().width).isEqualTo(LayoutParams.MATCH_PARENT); - assertThat(mLayoutParamsCaptor.getValue().height).isEqualTo(LayoutParams.WRAP_CONTENT); - } - - @Test - public void testBindModel_explicitDimensions() { - Frame frame = Frame.newBuilder().addContents(DEFAULT_CONTENT).build(); - int width = 123; - int height = 456; - when(mElementAdapter.getComputedWidthPx()).thenReturn(width); - when(mElementAdapter.getComputedHeightPx()).thenReturn(height); - - mFrameAdapter.bindModel(frame, FRAME_WIDTH, (ShardingControl) null, mPietSharedStates); - - assertThat(mFrameAdapter.getView().getChildCount()).isEqualTo(1); - - verify(mElementAdapter).setLayoutParams(mLayoutParamsCaptor.capture()); - assertThat(mLayoutParamsCaptor.getValue().width).isEqualTo(width); - assertThat(mLayoutParamsCaptor.getValue().height).isEqualTo(height); - } - - @Test - public void testBindModel_gravity() { - Frame frame = Frame.newBuilder().addContents(DEFAULT_CONTENT).build(); - when(mElementAdapter.getHorizontalGravity(anyInt())).thenReturn(Gravity.CENTER_HORIZONTAL); - when(mElementAdapter.getVerticalGravity(anyInt())).thenReturn(Gravity.BOTTOM); - when(mElementAdapter.getGravity(anyInt())) - .thenReturn(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM); - - mFrameAdapter.bindModel(frame, FRAME_WIDTH, (ShardingControl) null, mPietSharedStates); - - verify(mElementAdapter).setLayoutParams(mLayoutParamsCaptor.capture()); - assertThat(((LinearLayout.LayoutParams) mLayoutParamsCaptor.getValue()).gravity) - .isEqualTo(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM); - } - - @Test - public void testCreateFrameContext_recyclesPietStylesHelper() { - AdapterParameters adapterParameters = - new AdapterParameters(mContext, Suppliers.of(new LinearLayout(mContext)), - mHostProviders, new FakeClock(), false, false); - PietSharedState pietSharedState = PietSharedState.newBuilder() - .addStylesheets(Stylesheet.newBuilder().addStyles( - Style.newBuilder().setStyleId("style"))) - .build(); - mPietSharedStates.add(pietSharedState); - FrameAdapterImpl frameAdapter = new FrameAdapterImpl( - mContext, adapterParameters, mActionHandler, mEventLogger, mDebugBehavior); - - FrameContext frameContext1 = - frameAdapter.createFrameContext(Frame.newBuilder().setTag("frame1").build(), - FRAME_WIDTH, mPietSharedStates, frameAdapter.getView()); - FrameContext frameContext2 = - frameAdapter.createFrameContext(Frame.newBuilder().setTag("frame2").build(), - FRAME_WIDTH, mPietSharedStates, frameAdapter.getView()); - FrameContext frameContext3 = - frameAdapter.createFrameContext(Frame.newBuilder().setTag("frame3").build(), - FRAME_WIDTH + 1, mPietSharedStates, frameAdapter.getView()); - - // These should both pull the same object from the cache. - assertThat(frameContext1.mStyleshelper).isSameInstanceAs(frameContext2.mStyleshelper); - - // This one is different because of the different frame width. - assertThat(frameContext1.mStyleshelper).isNotEqualTo(frameContext3.mStyleshelper); - } - - @Test - public void testAdapterWithActions() { - String templateId = "lights-camera"; - String actionBindingId = "action"; - ActionsBindingRef actionBinding = - ActionsBindingRef.newBuilder().setBindingId(actionBindingId).build(); - Template templateWithActions = - Template.newBuilder() - .setTemplateId(templateId) - .setElement(Element.newBuilder() - .setActionsBinding(actionBinding) - .setElementList(ElementList.getDefaultInstance())) - .build(); - BindingValue actionBindingValue = BindingValue.newBuilder() - .setBindingId(actionBindingId) - .setActions(Actions.newBuilder().setOnClickAction( - Action.getDefaultInstance())) - .build(); - Content content = - Content.newBuilder() - .setTemplateInvocation( - TemplateInvocation.newBuilder() - .setTemplateId(templateId) - .addBindingContexts( - BindingContext.newBuilder().addBindingValues( - actionBindingValue))) - .build(); - Frame frame = Frame.newBuilder().addContents(content).build(); - PietSharedState pietSharedState = - PietSharedState.newBuilder().addTemplates(templateWithActions).build(); - - mPietSharedStates.add(pietSharedState); - - AdapterParameters parameters = new AdapterParameters( - mContext, Suppliers.of(null), mHostProviders, new FakeClock(), false, false); - FrameAdapterImpl frameAdapter = new FrameAdapterImpl( - mContext, parameters, mActionHandler, mEventLogger, mDebugBehavior); - - frameAdapter.bindModel(frame, FRAME_WIDTH, null, mPietSharedStates); - - assertThat(frameAdapter.getFrameContainer().getChildCount()).isEqualTo(1); - assertThat(frameAdapter.getFrameContainer().getChildAt(0).hasOnClickListeners()).isTrue(); - } - - @Test - public void testBackgroundColor() { - Frame frame = Frame.newBuilder().addContents(DEFAULT_CONTENT).build(); - mFrameAdapter.bindModel(frame, FRAME_WIDTH, (ShardingControl) null, mPietSharedStates); - mStyleProvider.createBackground(); - } - - @Test - public void testUnsetBackgroundIfNotDefined() { - Frame frame = Frame.newBuilder().addContents(DEFAULT_CONTENT).build(); - when(mFrameContext.getFrame()).thenReturn(frame); - - // Set background - when(mStyleProvider.createBackground()).thenReturn(new ColorDrawable(12345)); - mFrameAdapter.bindModel(frame, FRAME_WIDTH, (ShardingControl) null, mPietSharedStates); - assertThat(mFrameAdapter.getView().getBackground()).isNotNull(); - mFrameAdapter.unbindModel(); - - // Re-bind and check that background is unset - when(mStyleProvider.createBackground()).thenReturn(null); - mFrameAdapter.bindModel(frame, FRAME_WIDTH, (ShardingControl) null, mPietSharedStates); - assertThat(mFrameAdapter.getView().getBackground()).isNull(); - } - - @Test - public void testUnsetBackgroundIfCreateBackgroundFails() { - Frame frame = Frame.newBuilder().addContents(DEFAULT_CONTENT).build(); - when(mFrameContext.getFrame()).thenReturn(frame); - - // Set background - when(mStyleProvider.createBackground()).thenReturn(new ColorDrawable(12345)); - mFrameAdapter.bindModel(frame, FRAME_WIDTH, (ShardingControl) null, mPietSharedStates); - assertThat(mFrameAdapter.getView().getBackground()).isNotNull(); - mFrameAdapter.unbindModel(); - - // Re-bind and check that background is unset - when(mStyleProvider.createBackground()).thenReturn(null); - mFrameAdapter.bindModel(frame, FRAME_WIDTH, (ShardingControl) null, mPietSharedStates); - assertThat(mFrameAdapter.getView().getBackground()).isNull(); - } - - @Test - public void testRecycling_inlineSlice() { - Element element = - Element.newBuilder().setElementList(ElementList.getDefaultInstance()).build(); - Frame inlineSliceFrame = - Frame.newBuilder().addContents(Content.newBuilder().setElement(element)).build(); - when(mFrameContext.getFrame()).thenReturn(inlineSliceFrame); - - mFrameAdapter.bindModel( - inlineSliceFrame, FRAME_WIDTH, (ShardingControl) null, mPietSharedStates); - verify(mAdapterFactory).createAdapterForElement(element, mFrameContext); - verify(mElementAdapter).bindModel(element, mFrameContext); - - mFrameAdapter.unbindModel(); - verify(mAdapterFactory).releaseAdapter(mElementAdapter); - } - - @Test - public void testRecycling_templateSlice() { - String templateId = "bread"; - Template template = Template.newBuilder().setTemplateId(templateId).build(); - when(mFrameContext.getTemplate(templateId)).thenReturn(template); - BindingContext bindingContext = - BindingContext.newBuilder() - .addBindingValues(BindingValue.newBuilder().setBindingId("grain")) - .build(); - TemplateInvocation templateSlice = TemplateInvocation.newBuilder() - .setTemplateId(templateId) - .addBindingContexts(bindingContext) - .build(); - Frame templateSliceFrame = - Frame.newBuilder() - .addContents(Content.newBuilder().setTemplateInvocation(templateSlice)) - .build(); - when(mFrameContext.getFrame()).thenReturn(templateSliceFrame); - mFrameAdapter.bindModel( - templateSliceFrame, FRAME_WIDTH, (ShardingControl) null, mPietSharedStates); - TemplateAdapterModel model = new TemplateAdapterModel(template, bindingContext); - verify(mTemplateBinder).createAndBindTemplateAdapter(model, mFrameContext); - - mFrameAdapter.unbindModel(); - verify(mAdapterFactory).releaseAdapter(mTemplateAdapter); - } - - @Test - public void testErrorViewReporting() { - View warningView = new View(mContext); - View errorView = new View(mContext); - when(mDebugLogger.getReportView(MessageType.WARNING, mContext)).thenReturn(warningView); - when(mDebugLogger.getReportView(MessageType.ERROR, mContext)).thenReturn(errorView); - - Frame frame = Frame.newBuilder().addContents(DEFAULT_CONTENT).build(); - when(mFrameContext.getFrame()).thenReturn(frame); - - // Errors silenced by debug behavior - when(mFrameContext.getDebugBehavior()).thenReturn(DebugBehavior.SILENT); - mFrameAdapter.bindModel(frame, FRAME_WIDTH, (ShardingControl) null, mPietSharedStates); - - assertThat(mFrameAdapter.getView().getChildCount()).isEqualTo(1); - verify(mDebugLogger, never()).getReportView(anyInt(), any()); - - mFrameAdapter.unbindModel(); - - // Errors displayed in extra views - when(mFrameContext.getDebugBehavior()).thenReturn(DebugBehavior.VERBOSE); - mFrameAdapter.bindModel(frame, FRAME_WIDTH, (ShardingControl) null, mPietSharedStates); - - assertThat(mFrameAdapter.getView().getChildCount()).isEqualTo(3); - assertThat(mFrameAdapter.getView().getChildAt(1)).isSameInstanceAs(errorView); - assertThat(mFrameAdapter.getView().getChildAt(2)).isSameInstanceAs(warningView); - - mFrameAdapter.unbindModel(); - - // No errors - when(mDebugLogger.getReportView(MessageType.WARNING, mContext)).thenReturn(null); - when(mDebugLogger.getReportView(MessageType.ERROR, mContext)).thenReturn(null); - - mFrameAdapter.bindModel(frame, FRAME_WIDTH, (ShardingControl) null, mPietSharedStates); - - assertThat(mFrameAdapter.getView().getChildCount()).isEqualTo(1); - } - - @Test - public void testEventLoggerReporting() { - List<ErrorCode> errorCodes = new ArrayList<>(); - errorCodes.add(ErrorCode.ERR_DUPLICATE_STYLE); - errorCodes.add(ErrorCode.ERR_POOR_FRAME_RATE); - when(mDebugLogger.getErrorCodes()).thenReturn(errorCodes); - - Frame frame = Frame.newBuilder().addContents(DEFAULT_CONTENT).build(); - - mFrameAdapter.bindModel(frame, FRAME_WIDTH, (ShardingControl) null, mPietSharedStates); - - verify(mEventLogger).logEvents(errorCodes); - } - - @Test - public void testEventLoggerReporting_withFatalError() { - List<ErrorCode> errorCodes = new ArrayList<>(); - errorCodes.add(ErrorCode.ERR_DUPLICATE_STYLE); - errorCodes.add(ErrorCode.ERR_POOR_FRAME_RATE); - when(mDebugLogger.getErrorCodes()).thenReturn(errorCodes); - - when(mFrameContext.makeStyleFor(any())) - .thenThrow(new PietFatalException(ErrorCode.ERR_UNSPECIFIED, "test exception")); - - Frame frame = Frame.newBuilder().addContents(DEFAULT_CONTENT).build(); - - mFrameAdapter.bindModel(frame, FRAME_WIDTH, (ShardingControl) null, mPietSharedStates); - - verify(mFrameContext).makeStyleFor(any()); // Ensure an exception was thrown - verify(mEventLogger).logEvents(errorCodes); - } - - @Test - public void testUnbindTriggersHideActions() { - Action frameHideAction = Action.newBuilder().build(); - Action elementHideAction = Action.newBuilder().build(); - Frame frameWithNoActions = Frame.newBuilder() - .addContents(Content.newBuilder().setElement( - Element.newBuilder().setElementStack( - ElementStack.getDefaultInstance()))) - .build(); - Frame frameWithActions = - Frame.newBuilder() - .setActions(Actions.newBuilder().addOnHideActions( - VisibilityAction.newBuilder().setAction(frameHideAction))) - .addContents(Content.newBuilder().setElement( - Element.newBuilder() - .setActions(Actions.newBuilder().addOnHideActions( - VisibilityAction.newBuilder().setAction( - elementHideAction))) - .setElementStack(ElementStack.getDefaultInstance()))) - .build(); - - // Bind to a frame with no actions so the onHide actions don't get added to activeActions - when(mFrameContext.getFrame()).thenReturn(frameWithNoActions); - mFrameAdapter.bindModel( - frameWithNoActions, FRAME_WIDTH, (ShardingControl) null, mPietSharedStates); - - when(mFrameContext.getFrame()).thenReturn(frameWithActions); - when(mFrameContext.getActionHandler()).thenReturn(mActionHandler); - mFrameAdapter.unbindModel(); - - verify(mActionHandler) - .handleAction(same(frameHideAction), eq(ActionType.VIEW), eq(frameWithActions), - any(View.class), eq(LogData.getDefaultInstance())); - verify(mElementAdapter).triggerHideActions(mFrameContext); - } - - @Test - public void testBindModel_callsOnBindLogDataCallback() { - Frame frame = - Frame.newBuilder().addContents(DEFAULT_CONTENT).setLogData(mLogDataTest).build(); - when(mFrameContext.getFrame()).thenReturn(frame); - mFrameAdapter.bindModel(frame, FRAME_WIDTH, (ShardingControl) null, mPietSharedStates); - - assertThat(mCallbackBound).isTrue(); - } - - @Test - public void testUnbindModel_callsOnBindLogDataCallback() { - Frame frame = - Frame.newBuilder().addContents(DEFAULT_CONTENT).setLogData(mLogDataTest).build(); - when(mFrameContext.getFrame()).thenReturn(frame); - mFrameAdapter.bindModel(frame, FRAME_WIDTH, (ShardingControl) null, mPietSharedStates); - - when(mFrameContext.getActionHandler()).thenReturn(mActionHandler); - mFrameAdapter.unbindModel(); - assertThat(mCallbackUnbound).isTrue(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/FrameContextTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/FrameContextTest.java deleted file mode 100644 index 5bf77c22..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/FrameContextTest.java +++ /dev/null
@@ -1,1313 +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. - -package org.chromium.chrome.browser.feed.library.piet; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import static org.chromium.chrome.browser.feed.library.common.testing.RunnableSubject.assertThatRunnable; - -import android.app.Activity; -import android.content.Context; -import android.widget.FrameLayout; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.config.DebugBehavior; -import org.chromium.chrome.browser.feed.library.common.ui.LayoutUtils; -import org.chromium.chrome.browser.feed.library.piet.DebugLogger.MessageType; -import org.chromium.chrome.browser.feed.library.piet.PietStylesHelper.PietStylesHelperFactory; -import org.chromium.chrome.browser.feed.library.piet.host.ActionHandler; -import org.chromium.chrome.browser.feed.library.piet.host.AssetProvider; -import org.chromium.chrome.browser.feed.library.piet.host.CustomElementProvider; -import org.chromium.chrome.browser.feed.library.piet.host.HostBindingProvider; -import org.chromium.components.feed.core.proto.ui.piet.ActionsProto.Actions; -import org.chromium.components.feed.core.proto.ui.piet.BindingRefsProto.ActionsBindingRef; -import org.chromium.components.feed.core.proto.ui.piet.BindingRefsProto.ChunkedTextBindingRef; -import org.chromium.components.feed.core.proto.ui.piet.BindingRefsProto.CustomBindingRef; -import org.chromium.components.feed.core.proto.ui.piet.BindingRefsProto.ElementBindingRef; -import org.chromium.components.feed.core.proto.ui.piet.BindingRefsProto.GridCellWidthBindingRef; -import org.chromium.components.feed.core.proto.ui.piet.BindingRefsProto.ImageBindingRef; -import org.chromium.components.feed.core.proto.ui.piet.BindingRefsProto.LogDataBindingRef; -import org.chromium.components.feed.core.proto.ui.piet.BindingRefsProto.ParameterizedTextBindingRef; -import org.chromium.components.feed.core.proto.ui.piet.BindingRefsProto.StyleBindingRef; -import org.chromium.components.feed.core.proto.ui.piet.BindingRefsProto.TemplateBindingRef; -import org.chromium.components.feed.core.proto.ui.piet.BindingRefsProto.VisibilityBindingRef; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.BindingContext; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.BindingValue; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.CustomElementData; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.Element; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.GridCellWidth; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.HostBindingData; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.TemplateInvocation; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.TextElement; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.Visibility; -import org.chromium.components.feed.core.proto.ui.piet.GradientsProto.ColorStop; -import org.chromium.components.feed.core.proto.ui.piet.GradientsProto.Fill; -import org.chromium.components.feed.core.proto.ui.piet.GradientsProto.LinearGradient; -import org.chromium.components.feed.core.proto.ui.piet.ImagesProto.Image; -import org.chromium.components.feed.core.proto.ui.piet.ImagesProto.ImageSource; -import org.chromium.components.feed.core.proto.ui.piet.LogDataProto.LogData; -import org.chromium.components.feed.core.proto.ui.piet.MediaQueriesProto.ComparisonCondition; -import org.chromium.components.feed.core.proto.ui.piet.MediaQueriesProto.DarkLightCondition; -import org.chromium.components.feed.core.proto.ui.piet.MediaQueriesProto.DarkLightCondition.DarkLightMode; -import org.chromium.components.feed.core.proto.ui.piet.MediaQueriesProto.FrameWidthCondition; -import org.chromium.components.feed.core.proto.ui.piet.MediaQueriesProto.MediaQueryCondition; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.Frame; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.PietSharedState; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.Stylesheet; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.Stylesheets; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.Template; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.BoundStyle; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.Font; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.Style; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.StyleIdsStack; -import org.chromium.components.feed.core.proto.ui.piet.TextProto.Chunk; -import org.chromium.components.feed.core.proto.ui.piet.TextProto.ChunkedText; -import org.chromium.components.feed.core.proto.ui.piet.TextProto.ParameterizedText; -import org.chromium.components.feed.core.proto.ui.piet.TextProto.StyledTextChunk; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** Tests of the {@link FrameContext}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class FrameContextTest { - private static final String DEFAULT_TEMPLATE_ID = "TEMPLATE_ID"; - private static final Template DEFAULT_TEMPLATE = - Template.newBuilder().setTemplateId(DEFAULT_TEMPLATE_ID).build(); - private static final Frame DEFAULT_FRAME = - Frame.newBuilder().addTemplates(DEFAULT_TEMPLATE).build(); - private static final String SAMPLE_STYLE_ID = "STYLE_ID"; - private static final int BASE_STYLE_COLOR = 111111; - private static final int SAMPLE_STYLE_COLOR = 888888; - private static final Style SAMPLE_STYLE = - Style.newBuilder().setStyleId(SAMPLE_STYLE_ID).setColor(SAMPLE_STYLE_COLOR).build(); - private static final String STYLESHEET_ID = "STYLESHEET_ID"; - private static final Style BASE_STYLE = Style.newBuilder().setColor(BASE_STYLE_COLOR).build(); - private static final StyleIdsStack SAMPLE_STYLE_IDS = - StyleIdsStack.newBuilder().addStyleIds(SAMPLE_STYLE_ID).build(); - private static final String BINDING_ID = "BINDING_ID"; - private static final String INVALID_BINDING_ID = "NOT_A_REAL_BINDING_ID"; - private static final Map<String, Template> DEFAULT_TEMPLATES = new HashMap<>(); - private static final int FRAME_WIDTH_PX = 999999; - - static { - DEFAULT_TEMPLATES.put(DEFAULT_TEMPLATE_ID, DEFAULT_TEMPLATE); - } - - @Mock - private ActionHandler mActionHandler; - @Mock - private AssetProvider mAssetProvider; - - private final Map<String, Style> mDefaultStylesheet = new HashMap<>(); - private final DebugLogger mDebugLogger = new DebugLogger(); - - private HostBindingProvider mHostBindingProvider; - private HostProviders mHostProviders; - private FrameContext mFrameContext; - private List<PietSharedState> mPietSharedStates; - private PietStylesHelper mPietStylesHelper; - private StyleProvider mDefaultStyleProvider; - private Context mContext; - private FrameLayout mFrameView; - - @Before - public void setUp() throws Exception { - initMocks(this); - - mContext = Robolectric.buildActivity(Activity.class).get(); - mHostBindingProvider = new HostBindingProvider(); - mHostProviders = new HostProviders( - mAssetProvider, mock(CustomElementProvider.class), mHostBindingProvider, null); - mDefaultStyleProvider = new StyleProvider(mAssetProvider); - - mDefaultStylesheet.put(SAMPLE_STYLE_ID, SAMPLE_STYLE); - mPietSharedStates = new ArrayList<>(); - mPietStylesHelper = newPietStylesHelper(); - - mFrameView = new FrameLayout(mContext); - } - - @Test - public void testSharedStateTemplatesAddedToFrame() { - String sharedStateTemplateId = "SHARED_STATE_TEMPLATE_ID"; - Template sharedStateTemplate = - Template.newBuilder().setTemplateId(sharedStateTemplateId).build(); - mPietSharedStates.add( - PietSharedState.newBuilder().addTemplates(sharedStateTemplate).build()); - mFrameContext = defaultFrameContext(); - - assertThat(mFrameContext.getTemplate(sharedStateTemplateId)) - .isSameInstanceAs(sharedStateTemplate); - assertThat(mFrameContext.getTemplate(DEFAULT_TEMPLATE_ID)) - .isSameInstanceAs(DEFAULT_TEMPLATE); - } - - @Test - public void testThrowsIfSharedStateTemplatesConflictWithFrameTemplates() { - Template sharedStateTemplate = - Template.newBuilder().setTemplateId(DEFAULT_TEMPLATE_ID).build(); - mPietSharedStates.add( - PietSharedState.newBuilder().addTemplates(sharedStateTemplate).build()); - assertThatRunnable(this::defaultFrameContext) - .throwsAnExceptionOfType(IllegalArgumentException.class) - .that() - .hasMessageThat() - .contains("Template key 'TEMPLATE_ID' already defined"); - } - - @Test - public void testThrowsIfDuplicateBindingValueId() { - mFrameContext = defaultFrameContext(); - BindingContext bindingContextWithDuplicateIds = - BindingContext.newBuilder() - .addBindingValues(BindingValue.newBuilder().setBindingId(BINDING_ID)) - .addBindingValues(BindingValue.newBuilder().setBindingId(BINDING_ID)) - .build(); - assertThatRunnable(() - -> mFrameContext.createTemplateContext( - DEFAULT_TEMPLATE, bindingContextWithDuplicateIds)) - .throwsAnExceptionOfType(IllegalArgumentException.class) - .that() - .hasMessageThat() - .contains("BindingValue key 'BINDING_ID' already defined"); - } - - @Test - public void testGetters() { - String template2BindingId = "TEMPLATE_2"; - Template template2 = Template.newBuilder().setTemplateId(template2BindingId).build(); - PietSharedState sharedState = PietSharedState.newBuilder().addTemplates(template2).build(); - mPietSharedStates.add(sharedState); - mFrameContext = new FrameContext(DEFAULT_FRAME, mDefaultStylesheet, mPietSharedStates, - newPietStylesHelper(), DebugBehavior.VERBOSE, mDebugLogger, mActionHandler, - mHostProviders, mFrameView); - - assertThat(mFrameContext.getFrame()).isEqualTo(DEFAULT_FRAME); - assertThat(mFrameContext.getActionHandler()).isEqualTo(mActionHandler); - - assertThat(mFrameContext.getTemplate(DEFAULT_TEMPLATE_ID)).isEqualTo(DEFAULT_TEMPLATE); - assertThat(mFrameContext.getTemplate(template2BindingId)).isEqualTo(template2); - } - - @Test - public void testThrowsWithNoBindingContext() { - mFrameContext = makeFrameContextForDefaultFrame(); - - assertThatRunnable( - () -> mFrameContext.getActionsFromBinding(ActionsBindingRef.getDefaultInstance())) - .throwsAnExceptionOfType(IllegalArgumentException.class) - .that() - .hasMessageThat() - .contains("no BindingValues defined"); - } - - @Test - public void testCreateTemplateContext_lotsOfStuff() { - mFrameContext = defaultFrameContext(); - - // createTemplateContext should add new BindingValues - ParameterizedText text = ParameterizedText.newBuilder().setText("Calico").build(); - BindingValue textBinding = BindingValue.newBuilder() - .setBindingId(BINDING_ID) - .setParameterizedText(text) - .build(); - FrameContext frameContextWithBindings = - mFrameContext.createTemplateContext(DEFAULT_TEMPLATE, - BindingContext.newBuilder().addBindingValues(textBinding).build()); - assertThat( - frameContextWithBindings - .getParameterizedTextBindingValue(ParameterizedTextBindingRef.newBuilder() - .setBindingId(BINDING_ID) - .build()) - .getParameterizedText()) - .isEqualTo(text); - - // and clear out all the previous styles - assertThat(frameContextWithBindings.makeStyleFor(StyleIdsStack.getDefaultInstance())) - .isEqualTo(mDefaultStyleProvider); - assertThat(frameContextWithBindings.makeStyleFor(SAMPLE_STYLE_IDS).getColor()) - .isEqualTo(mDefaultStyleProvider.getColor()); - } - - @Test - public void testCreateTemplateContext_stylesheetId() { - String styleId = "cotton"; - int width = 343; - Style style = Style.newBuilder().setStyleId(styleId).setWidth(width).build(); - String stylesheetId = "linen"; - Stylesheet stylesheet = - Stylesheet.newBuilder().setStylesheetId(stylesheetId).addStyles(style).build(); - mPietSharedStates.add(PietSharedState.newBuilder().addStylesheets(stylesheet).build()); - mFrameContext = defaultFrameContext(); - - Template template = - Template.newBuilder() - .setTemplateId("kingSize") - .setStylesheets(Stylesheets.newBuilder().addStylesheetIds(stylesheetId)) - .build(); - - FrameContext templateContext = - mFrameContext.createTemplateContext(template, BindingContext.getDefaultInstance()); - - StyleIdsStack styleRef = StyleIdsStack.newBuilder().addStyleIds(styleId).build(); - assertThat(templateContext.makeStyleFor(styleRef).getWidthSpecPx(mContext)) - .isEqualTo((int) LayoutUtils.dpToPx(width, mContext)); - } - - @Test - public void testCreateTemplateContext_multipleStylesheets() { - String styleId = "cotton"; - int width = 343; - Style style = Style.newBuilder().setStyleId(styleId).setWidth(width).build(); - String stylesheetId = "linen"; - Stylesheet stylesheet = - Stylesheet.newBuilder().setStylesheetId(stylesheetId).addStyles(style).build(); - mPietSharedStates.add(PietSharedState.newBuilder().addStylesheets(stylesheet).build()); - mFrameContext = defaultFrameContext(); - int templateStyleColor = 343434; - String templateStyleId = "templateStyle"; - - Template template = - Template.newBuilder() - .setTemplateId("kingSize") - .setStylesheets(Stylesheets.newBuilder() - .addStylesheetIds(stylesheetId) - .addStylesheets(Stylesheet.newBuilder().addStyles( - Style.newBuilder() - .setStyleId(templateStyleId) - .setColor(templateStyleColor)))) - .build(); - - FrameContext templateContext = - mFrameContext.createTemplateContext(template, BindingContext.getDefaultInstance()); - - StyleIdsStack styleRef = StyleIdsStack.newBuilder().addStyleIds(styleId).build(); - assertThat(templateContext.makeStyleFor(styleRef).getWidthSpecPx(mContext)) - .isEqualTo((int) LayoutUtils.dpToPx(width, mContext)); - styleRef = StyleIdsStack.newBuilder().addStyleIds(templateStyleId).build(); - assertThat(templateContext.makeStyleFor(styleRef).getColor()).isEqualTo(templateStyleColor); - } - - @Test - public void testCreateTemplateContext_transcludingBinding() { - String parentBindingId = "PARENT"; - String childBindingId = "CHILD"; - ParameterizedText parentBoundText = - ParameterizedText.newBuilder().setText("parent_text").build(); - BindingValue parentBindingValue = BindingValue.newBuilder() - .setBindingId(parentBindingId) - .setParameterizedText(parentBoundText) - .build(); - ParameterizedTextBindingRef childTextBindingRef = - ParameterizedTextBindingRef.newBuilder().setBindingId(childBindingId).build(); - mFrameContext = makeFrameContextWithBinding(parentBindingValue); - FrameContext childContext = mFrameContext.createTemplateContext( - Template.newBuilder() - .setElement(Element.newBuilder().setTextElement( - TextElement.newBuilder().setParameterizedTextBinding( - childTextBindingRef))) - .build(), - BindingContext.newBuilder() - .addBindingValues( - BindingValue.newBuilder() - .setBindingId(childBindingId) - .setBindingIdFromTranscludingTemplate(parentBindingId)) - .build()); - - assertThat(childContext.getParameterizedTextBindingValue(childTextBindingRef)) - .isEqualTo(BindingValue.newBuilder() - .setBindingId(childBindingId) - .setParameterizedText(parentBoundText) - .build()); - } - - @Test - public void testCreateTemplateContext_transcludingBindingNotFound() { - String invalidParentBindingId = "NOT_FOUND"; - String childBindingId = "CHILD"; - ParameterizedTextBindingRef childTextBindingRef = - ParameterizedTextBindingRef.newBuilder().setBindingId(childBindingId).build(); - mFrameContext = makeFrameContextWithNoBindings(); - FrameContext childContext = mFrameContext.createTemplateContext( - Template.newBuilder() - .setElement(Element.newBuilder().setTextElement( - TextElement.newBuilder().setParameterizedTextBinding( - childTextBindingRef))) - .build(), - BindingContext.newBuilder() - .addBindingValues(BindingValue.newBuilder() - .setBindingId(childBindingId) - .setBindingIdFromTranscludingTemplate( - invalidParentBindingId)) - .build()); - - assertThat(mDebugLogger.getMessages(MessageType.ERROR)).isEmpty(); - assertThatRunnable(() -> childContext.getParameterizedTextBindingValue(childTextBindingRef)) - .throwsAnExceptionOfType(PietFatalException.class) - .that() - .hasMessageThat() - .contains("Parameterized text binding not found for CHILD"); - } - - @Test - public void testCreateTemplateContext_optionalTranscludingBindingNotFound() { - String invalidParentBindingId = "NOT_FOUND"; - String childBindingId = "CHILD"; - ParameterizedTextBindingRef childTextBindingRef = ParameterizedTextBindingRef.newBuilder() - .setBindingId(childBindingId) - .setIsOptional(true) - .build(); - mFrameContext = makeFrameContextWithNoBindings(); - FrameContext childContext = mFrameContext.createTemplateContext( - Template.newBuilder() - .setElement(Element.newBuilder().setTextElement( - TextElement.newBuilder().setParameterizedTextBinding( - childTextBindingRef))) - .build(), - BindingContext.newBuilder() - .addBindingValues(BindingValue.newBuilder() - .setBindingId(childBindingId) - .setBindingIdFromTranscludingTemplate( - invalidParentBindingId)) - .build()); - - assertThat(mDebugLogger.getMessages(MessageType.ERROR)).isEmpty(); - assertThat(childContext.getParameterizedTextBindingValue(childTextBindingRef)) - .isEqualTo(BindingValue.getDefaultInstance()); - } - - @Test - public void testMakeStyleFor() { - mFrameContext = defaultFrameContext(); - - // Returns base style provider if there are no styles defined - StyleProvider noStyle = mFrameContext.makeStyleFor(StyleIdsStack.getDefaultInstance()); - assertThat(noStyle).isEqualTo(mDefaultStyleProvider); - - // Successful lookup results in a new style provider - StyleProvider defaultStyle = mFrameContext.makeStyleFor(SAMPLE_STYLE_IDS); - assertThat(defaultStyle.getColor()).isEqualTo(SAMPLE_STYLE_COLOR); - - // Failed lookup returns the current style provider - StyleProvider notFoundStyle = mFrameContext.makeStyleFor( - StyleIdsStack.newBuilder().addStyleIds(INVALID_BINDING_ID).build()); - assertThat(notFoundStyle).isEqualTo(mDefaultStyleProvider); - } - - @Test - public void testGetText() { - ParameterizedText text = ParameterizedText.newBuilder().setText("tabby").build(); - BindingValue textBindingValue = defaultBinding().setParameterizedText(text).build(); - ParameterizedTextBindingRef textBindingRef = - ParameterizedTextBindingRef.newBuilder().setBindingId(BINDING_ID).build(); - - mFrameContext = makeFrameContextWithBinding(textBindingValue); - - // Succeed in looking up binding - assertThat(mFrameContext.getParameterizedTextBindingValue(textBindingRef)) - .isEqualTo(textBindingValue); - - // Can't look up binding - assertThatRunnable(() - -> mFrameContext.getParameterizedTextBindingValue( - ParameterizedTextBindingRef.newBuilder() - .setBindingId(INVALID_BINDING_ID) - .build())) - .throwsAnExceptionOfType(PietFatalException.class) - .that() - .hasMessageThat() - .contains("Parameterized text binding not found"); - - // Binding has no content - assertThatRunnable( - () - -> makeFrameContextWithNoBindings().getParameterizedTextBindingValue( - textBindingRef)) - .throwsAnExceptionOfType(PietFatalException.class) - .that() - .hasMessageThat() - .contains("Parameterized text binding not found"); - - // Binding is invalid but is optional - ParameterizedTextBindingRef textBindingRefInvalidOptional = - ParameterizedTextBindingRef.newBuilder() - .setBindingId(INVALID_BINDING_ID) - .setIsOptional(true) - .build(); - assertThat(makeFrameContextWithNoBindings().getParameterizedTextBindingValue( - textBindingRefInvalidOptional)) - .isEqualTo(BindingValue.getDefaultInstance()); - - // Binding has no content but is optional - ParameterizedTextBindingRef textBindingRefOptional = - ParameterizedTextBindingRef.newBuilder() - .setBindingId(BINDING_ID) - .setIsOptional(true) - .build(); - assertThat(makeFrameContextWithNoBindings().getParameterizedTextBindingValue( - textBindingRefOptional)) - .isEqualTo(BindingValue.getDefaultInstance()); - } - - @Test - public void testGetText_hostBinding() { - ParameterizedText text = ParameterizedText.newBuilder().setText("tabby").build(); - BindingValue textBindingValue = defaultBinding().setParameterizedText(text).build(); - BindingValue hostTextBindingValue = - defaultBinding() - .setHostBindingData(HostBindingData.newBuilder()) - .setParameterizedText(text) - .build(); - ParameterizedTextBindingRef textBindingRef = - ParameterizedTextBindingRef.newBuilder().setBindingId(BINDING_ID).build(); - - mFrameContext = makeFrameContextWithBinding(hostTextBindingValue); - - // Succeed in looking up binding - assertThat(mFrameContext.getParameterizedTextBindingValue(textBindingRef)) - .isEqualTo(textBindingValue); - } - - @Test - public void testGetImage() { - Image image = - Image.newBuilder().addSources(ImageSource.newBuilder().setUrl("myUrl")).build(); - BindingValue imageBindingValue = defaultBinding().setImage(image).build(); - ImageBindingRef imageBindingRef = - ImageBindingRef.newBuilder().setBindingId(BINDING_ID).build(); - - mFrameContext = makeFrameContextWithBinding(imageBindingValue); - - // Succeed in looking up binding - assertThat(mFrameContext.getImageBindingValue(imageBindingRef)) - .isEqualTo(imageBindingValue); - - // Can't look up binding - assertThatRunnable(() - -> mFrameContext.getImageBindingValue( - ImageBindingRef.newBuilder() - .setBindingId(INVALID_BINDING_ID) - .build())) - .throwsAnExceptionOfType(PietFatalException.class) - .that() - .hasMessageThat() - .contains("Image binding not found"); - - // Binding has no content - assertThatRunnable( - () -> makeFrameContextWithNoBindings().getImageBindingValue(imageBindingRef)) - .throwsAnExceptionOfType(PietFatalException.class) - .that() - .hasMessageThat() - .contains("Image binding not found"); - - // Binding is invalid but is optional - ImageBindingRef imageBindingRefInvalidOptional = ImageBindingRef.newBuilder() - .setBindingId(INVALID_BINDING_ID) - .setIsOptional(true) - .build(); - assertThat(makeFrameContextWithNoBindings().getImageBindingValue( - imageBindingRefInvalidOptional)) - .isEqualTo(BindingValue.getDefaultInstance()); - - // Binding has no content but is optional - ImageBindingRef imageBindingRefOptional = - ImageBindingRef.newBuilder().setBindingId(BINDING_ID).setIsOptional(true).build(); - assertThat(makeFrameContextWithNoBindings().getImageBindingValue(imageBindingRefOptional)) - .isEqualTo(BindingValue.getDefaultInstance()); - } - - @Test - public void testGetImage_hostBinding() { - Image image = - Image.newBuilder().addSources(ImageSource.newBuilder().setUrl("myUrl")).build(); - BindingValue imageBindingValue = defaultBinding().setImage(image).build(); - BindingValue hostImageBindingValue = - defaultBinding() - .setHostBindingData(HostBindingData.newBuilder()) - .setImage(image) - .build(); - ImageBindingRef imageBindingRef = - ImageBindingRef.newBuilder().setBindingId(BINDING_ID).build(); - - mFrameContext = makeFrameContextWithBinding(hostImageBindingValue); - - // Succeed in looking up binding - assertThat(mFrameContext.getImageBindingValue(imageBindingRef)) - .isEqualTo(imageBindingValue); - } - - @Test - public void testGetElement() { - Element element = Element.newBuilder() - .setStyleReferences(StyleIdsStack.newBuilder().addStyleIds("el")) - .build(); - BindingValue elementBindingValue = defaultBinding().setElement(element).build(); - ElementBindingRef elementBindingRef = - ElementBindingRef.newBuilder().setBindingId(BINDING_ID).build(); - - mFrameContext = makeFrameContextWithBinding(elementBindingValue); - - // Succeed in looking up binding - assertThat(mFrameContext.getElementBindingValue(elementBindingRef)) - .isEqualTo(elementBindingValue); - - // Can't look up binding - assertThatRunnable(() - -> mFrameContext.getElementBindingValue( - ElementBindingRef.newBuilder() - .setBindingId(INVALID_BINDING_ID) - .build())) - .throwsAnExceptionOfType(PietFatalException.class) - .that() - .hasMessageThat() - .contains("Element binding not found"); - - // Binding has no content - assertThatRunnable( - () -> makeFrameContextWithNoBindings().getElementBindingValue(elementBindingRef)) - .throwsAnExceptionOfType(PietFatalException.class) - .that() - .hasMessageThat() - .contains("Element binding not found"); - - // Binding is missing but is optional - ElementBindingRef elementBindingRefInvalidOptional = - ElementBindingRef.newBuilder() - .setBindingId(INVALID_BINDING_ID) - .setIsOptional(true) - .build(); - assertThat(makeFrameContextWithNoBindings().getElementBindingValue( - elementBindingRefInvalidOptional)) - .isEqualTo(BindingValue.getDefaultInstance()); - - // Binding has no content but is optional - ElementBindingRef elementBindingRefOptional = - ElementBindingRef.newBuilder().setBindingId(BINDING_ID).setIsOptional(true).build(); - assertThat( - makeFrameContextWithNoBindings().getElementBindingValue(elementBindingRefOptional)) - .isEqualTo(BindingValue.getDefaultInstance()); - } - - @Test - public void testGetElement_hostBinding() { - Element element = Element.newBuilder() - .setStyleReferences(StyleIdsStack.newBuilder().addStyleIds("el")) - .build(); - BindingValue elementBindingValue = defaultBinding().setElement(element).build(); - BindingValue hostListBindingValue = - defaultBinding() - .setHostBindingData(HostBindingData.newBuilder()) - .setElement(element) - .build(); - ElementBindingRef elementBindingRef = - ElementBindingRef.newBuilder().setBindingId(BINDING_ID).build(); - - mFrameContext = makeFrameContextWithBinding(hostListBindingValue); - - // Succeed in looking up binding - assertThat(mFrameContext.getElementBindingValue(elementBindingRef)) - .isEqualTo(elementBindingValue); - } - - @Test - public void testGetVisibility() { - Visibility visibility = Visibility.INVISIBLE; - BindingValue visibilityBindingValue = defaultBinding().setVisibility(visibility).build(); - VisibilityBindingRef visibilityBindingRef = - VisibilityBindingRef.newBuilder().setBindingId(BINDING_ID).build(); - - mFrameContext = makeFrameContextWithBinding(visibilityBindingValue); - - // Succeed in looking up binding - assertThat(mFrameContext.getVisibilityFromBinding(visibilityBindingRef)) - .isEqualTo(visibility); - - // Can't look up binding - assertThat( - mFrameContext.getVisibilityFromBinding( - VisibilityBindingRef.newBuilder().setBindingId(INVALID_BINDING_ID).build())) - .isNull(); - - // Binding has no content - assertThat(makeFrameContextWithNoBindings().getVisibilityFromBinding(visibilityBindingRef)) - .isNull(); - } - - @Test - public void testGetVisibility_hostBinding() { - Visibility visibility = Visibility.INVISIBLE; - BindingValue hostListBindingValue = - defaultBinding() - .setHostBindingData(HostBindingData.newBuilder()) - .setVisibility(visibility) - .build(); - VisibilityBindingRef visibilityBindingRef = - VisibilityBindingRef.newBuilder().setBindingId(BINDING_ID).build(); - - mFrameContext = makeFrameContextWithBinding(hostListBindingValue); - - // Succeed in looking up binding - assertThat(mFrameContext.getVisibilityFromBinding(visibilityBindingRef)) - .isEqualTo(visibility); - } - - @Test - public void testGetGridCellWidthFromBinding() { - GridCellWidth cellWidth = GridCellWidth.newBuilder().setWeight(123).build(); - mFrameContext = - makeFrameContextWithBinding(defaultBinding().setCellWidth(cellWidth).build()); - assertThat(mFrameContext.getGridCellWidthFromBinding( - GridCellWidthBindingRef.newBuilder().setBindingId(BINDING_ID).build())) - .isEqualTo(cellWidth); - assertThat( - mFrameContext.getGridCellWidthFromBinding(GridCellWidthBindingRef.newBuilder() - .setBindingId(INVALID_BINDING_ID) - .build())) - .isNull(); - - mFrameContext = makeFrameContextWithNoBindings(); - assertThat(mFrameContext.getGridCellWidthFromBinding( - GridCellWidthBindingRef.newBuilder().setBindingId(BINDING_ID).build())) - .isNull(); - } - - @Test - public void testGetGridCellWidthFromBinding_hostBinding() { - GridCellWidth cellWidth = GridCellWidth.newBuilder().setWeight(123).build(); - mFrameContext = makeFrameContextWithBinding( - defaultBinding() - .setHostBindingData(HostBindingData.newBuilder()) - .setCellWidth(cellWidth) - .build()); - assertThat(mFrameContext.getGridCellWidthFromBinding( - GridCellWidthBindingRef.newBuilder().setBindingId(BINDING_ID).build())) - .isEqualTo(cellWidth); - } - - @Test - public void testGetActionsFromBinding() { - Actions actions = Actions.newBuilder().build(); - mFrameContext = makeFrameContextWithBinding(defaultBinding().setActions(actions).build()); - assertThat(mFrameContext.getActionsFromBinding( - ActionsBindingRef.newBuilder().setBindingId(BINDING_ID).build())) - .isSameInstanceAs(actions); - assertThat(mFrameContext.getActionsFromBinding( - ActionsBindingRef.newBuilder().setBindingId(INVALID_BINDING_ID).build())) - .isSameInstanceAs(Actions.getDefaultInstance()); - - mFrameContext = makeFrameContextWithNoBindings(); - assertThat(mFrameContext.getActionsFromBinding( - ActionsBindingRef.newBuilder().setBindingId(BINDING_ID).build())) - .isSameInstanceAs(Actions.getDefaultInstance()); - } - - @Test - public void testGetActionsFromBinding_hostBinding() { - mFrameContext = makeFrameContextWithBinding( - defaultBinding() - .setHostBindingData(HostBindingData.newBuilder()) - .setActions(Actions.getDefaultInstance()) - .build()); - assertThat(mFrameContext.getActionsFromBinding( - ActionsBindingRef.newBuilder().setBindingId(BINDING_ID).build())) - .isEqualTo(Actions.getDefaultInstance()); - } - - @Test - public void testGetLogDataFromBinding() { - LogData logData = LogData.newBuilder().build(); - mFrameContext = makeFrameContextWithBinding(defaultBinding().setLogData(logData).build()); - assertThat(mFrameContext.getLogDataFromBinding( - LogDataBindingRef.newBuilder().setBindingId(BINDING_ID).build())) - .isSameInstanceAs(logData); - - assertThat(mFrameContext.getLogDataFromBinding( - LogDataBindingRef.newBuilder().setBindingId(INVALID_BINDING_ID).build())) - .isNull(); - - mFrameContext = makeFrameContextWithNoBindings(); - assertThat(mFrameContext.getLogDataFromBinding( - LogDataBindingRef.newBuilder().setBindingId(BINDING_ID).build())) - .isNull(); - } - - @Test - public void testGetLogDataFromBinding_hostBinding() { - mFrameContext = makeFrameContextWithBinding( - defaultBinding() - .setHostBindingData(HostBindingData.newBuilder()) - .setLogData(LogData.getDefaultInstance()) - .build()); - assertThat(mFrameContext.getLogDataFromBinding( - LogDataBindingRef.newBuilder().setBindingId(BINDING_ID).build())) - .isEqualTo(LogData.getDefaultInstance()); - } - - @Test - public void testGetStyleFromBinding() { - BoundStyle boundStyle = BoundStyle.newBuilder().setColor(12345).build(); - mFrameContext = - makeFrameContextWithBinding(defaultBinding().setBoundStyle(boundStyle).build()); - assertThat(mFrameContext.getStyleFromBinding( - StyleBindingRef.newBuilder().setBindingId(BINDING_ID).build())) - .isEqualTo(boundStyle); - assertThat(mFrameContext.getStyleFromBinding( - StyleBindingRef.newBuilder().setBindingId(INVALID_BINDING_ID).build())) - .isEqualTo(BoundStyle.getDefaultInstance()); - - mFrameContext = makeFrameContextWithNoBindings(); - assertThat(mFrameContext.getStyleFromBinding( - StyleBindingRef.newBuilder().setBindingId(BINDING_ID).build())) - .isEqualTo(BoundStyle.getDefaultInstance()); - } - - @Test - public void testGetStyleFromBinding_hostBinding() { - BoundStyle boundStyle = BoundStyle.newBuilder().setColor(12345).build(); - mFrameContext = makeFrameContextWithBinding( - defaultBinding() - .setHostBindingData(HostBindingData.newBuilder()) - .setBoundStyle(boundStyle) - .build()); - assertThat(mFrameContext.getStyleFromBinding( - StyleBindingRef.newBuilder().setBindingId(BINDING_ID).build())) - .isEqualTo(boundStyle); - } - - @Test - public void testGetTemplateInvocationFromBinding() { - TemplateInvocation templateInvocation = - TemplateInvocation.newBuilder().setTemplateId("carboncopy").build(); - BindingValue templateBindingValue = - defaultBinding().setTemplateInvocation(templateInvocation).build(); - mFrameContext = makeFrameContextWithBinding(templateBindingValue); - assertThat(mFrameContext.getTemplateInvocationBindingValue( - TemplateBindingRef.newBuilder().setBindingId(BINDING_ID).build())) - .isEqualTo(templateBindingValue); - assertThat(mFrameContext.getTemplateInvocationBindingValue( - TemplateBindingRef.newBuilder() - .setIsOptional(true) - .setBindingId(INVALID_BINDING_ID) - .build())) - .isEqualTo(BindingValue.getDefaultInstance()); - assertThatRunnable(() - -> mFrameContext.getTemplateInvocationBindingValue( - TemplateBindingRef.newBuilder() - .setBindingId(INVALID_BINDING_ID) - .build())) - .throwsAnExceptionOfType(PietFatalException.class) - .that() - .hasMessageThat() - .contains("Template binding not found for NOT_A_REAL_BINDING_ID"); - - mFrameContext = makeFrameContextWithNoBindings(); - assertThatRunnable( - () - -> mFrameContext.getTemplateInvocationBindingValue( - TemplateBindingRef.newBuilder().setBindingId(BINDING_ID).build())) - .throwsAnExceptionOfType(PietFatalException.class) - .that() - .hasMessageThat() - .contains("Template binding not found for BINDING_ID"); - } - - @Test - public void testGetTemplateInvocationFromBinding_hostBinding() { - TemplateInvocation templateInvocation = - TemplateInvocation.newBuilder().setTemplateId("carboncopy").build(); - mFrameContext = makeFrameContextWithBinding( - defaultBinding() - .setHostBindingData(HostBindingData.newBuilder()) - .setTemplateInvocation(templateInvocation) - .build()); - } - - @Test - public void testGetCustomElementBindingValue() { - CustomElementData customElement = CustomElementData.getDefaultInstance(); - BindingValue customElementBindingValue = - defaultBinding().setCustomElementData(customElement).build(); - CustomBindingRef customBindingRef = - CustomBindingRef.newBuilder().setBindingId(BINDING_ID).build(); - - mFrameContext = makeFrameContextWithBinding(customElementBindingValue); - - // Succeed in looking up binding - assertThat(mFrameContext.getCustomElementBindingValue(customBindingRef)) - .isEqualTo(customElementBindingValue); - - // Can't look up binding - assertThatRunnable(() - -> mFrameContext.getCustomElementBindingValue( - CustomBindingRef.newBuilder() - .setBindingId(INVALID_BINDING_ID) - .build())) - .throwsAnExceptionOfType(PietFatalException.class) - .that() - .hasMessageThat() - .contains("Custom element binding not found"); - - // Binding has no content - assertThatRunnable(() - -> makeFrameContextWithNoBindings().getCustomElementBindingValue( - customBindingRef)) - .throwsAnExceptionOfType(PietFatalException.class) - .that() - .hasMessageThat() - .contains("Custom element binding not found"); - - // Binding is missing but is optional - CustomBindingRef customBindingRefInvalidOptional = CustomBindingRef.newBuilder() - .setBindingId(INVALID_BINDING_ID) - .setIsOptional(true) - .build(); - assertThat(makeFrameContextWithNoBindings().getCustomElementBindingValue( - customBindingRefInvalidOptional)) - .isEqualTo(BindingValue.getDefaultInstance()); - - // Binding has no content but is optional - CustomBindingRef customBindingRefOptional = - CustomBindingRef.newBuilder().setBindingId(BINDING_ID).setIsOptional(true).build(); - assertThat(makeFrameContextWithNoBindings().getCustomElementBindingValue( - customBindingRefOptional)) - .isEqualTo(BindingValue.getDefaultInstance()); - } - - @Test - public void testGetCustomElementBindingValue_hostBinding() { - CustomElementData customElement = CustomElementData.getDefaultInstance(); - BindingValue customElementBindingValue = - defaultBinding().setCustomElementData(customElement).build(); - BindingValue hostCustomElementBindingValue = - defaultBinding() - .setHostBindingData(HostBindingData.newBuilder()) - .setCustomElementData(customElement) - .build(); - CustomBindingRef customBindingRef = - CustomBindingRef.newBuilder().setBindingId(BINDING_ID).build(); - - mFrameContext = makeFrameContextWithBinding(hostCustomElementBindingValue); - - // Succeed in looking up binding - assertThat(mFrameContext.getCustomElementBindingValue(customBindingRef)) - .isEqualTo(customElementBindingValue); - } - - @Test - public void testGetChunkedTextBindingValue() { - ChunkedText text = ChunkedText.newBuilder() - .addChunks(Chunk.newBuilder().setTextChunk( - StyledTextChunk.newBuilder().setParameterizedText( - ParameterizedText.newBuilder().setText("text")))) - .build(); - BindingValue textBindingValue = defaultBinding().setChunkedText(text).build(); - ChunkedTextBindingRef textBindingRef = - ChunkedTextBindingRef.newBuilder().setBindingId(BINDING_ID).build(); - - mFrameContext = makeFrameContextWithBinding(textBindingValue); - - // Succeed in looking up binding - assertThat(mFrameContext.getChunkedTextBindingValue(textBindingRef)) - .isEqualTo(textBindingValue); - - // Can't look up binding - assertThatRunnable(() - -> mFrameContext.getChunkedTextBindingValue( - ChunkedTextBindingRef.newBuilder() - .setBindingId(INVALID_BINDING_ID) - .build())) - .throwsAnExceptionOfType(PietFatalException.class) - .that() - .hasMessageThat() - .contains("Chunked text binding not found"); - - // Binding has no content - assertThatRunnable( - () -> makeFrameContextWithNoBindings().getChunkedTextBindingValue(textBindingRef)) - .throwsAnExceptionOfType(PietFatalException.class) - .that() - .hasMessageThat() - .contains("Chunked text binding not found"); - - // Binding is missing but is optional - ChunkedTextBindingRef textBindingRefInvalidOptional = - ChunkedTextBindingRef.newBuilder() - .setBindingId(INVALID_BINDING_ID) - .setIsOptional(true) - .build(); - assertThat(makeFrameContextWithNoBindings().getChunkedTextBindingValue( - textBindingRefInvalidOptional)) - .isEqualTo(BindingValue.getDefaultInstance()); - - // Binding has no content but is optional - ChunkedTextBindingRef textBindingRefOptional = ChunkedTextBindingRef.newBuilder() - .setBindingId(BINDING_ID) - .setIsOptional(true) - .build(); - assertThat( - makeFrameContextWithNoBindings().getChunkedTextBindingValue(textBindingRefOptional)) - .isEqualTo(BindingValue.getDefaultInstance()); - } - - @Test - public void testGetChunkedTextBindingValue_hostBinding() { - ChunkedText text = ChunkedText.newBuilder() - .addChunks(Chunk.newBuilder().setTextChunk( - StyledTextChunk.newBuilder().setParameterizedText( - ParameterizedText.newBuilder().setText("text")))) - .build(); - BindingValue textBindingValue = defaultBinding().setChunkedText(text).build(); - BindingValue hostTextBindingValue = - defaultBinding() - .setHostBindingData(HostBindingData.newBuilder()) - .setChunkedText(text) - .build(); - ChunkedTextBindingRef textBindingRef = - ChunkedTextBindingRef.newBuilder().setBindingId(BINDING_ID).build(); - - mFrameContext = makeFrameContextWithBinding(hostTextBindingValue); - - // Succeed in looking up binding - assertThat(mFrameContext.getChunkedTextBindingValue(textBindingRef)) - .isEqualTo(textBindingValue); - } - - @Test - public void testCreateWithoutError() { - Frame frame = getWorkingFrame(); - FrameContext frameContext = makeFrameContextFromFrame(frame); - assertThat(frameContext).isNotNull(); - assertThat(frameContext.getDebugLogger().getMessages(MessageType.ERROR)).isEmpty(); - } - - @Test - public void testBindFrame_withStylesheetId() { - Frame frame = - Frame.newBuilder() - .setStylesheets(Stylesheets.newBuilder().addStylesheetIds(STYLESHEET_ID)) - .build(); - setUpPietSharedStates(); - FrameContext frameContext = makeFrameContextFromFrame(frame); - - // The style is not currently bound, but available from the stylesheet. - assertThat(frameContext.makeStyleFor(StyleIdsStack.getDefaultInstance()).getColor()) - .isNotEqualTo(SAMPLE_STYLE_COLOR); - assertThat(frameContext.makeStyleFor(SAMPLE_STYLE_IDS).getColor()) - .isEqualTo(SAMPLE_STYLE_COLOR); - assertThat(frameContext.getDebugLogger().getMessages(MessageType.ERROR)).isEmpty(); - } - - @Test - public void testBindFrame_withStylesheet() { - Frame frame = Frame.newBuilder() - .setStylesheets(Stylesheets.newBuilder().addStylesheets( - Stylesheet.newBuilder().addStyles(SAMPLE_STYLE))) - .build(); - - FrameContext frameContext = makeFrameContextFromFrame(frame); - - // The style is not currently bound, but available from the stylesheet. - assertThat(frameContext.makeStyleFor(StyleIdsStack.getDefaultInstance()).getColor()) - .isNotEqualTo(SAMPLE_STYLE_COLOR); - assertThat(frameContext.makeStyleFor(SAMPLE_STYLE_IDS).getColor()) - .isEqualTo(SAMPLE_STYLE_COLOR); - assertThat(frameContext.getDebugLogger().getMessages(MessageType.ERROR)).isEmpty(); - } - - @Test - public void testBindFrame_withMultipleStylesheets() { - Frame frame = Frame.newBuilder() - .setStylesheets(Stylesheets.newBuilder() - .addStylesheetIds(STYLESHEET_ID) - .addStylesheets(Stylesheet.newBuilder() - .addStyles(BASE_STYLE) - .build())) - .build(); - - setUpPietSharedStates(); - - FrameContext frameContext = makeFrameContextFromFrame(frame); - - assertThat(frameContext.makeStyleFor(StyleIdsStack.getDefaultInstance()).getColor()) - .isNotEqualTo(SAMPLE_STYLE_COLOR); - assertThat(frameContext.makeStyleFor(SAMPLE_STYLE_IDS).getColor()) - .isEqualTo(SAMPLE_STYLE_COLOR); - assertThat(frameContext - .makeStyleFor(StyleIdsStack.newBuilder() - .addStyleIds(BASE_STYLE.getStyleId()) - .build()) - .getColor()) - .isEqualTo(BASE_STYLE_COLOR); - assertThat(frameContext.getDebugLogger().getMessages(MessageType.ERROR)).isEmpty(); - } - - @Test - public void testBindFrame_withFrameStyle() { - Frame frame = Frame.newBuilder() - .setStylesheets(Stylesheets.newBuilder().addStylesheets( - Stylesheet.newBuilder().addStyles(SAMPLE_STYLE))) - .setStyleReferences(SAMPLE_STYLE_IDS) - .build(); - - FrameContext frameContext = makeFrameContextFromFrame(frame); - - assertThat(frameContext.makeStyleFor(StyleIdsStack.getDefaultInstance())) - .isEqualTo(mDefaultStyleProvider); - assertThat(frameContext.getDebugLogger().getMessages(MessageType.ERROR)).isEmpty(); - } - - @Test - public void testBindFrame_withoutFrameStyle() { - Frame frame = Frame.newBuilder() - .setStylesheets(Stylesheets.newBuilder().addStylesheets( - Stylesheet.newBuilder().addStyles(SAMPLE_STYLE))) - .build(); - - FrameContext frameContext = makeFrameContextFromFrame(frame); - - assertThat(frameContext.makeStyleFor(StyleIdsStack.getDefaultInstance())) - .isEqualTo(mDefaultStyleProvider); - assertThat(frameContext.getDebugLogger().getMessages(MessageType.ERROR)).isEmpty(); - } - - @Test - public void testBindFrame_baseStyle() { - int styleHeight = 747; - String heightStyleId = "JUMBO"; - Frame frame = Frame.newBuilder() - .setStylesheets(Stylesheets.newBuilder().addStylesheets( - Stylesheet.newBuilder() - .addStyles(SAMPLE_STYLE) - .addStyles(Style.newBuilder() - .setStyleId(heightStyleId) - .setHeight(styleHeight)))) - .setStyleReferences(SAMPLE_STYLE_IDS) - .build(); - - // Set up a frame with a color applied to the frame. - FrameContext frameContext = makeFrameContextFromFrame(frame); - StyleProvider baseStyleWithHeight = frameContext.makeStyleFor( - StyleIdsStack.newBuilder().addStyleIds(heightStyleId).build()); - - // Make a style for something that doesn't override color, and check that the base color is - // a default, not the frame color. - assertThat(baseStyleWithHeight.getColor()).isEqualTo(Style.getDefaultInstance().getColor()); - assertThat(baseStyleWithHeight.getHeightSpecPx(mContext)) - .isEqualTo((int) LayoutUtils.dpToPx(styleHeight, mContext)); - assertThat(frameContext.getDebugLogger().getMessages(MessageType.ERROR)).isEmpty(); - } - - @Test - public void testMergeStyleIdsStack() { - String styleId1 = "STYLE1"; - Style style1 = Style.newBuilder() - .setColor(12345) // Not overridden - .setMaxLines(54321) // Overridden - .setFont(Font.newBuilder().setSize(11).setItalic(true)) - .setBackground(Fill.newBuilder().setLinearGradient( - LinearGradient.newBuilder().addStops( - ColorStop.newBuilder().setColor(1234)))) - .setStyleId(styleId1) - .build(); - String styleId2 = "STYLE2"; - Style style2 = Style.newBuilder() - .setMaxLines(22222) // Overrides - .setMinHeight(33333) // Not an override - .setFont(Font.newBuilder().setSize(13)) - .setBackground(Fill.newBuilder().setLinearGradient( - LinearGradient.newBuilder().setDirectionDeg(321))) - .setStyleId(styleId2) - .build(); - StyleIdsStack twoStyles = - StyleIdsStack.newBuilder().addStyleIds(styleId1).addStyleIds(styleId2).build(); - Frame frame = - Frame.newBuilder() - .setStylesheets(Stylesheets.newBuilder().addStylesheetIds(STYLESHEET_ID)) - .setStyleReferences(twoStyles) - .build(); - mPietSharedStates.add(PietSharedState.newBuilder() - .addStylesheets(Stylesheet.newBuilder() - .setStylesheetId(STYLESHEET_ID) - .addStyles(style1) - .addStyles(style2) - .build()) - .build()); - - FrameContext frameContext = makeFrameContextFromFrame(frame); - - StyleProvider defaultFrameStyle = frameContext.makeStyleFor(twoStyles); - assertThat(defaultFrameStyle.getColor()).isEqualTo(12345); - assertThat(defaultFrameStyle.getMaxLines()).isEqualTo(22222); - assertThat(defaultFrameStyle.getMinHeight()).isEqualTo(33333); - assertThat(defaultFrameStyle.getFont()) - .isEqualTo(Font.newBuilder().setSize(13).setItalic(true).build()); - assertThat(defaultFrameStyle.getBackground()) - .isEqualTo(Fill.newBuilder() - .setLinearGradient( - LinearGradient.newBuilder() - .addStops(ColorStop.newBuilder().setColor(1234)) - .setDirectionDeg(321)) - .build()); - assertThat(frameContext.getDebugLogger().getMessages(MessageType.ERROR)).isEmpty(); - - // Frame's styles don't affect the childrens' styles. - assertThat(frameContext.makeStyleFor(StyleIdsStack.getDefaultInstance())) - .isEqualTo(mDefaultStyleProvider); - assertThat(frameContext.getDebugLogger().getMessages(MessageType.ERROR)).isEmpty(); - } - - @Test - public void testGetMediaQueryStylesheets() { - String noMediaQueryStylesheetId = "noMediaQueries"; - Stylesheet noMediaQueryStylesheet = - Stylesheet.newBuilder().setStylesheetId(noMediaQueryStylesheetId).build(); - - String mediaQueryStylesheetId = "mediaQueries"; - Stylesheet mediaQueryStylesheet = - Stylesheet.newBuilder() - .setStylesheetId(mediaQueryStylesheetId) - .addConditions(MediaQueryCondition.newBuilder().setFrameWidth( - FrameWidthCondition.newBuilder().setWidth(0).setCondition( - ComparisonCondition.GREATER_THAN))) - .build(); - - mPietSharedStates.add(PietSharedState.newBuilder() - .addStylesheets(mediaQueryStylesheet) - .addStylesheets(noMediaQueryStylesheet) - .build()); - - FrameContext frameContext = defaultFrameContext(); - - Template inlineStylesheetTemplate = - Template.newBuilder() - .setStylesheets(Stylesheets.newBuilder().addStylesheets( - Stylesheet.newBuilder().setStylesheetId("inline"))) - .build(); - assertThat(frameContext.getMediaQueryStylesheets(inlineStylesheetTemplate)).isEmpty(); - - Template notFoundStylesheetTemplate = - Template.newBuilder() - .setStylesheets(Stylesheets.newBuilder().addStylesheetIds("NotFound")) - .build(); - assertThat(frameContext.getMediaQueryStylesheets(notFoundStylesheetTemplate)).isEmpty(); - - Template noConditionsTemplate = - Template.newBuilder() - .setStylesheets( - Stylesheets.newBuilder().addStylesheetIds(noMediaQueryStylesheetId)) - .build(); - assertThat(frameContext.getMediaQueryStylesheets(noConditionsTemplate)).isEmpty(); - - Template mediaQueryTemplate = - Template.newBuilder() - .setStylesheets( - Stylesheets.newBuilder().addStylesheetIds(mediaQueryStylesheetId)) - .build(); - assertThat(frameContext.getMediaQueryStylesheets(mediaQueryTemplate)) - .containsExactly(mediaQueryStylesheet); - } - - @Test - public void testFilterImageSourcesByMediaQueryCondition() { - ImageSource activeSource = - ImageSource.newBuilder() - .addConditions(MediaQueryCondition.newBuilder().setDarkLight( - DarkLightCondition.newBuilder().setMode(DarkLightMode.DARK))) - .build(); - ImageSource inactiveSource = - ImageSource.newBuilder() - .addConditions(MediaQueryCondition.newBuilder().setDarkLight( - DarkLightCondition.newBuilder().setMode(DarkLightMode.LIGHT))) - .build(); - ImageSource sourceWithNoConditions = ImageSource.getDefaultInstance(); - Image image = Image.newBuilder() - .addSources(activeSource) - .addSources(inactiveSource) - .addSources(sourceWithNoConditions) - .build(); - when(mAssetProvider.isDarkTheme()).thenReturn(true); - mFrameContext = defaultFrameContext(); - - Image resultImage = mFrameContext.filterImageSourcesByMediaQueryCondition(image); - assertThat(resultImage.getSourcesList()) - .containsExactly(activeSource, sourceWithNoConditions); - } - - private FrameContext defaultFrameContext() { - return makeFrameContextForDefaultFrame(); - } - - private FrameContext makeFrameContextForDefaultFrame() { - return new FrameContext(DEFAULT_FRAME, mDefaultStylesheet, mPietSharedStates, - newPietStylesHelper(), DebugBehavior.VERBOSE, mDebugLogger, mActionHandler, - mHostProviders, mFrameView); - } - - private FrameContext makeFrameContextWithBinding(BindingValue bindingValue) { - Map<String, BindingValue> bindingValueMap = new HashMap<>(); - bindingValueMap.put(bindingValue.getBindingId(), bindingValue); - return new FrameContext(DEFAULT_FRAME, mDefaultStylesheet, bindingValueMap, - mPietSharedStates, mPietStylesHelper, DebugBehavior.VERBOSE, mDebugLogger, - mActionHandler, mHostProviders, DEFAULT_TEMPLATES, mFrameView); - } - - private FrameContext makeFrameContextWithNoBindings() { - Map<String, BindingValue> bindingValueMap = new HashMap<>(); - bindingValueMap.put(BINDING_ID, BindingValue.getDefaultInstance()); - return new FrameContext(DEFAULT_FRAME, mDefaultStylesheet, bindingValueMap, - mPietSharedStates, mPietStylesHelper, DebugBehavior.VERBOSE, mDebugLogger, - mActionHandler, mHostProviders, DEFAULT_TEMPLATES, mFrameView); - } - - private FrameContext makeFrameContextFromFrame(Frame frame) { - return FrameContext.createFrameContext(frame, mPietSharedStates, newPietStylesHelper(), - DebugBehavior.VERBOSE, mDebugLogger, mActionHandler, mHostProviders, mFrameView); - } - - private void setUpPietSharedStates() { - mPietSharedStates.add(PietSharedState.newBuilder() - .addStylesheets(Stylesheet.newBuilder() - .setStylesheetId(STYLESHEET_ID) - .addStyles(SAMPLE_STYLE)) - .build()); - } - - private Frame getWorkingFrame() { - setUpPietSharedStates(); - return getBaseFrame(); - } - - private Frame getBaseFrame() { - return Frame.newBuilder() - .setStylesheets(Stylesheets.newBuilder().addStylesheetIds(STYLESHEET_ID)) - .setStyleReferences(SAMPLE_STYLE_IDS) - .build(); - } - - private BindingValue.Builder defaultBinding() { - return BindingValue.newBuilder().setBindingId(BINDING_ID); - } - - private PietStylesHelper newPietStylesHelper() { - return new PietStylesHelperFactory().get( - mPietSharedStates, new MediaQueryHelper(FRAME_WIDTH_PX, mAssetProvider, mContext)); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/GridRowAdapterTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/GridRowAdapterTest.java deleted file mode 100644 index e948381..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/GridRowAdapterTest.java +++ /dev/null
@@ -1,980 +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. - -package org.chromium.chrome.browser.feed.library.piet; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import static org.chromium.chrome.browser.feed.library.common.testing.RunnableSubject.assertThatRunnable; -import static org.chromium.chrome.browser.feed.library.piet.StyleProvider.DIMENSION_NOT_SET; - -import android.app.Activity; -import android.content.Context; -import android.view.Gravity; -import android.view.ViewGroup.MarginLayoutParams; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.LinearLayout.LayoutParams; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.config.DebugBehavior; -import org.chromium.chrome.browser.feed.library.common.functional.Suppliers; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.common.ui.LayoutUtils; -import org.chromium.chrome.browser.feed.library.piet.DebugLogger.MessageType; -import org.chromium.chrome.browser.feed.library.piet.GridRowAdapter.KeySupplier; -import org.chromium.chrome.browser.feed.library.piet.host.ActionHandler; -import org.chromium.chrome.browser.feed.library.piet.host.AssetProvider; -import org.chromium.chrome.browser.feed.library.piet.host.EventLogger; -import org.chromium.chrome.browser.feed.library.piet.ui.GridRowView; -import org.chromium.components.feed.core.proto.ui.piet.BindingRefsProto.ElementBindingRef; -import org.chromium.components.feed.core.proto.ui.piet.BindingRefsProto.GridCellWidthBindingRef; -import org.chromium.components.feed.core.proto.ui.piet.BindingRefsProto.StyleBindingRef; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.BindingValue; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.Content; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.CustomElement; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.Element; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.ElementList; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.ElementStack; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.GridCell; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.GridCellWidth; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.GridCellWidth.ContentWidth; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.GridRow; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.ImageElement; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.TextElement; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.Visibility; -import org.chromium.components.feed.core.proto.ui.piet.ErrorsProto.ErrorCode; -import org.chromium.components.feed.core.proto.ui.piet.ImagesProto.Image; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.Frame; -import org.chromium.components.feed.core.proto.ui.piet.RoundedCornersProto.RoundedCorners; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.EdgeWidths; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.StyleIdsStack; -import org.chromium.components.feed.core.proto.ui.piet.TextProto.ParameterizedText; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.Collections; - -/** Tests of the {@link GridRowAdapter}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class GridRowAdapterTest { - private static final String GRID_STYLE_ID = "cybercat"; - private static final StyleIdsStack GRID_STYLES = - StyleIdsStack.newBuilder().addStyleIds(GRID_STYLE_ID).build(); - private static final Element DEFAULT_ELEMENT = - Element.newBuilder().setElementStack(ElementStack.getDefaultInstance()).build(); - private static final Content DEFAULT_CONTENT = - Content.newBuilder().setElement(DEFAULT_ELEMENT).build(); - private static final Content TEXT_CONTENT = - Content.newBuilder() - .setElement(Element.newBuilder().setTextElement( - TextElement.newBuilder().setParameterizedText( - ParameterizedText.newBuilder().setText("TheGrid")))) - .build(); - private static final String BINDING_ID = "stripes"; - private static final ElementBindingRef ELEMENT_BINDING = - ElementBindingRef.newBuilder().setBindingId(BINDING_ID).build(); - private static final Content BOUND_CONTENTS = - Content.newBuilder().setBoundElement(ELEMENT_BINDING).build(); - private static final Element GRID_ROW_WITH_BOUND_CELL = - Element.newBuilder() - .setGridRow(GridRow.newBuilder().addCells( - GridCell.newBuilder().setContent(BOUND_CONTENTS))) - .build(); - - private Context mContext; - private AdapterParameters mAdapterParameters; - - @Mock - private ActionHandler mActionHandler; - @Mock - private FrameContext mFrameContext; - @Mock - private StyleProvider mStyleProvider; - @Mock - private HostProviders mHostProviders; - @Mock - private AssetProvider mAssetProvider; - - private GridRowAdapter mAdapter; - - @Before - public void setUp() throws Exception { - initMocks(this); - mContext = Robolectric.buildActivity(Activity.class).get(); - - when(mHostProviders.getAssetProvider()).thenReturn(mAssetProvider); - when(mAssetProvider.isRtL()).thenReturn(false); - when(mAssetProvider.isRtLSupplier()).thenReturn(Suppliers.of(false)); - when(mFrameContext.makeStyleFor(GRID_STYLES)).thenReturn(mStyleProvider); - when(mFrameContext.getActionHandler()).thenReturn(mActionHandler); - when(mFrameContext.filterImageSourcesByMediaQueryCondition(any(Image.class))) - .thenAnswer(invocation -> invocation.getArguments()[0]); - when(mFrameContext.reportMessage(anyInt(), any(), anyString())) - .thenAnswer(invocation -> invocation.getArguments()[2]); - when(mStyleProvider.getPadding()).thenReturn(EdgeWidths.getDefaultInstance()); - when(mStyleProvider.getRoundedCorners()).thenReturn(RoundedCorners.getDefaultInstance()); - - mAdapterParameters = new AdapterParameters( - mContext, Suppliers.of(null), mHostProviders, new FakeClock(), false, false); - - when(mFrameContext.makeStyleFor(StyleIdsStack.getDefaultInstance())) - .thenReturn(mAdapterParameters.mDefaultStyleProvider); - - mAdapter = new KeySupplier().getAdapter(mContext, mAdapterParameters); - } - - @Test - public void testViewDoesNotClip() { - assertThat(mAdapter.getBaseView().getClipToPadding()).isFalse(); - } - - @Test - public void testOnCreateAdapter_makesRow() { - // We create an adapter for the inline content, but not for the bound content. - GridRow model = GridRow.newBuilder() - .addCells(GridCell.newBuilder().setContent(DEFAULT_CONTENT)) - .addCells(GridCell.newBuilder().setContent(BOUND_CONTENTS)) - .build(); - - when(mFrameContext.getElementBindingValue(ELEMENT_BINDING)) - .thenReturn(BindingValue.newBuilder().setElement(DEFAULT_ELEMENT).build()); - - mAdapter.createAdapter(asElement(model), mFrameContext); - - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(1); - assertThat(mAdapter.getBaseView().getBaseline()).isEqualTo(-1); - assertThat(mAdapter.mChildAdapters).hasSize(1); - assertThat(mAdapter.getBaseView().getChildAt(0)) - .isSameInstanceAs(mAdapter.mChildAdapters.get(0).getView()); - } - - @Test - public void testOnCreateAdapter_missingContentIsException() { - GridRow model = GridRow.newBuilder().addCells(GridCell.getDefaultInstance()).build(); - - assertThatRunnable(() -> mAdapter.createAdapter(asElement(model), mFrameContext)) - .throwsAnExceptionOfType(PietFatalException.class) - .that() - .hasMessageThat() - .contains("Unhandled Content type: CONTENTTYPE_NOT_SET"); - } - - @Test - public void testOnCreateAdapter_setsGridRowStyles() { - GridRow model = GridRow.newBuilder() - .addCells(GridCell.newBuilder().setContent(DEFAULT_CONTENT)) - .build(); - - mAdapter.createAdapter(asElement(model), mFrameContext); - - verify(mFrameContext).makeStyleFor(GRID_STYLES); - verify(mStyleProvider).applyElementStyles(mAdapter); - } - - @Test - public void testOnBindModel_setsLayoutParamsOnCell_widthDefaultsToWeight() { - GridRow model = - GridRow.newBuilder() - .addCells(GridCell.newBuilder().setContent(DEFAULT_CONTENT).clearWidth()) - .build(); - - mAdapter.createAdapter(asElement(model), mFrameContext); - mAdapter.bindModel(asElement(model), mFrameContext); - - assertThat(mAdapter.getBaseView().getChildAt(0).getLayoutParams()) - .isInstanceOf(LinearLayout.LayoutParams.class); - LayoutParams params = - (LinearLayout.LayoutParams) mAdapter.getBaseView().getChildAt(0).getLayoutParams(); - assertThat(params.width).isEqualTo(0); - assertThat(params.weight).isEqualTo(1.0f); - } - - @Test - public void testOnBindModel_setsLayoutParamsOnCell_widthDp() { - int widthDp = 123; - GridRow model = - GridRow.newBuilder() - .addCells(GridCell.newBuilder() - .setContent(DEFAULT_CONTENT) - .setWidth(GridCellWidth.newBuilder().setDp(widthDp))) - .build(); - - mAdapter.createAdapter(asElement(model), mFrameContext); - mAdapter.bindModel(asElement(model), mFrameContext); - - assertThat(mAdapter.getBaseView().getChildAt(0).getLayoutParams()) - .isInstanceOf(LinearLayout.LayoutParams.class); - LayoutParams params = - (LinearLayout.LayoutParams) mAdapter.getBaseView().getChildAt(0).getLayoutParams(); - assertThat(params.width).isEqualTo((int) LayoutUtils.dpToPx(widthDp, mContext)); - assertThat(params.weight).isEqualTo(0.0f); - } - - @Test - public void testOnBindModel_setsLayoutParamsOnCell_widthWeight() { - int widthWeight = 321; - GridRow model = GridRow.newBuilder() - .addCells(GridCell.newBuilder() - .setContent(DEFAULT_CONTENT) - .setWidth(GridCellWidth.newBuilder().setWeight( - widthWeight))) - .build(); - - mAdapter.createAdapter(asElement(model), mFrameContext); - mAdapter.bindModel(asElement(model), mFrameContext); - - assertThat(mAdapter.getBaseView().getChildAt(0).getLayoutParams()) - .isInstanceOf(LinearLayout.LayoutParams.class); - LayoutParams params = - (LinearLayout.LayoutParams) mAdapter.getBaseView().getChildAt(0).getLayoutParams(); - assertThat(params.weight).isEqualTo((float) widthWeight); - assertThat(params.width).isEqualTo(0); - } - - @Test - public void testOnBindModel_setsLayoutParamsOnCell_widthBinding() { - GridCellWidthBindingRef widthBindingRef = - GridCellWidthBindingRef.newBuilder().setBindingId("fatcat").build(); - int widthDp = 222; - GridRow model = GridRow.newBuilder() - .addCells(GridCell.newBuilder() - .setContent(DEFAULT_CONTENT) - .setWidthBinding(widthBindingRef)) - .build(); - when(mFrameContext.getGridCellWidthFromBinding(widthBindingRef)) - .thenReturn(GridCellWidth.newBuilder().setDp(widthDp).build()); - - mAdapter.createAdapter(asElement(model), mFrameContext); - mAdapter.bindModel(asElement(model), mFrameContext); - - assertThat(mAdapter.getBaseView().getChildAt(0).getLayoutParams()) - .isInstanceOf(LinearLayout.LayoutParams.class); - LayoutParams params = - (LinearLayout.LayoutParams) mAdapter.getBaseView().getChildAt(0).getLayoutParams(); - assertThat(params.width).isEqualTo((int) LayoutUtils.dpToPx(widthDp, mContext)); - assertThat(params.weight).isEqualTo(0.0f); - } - - @Test - public void testOnBindModel_setsLayoutParamsOnCell_invalidContentWidth() { - GridRow model = - GridRow.newBuilder() - .addCells(GridCell.newBuilder() - .setContent(DEFAULT_CONTENT) - .setWidth(GridCellWidth.newBuilder().setContentWidth( - ContentWidth.INVALID_CONTENT_WIDTH))) - .build(); - - mAdapter.createAdapter(asElement(model), mFrameContext); - mAdapter.bindModel(asElement(model), mFrameContext); - - LayoutParams params = - (LinearLayout.LayoutParams) mAdapter.getBaseView().getChildAt(0).getLayoutParams(); - assertThat(params.width).isEqualTo(LayoutParams.WRAP_CONTENT); - assertThat(params.weight).isEqualTo(0.0f); - verify(mFrameContext) - .reportMessage(MessageType.WARNING, ErrorCode.ERR_GRID_CELL_WIDTH_WITHOUT_CONTENTS, - "Invalid content width: INVALID_CONTENT_WIDTH"); - } - - @Test - public void testOnBindModel_setsLayoutParamsOnCell_widthOfChildAdapter() { - StyleIdsStack childStyles = StyleIdsStack.newBuilder().addStyleIds("child").build(); - GridRow model = - GridRow.newBuilder() - .addCells( - GridCell.newBuilder() - .setWidth(GridCellWidth.newBuilder().setContentWidth( - ContentWidth.CONTENT_WIDTH)) - .setContent(Content.newBuilder().setElement( - // clang-format off - Element.newBuilder() - .setStyleReferences(childStyles) - .setImageElement( - ImageElement.newBuilder().setImage( - Image.getDefaultInstance())) - // clang-format on - ))) - .build(); - - StyleProvider childStyleProvider = mock(StyleProvider.class); - when(childStyleProvider.hasWidth()).thenReturn(true); - when(childStyleProvider.getWidthSpecPx(mContext)).thenReturn(456); - when(childStyleProvider.getRoundedCorners()) - .thenReturn(RoundedCorners.getDefaultInstance()); - when(childStyleProvider.getScaleType()).thenReturn(ImageView.ScaleType.CENTER_CROP); - - when(mFrameContext.makeStyleFor(childStyles)).thenReturn(childStyleProvider); - - mAdapter.createAdapter(asElement(model), mFrameContext); - mAdapter.bindModel(asElement(model), mFrameContext); - - assertThat(mAdapter.getBaseView().getChildAt(0).getLayoutParams()) - .isInstanceOf(LinearLayout.LayoutParams.class); - LayoutParams params = - (LinearLayout.LayoutParams) mAdapter.getBaseView().getChildAt(0).getLayoutParams(); - assertThat(params.width).isEqualTo((int) LayoutUtils.dpToPx(456, mContext)); - assertThat(params.weight).isEqualTo(0.0f); - } - - @Test - public void testOnBindModel_setsLayoutParamsOnCell_heightOfChildAdapter() { - StyleIdsStack childStyles = StyleIdsStack.newBuilder().addStyleIds("child").build(); - GridRow model = - GridRow.newBuilder() - .addCells(GridCell.newBuilder().setContent(Content.newBuilder().setElement( - Element.newBuilder() - .setStyleReferences(childStyles) - .setImageElement(ImageElement.newBuilder().setImage( - Image.getDefaultInstance()))))) - .build(); - - StyleProvider childStyleProvider = mock(StyleProvider.class); - when(childStyleProvider.hasHeight()).thenReturn(true); - when(childStyleProvider.getHeightSpecPx(mContext)).thenReturn(123); - when(childStyleProvider.getRoundedCorners()) - .thenReturn(RoundedCorners.getDefaultInstance()); - when(childStyleProvider.getScaleType()).thenReturn(ImageView.ScaleType.CENTER_CROP); - - when(mFrameContext.makeStyleFor(childStyles)).thenReturn(childStyleProvider); - - mAdapter.createAdapter(asElement(model), mFrameContext); - mAdapter.bindModel(asElement(model), mFrameContext); - - assertThat(mAdapter.getBaseView().getChildAt(0).getLayoutParams()) - .isInstanceOf(LinearLayout.LayoutParams.class); - LayoutParams params = - (LinearLayout.LayoutParams) mAdapter.getBaseView().getChildAt(0).getLayoutParams(); - assertThat(params.height).isEqualTo((int) LayoutUtils.dpToPx(123, mContext)); - } - - @Test - public void testOnBindModel_setsLayoutParamsOnCell_heightOfChildAdapterNotDefined() { - StyleIdsStack childStyles = StyleIdsStack.newBuilder().addStyleIds("child").build(); - GridRow model = - GridRow.newBuilder() - .addCells(GridCell.newBuilder().setContent(Content.newBuilder().setElement( - Element.newBuilder().setImageElement( - ImageElement.newBuilder().setImage( - Image.getDefaultInstance()))))) - .build(); - - StyleProvider childStyleProvider = mock(StyleProvider.class); - when(childStyleProvider.hasHeight()).thenReturn(false); - when(childStyleProvider.getHeightSpecPx(mContext)).thenReturn(DIMENSION_NOT_SET); - when(childStyleProvider.getRoundedCorners()) - .thenReturn(RoundedCorners.getDefaultInstance()); - - when(mFrameContext.makeStyleFor(childStyles)).thenReturn(childStyleProvider); - - mAdapter.createAdapter(asElement(model), mFrameContext); - mAdapter.bindModel(asElement(model), mFrameContext); - - assertThat(mAdapter.getBaseView().getChildAt(0).getLayoutParams()) - .isInstanceOf(LinearLayout.LayoutParams.class); - LayoutParams params = - (LinearLayout.LayoutParams) mAdapter.getBaseView().getChildAt(0).getLayoutParams(); - assertThat(params.height).isEqualTo(LayoutParams.MATCH_PARENT); - } - - @Test - public void testOnBindModel_setsLayoutParamsOnCell_margins() { - StyleIdsStack childStyles = StyleIdsStack.newBuilder().addStyleIds("child").build(); - GridRow model = - GridRow.newBuilder() - .addCells(GridCell.newBuilder().setContent(Content.newBuilder().setElement( - Element.newBuilder() - .setStyleReferences(childStyles) - .setElementStack(ElementStack.getDefaultInstance())))) - .build(); - - StyleProvider childStyleProvider = mock(StyleProvider.class); - when(childStyleProvider.getPadding()).thenReturn(EdgeWidths.getDefaultInstance()); - when(childStyleProvider.getRoundedCorners()) - .thenReturn(RoundedCorners.getDefaultInstance()); - - when(mFrameContext.makeStyleFor(childStyles)).thenReturn(childStyleProvider); - - mAdapter.createAdapter(asElement(model), mFrameContext); - mAdapter.bindModel(asElement(model), mFrameContext); - - verify(childStyleProvider) - .applyMargins(mContext, - (MarginLayoutParams) mAdapter.getBaseView() - .getChildAt(0) - .getLayoutParams()); - } - - @Test - public void testOnBindModel_setsLayoutParamsOnCell_verticalGravityCenter() { - StyleIdsStack centerVertical = - StyleIdsStack.newBuilder().addStyleIds("center_vertical").build(); - StyleProvider centerVerticalProvider = mock(StyleProvider.class); - when(mFrameContext.makeStyleFor(centerVertical)).thenReturn(centerVerticalProvider); - when(centerVerticalProvider.getGravityVertical(anyInt())) - .thenReturn(Gravity.CENTER_VERTICAL); - GridRow gridRowTop = - GridRow.newBuilder() - .addCells(GridCell.newBuilder().setContent(Content.newBuilder().setElement( - DEFAULT_ELEMENT.toBuilder().setStyleReferences(centerVertical)))) - .build(); - - mAdapter.createAdapter(asElement(gridRowTop), mFrameContext); - mAdapter.bindModel(asElement(gridRowTop), mFrameContext); - - ElementStackAdapter cellAdapter = (ElementStackAdapter) mAdapter.mChildAdapters.get(0); - LayoutParams params = (LinearLayout.LayoutParams) cellAdapter.getView().getLayoutParams(); - assertThat(params.gravity).isEqualTo(Gravity.CENTER_VERTICAL); - } - - @Test - public void testOnBindModel_collapsibleCells_valid() { - GridRow gridRow = - GridRow.newBuilder() - .addCells(GridCell.newBuilder() - .setWidth(GridCellWidth.newBuilder().setContentWidth( - ContentWidth.CONTENT_WIDTH)) - .setContent(TEXT_CONTENT)) - .addCells(GridCell.newBuilder() - .setWidth(GridCellWidth.newBuilder() - .setContentWidth( - ContentWidth.CONTENT_WIDTH) - .setIsCollapsible(true)) - .setContent(TEXT_CONTENT)) - .addCells(GridCell.newBuilder() - .setWidth(GridCellWidth.newBuilder().setDp(123)) - .setContent(TEXT_CONTENT)) - .build(); - - mAdapter.createAdapter(asElement(gridRow), mFrameContext); - mAdapter.bindModel(asElement(gridRow), mFrameContext); - - assertThat(mAdapter.getBaseView().getChildAt(0).getLayoutParams().width) - .isEqualTo(LayoutParams.WRAP_CONTENT); - assertThat(mAdapter.getBaseView().getChildAt(1).getLayoutParams().width) - .isEqualTo(LayoutParams.WRAP_CONTENT); - assertThat( - ((GridRowView.LayoutParams) mAdapter.getBaseView().getChildAt(1).getLayoutParams()) - .getIsCollapsible()) - .isTrue(); - assertThat(mAdapter.getBaseView().getChildAt(2).getLayoutParams().width) - .isEqualTo((int) LayoutUtils.dpToPx(123, mContext)); - } - - @Test - public void testOnBindModel_collapsibleCells_multipleCollapsible() { - GridRow gridRow = - GridRow.newBuilder() - .addCells(GridCell.newBuilder() - .setWidth(GridCellWidth.newBuilder() - .setContentWidth( - ContentWidth.CONTENT_WIDTH) - .setIsCollapsible(true)) - .setContent(TEXT_CONTENT)) - .addCells(GridCell.newBuilder() - .setWidth(GridCellWidth.newBuilder() - .setDp(456) - .setIsCollapsible(true)) - .setContent(TEXT_CONTENT)) - .addCells(GridCell.newBuilder() - .setWidth(GridCellWidth.newBuilder().setDp(123)) - .setContent(TEXT_CONTENT)) - .build(); - - mAdapter.createAdapter(asElement(gridRow), mFrameContext); - mAdapter.bindModel(asElement(gridRow), mFrameContext); - - assertThat(mAdapter.getBaseView().getChildAt(0).getLayoutParams().width) - .isEqualTo(LayoutParams.WRAP_CONTENT); - assertThat( - ((GridRowView.LayoutParams) mAdapter.getBaseView().getChildAt(0).getLayoutParams()) - .getIsCollapsible()) - .isTrue(); - assertThat(mAdapter.getBaseView().getChildAt(1).getLayoutParams().width).isEqualTo(456); - assertThat( - ((GridRowView.LayoutParams) mAdapter.getBaseView().getChildAt(1).getLayoutParams()) - .getIsCollapsible()) - .isTrue(); - assertThat(mAdapter.getBaseView().getChildAt(2).getLayoutParams().width) - .isEqualTo((int) LayoutUtils.dpToPx(123, mContext)); - } - - @Test - public void testOnBindModel_collapsibleCells_mixingCollapsibleAndWeight() { - GridRow gridRow = - GridRow.newBuilder() - .addCells(GridCell.newBuilder() - .setWidth(GridCellWidth.newBuilder() - .setContentWidth( - ContentWidth.CONTENT_WIDTH) - .setIsCollapsible(true)) - .setContent(TEXT_CONTENT)) - .addCells(GridCell.newBuilder() - .setWidth(GridCellWidth.newBuilder().setWeight(4)) - .setContent(TEXT_CONTENT)) - .addCells(GridCell.newBuilder() - .setWidth(GridCellWidth.newBuilder().setDp(123)) - .setContent(TEXT_CONTENT)) - .build(); - - mAdapter.createAdapter(asElement(gridRow), mFrameContext); - mAdapter.bindModel(asElement(gridRow), mFrameContext); - - assertThat(mAdapter.getBaseView().getChildAt(0).getLayoutParams().width) - .isEqualTo(LayoutParams.WRAP_CONTENT); - assertThat( - ((GridRowView.LayoutParams) mAdapter.getBaseView().getChildAt(0).getLayoutParams()) - .getIsCollapsible()) - .isTrue(); - assertThat(mAdapter.getBaseView().getChildAt(1).getLayoutParams().width).isEqualTo(0); - assertThat( - ((LinearLayout.LayoutParams) mAdapter.getBaseView().getChildAt(1).getLayoutParams()) - .weight) - .isEqualTo(4.0f); - assertThat(mAdapter.getBaseView().getChildAt(2).getLayoutParams().width) - .isEqualTo((int) LayoutUtils.dpToPx(123, mContext)); - } - - @Test - public void testOnBindModel_recreatesBindingCells() { - Element cellWithOneElement = - Element.newBuilder() - .setElementList(ElementList.newBuilder().addContents( - Content.newBuilder().setElement( - Element.newBuilder().setElementStack( - ElementStack.getDefaultInstance())))) - .build(); - Element cellWithTwoElements = - Element.newBuilder() - .setElementList( - ElementList.newBuilder() - .addContents(Content.newBuilder().setElement( - Element.newBuilder().setElementStack( - ElementStack.getDefaultInstance()))) - .addContents(Content.newBuilder().setElement( - Element.newBuilder().setElementStack( - ElementStack.getDefaultInstance())))) - .build(); - - when(mFrameContext.getElementBindingValue(ELEMENT_BINDING)) - .thenReturn(BindingValue.newBuilder().setElement(cellWithOneElement).build()); - mAdapter.createAdapter(GRID_ROW_WITH_BOUND_CELL, mFrameContext); - // The cell adapter has not been created yet - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(0); - assertThat(mAdapter.mChildAdapters).isEmpty(); - - when(mFrameContext.getElementBindingValue(ELEMENT_BINDING)) - .thenReturn(BindingValue.newBuilder().setElement(cellWithTwoElements).build()); - mAdapter.bindModel(GRID_ROW_WITH_BOUND_CELL, mFrameContext); - // The cell adapter creates its one view on bind. - assertThat(((LinearLayout) mAdapter.getBaseView().getChildAt(0)).getChildCount()) - .isEqualTo(2); - - mAdapter.unbindModel(); - // The cell adapter has been released. - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(0); - assertThat(mAdapter.mChildAdapters).isEmpty(); - - when(mFrameContext.getElementBindingValue(ELEMENT_BINDING)) - .thenReturn(BindingValue.newBuilder().setElement(cellWithOneElement).build()); - mAdapter.bindModel(GRID_ROW_WITH_BOUND_CELL, mFrameContext); - // The cell adapter can bind to a different model. - assertThat(((LinearLayout) mAdapter.getBaseView().getChildAt(0)).getChildCount()) - .isEqualTo(1); - } - - @Test - public void testOnBindModel_visibilityGone() { - when(mFrameContext.getElementBindingValue(ELEMENT_BINDING)) - .thenReturn(BindingValue.newBuilder() - .setBindingId(BINDING_ID) - .setElement(DEFAULT_ELEMENT) - .build()); - mAdapter.createAdapter(GRID_ROW_WITH_BOUND_CELL, mFrameContext); - when(mFrameContext.getElementBindingValue(ELEMENT_BINDING)) - .thenReturn(BindingValue.newBuilder() - .setBindingId(BINDING_ID) - .setVisibility(Visibility.GONE) - .build()); - - mAdapter.bindModel(GRID_ROW_WITH_BOUND_CELL, mFrameContext); - - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(0); - assertThat(mAdapter.mChildAdapters).isEmpty(); - } - - @Test - public void testOnBindModel_noContent() { - when(mFrameContext.getElementBindingValue(ELEMENT_BINDING)) - .thenReturn(BindingValue.newBuilder() - .setBindingId(BINDING_ID) - .setElement(DEFAULT_ELEMENT) - .build()); - mAdapter.createAdapter(GRID_ROW_WITH_BOUND_CELL, mFrameContext); - when(mFrameContext.getElementBindingValue(ELEMENT_BINDING)) - .thenReturn(BindingValue.newBuilder().setBindingId(BINDING_ID).build()); - - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(0); - assertThat(mAdapter.mChildAdapters).isEmpty(); - } - - @Test - public void testOnBindModel_optionalAbsent() { - when(mFrameContext.getElementBindingValue(ELEMENT_BINDING)) - .thenReturn(BindingValue.newBuilder() - .setBindingId(BINDING_ID) - .setElement(DEFAULT_ELEMENT) - .build()); - mAdapter.createAdapter(GRID_ROW_WITH_BOUND_CELL, mFrameContext); - - ElementBindingRef optionalBinding = ELEMENT_BINDING.toBuilder().setIsOptional(true).build(); - GridRow optionalBindingRow = - GridRow.newBuilder() - .addCells(GridCell.newBuilder().setContent( - Content.newBuilder().setBoundElement(optionalBinding))) - .build(); - when(mFrameContext.getElementBindingValue(optionalBinding)) - .thenReturn(BindingValue.newBuilder().setBindingId(BINDING_ID).build()); - - mAdapter.bindModel(asElement(optionalBindingRow), mFrameContext); - - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(0); - assertThat(mAdapter.mChildAdapters).isEmpty(); - } - - @Test - public void testOnBindModel_throwsExceptionOnCellCountMismatch() { - GridRow gridRowWithTwoElements = - GridRow.newBuilder() - .addCells(GridCell.newBuilder().setContent(DEFAULT_CONTENT)) - .addCells(GridCell.newBuilder().setContent(DEFAULT_CONTENT)) - .build(); - - GridRow gridRowWithOneElement = - GridRow.newBuilder() - .addCells(GridCell.newBuilder().setContent(DEFAULT_CONTENT)) - .build(); - - mAdapter.createAdapter(asElement(gridRowWithTwoElements), mFrameContext); - - assertThatRunnable( - () -> mAdapter.bindModel(asElement(gridRowWithOneElement), mFrameContext)) - .throwsAnExceptionOfType(IllegalStateException.class) - .that() - .hasMessageThat() - .contains("Internal error in adapters per content"); - } - - @Test - public void testOnBindModel_setsStylesOnlyIfBindingIsDefined() { - GridRow gridRow = GridRow.newBuilder() - .addCells(GridCell.newBuilder().setContent(DEFAULT_CONTENT)) - .build(); - - mAdapter.createAdapter(asElement(gridRow, GRID_STYLES), mFrameContext); - verify(mFrameContext).makeStyleFor(GRID_STYLES); - - // When we bind a new model, the style does not change. - StyleIdsStack otherStyles = StyleIdsStack.newBuilder().addStyleIds("ignored").build(); - - mAdapter.bindModel(asElement(gridRow, otherStyles), mFrameContext); - verify(mFrameContext, never()).makeStyleFor(otherStyles); - - // If we bind a model that has a style binding, then the style does get re-applied. - StyleIdsStack styleWithBinding = - StyleIdsStack.newBuilder() - .setStyleBinding(StyleBindingRef.newBuilder().setBindingId("homewardbound")) - .build(); - StyleProvider otherStyleProvider = mock(StyleProvider.class); - when(mFrameContext.makeStyleFor(styleWithBinding)).thenReturn(otherStyleProvider); - - mAdapter.bindModel(asElement(gridRow, styleWithBinding), mFrameContext); - verify(mFrameContext).makeStyleFor(styleWithBinding); - verify(otherStyleProvider).applyElementStyles(mAdapter); - } - - @Test - public void testOnBindModel_collapsibleCells_valid_boundWidth() { - GridCellWidthBindingRef widthBinding = - GridCellWidthBindingRef.newBuilder().setBindingId("width").build(); - GridRow gridRow = - GridRow.newBuilder() - .addCells(GridCell.newBuilder() - .setWidth(GridCellWidth.newBuilder().setContentWidth( - ContentWidth.CONTENT_WIDTH)) - .setContent(TEXT_CONTENT)) - .addCells(GridCell.newBuilder() - .setWidthBinding(widthBinding) - .setContent(TEXT_CONTENT)) - .addCells(GridCell.newBuilder() - .setWidth(GridCellWidth.newBuilder().setDp(123)) - .setContent(TEXT_CONTENT)) - .build(); - - when(mFrameContext.getGridCellWidthFromBinding(widthBinding)) - .thenReturn(GridCellWidth.newBuilder().setDp(456).build()); - mAdapter.createAdapter(asElement(gridRow), mFrameContext); - - when(mFrameContext.getGridCellWidthFromBinding(widthBinding)) - .thenReturn(GridCellWidth.newBuilder() - .setContentWidth(ContentWidth.CONTENT_WIDTH) - .setIsCollapsible(true) - .build()); - mAdapter.bindModel(asElement(gridRow), mFrameContext); - - assertThat(mAdapter.getBaseView().getChildAt(0).getLayoutParams().width) - .isEqualTo(LayoutParams.WRAP_CONTENT); - assertThat(mAdapter.getBaseView().getChildAt(1).getLayoutParams().width) - .isEqualTo(LayoutParams.WRAP_CONTENT); - assertThat( - ((GridRowView.LayoutParams) mAdapter.getBaseView().getChildAt(1).getLayoutParams()) - .getIsCollapsible()) - .isTrue(); - assertThat(mAdapter.getBaseView().getChildAt(2).getLayoutParams().width) - .isEqualTo((int) LayoutUtils.dpToPx(123, mContext)); - } - - @Test - public void testOnBindModel_collapsibleCells_multipleCollapsible_boundWidth() { - GridCellWidthBindingRef widthBinding = - GridCellWidthBindingRef.newBuilder().setBindingId("width").build(); - GridRow gridRow = - GridRow.newBuilder() - .addCells(GridCell.newBuilder() - .setWidth(GridCellWidth.newBuilder() - .setContentWidth( - ContentWidth.CONTENT_WIDTH) - .setIsCollapsible(true)) - .setContent(TEXT_CONTENT)) - .addCells(GridCell.newBuilder() - .setWidthBinding(widthBinding) - .setContent(TEXT_CONTENT)) - .addCells(GridCell.newBuilder() - .setWidth(GridCellWidth.newBuilder().setDp(123)) - .setContent(TEXT_CONTENT)) - .build(); - - when(mFrameContext.getGridCellWidthFromBinding(widthBinding)) - .thenReturn(GridCellWidth.newBuilder().setDp(456).build()); - mAdapter.createAdapter(asElement(gridRow), mFrameContext); - - when(mFrameContext.getGridCellWidthFromBinding(widthBinding)) - .thenReturn(GridCellWidth.newBuilder() - .setContentWidth(ContentWidth.CONTENT_WIDTH) - .setIsCollapsible(true) - .build()); - mAdapter.bindModel(asElement(gridRow), mFrameContext); - - assertThat(mAdapter.getBaseView().getChildAt(0).getLayoutParams().width) - .isEqualTo(LayoutParams.WRAP_CONTENT); - assertThat( - ((GridRowView.LayoutParams) mAdapter.getBaseView().getChildAt(0).getLayoutParams()) - .getIsCollapsible()) - .isTrue(); - assertThat(mAdapter.getBaseView().getChildAt(1).getLayoutParams().width) - .isEqualTo(LayoutParams.WRAP_CONTENT); - assertThat( - ((GridRowView.LayoutParams) mAdapter.getBaseView().getChildAt(1).getLayoutParams()) - .getIsCollapsible()) - .isTrue(); - assertThat(mAdapter.getBaseView().getChildAt(2).getLayoutParams().width) - .isEqualTo((int) LayoutUtils.dpToPx(123, mContext)); - } - - @Test - public void testUnbindModel() { - GridRow model = GridRow.newBuilder() - .addCells(GridCell.newBuilder().setContent(DEFAULT_CONTENT)) - .addCells(GridCell.newBuilder().setContent( - Content.newBuilder().setBoundElement(ELEMENT_BINDING))) - .build(); - - when(mFrameContext.getElementBindingValue(ELEMENT_BINDING)) - .thenReturn(BindingValue.newBuilder().setElement(DEFAULT_ELEMENT).build()); - - mAdapter.createAdapter(asElement(model), mFrameContext); - mAdapter.bindModel(asElement(model), mFrameContext); - - mAdapter.unbindModel(); - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(1); - assertThat(mAdapter.mChildAdapters).hasSize(1); - - // The inline adapter has been unbound. - assertThat(mAdapter.mChildAdapters.get(0).getRawModel()).isNull(); - } - - @Test - public void testUnbindModel_worksTwice() { - GridRow model = - GridRow.newBuilder() - .addCells(GridCell.newBuilder() - .setWidth(GridCellWidth.newBuilder() - .setContentWidth( - ContentWidth.CONTENT_WIDTH) - .setIsCollapsible(true)) - .setContent(TEXT_CONTENT)) - .build(); - - mAdapter.createAdapter(asElement(model), mFrameContext); - mAdapter.bindModel(asElement(model), mFrameContext); - - mAdapter.unbindModel(); - mAdapter.unbindModel(); - - // assert no failure. - } - - @Test - public void testReleaseAdapter() { - GridRow model = GridRow.newBuilder() - .addCells(GridCell.newBuilder().setContent(DEFAULT_CONTENT)) - .addCells(GridCell.newBuilder().setContent( - Content.newBuilder().setBoundElement(ELEMENT_BINDING))) - .build(); - - when(mFrameContext.getElementBindingValue(ELEMENT_BINDING)) - .thenReturn(BindingValue.newBuilder().setElement(DEFAULT_ELEMENT).build()); - - mAdapter.createAdapter(asElement(model), mFrameContext); - mAdapter.bindModel(asElement(model), mFrameContext); - - mAdapter.unbindModel(); - mAdapter.releaseAdapter(); - assertThat(mAdapter.getBaseView().getChildCount()).isEqualTo(0); - assertThat(mAdapter.mChildAdapters).isEmpty(); - } - - @Test - public void testReleaseAdapter_collapsibleCells() { - GridRow model = - GridRow.newBuilder() - .addCells(GridCell.newBuilder() - .setWidth(GridCellWidth.newBuilder() - .setContentWidth( - ContentWidth.CONTENT_WIDTH) - .setIsCollapsible(true)) - .setContent(TEXT_CONTENT)) - .build(); - - mAdapter.createAdapter(asElement(model), mFrameContext); - mAdapter.bindModel(asElement(model), mFrameContext); - - mAdapter.unbindModel(); - mAdapter.releaseAdapter(); - - assertThat(mAdapter.getBaseView().hasCollapsibleCells()).isFalse(); - } - - /** - * Mini integration test to ensure that WRAP_CONTENT is set on GridRowAdapter when it is within - * a hierarchy - */ - @Test - public void testCollapsibleCells_integration() { - GridRow gridRow = - GridRow.newBuilder() - .addCells(GridCell.newBuilder() - .setWidth(GridCellWidth.newBuilder().setDp(123)) - .setContent(TEXT_CONTENT)) - .addCells(GridCell.newBuilder() - .setWidth(GridCellWidth.newBuilder() - .setContentWidth( - ContentWidth.CONTENT_WIDTH) - .setIsCollapsible(true)) - .setContent(TEXT_CONTENT)) - .addCells(GridCell.newBuilder() - .setWidth(GridCellWidth.newBuilder().setContentWidth( - ContentWidth.CONTENT_WIDTH)) - .setContent(TEXT_CONTENT)) - .build(); - Frame frame = Frame.newBuilder() - .addContents(Content.newBuilder().setElement( - Element.newBuilder().setElementList( - ElementList.newBuilder().addContents( - Content.newBuilder().setElement( - Element.newBuilder().setGridRow( - gridRow)))))) - .build(); - EventLogger mockEventLogger = mock(EventLogger.class); - FrameAdapterImpl frameAdapter = new FrameAdapterImpl(mContext, mAdapterParameters, - mActionHandler, mockEventLogger, DebugBehavior.SILENT); - frameAdapter.bindModel(frame, 0, null, Collections.emptyList()); - LinearLayout gridRowView = - ((LinearLayout) ((LinearLayout) frameAdapter.getView().getChildAt(0)) - .getChildAt(0)); - assertThat(gridRowView.getChildCount()).isEqualTo(3); - assertThat(gridRowView.getChildAt(0).getLayoutParams().width) - .isEqualTo((int) LayoutUtils.dpToPx(123, mContext)); - assertThat(((GridRowView.LayoutParams) gridRowView.getChildAt(1).getLayoutParams()) - .getIsCollapsible()) - .isTrue(); - assertThat(gridRowView.getChildAt(2).getLayoutParams().width) - .isEqualTo(LayoutParams.WRAP_CONTENT); - } - - @Test - public void testGetStyleIdsStack() { - mAdapter.createAdapter(asElement(GridRow.getDefaultInstance(), GRID_STYLES), mFrameContext); - assertThat(mAdapter.getElementStyleIdsStack()).isEqualTo(GRID_STYLES); - } - - @Test - public void testCreateViewGroup() { - LinearLayout gridView = GridRowAdapter.createView(mContext, Suppliers.of(false)); - assertThat(gridView.getOrientation()).isEqualTo(LinearLayout.HORIZONTAL); - assertThat(gridView.getLayoutParams().width).isEqualTo(LayoutParams.MATCH_PARENT); - assertThat(gridView.getLayoutParams().height).isEqualTo(LayoutParams.WRAP_CONTENT); - } - - @Test - public void testGetModelFromElement() { - GridRow model = GridRow.newBuilder().build(); - - Element elementWithModel = - Element.newBuilder() - .setStyleReferences(StyleIdsStack.newBuilder().addStyleIds("spacer")) - .setGridRow(model) - .build(); - assertThat(mAdapter.getModelFromElement(elementWithModel)).isSameInstanceAs(model); - - Element elementWithWrongModel = - Element.newBuilder().setCustomElement(CustomElement.getDefaultInstance()).build(); - assertThatRunnable(() -> mAdapter.getModelFromElement(elementWithWrongModel)) - .throwsAnExceptionOfType(PietFatalException.class) - .that() - .hasMessageThat() - .contains("Missing GridRow"); - - Element emptyElement = Element.getDefaultInstance(); - assertThatRunnable(() -> mAdapter.getModelFromElement(emptyElement)) - .throwsAnExceptionOfType(PietFatalException.class) - .that() - .hasMessageThat() - .contains("Missing GridRow"); - } - - private static Element asElement(GridRow gridRow, StyleIdsStack styles) { - return Element.newBuilder().setStyleReferences(styles).setGridRow(gridRow).build(); - } - - private static Element asElement(GridRow gridRow) { - return Element.newBuilder().setStyleReferences(GRID_STYLES).setGridRow(gridRow).build(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ImageElementAdapterTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ImageElementAdapterTest.java deleted file mode 100644 index 7760665..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ImageElementAdapterTest.java +++ /dev/null
@@ -1,612 +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. - -package org.chromium.chrome.browser.feed.library.piet; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import static org.chromium.chrome.browser.feed.library.api.host.imageloader.ImageLoaderApi.DIMENSION_UNKNOWN; -import static org.chromium.chrome.browser.feed.library.common.testing.RunnableSubject.assertThatRunnable; -import static org.chromium.chrome.browser.feed.library.piet.StyleProvider.DIMENSION_NOT_SET; - -import android.app.Activity; -import android.content.Context; -import android.graphics.Color; -import android.graphics.drawable.ColorDrawable; -import android.graphics.drawable.Drawable; -import android.view.View; -import android.view.View.MeasureSpec; -import android.widget.ImageView; -import android.widget.ImageView.ScaleType; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.common.functional.Suppliers; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.common.ui.LayoutUtils; -import org.chromium.chrome.browser.feed.library.piet.PietStylesHelper.PietStylesHelperFactory; -import org.chromium.chrome.browser.feed.library.piet.host.AssetProvider; -import org.chromium.chrome.browser.feed.library.piet.ui.RoundedCornerMaskCache; -import org.chromium.chrome.browser.feed.library.piet.ui.RoundedCornerWrapperView; -import org.chromium.components.feed.core.proto.ui.piet.BindingRefsProto.ImageBindingRef; -import org.chromium.components.feed.core.proto.ui.piet.BindingRefsProto.StyleBindingRef; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.BindingValue; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.CustomElement; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.Element; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.ImageElement; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.Visibility; -import org.chromium.components.feed.core.proto.ui.piet.ImagesProto.Image; -import org.chromium.components.feed.core.proto.ui.piet.ImagesProto.ImageSource; -import org.chromium.components.feed.core.proto.ui.piet.MediaQueriesProto.DarkLightCondition; -import org.chromium.components.feed.core.proto.ui.piet.MediaQueriesProto.DarkLightCondition.DarkLightMode; -import org.chromium.components.feed.core.proto.ui.piet.MediaQueriesProto.MediaQueryCondition; -import org.chromium.components.feed.core.proto.ui.piet.RoundedCornersProto.RoundedCorners; -import org.chromium.components.feed.core.proto.ui.piet.RoundedCornersProto.RoundedCorners.Corners; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.EdgeWidths; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.Style; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.StyleIdsStack; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests of the {@link ImageElementAdapter}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ImageElementAdapterTest { - private static final int HEIGHT_DP = 123; - private static final int WIDTH_DP = 321; - private static final EdgeWidths PADDING = - EdgeWidths.newBuilder().setBottom(1).setTop(2).setStart(3).setEnd(4).build(); - private static final RoundedCorners CORNERS = RoundedCorners.newBuilder() - .setBitmask(Corners.BOTTOM_START_VALUE) - .setRadiusDp(34) - .build(); - private static final Image DEFAULT_IMAGE = - Image.newBuilder().addSources(ImageSource.newBuilder().setUrl("icanhas.chz")).build(); - private static final Element DEFAULT_MODEL = - asElement(ImageElement.newBuilder().setImage(DEFAULT_IMAGE).build()); - private static final boolean LEGACY_CORNERS_FLAG = false; - private static final boolean OUTLINE_CORNERS_FLAG = false; - - @Mock - private ElementAdapterFactory mAdapterFactory; - @Mock - private TemplateBinder mTemplateBinder; - @Mock - private FrameContext mFrameContext; - @Mock - private AssetProvider mAssetProvider; - @Mock - private StyleProvider mStyleProvider; - @Mock - private HostProviders mHostProviders; - @Mock - private LoadImageCallback mLoadImageCallback; - - private Context mContext; - private int mHeightPx; - private int mWidthPx; - private ImageView mImageView; - private final FakeClock mClock = new FakeClock(); - private RoundedCornerMaskCache mMaskCache; - - private ImageElementAdapterForTest mAdapter; - - @Before - public void setUp() throws Exception { - initMocks(this); - mContext = Robolectric.buildActivity(Activity.class).get(); - mHeightPx = (int) LayoutUtils.dpToPx(HEIGHT_DP, mContext); - mWidthPx = (int) LayoutUtils.dpToPx(WIDTH_DP, mContext); - mMaskCache = new RoundedCornerMaskCache(); - AdapterParameters parameters = new AdapterParameters(mContext, null, mHostProviders, null, - mAdapterFactory, mTemplateBinder, mClock, new PietStylesHelperFactory(), mMaskCache, - LEGACY_CORNERS_FLAG, OUTLINE_CORNERS_FLAG); - - when(mFrameContext.makeStyleFor(any(StyleIdsStack.class))).thenReturn(mStyleProvider); - when(mFrameContext.filterImageSourcesByMediaQueryCondition(any(Image.class))) - .thenAnswer(invocation -> invocation.getArguments()[0]); - when(mHostProviders.getAssetProvider()).thenReturn(mAssetProvider); - when(mStyleProvider.getPadding()).thenReturn(PADDING); - when(mStyleProvider.hasRoundedCorners()).thenReturn(true); - when(mStyleProvider.getRoundedCorners()).thenReturn(CORNERS); - when(mStyleProvider.getScaleType()).thenReturn(ScaleType.FIT_CENTER); - when(mStyleProvider.createWrapperView( - mContext, mMaskCache, LEGACY_CORNERS_FLAG, OUTLINE_CORNERS_FLAG)) - .thenReturn(new RoundedCornerWrapperView(mContext, CORNERS, mMaskCache, - Suppliers.of(false), - /*radiusOverride= */ 0, - /* borders= */ null, - /* allowClipPath= */ false, - /* allowOutlineRounding= */ false)); - setStyle(null, null); - - mAdapter = new ImageElementAdapterForTest(mContext, parameters); - } - - @Test - public void testCreate() { - assertThat(mAdapter).isNotNull(); - } - - @Test - public void testCreateAdapter() { - setStyle(HEIGHT_DP, WIDTH_DP); - mAdapter.createAdapter(DEFAULT_MODEL, mFrameContext); - assertThat(mAdapter.getModel()).isSameInstanceAs(DEFAULT_MODEL.getImageElement()); - - assertThat(mAdapter.getView()).isNotNull(); - - assertThat(mAdapter.getComputedHeightPx()).isEqualTo(mHeightPx); - assertThat(mAdapter.getComputedWidthPx()).isEqualTo(mWidthPx); - assertThat(mAdapter.getBaseView().getCropToPadding()).isTrue(); - verify(mStyleProvider).applyElementStyles(mAdapter); - } - - @Test - public void testCreateAdapter_noDimensionsSet() { - setStyle(null, null); - mAdapter.createAdapter(DEFAULT_MODEL, mFrameContext); - - assertThat(mAdapter.getModel()).isSameInstanceAs(DEFAULT_MODEL.getImageElement()); - - assertThat(mAdapter.getView()).isNotNull(); - - // Assert that width and height are set to the defaults - assertThat(mAdapter.getComputedHeightPx()).isEqualTo(DIMENSION_NOT_SET); - assertThat(mAdapter.getComputedWidthPx()).isEqualTo(DIMENSION_NOT_SET); - } - - @Test - public void testCreateAdapter_heightOnly() { - setStyle(HEIGHT_DP, null); - mAdapter.createAdapter(DEFAULT_MODEL, mFrameContext); - - assertThat(mAdapter.getModel()).isEqualTo(DEFAULT_MODEL.getImageElement()); - - assertThat(mAdapter.getView()).isNotNull(); - - // Width defaults to MATCH_PARENT - assertThat(mAdapter.getComputedHeightPx()).isEqualTo(mHeightPx); - assertThat(mAdapter.getComputedWidthPx()).isEqualTo(DIMENSION_NOT_SET); - } - - @Test - public void testCreateAdapter_widthOnly() { - setStyle(null, WIDTH_DP); - mAdapter.createAdapter(DEFAULT_MODEL, mFrameContext); - - assertThat(mAdapter.getModel()).isEqualTo(DEFAULT_MODEL.getImageElement()); - - assertThat(mAdapter.getView()).isNotNull(); - - // Image defaults to a square. - assertThat(mAdapter.getComputedHeightPx()).isEqualTo(mWidthPx); - assertThat(mAdapter.getComputedWidthPx()).isEqualTo(mWidthPx); - } - - @Test - public void testCreateAdapter_noContent() { - Element model = asElement(ImageElement.getDefaultInstance()); - - mAdapter.createAdapter(model, mFrameContext); - - assertThatRunnable(() -> mAdapter.bindModel(model, mFrameContext)) - .throwsAnExceptionOfType(PietFatalException.class) - .that() - .hasMessageThat() - .contains("Unsupported or missing content"); - } - - @Test - public void testBindModel_image() { - StyleIdsStack styles = StyleIdsStack.newBuilder().addStyleIds("stylecat").build(); - Element model = Element.newBuilder() - .setStyleReferences(styles) - .setImageElement(ImageElement.newBuilder().setImage(DEFAULT_IMAGE)) - .build(); - - mAdapter.createAdapter(model, mFrameContext); - mAdapter.bindModel(model, mFrameContext); - - mImageView = mAdapter.getBaseView(); - verify(mAssetProvider) - .getImage(DEFAULT_IMAGE, DIMENSION_UNKNOWN, DIMENSION_UNKNOWN, mLoadImageCallback); - - assertThat(mAdapter.getModel()).isSameInstanceAs(model.getImageElement()); - assertThat(mAdapter.getElementStyleIdsStack()).isEqualTo(styles); - } - - @Test - public void testBindModel_imageBinding() { - ImageBindingRef imageBinding = ImageBindingRef.newBuilder().setBindingId("feline").build(); - Element model = asElement(ImageElement.newBuilder().setImageBinding(imageBinding).build()); - when(mFrameContext.getImageBindingValue(imageBinding)) - .thenReturn(BindingValue.newBuilder().setImage(DEFAULT_IMAGE).build()); - - mAdapter.createAdapter(model, mFrameContext); - mAdapter.bindModel(model, mFrameContext); - - verify(mAssetProvider) - .getImage(DEFAULT_IMAGE, DIMENSION_UNKNOWN, DIMENSION_UNKNOWN, mLoadImageCallback); - assertThat(mAdapter.getModel()).isSameInstanceAs(model.getImageElement()); - } - - @Test - public void testBindModel_optionalAbsent() { - String bindingRef = "foto"; - ImageBindingRef imageBindingRef = - ImageBindingRef.newBuilder().setBindingId(bindingRef).setIsOptional(true).build(); - Element imageBindingElement = - asElement(ImageElement.newBuilder().setImageBinding(imageBindingRef).build()); - mAdapter.createAdapter( - asElement(ImageElement.newBuilder().setImage(Image.getDefaultInstance()).build()), - mFrameContext); - when(mFrameContext.getImageBindingValue(imageBindingRef)) - .thenReturn(BindingValue.getDefaultInstance()); - - mAdapter.bindModel(imageBindingElement, mFrameContext); - assertThat(mAdapter.getBaseView().getDrawable()).isNull(); - assertThat(mAdapter.getBaseView().getVisibility()).isEqualTo(View.GONE); - } - - @Test - public void testBindModel_noContentInBindingValue() { - String bindingRef = "foto"; - ImageBindingRef imageBindingRef = - ImageBindingRef.newBuilder().setBindingId(bindingRef).build(); - Element imageBindingElement = - asElement(ImageElement.newBuilder().setImageBinding(imageBindingRef).build()); - mAdapter.createAdapter( - asElement(ImageElement.newBuilder().setImage(Image.getDefaultInstance()).build()), - mFrameContext); - when(mFrameContext.getImageBindingValue(imageBindingRef)) - .thenReturn(BindingValue.newBuilder() - .setBindingId(bindingRef) - .setVisibility(Visibility.VISIBLE) - .clearImage() - .build()); - - assertThatRunnable(() -> mAdapter.bindModel(imageBindingElement, mFrameContext)) - .throwsAnExceptionOfType(PietFatalException.class) - .that() - .hasMessageThat() - .contains("Image binding foto had no content"); - } - - @Test - public void testBindModel_setsScaleType() { - StyleIdsStack styles = StyleIdsStack.newBuilder().addStyleIds("stylecat").build(); - when(mStyleProvider.getScaleType()).thenReturn(ImageView.ScaleType.CENTER_CROP); - Element model = asElement(ImageElement.newBuilder() - .setImage(DEFAULT_IMAGE) - .setStyleReferences(styles) - .build()); - - mAdapter.createAdapter(model, mFrameContext); - mAdapter.bindModel(model, mFrameContext); - - verify(mAssetProvider) - .getImage(DEFAULT_IMAGE, DIMENSION_UNKNOWN, DIMENSION_UNKNOWN, mLoadImageCallback); - assertThat(mAdapter.mScaleTypeForCallback).isEqualTo(ScaleType.CENTER_CROP); - } - - @Test - public void testBindModel_again() { - // Bind a model, then unbind it. - setStyle(HEIGHT_DP, WIDTH_DP); - mAdapter.createAdapter(DEFAULT_MODEL, mFrameContext); - mAdapter.bindModel(DEFAULT_MODEL, mFrameContext); - mImageView = mAdapter.getBaseView(); - RecyclerKey key1 = mAdapter.getKey(); - mAdapter.unbindModel(); - - // Bind a different model - Element model2 = - asElement(ImageElement.newBuilder().setImage(Image.getDefaultInstance()).build()); - mAdapter.bindModel(model2, mFrameContext); - verify(mAssetProvider) - .getImage(Image.getDefaultInstance(), WIDTH_DP, HEIGHT_DP, mLoadImageCallback); - - RecyclerKey key2 = mAdapter.getKey(); - assertThat(key1).isSameInstanceAs(key2); - assertThat(mAdapter.getModel()).isSameInstanceAs(model2.getImageElement()); - assertThat(mAdapter.getView()).isNotNull(); - - ImageView imageView2 = mAdapter.getBaseView(); - - assertThat(imageView2).isSameInstanceAs(mImageView); - } - - @Test - public void testBindModel_bindingTwiceThrowsException() { - setStyle(HEIGHT_DP, WIDTH_DP); - - mAdapter.createAdapter(DEFAULT_MODEL, mFrameContext); - mAdapter.bindModel(DEFAULT_MODEL, mFrameContext); - - assertThatRunnable(() -> mAdapter.bindModel(DEFAULT_MODEL, mFrameContext)) - .throwsAnExceptionOfType(IllegalStateException.class) - .that() - .hasMessageThat() - .contains("An image loading callback exists"); - } - - @Test - public void testBindModel_setsStylesOnlyIfBindingIsDefined() { - // Create an adapter with a default style - setStyle(HEIGHT_DP, WIDTH_DP); - mAdapter.createAdapter(DEFAULT_MODEL, mFrameContext); - - verify(mStyleProvider).applyElementStyles(mAdapter); - - // Styles do not change when a different model is bound - StyleIdsStack otherStyle = StyleIdsStack.newBuilder().addStyleIds("ignored").build(); - Element imageWithOtherStyle = - DEFAULT_MODEL.toBuilder().setStyleReferences(otherStyle).build(); - mAdapter.bindModel(imageWithOtherStyle, mFrameContext); - mAdapter.unbindModel(); - - verify(mFrameContext, never()).makeStyleFor(otherStyle); - - // Styles do change when a model with a style binding is bound - StyleIdsStack boundStyle = - StyleIdsStack.newBuilder() - .setStyleBinding(StyleBindingRef.newBuilder().setBindingId("tuna")) - .build(); - Element imageWithBoundStyle = - DEFAULT_MODEL.toBuilder().setStyleReferences(boundStyle).build(); - mAdapter.bindModel(imageWithBoundStyle, mFrameContext); - - verify(mFrameContext).makeStyleFor(boundStyle); - - verify(mStyleProvider, times(2)).applyElementStyles(mAdapter); - } - - @Test - public void testBindModel_preLoadFill() { - Drawable preLoadFillDrawable = new ColorDrawable(Color.RED); - - // Set up the StyleProvider mock - when(mStyleProvider.createPreLoadFill()).thenReturn(preLoadFillDrawable); - when(mStyleProvider.hasPreLoadFill()).thenReturn(true); - - // Bind and expect the pre-load fill to be set - mAdapter.createAdapter(DEFAULT_MODEL, mFrameContext); - mAdapter.bindModel(DEFAULT_MODEL, mFrameContext); - assertThat(mAdapter.getBaseView().getDrawable()).isSameInstanceAs(preLoadFillDrawable); - - // Load drawable and replace pre-load fill - verify(mAssetProvider) - .getImage(DEFAULT_IMAGE, DIMENSION_UNKNOWN, DIMENSION_UNKNOWN, mLoadImageCallback); - } - - @Test - public void testBindModel_color() { - int red = 0xFFFF0000; - ImageElement defaultImageElement = - ImageElement.newBuilder().setImage(DEFAULT_IMAGE).build(); - StyleProvider redTintStyleProvider = new StyleProvider( - Style.newBuilder().setStyleId("red").setColor(red).build(), mAssetProvider); - StyleIdsStack redTintStyle = StyleIdsStack.newBuilder().addStyleIds("red").build(); - when(mFrameContext.makeStyleFor(redTintStyle)).thenReturn(redTintStyleProvider); - - Element modelWithOverlayColor = Element.newBuilder() - .setStyleReferences(redTintStyle) - .setImageElement(defaultImageElement) - .build(); - - // Bind and expect tint to be set - mAdapter.createAdapter(modelWithOverlayColor, mFrameContext); - mAdapter.bindModel(modelWithOverlayColor, mFrameContext); - verify(mFrameContext).makeStyleFor(redTintStyle); - assertThat(mAdapter.mOverlayColorForCallback).isEqualTo(red); - } - - @Test - public void testBindModel_filtersImageSources() { - ImageSource activeSource = - ImageSource.newBuilder() - .addConditions(MediaQueryCondition.newBuilder().setDarkLight( - DarkLightCondition.newBuilder().setMode(DarkLightMode.DARK))) - .build(); - ImageSource inactiveSource = - ImageSource.newBuilder() - .addConditions(MediaQueryCondition.newBuilder().setDarkLight( - DarkLightCondition.newBuilder().setMode(DarkLightMode.LIGHT))) - .build(); - Image image = - Image.newBuilder().addSources(activeSource).addSources(inactiveSource).build(); - Image filteredImage = Image.newBuilder().addSources(activeSource).build(); - when(mFrameContext.filterImageSourcesByMediaQueryCondition(image)) - .thenReturn(filteredImage); - - Element model = asElement(ImageElement.newBuilder().setImage(image).build()); - - mAdapter.createAdapter(model, mFrameContext); - mAdapter.bindModel(model, mFrameContext); - - verify(mAssetProvider) - .getImage(eq(filteredImage), anyInt(), anyInt(), any(LoadImageCallback.class)); - } - - @Test - public void testBindModel_setsAspectRatio() { - StyleIdsStack styles = StyleIdsStack.newBuilder().addStyleIds("stylecat").build(); - setStyle(null, null); - Element model = asElement(ImageElement.newBuilder() - .setImage(Image.newBuilder().addSources( - ImageSource.newBuilder() - .setWidthPx(100) - .setHeightPx(20) // Aspect ratio of 5.0 - .setUrl("http://whatever"))) - .setStyleReferences(styles) - .build()); - - mAdapter.createAdapter(model, mFrameContext); - mAdapter.bindModel(model, mFrameContext); - - mImageView = mAdapter.getBaseView(); - - mImageView.measure(MeasureSpec.makeMeasureSpec(10, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); - - assertThat(mImageView.getMeasuredWidth()).isEqualTo(10); - assertThat(mImageView.getMeasuredHeight()).isEqualTo(2); - } - - @Test - public void testUnbind() { - setStyle(HEIGHT_DP, WIDTH_DP); - mAdapter.createAdapter(DEFAULT_MODEL, mFrameContext); - mAdapter.bindModel(DEFAULT_MODEL, mFrameContext); - mAdapter.unbindModel(); - - assertThat(mAdapter.getView()).isNotNull(); - assertThat(mAdapter.getBaseView().getDrawable()).isNull(); - - assertThat(mAdapter.getComputedHeightPx()).isEqualTo(mHeightPx); - assertThat(mAdapter.getComputedWidthPx()).isEqualTo(mWidthPx); - } - - @Test - public void testUnbind_cancelsCallback() { - setStyle(HEIGHT_DP, WIDTH_DP); - mAdapter.createAdapter(DEFAULT_MODEL, mFrameContext); - mAdapter.bindModel(DEFAULT_MODEL, mFrameContext); - - mImageView = mAdapter.getBaseView(); - - mAdapter.unbindModel(); - verify(mAssetProvider).getImage(DEFAULT_IMAGE, WIDTH_DP, HEIGHT_DP, mLoadImageCallback); - verify(mLoadImageCallback).cancel(); - } - - @Test - public void testReleaseAdapter_resetsDims() { - setStyle(HEIGHT_DP, WIDTH_DP); - mAdapter.createAdapter(DEFAULT_MODEL, mFrameContext); - mAdapter.bindModel(DEFAULT_MODEL, mFrameContext); - mAdapter.unbindModel(); - mAdapter.releaseAdapter(); - - assertThat(mAdapter.getComputedHeightPx()).isEqualTo(DIMENSION_NOT_SET); - assertThat(mAdapter.getComputedWidthPx()).isEqualTo(DIMENSION_NOT_SET); - } - - @Test - public void testComputedDimensions_unbound() { - assertThat(mAdapter.getComputedHeightPx()).isEqualTo(DIMENSION_NOT_SET); - assertThat(mAdapter.getComputedWidthPx()).isEqualTo(DIMENSION_NOT_SET); - } - - @Test - public void testComputedDimensions_bound() { - setStyle(HEIGHT_DP, WIDTH_DP); - mAdapter.createAdapter(DEFAULT_MODEL, mFrameContext); - - assertThat(mAdapter.getComputedHeightPx()).isEqualTo(mHeightPx); - assertThat(mAdapter.getComputedWidthPx()).isEqualTo(mWidthPx); - } - - @Test - public void testGetAspectRatio_succeeds() { - Image image = Image.newBuilder() - .addSources(ImageSource.getDefaultInstance()) - .addSources(ImageSource.newBuilder().setHeightPx(123)) - .addSources(ImageSource.newBuilder().setWidthPx(456)) - .addSources(ImageSource.newBuilder().setWidthPx(99).setHeightPx( - 33)) // This one gets picked - .addSources(ImageSource.newBuilder().setWidthPx(100).setHeightPx(50)) - .build(); - assertThat(ImageElementAdapter.getAspectRatio(image)).isWithin(0.01f).of(3.0f); - } - - @Test - public void testGetAspectRatio_fails() { - Image image = Image.newBuilder() - .addSources(ImageSource.getDefaultInstance()) - .addSources(ImageSource.newBuilder().setHeightPx(123)) - .addSources(ImageSource.newBuilder().setWidthPx(456)) - .build(); - assertThat(ImageElementAdapter.getAspectRatio(image)).isZero(); - assertThat(ImageElementAdapter.getAspectRatio(Image.getDefaultInstance())).isZero(); - } - - @Test - public void testGetModelFromElement() { - ImageElement model = - ImageElement.newBuilder() - .setStyleReferences(StyleIdsStack.newBuilder().addStyleIds("image")) - .build(); - - Element elementWithModel = Element.newBuilder().setImageElement(model).build(); - assertThat(mAdapter.getModelFromElement(elementWithModel)).isSameInstanceAs(model); - - Element elementWithWrongModel = - Element.newBuilder().setCustomElement(CustomElement.getDefaultInstance()).build(); - assertThatRunnable(() -> mAdapter.getModelFromElement(elementWithWrongModel)) - .throwsAnExceptionOfType(PietFatalException.class) - .that() - .hasMessageThat() - .contains("Missing ImageElement"); - - Element emptyElement = Element.getDefaultInstance(); - assertThatRunnable(() -> mAdapter.getModelFromElement(emptyElement)) - .throwsAnExceptionOfType(PietFatalException.class) - .that() - .hasMessageThat() - .contains("Missing ImageElement"); - } - - private void setStyle(/*@Nullable*/ Integer height, /*@Nullable*/ Integer width) { - if (height != null) { - when(mStyleProvider.hasHeight()).thenReturn(true); - when(mStyleProvider.getHeightSpecPx(mContext)).thenReturn(height); - } else { - when(mStyleProvider.hasHeight()).thenReturn(false); - when(mStyleProvider.getHeightSpecPx(mContext)).thenReturn(DIMENSION_NOT_SET); - } - if (width != null) { - when(mStyleProvider.hasWidth()).thenReturn(true); - when(mStyleProvider.getWidthSpecPx(mContext)).thenReturn(width); - } else { - when(mStyleProvider.hasWidth()).thenReturn(false); - when(mStyleProvider.getWidthSpecPx(mContext)).thenReturn(DIMENSION_NOT_SET); - } - } - - private static Element asElement(ImageElement imageElement) { - return Element.newBuilder().setImageElement(imageElement).build(); - } - - private class ImageElementAdapterForTest extends ImageElementAdapter { - private ScaleType mScaleTypeForCallback; - private Integer mOverlayColorForCallback; - - private ImageElementAdapterForTest(Context context, AdapterParameters parameters) { - super(context, parameters); - } - - @Override - LoadImageCallback createLoadImageCallback(ScaleType scaleType, - /*@Nullable*/ Integer overlayColor, FrameContext frameContext) { - this.mScaleTypeForCallback = scaleType; - this.mOverlayColorForCallback = overlayColor; - return mLoadImageCallback; - } - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/KeyedRecyclerPoolTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/KeyedRecyclerPoolTest.java deleted file mode 100644 index 50117fd1..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/KeyedRecyclerPoolTest.java +++ /dev/null
@@ -1,196 +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. - -package org.chromium.chrome.browser.feed.library.piet; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.MockitoAnnotations.initMocks; - -import static org.chromium.chrome.browser.feed.library.common.testing.RunnableSubject.assertThatRunnable; - -import android.app.Activity; -import android.content.Context; -import android.view.View; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.Element; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests of the {@link KeyedRecyclerPool} */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class KeyedRecyclerPoolTest { - private static final RecyclerKey KEY1 = new TestRecyclerKey("KEY1"); - private static final RecyclerKey KEY2 = new TestRecyclerKey("KEY2"); - private static final RecyclerKey KEY3 = new TestRecyclerKey("KEY3"); - private static final int MAX_KEYS = 10; - private static final int CAPACITY = 11; - - @Mock - TestElementAdapter mAdapter; - @Mock - TestElementAdapter mAdapter2; - @Mock - TestElementAdapter mAdapter3; - @Mock - TestElementAdapter mAdapter4; - - private Context mTestContext; - - @Before - public void setUp() { - mTestContext = Robolectric.buildActivity(Activity.class).get(); - initMocks(this); - } - - @Test - public void testPutAndGetOneElement() { - KeyedRecyclerPool<TestElementAdapter> pool = new KeyedRecyclerPool<>(MAX_KEYS, CAPACITY); - pool.put(KEY1, mAdapter); - assertThat(pool.get(KEY1)).isEqualTo(mAdapter); - } - - @Test - public void testGetFromEmptyPoolReturnsNull() { - KeyedRecyclerPool<TestElementAdapter> pool = new KeyedRecyclerPool<>(MAX_KEYS, CAPACITY); - assertThat(pool.get(KEY1)).isNull(); - } - - @Test - public void testGetFromEmptyPoolWithDifferentKeyReturnsNull() { - KeyedRecyclerPool<TestElementAdapter> pool = new KeyedRecyclerPool<>(MAX_KEYS, CAPACITY); - pool.put(KEY1, mAdapter); - assertThat(pool.get(KEY2)).isNull(); - } - - @Test - public void testPutAndGetElementsWithDifferentKeys() { - KeyedRecyclerPool<TestElementAdapter> pool = new KeyedRecyclerPool<>(MAX_KEYS, CAPACITY); - pool.put(KEY1, mAdapter); - pool.put(KEY2, mAdapter2); - assertThat(pool.get(KEY2)).isEqualTo(mAdapter2); - assertThat(pool.get(KEY1)).isEqualTo(mAdapter); - } - - @Test - public void testPutNullElementFails() { - KeyedRecyclerPool<TestElementAdapter> pool = new KeyedRecyclerPool<>(MAX_KEYS, CAPACITY); - pool.put(KEY1, null); - assertThat(pool.get(KEY1)).isNull(); - } - - @Test - public void testPutNullKeyFails() { - KeyedRecyclerPool<TestElementAdapter> pool = new KeyedRecyclerPool<>(MAX_KEYS, CAPACITY); - assertThatRunnable(() -> pool.put(null, mAdapter)) - .throwsAnExceptionOfType(NullPointerException.class) - .that() - .hasMessageThat() - .contains("null key for mAdapter"); - } - - @Test - public void testGetNullKeyReturnsNull() { - KeyedRecyclerPool<TestElementAdapter> pool = new KeyedRecyclerPool<>(MAX_KEYS, CAPACITY); - assertThat(pool.get(null)).isNull(); - } - - @Test - public void testCacheOverflowEjectsPool() { - KeyedRecyclerPool<TestElementAdapter> pool = new KeyedRecyclerPool<>(2, CAPACITY); - pool.put(KEY1, mAdapter); - pool.put(KEY2, mAdapter2); - pool.put(KEY3, mAdapter3); - assertThat(pool.get(KEY1)).isNull(); - assertThat(pool.get(KEY2)).isEqualTo(mAdapter2); - assertThat(pool.get(KEY3)).isEqualTo(mAdapter3); - } - - @Test - public void testOverflowSinglePoolIgnoresLastElement() { - KeyedRecyclerPool<TestElementAdapter> pool = new KeyedRecyclerPool<>(MAX_KEYS, 2); - pool.put(KEY1, mAdapter); - pool.put(KEY1, mAdapter2); - pool.put(KEY1, mAdapter3); - assertThat(pool.get(KEY1)).isNotNull(); - assertThat(pool.get(KEY1)).isNotNull(); - assertThat(pool.get(KEY1)).isNull(); - } - - @Test - public void testFillAllPools() { - KeyedRecyclerPool<TestElementAdapter> pool = new KeyedRecyclerPool<>(2, 2); - pool.put(KEY1, mAdapter); - pool.put(KEY1, mAdapter2); - pool.put(KEY2, mAdapter3); - pool.put(KEY2, mAdapter4); - assertThat(pool.get(KEY1)).isNotNull(); - assertThat(pool.get(KEY1)).isNotNull(); - assertThat(pool.get(KEY1)).isNull(); - assertThat(pool.get(KEY2)).isNotNull(); - assertThat(pool.get(KEY2)).isNotNull(); - assertThat(pool.get(KEY2)).isNull(); - } - - @Test - public void testClear() { - KeyedRecyclerPool<TestElementAdapter> pool = new KeyedRecyclerPool<>(MAX_KEYS, MAX_KEYS); - pool.put(KEY1, mAdapter); - pool.put(KEY1, mAdapter2); - pool.put(KEY2, mAdapter3); - pool.put(KEY2, mAdapter4); - pool.clear(); - assertThat(pool.get(KEY1)).isNull(); - assertThat(pool.get(KEY2)).isNull(); - } - - private static class TestRecyclerKey extends RecyclerKey { - private final String mKey; - - TestRecyclerKey(String key) { - this.mKey = key; - } - - @Override - public int hashCode() { - return mKey.hashCode(); - } - - @Override - public boolean equals(/*@Nullable*/ Object obj) { - if (obj == this) { - return true; - } - - if (obj == null) { - return false; - } - - if (!(obj instanceof TestRecyclerKey)) { - return false; - } - - TestRecyclerKey otherKey = (TestRecyclerKey) obj; - return otherKey.mKey.equals(this.mKey); - } - } - - private class TestElementAdapter extends ElementAdapter<View, Object> { - TestElementAdapter() { - super(mTestContext, null, new View(mTestContext)); - } - - @Override - protected Object getModelFromElement(Element baseElement) { - return null; - } - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/LoadImageCallbackTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/LoadImageCallbackTest.java deleted file mode 100644 index 6948b8e..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/LoadImageCallbackTest.java +++ /dev/null
@@ -1,189 +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. - -package org.chromium.chrome.browser.feed.library.piet; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import android.app.Activity; -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Bitmap.Config; -import android.graphics.Color; -import android.graphics.PorterDuff.Mode; -import android.graphics.PorterDuffColorFilter; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.ColorDrawable; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.TransitionDrawable; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.ImageView.ScaleType; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.shadows.ShadowLooper; - -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.piet.host.AssetProvider; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests of the {@link LoadImageCallback}. */ -@RunWith(LocalRobolectricTestRunner.class) -@org.robolectric.annotation.Config(sdk = 27, manifest = org.robolectric.annotation.Config.NONE) -public class LoadImageCallbackTest { - private static final long FADE_IMAGE_THRESHOLD_MS = 682L; - // null is a special value indicating no overlay. - private static final Integer NO_OVERLAY_COLOR = null; - private static final boolean FADE_IMAGE = true; - private static final boolean NO_FADE_IMAGE = false; - - @Mock - private HostProviders mHostProviders; - @Mock - private AssetProvider mAssetProvider; - @Mock - private FrameContext mFrameContext; - - private final Drawable mInitialDrawable = new ColorDrawable(Color.RED); - private final Drawable mFinalDrawable = - new BitmapDrawable(Bitmap.createBitmap(12, 34, Config.ARGB_8888)); - private final FakeClock mClock = new FakeClock(); - private AdapterParameters mParameters; - private Context mContext; - - @Before - public void setup() { - initMocks(this); - mContext = Robolectric.buildActivity(Activity.class).get(); - - when(mHostProviders.getAssetProvider()).thenReturn(mAssetProvider); - when(mAssetProvider.getFadeImageThresholdMs()).thenReturn(FADE_IMAGE_THRESHOLD_MS); - when(mFrameContext.getFrameView()).thenReturn(new FrameLayout(mContext)); - - mParameters = new AdapterParameters(mContext, null, mHostProviders, null, - mock(ElementAdapterFactory.class), mock(TemplateBinder.class), mClock); - } - - @Test - public void testInitialDrawable_fromImageView() { - ImageView imageView = new ImageView(mContext); - imageView.setImageDrawable(mInitialDrawable); - - LoadImageCallback callback = new LoadImageCallback(imageView, ScaleType.CENTER, - NO_OVERLAY_COLOR, FADE_IMAGE, mParameters, mFrameContext); - - mClock.advance(FADE_IMAGE_THRESHOLD_MS + 1); - callback.accept(mFinalDrawable); - - assertThat(imageView.getDrawable()).isInstanceOf(TransitionDrawable.class); - - TransitionDrawable drawable = (TransitionDrawable) imageView.getDrawable(); - - assertThat(drawable.getDrawable(0)).isSameInstanceAs(mInitialDrawable); - assertThat(drawable.getDrawable(1)).isSameInstanceAs(mFinalDrawable); - } - - @Test - public void testInitialDrawable_transparent() { - ImageView imageView = new ImageView(mContext); - - LoadImageCallback callback = new LoadImageCallback(imageView, ScaleType.CENTER, - NO_OVERLAY_COLOR, FADE_IMAGE, mParameters, mFrameContext); - - mClock.advance(FADE_IMAGE_THRESHOLD_MS + 1); - callback.accept(mFinalDrawable); - - assertThat(imageView.getDrawable()).isInstanceOf(TransitionDrawable.class); - - TransitionDrawable drawable = (TransitionDrawable) imageView.getDrawable(); - - assertThat(((ColorDrawable) drawable.getDrawable(0)).getColor()) - .isEqualTo(Color.TRANSPARENT); - } - - @Test - public void testQuickLoad_doesntFade_fadingDisabled() { - ImageView imageView = new ImageView(mContext); - - LoadImageCallback callback = new LoadImageCallback(imageView, ScaleType.CENTER, - NO_OVERLAY_COLOR, NO_FADE_IMAGE, mParameters, mFrameContext); - - mClock.advance(FADE_IMAGE_THRESHOLD_MS + 1); - callback.accept(mFinalDrawable); - - assertThat(imageView.getDrawable()).isSameInstanceAs(mFinalDrawable); - } - - @Test - public void testQuickLoad_doesntFade_loadsBeforeTimeout() { - ImageView imageView = new ImageView(mContext); - - LoadImageCallback callback = new LoadImageCallback(imageView, ScaleType.CENTER, - NO_OVERLAY_COLOR, FADE_IMAGE, mParameters, mFrameContext); - - mClock.advance(FADE_IMAGE_THRESHOLD_MS - 1); - callback.accept(mFinalDrawable); - - assertThat(imageView.getDrawable()).isSameInstanceAs(mFinalDrawable); - } - - @Test - public void testDelayedTask() { - ImageView imageView = new ImageView(mContext); - LoadImageCallback callback = new LoadImageCallback(imageView, ScaleType.CENTER, - NO_OVERLAY_COLOR, FADE_IMAGE, mParameters, mFrameContext); - mClock.advance(FADE_IMAGE_THRESHOLD_MS + 1); - callback.accept(mFinalDrawable); - - // Starts as transition drawable. - assertThat(imageView.getDrawable()).isInstanceOf(TransitionDrawable.class); - - ShadowLooper.runUiThreadTasksIncludingDelayedTasks(); - - // After the delayed task is run, the drawable is set to the mFinalDrawable instead of the - // TransitionDrawable to allow for garbage collection of the TransitionDrawable and - // initialDrawable. - assertThat(imageView.getDrawable()).isSameInstanceAs(mFinalDrawable); - } - - @Test - public void testSetsScaleType() { - ImageView imageView = new ImageView(mContext); - LoadImageCallback callback = new LoadImageCallback(imageView, ScaleType.CENTER, - NO_OVERLAY_COLOR, NO_FADE_IMAGE, mParameters, mFrameContext); - callback.accept(mFinalDrawable); - - assertThat(imageView.getScaleType()).isEqualTo(ScaleType.CENTER); - } - - @Test - public void testSetsOverlayColor() { - int color = 0xFEEDFACE; - ImageView imageView = new ImageView(mContext); - LoadImageCallback callback = new LoadImageCallback( - imageView, ScaleType.CENTER, color, NO_FADE_IMAGE, mParameters, mFrameContext); - callback.accept(mFinalDrawable); - - assertThat(imageView.getDrawable().getColorFilter()) - .isEqualTo(new PorterDuffColorFilter(color, Mode.SRC_IN)); - } - - @Test - public void testSetsOverlayColor_null() { - ImageView imageView = new ImageView(mContext); - LoadImageCallback callback = new LoadImageCallback(imageView, ScaleType.CENTER, - NO_OVERLAY_COLOR, NO_FADE_IMAGE, mParameters, mFrameContext); - callback.accept(mFinalDrawable); - - assertThat(imageView.getDrawable().getColorFilter()).isNull(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/MediaQueryHelperTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/MediaQueryHelperTest.java deleted file mode 100644 index 03f4139..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/MediaQueryHelperTest.java +++ /dev/null
@@ -1,282 +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. - -package org.chromium.chrome.browser.feed.library.piet; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import static org.chromium.chrome.browser.feed.library.common.testing.RunnableSubject.assertThatRunnable; - -import android.app.Activity; -import android.content.Context; -import android.content.res.Configuration; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.piet.host.AssetProvider; -import org.chromium.components.feed.core.proto.ui.piet.MediaQueriesProto.ComparisonCondition; -import org.chromium.components.feed.core.proto.ui.piet.MediaQueriesProto.DarkLightCondition; -import org.chromium.components.feed.core.proto.ui.piet.MediaQueriesProto.DarkLightCondition.DarkLightMode; -import org.chromium.components.feed.core.proto.ui.piet.MediaQueriesProto.FrameWidthCondition; -import org.chromium.components.feed.core.proto.ui.piet.MediaQueriesProto.MediaQueryCondition; -import org.chromium.components.feed.core.proto.ui.piet.MediaQueriesProto.OrientationCondition; -import org.chromium.components.feed.core.proto.ui.piet.MediaQueriesProto.OrientationCondition.Orientation; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.Arrays; -import java.util.List; - -/** Tests for the MediaQueryHelper. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class MediaQueryHelperTest { - private static final int DEFAULT_FRAME_WIDTH = 123; - - @Mock - private AssetProvider mAssetProvider; - - private Context mContext; - - private MediaQueryHelper mMediaQueryHelper; - - @Before - public void setUp() { - initMocks(this); - mContext = Robolectric.buildActivity(Activity.class).get(); - mMediaQueryHelper = new MediaQueryHelper(DEFAULT_FRAME_WIDTH, mAssetProvider, mContext); - } - - @Test - public void testMediaQueryConditions_frameWidth() { - int smallWidth = 1; - int midWidth = 10; - int bigWidth = 100; - - mMediaQueryHelper = new MediaQueryHelper(midWidth, mAssetProvider, mContext); - assertThat(mMediaQueryHelper.isMediaQueryMet( - MediaQueryCondition.newBuilder() - .setFrameWidth(FrameWidthCondition.newBuilder() - .setWidth(midWidth) - .setCondition(ComparisonCondition.EQUALS)) - .build())) - .isTrue(); - assertThat(mMediaQueryHelper.isMediaQueryMet( - MediaQueryCondition.newBuilder() - .setFrameWidth(FrameWidthCondition.newBuilder() - .setWidth(smallWidth) - .setCondition(ComparisonCondition.EQUALS)) - .build())) - .isFalse(); - assertThat(mMediaQueryHelper.isMediaQueryMet( - MediaQueryCondition.newBuilder() - .setFrameWidth( - FrameWidthCondition.newBuilder() - .setWidth(smallWidth) - .setCondition(ComparisonCondition.GREATER_THAN)) - .build())) - .isTrue(); - assertThat(mMediaQueryHelper.isMediaQueryMet( - MediaQueryCondition.newBuilder() - .setFrameWidth( - FrameWidthCondition.newBuilder() - .setWidth(bigWidth) - .setCondition(ComparisonCondition.GREATER_THAN)) - .build())) - .isFalse(); - assertThat( - mMediaQueryHelper.isMediaQueryMet( - MediaQueryCondition.newBuilder() - .setFrameWidth(FrameWidthCondition.newBuilder() - .setWidth(bigWidth) - .setCondition(ComparisonCondition.LESS_THAN)) - .build())) - .isTrue(); - assertThat( - mMediaQueryHelper.isMediaQueryMet( - MediaQueryCondition.newBuilder() - .setFrameWidth(FrameWidthCondition.newBuilder() - .setWidth(smallWidth) - .setCondition(ComparisonCondition.LESS_THAN)) - .build())) - .isFalse(); - assertThat(mMediaQueryHelper.isMediaQueryMet( - MediaQueryCondition.newBuilder() - .setFrameWidth( - FrameWidthCondition.newBuilder() - .setWidth(smallWidth) - .setCondition(ComparisonCondition.NOT_EQUALS)) - .build())) - .isTrue(); - assertThat(mMediaQueryHelper.isMediaQueryMet( - MediaQueryCondition.newBuilder() - .setFrameWidth( - FrameWidthCondition.newBuilder() - .setWidth(midWidth) - .setCondition(ComparisonCondition.NOT_EQUALS)) - .build())) - .isFalse(); - - assertThatRunnable( - () - -> mMediaQueryHelper.isMediaQueryMet( - MediaQueryCondition.newBuilder() - .setFrameWidth( - FrameWidthCondition.newBuilder() - .setWidth(midWidth) - .setCondition( - ComparisonCondition.UNSPECIFIED)) - .build())) - .throwsAnExceptionOfType(IllegalArgumentException.class) - .that() - .hasMessageThat() - .contains("Unhandled ComparisonCondition: UNSPECIFIED"); - } - - @Test - public void testMediaQueryConditions_orientation() { - mContext.getResources().getConfiguration().orientation = - Configuration.ORIENTATION_LANDSCAPE; - mMediaQueryHelper = new MediaQueryHelper(DEFAULT_FRAME_WIDTH, mAssetProvider, mContext); - assertThat(mMediaQueryHelper.isMediaQueryMet( - MediaQueryCondition.newBuilder() - .setOrientation(OrientationCondition.newBuilder().setOrientation( - Orientation.LANDSCAPE)) - .build())) - .isTrue(); - assertThat(mMediaQueryHelper.isMediaQueryMet( - MediaQueryCondition.newBuilder() - .setOrientation(OrientationCondition.newBuilder().setOrientation( - Orientation.PORTRAIT)) - .build())) - .isFalse(); - - mContext.getResources().getConfiguration().orientation = Configuration.ORIENTATION_PORTRAIT; - mMediaQueryHelper = new MediaQueryHelper(DEFAULT_FRAME_WIDTH, mAssetProvider, mContext); - assertThat(mMediaQueryHelper.isMediaQueryMet( - MediaQueryCondition.newBuilder() - .setOrientation(OrientationCondition.newBuilder().setOrientation( - Orientation.LANDSCAPE)) - .build())) - .isFalse(); - assertThat(mMediaQueryHelper.isMediaQueryMet( - MediaQueryCondition.newBuilder() - .setOrientation(OrientationCondition.newBuilder().setOrientation( - Orientation.PORTRAIT)) - .build())) - .isTrue(); - assertThat(mMediaQueryHelper.isMediaQueryMet( - MediaQueryCondition.newBuilder() - .setOrientation(OrientationCondition.newBuilder().setOrientation( - Orientation.UNSPECIFIED)) - .build())) - .isTrue(); - - mContext.getResources().getConfiguration().orientation = - Configuration.ORIENTATION_UNDEFINED; - mMediaQueryHelper = new MediaQueryHelper(DEFAULT_FRAME_WIDTH, mAssetProvider, mContext); - assertThat(mMediaQueryHelper.isMediaQueryMet( - MediaQueryCondition.newBuilder() - .setOrientation(OrientationCondition.newBuilder().setOrientation( - Orientation.LANDSCAPE)) - .build())) - .isFalse(); - assertThat(mMediaQueryHelper.isMediaQueryMet( - MediaQueryCondition.newBuilder() - .setOrientation(OrientationCondition.newBuilder().setOrientation( - Orientation.PORTRAIT)) - .build())) - .isFalse(); - assertThat(mMediaQueryHelper.isMediaQueryMet( - MediaQueryCondition.newBuilder() - .setOrientation(OrientationCondition.newBuilder().setOrientation( - Orientation.UNSPECIFIED)) - .build())) - .isFalse(); - } - - @Test - public void testMediaQueryConditions_darkLight() { - when(mAssetProvider.isDarkTheme()).thenReturn(true); - mMediaQueryHelper = new MediaQueryHelper(DEFAULT_FRAME_WIDTH, mAssetProvider, mContext); - assertThat(mMediaQueryHelper.isMediaQueryMet( - MediaQueryCondition.newBuilder() - .setDarkLight(DarkLightCondition.newBuilder().setMode( - DarkLightMode.DARK)) - .build())) - .isTrue(); - assertThat(mMediaQueryHelper.isMediaQueryMet( - MediaQueryCondition.newBuilder() - .setDarkLight(DarkLightCondition.newBuilder().setMode( - DarkLightMode.LIGHT)) - .build())) - .isFalse(); - assertThat(mMediaQueryHelper.isMediaQueryMet( - MediaQueryCondition.newBuilder() - .setDarkLight(DarkLightCondition.newBuilder().setMode( - DarkLightMode.UNSPECIFIED)) - .build())) - .isFalse(); - - when(mAssetProvider.isDarkTheme()).thenReturn(false); - mMediaQueryHelper = new MediaQueryHelper(DEFAULT_FRAME_WIDTH, mAssetProvider, mContext); - assertThat(mMediaQueryHelper.isMediaQueryMet( - MediaQueryCondition.newBuilder() - .setDarkLight(DarkLightCondition.newBuilder().setMode( - DarkLightMode.DARK)) - .build())) - .isFalse(); - assertThat(mMediaQueryHelper.isMediaQueryMet( - MediaQueryCondition.newBuilder() - .setDarkLight(DarkLightCondition.newBuilder().setMode( - DarkLightMode.LIGHT)) - .build())) - .isTrue(); - assertThat(mMediaQueryHelper.isMediaQueryMet( - MediaQueryCondition.newBuilder() - .setDarkLight(DarkLightCondition.newBuilder().setMode( - DarkLightMode.UNSPECIFIED)) - .build())) - .isTrue(); - } - - @Test - public void testMediaQueryConditions_allConditionsTrue() { - MediaQueryCondition landscapeCondition = - MediaQueryCondition.newBuilder() - .setOrientation(OrientationCondition.newBuilder().setOrientation( - Orientation.LANDSCAPE)) - .build(); - MediaQueryCondition darkThemeCondition = - MediaQueryCondition.newBuilder() - .setDarkLight(DarkLightCondition.newBuilder().setMode(DarkLightMode.DARK)) - .build(); - MediaQueryCondition frameWidthCondition = - MediaQueryCondition.newBuilder() - .setFrameWidth(FrameWidthCondition.newBuilder().setWidth(100).setCondition( - ComparisonCondition.GREATER_THAN)) - .build(); - - List<MediaQueryCondition> conditions = - Arrays.asList(landscapeCondition, darkThemeCondition, frameWidthCondition); - - mContext.getResources().getConfiguration().orientation = - Configuration.ORIENTATION_LANDSCAPE; - - when(mAssetProvider.isDarkTheme()).thenReturn(true); - mMediaQueryHelper = new MediaQueryHelper(DEFAULT_FRAME_WIDTH, mAssetProvider, mContext); - assertThat(mMediaQueryHelper.areMediaQueriesMet(conditions)).isTrue(); - - when(mAssetProvider.isDarkTheme()).thenReturn(false); - mMediaQueryHelper = new MediaQueryHelper(DEFAULT_FRAME_WIDTH, mAssetProvider, mContext); - assertThat(mMediaQueryHelper.areMediaQueriesMet(conditions)).isFalse(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/NoKeyOverwriteHashMapTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/NoKeyOverwriteHashMapTest.java deleted file mode 100644 index aacde205..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/NoKeyOverwriteHashMapTest.java +++ /dev/null
@@ -1,36 +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. - -package org.chromium.chrome.browser.feed.library.piet; - -import static org.chromium.chrome.browser.feed.library.common.testing.RunnableSubject.assertThatRunnable; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -import org.chromium.components.feed.core.proto.ui.piet.ErrorsProto.ErrorCode; - -/** Tests of the NoKeyOverwriteHashMap */ -@RunWith(JUnit4.class) -public class NoKeyOverwriteHashMapTest { - private final NoKeyOverwriteHashMap<String, String> mMap = - new NoKeyOverwriteHashMap<>("Acronym", ErrorCode.ERR_DUPLICATE_BINDING_VALUE); - - @Test - public void testPutTwoDifferentKeys() { - mMap.put("CPA", "Certified Public Accountant"); - mMap.put("CPU", "Central Processing Unit"); - } - - @Test - public void testPutTwoSameKeysThrows() { - mMap.put("CD", "Compact Disc"); - assertThatRunnable(() -> mMap.put("CD", "Certificate of Deposit")) - .throwsAnExceptionOfType(PietFatalException.class) - .that() - .hasMessageThat() - .contains("Acronym key 'CD' already defined"); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ParameterizedTextElementAdapterFactoryTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ParameterizedTextElementAdapterFactoryTest.java deleted file mode 100644 index d49352eaa..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ParameterizedTextElementAdapterFactoryTest.java +++ /dev/null
@@ -1,151 +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. - -package org.chromium.chrome.browser.feed.library.piet; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import android.app.Activity; -import android.content.Context; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.piet.TextElementAdapter.TextElementKey; -import org.chromium.chrome.browser.feed.library.piet.host.AssetProvider; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.Element; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.TextElement; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.Font; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.StyleIdsStack; -import org.chromium.components.feed.core.proto.ui.piet.TextProto.ParameterizedText; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests of the {@link TextElementAdapter} instance of the {@link AdapterFactory}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ParameterizedTextElementAdapterFactoryTest { - private static final String TEXT_LINE_CONTENT = "Content"; - - @Mock - private FrameContext mFrameContext; - @Mock - ParameterizedTextElementAdapter.KeySupplier mKeySupplier; - @Mock - ParameterizedTextElementAdapter mAdapter; - @Mock - ParameterizedTextElementAdapter mAdapter2; - - private AdapterParameters mAdapterParameters; - private Context mContext; - - @Before - public void setUp() throws Exception { - initMocks(this); - mContext = Robolectric.buildActivity(Activity.class).get(); - mAdapterParameters = new AdapterParameters(null, null, - new HostProviders(mock(AssetProvider.class), null, null, null), new FakeClock(), - false, false); - when(mKeySupplier.getAdapter(mContext, mAdapterParameters)) - .thenReturn(mAdapter) - .thenReturn(mAdapter2); - } - - @Test - public void testKeySupplier() { - String styleId = "text"; - StyleIdsStack style = StyleIdsStack.newBuilder().addStyleIds(styleId).build(); - Font font = Font.newBuilder().setSize(123).setItalic(true).build(); - Element model = Element.newBuilder() - .setStyleReferences(style) - .setTextElement(TextElement.getDefaultInstance()) - .build(); - StyleProvider styleProvider = mock(StyleProvider.class); - when(mFrameContext.makeStyleFor(style)).thenReturn(styleProvider); - when(styleProvider.getFont()).thenReturn(font); - ParameterizedTextElementAdapter.KeySupplier keySupplier = - new ParameterizedTextElementAdapter.KeySupplier(); - - assertThat(keySupplier.getAdapterTag()).isEqualTo("ParameterizedTextElementAdapter"); - - assertThat(keySupplier.getAdapter(mContext, mAdapterParameters)).isNotNull(); - - TextElementKey key = new TextElementKey(font); - assertThat(keySupplier.getKey(mFrameContext, model)).isEqualTo(key); - } - - @Test - public void testGetAdapterFromFactory() { - AdapterFactory<ParameterizedTextElementAdapter, Element> textElementFactory = - new AdapterFactory<>(mContext, mAdapterParameters, mKeySupplier); - Element textElement = getBaseTextElementModel(null); - - ParameterizedTextElementAdapter textElementAdapter = - textElementFactory.get(textElement, mFrameContext); - - // Verify we get the adapter from the KeySupplier, and we create but not bind it. - assertThat(textElementAdapter).isSameInstanceAs(mAdapter); - verify(mAdapter, never()).createAdapter(any(), any(), any()); - verify(mAdapter, never()).bindModel(any(), any(), any()); - } - - @Test - public void testReleaseAndRecycling() { - AdapterFactory<ParameterizedTextElementAdapter, Element> textElementFactory = - new AdapterFactory<>(mContext, mAdapterParameters, mKeySupplier); - Element textElement = getBaseTextElementModel(null); - TextElementKey adapterKey = - new TextElementKey(mAdapterParameters.mDefaultStyleProvider.getFont()); - when(mAdapter.getKey()).thenReturn(adapterKey); - when(mKeySupplier.getKey(mFrameContext, textElement)).thenReturn(adapterKey); - - ParameterizedTextElementAdapter textElementAdapter = - textElementFactory.get(textElement, mFrameContext); - assertThat(textElementAdapter).isSameInstanceAs(mAdapter); - textElementAdapter.createAdapter(textElement, mFrameContext); - - // Ensure that releasing in the factory releases the adapter. - textElementFactory.release(textElementAdapter); - verify(mAdapter).releaseAdapter(); - - // Verify we get the same item when we create it again. - TextElementAdapter textElementAdapter2 = textElementFactory.get(textElement, mFrameContext); - assertThat(textElementAdapter2).isSameInstanceAs(mAdapter); - assertThat(textElementAdapter2).isEqualTo(textElementAdapter); - verify(mAdapter, never()) - .createAdapter(textElement, Element.getDefaultInstance(), mFrameContext); - verify(mAdapter, never()).bindModel(any(), any(), any()); - - // Verify we get a new item when we create another. - TextElementAdapter textElementAdapter3 = textElementFactory.get(textElement, mFrameContext); - assertThat(textElementAdapter3).isSameInstanceAs(mAdapter2); - assertThat(textElementAdapter3).isNotSameInstanceAs(textElementAdapter); - } - - private Element getBaseTextElementModel(/*@Nullable*/ StyleProvider styleProvider) { - return Element.newBuilder().setTextElement(getBaseTextElement(styleProvider)).build(); - } - - private TextElement getBaseTextElement(/*@Nullable*/ StyleProvider styleProvider) { - StyleProvider sp = - styleProvider != null ? styleProvider : mAdapterParameters.mDefaultStyleProvider; - when(mFrameContext.makeStyleFor(any(StyleIdsStack.class))).thenReturn(sp); - - TextElement.Builder textElement = TextElement.newBuilder(); - ParameterizedText text = ParameterizedText.newBuilder().setText(TEXT_LINE_CONTENT).build(); - textElement.setParameterizedText(text); - return textElement.build(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ParameterizedTextElementAdapterTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ParameterizedTextElementAdapterTest.java deleted file mode 100644 index 8170a1f..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ParameterizedTextElementAdapterTest.java +++ /dev/null
@@ -1,231 +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. - -package org.chromium.chrome.browser.feed.library.piet; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import static org.chromium.chrome.browser.feed.library.common.testing.RunnableSubject.assertThatRunnable; - -import android.app.Activity; -import android.content.Context; -import android.view.Gravity; -import android.widget.TextView; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.piet.DebugLogger.MessageType; -import org.chromium.chrome.browser.feed.library.piet.host.AssetProvider; -import org.chromium.components.feed.core.proto.ui.piet.BindingRefsProto.ParameterizedTextBindingRef; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.BindingValue; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.Element; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.TextElement; -import org.chromium.components.feed.core.proto.ui.piet.ErrorsProto.ErrorCode; -import org.chromium.components.feed.core.proto.ui.piet.RoundedCornersProto.RoundedCorners; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.Font; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.StyleIdsStack; -import org.chromium.components.feed.core.proto.ui.piet.TextProto.ParameterizedText; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** - * Tests of the {@link ParameterizedTextElementAdapter}; also tests base features of {@link - * TextElementAdapter}. - */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ParameterizedTextElementAdapterTest { - private static final String TEXT_LINE_CONTENT = "Content"; - private static final String BINDING = "binding"; - private static final ParameterizedTextBindingRef DEFAULT_BINDING_REF = - ParameterizedTextBindingRef.newBuilder().setBindingId(BINDING).build(); - - @Mock - private FrameContext mFrameContext; - @Mock - private StyleProvider mMockStyleProvider; - @Mock - private HostProviders mHostProviders; - @Mock - private AssetProvider mAssetProvider; - - private AdapterParameters mAdapterParameters; - - private Context mContext; - - private ParameterizedTextElementAdapter mAdapter; - - @Before - public void setUp() throws Exception { - initMocks(this); - mContext = Robolectric.buildActivity(Activity.class).get(); - - when(mHostProviders.getAssetProvider()).thenReturn(mAssetProvider); - when(mAssetProvider.isRtL()).thenReturn(false); - when(mMockStyleProvider.getRoundedCorners()) - .thenReturn(RoundedCorners.getDefaultInstance()); - when(mMockStyleProvider.getTextAlignment()).thenReturn(Gravity.START | Gravity.TOP); - - mAdapterParameters = new AdapterParameters(null, null, mHostProviders, - new ParameterizedTextEvaluator(new FakeClock()), null, null, new FakeClock()); - - when(mFrameContext.makeStyleFor(any(StyleIdsStack.class))) - .thenReturn(mAdapterParameters.mDefaultStyleProvider); - - mAdapter = new ParameterizedTextElementAdapter.KeySupplier().getAdapter( - mContext, mAdapterParameters); - } - - @Test - public void testCreate() { - assertThat(mAdapter).isNotNull(); - } - - @Test - public void testBindModel_basic() { - Element model = getBaseTextElement(); - mAdapter.createAdapter(model, mFrameContext); - mAdapter.bindModel(model, mFrameContext); - assertThat(mAdapter.getView()).isNotNull(); - TextView textView = mAdapter.getBaseView(); - assertThat(textView).isNotNull(); - assertThat(textView.getText().toString()).isEqualTo(TEXT_LINE_CONTENT); - } - - @Test - public void testBindModel_noContent() { - mAdapter.createAdapter(getBaseTextElement(), mFrameContext); - Element model = asElement(TextElement.getDefaultInstance()); - mAdapter.bindModel(model, mFrameContext); - - TextView textView = mAdapter.getBaseView(); - assertThat(textView).isNotNull(); - assertThat(textView.getText().toString()).isEmpty(); - verify(mFrameContext) - .reportMessage(MessageType.ERROR, ErrorCode.ERR_MISSING_OR_UNHANDLED_CONTENT, - "TextElement missing ParameterizedText content; has CONTENT_NOT_SET"); - } - - @Test - public void testBindModel_withBinding_someText() { - ParameterizedText parameterizedText = - ParameterizedText.newBuilder().setText(TEXT_LINE_CONTENT).build(); - BindingValue bindingValue = - BindingValue.newBuilder().setParameterizedText(parameterizedText).build(); - when(mFrameContext.getParameterizedTextBindingValue(DEFAULT_BINDING_REF)) - .thenReturn(bindingValue); - - Element model = getBindingTextElement(null); - mAdapter.createAdapter(model, mFrameContext); - mAdapter.bindModel(model, mFrameContext); - assertThat(mAdapter.getView()).isNotNull(); - TextView textView = mAdapter.getBaseView(); - assertThat(textView).isNotNull(); - assertThat(textView.getText().toString()).isEqualTo(TEXT_LINE_CONTENT); - } - - @Test - public void testBindModel_withBinding_noContent() { - when(mFrameContext.getParameterizedTextBindingValue(DEFAULT_BINDING_REF)) - .thenReturn(BindingValue.newBuilder().setBindingId(BINDING).build()); - - Element model = getBindingTextElement(null); - mAdapter.createAdapter(model, mFrameContext); - - assertThatRunnable(() -> mAdapter.bindModel(model, mFrameContext)) - .throwsAnExceptionOfType(PietFatalException.class) - .that() - .hasMessageThat() - .contains("Parameterized text binding binding had no content"); - } - - @Test - public void testBindModel_withBinding_optionalAbsent() { - Element model = getBindingTextElement(null /* StyleProvider*/); - mAdapter.createAdapter(model, mFrameContext); - Element modelOptionalBinding = - asElement(TextElement.newBuilder() - .setParameterizedTextBinding( - DEFAULT_BINDING_REF.toBuilder().setIsOptional(true)) - .build()); - when(mFrameContext.getParameterizedTextBindingValue( - modelOptionalBinding.getTextElement().getParameterizedTextBinding())) - .thenReturn(BindingValue.getDefaultInstance()); - - mAdapter.bindModel(modelOptionalBinding, mFrameContext); - - assertThat(mAdapter.getView()).isNotNull(); - TextView textView = mAdapter.getBaseView(); - assertThat(textView).isNotNull(); - assertThat(textView.getText().toString()).isEmpty(); - } - - @Test - public void testBindModel_html() { - Element model = - asElement(TextElement.newBuilder() - .setParameterizedText( - ParameterizedText.newBuilder().setIsHtml(true).setText( - "<h1>HEADING!</h1>")) - .build()); - mAdapter.createAdapter(model, mFrameContext); - mAdapter.bindModel(model, mFrameContext); - assertThat(mAdapter.getView()).isNotNull(); - TextView textView = mAdapter.getBaseView(); - assertThat(textView).isNotNull(); - assertThat(textView.getText().toString()).isEqualTo("HEADING!\n\n"); - } - - @Test - public void testStyles_padding() { - Element model = asElement(TextElement.getDefaultInstance()); - - when(mFrameContext.makeStyleFor(any(StyleIdsStack.class))).thenReturn(mMockStyleProvider); - - when(mMockStyleProvider.getFont()).thenReturn(Font.getDefaultInstance()); - - mAdapter.createAdapter(model, mFrameContext); - assertThat(mAdapter.getView()).isNotNull(); - verify(mMockStyleProvider).applyElementStyles(mAdapter); - TextView textView = mAdapter.getBaseView(); - assertThat(textView).isNotNull(); - } - - private Element getBindingTextElement(/*@Nullable*/ StyleProvider styleProvider) { - StyleProvider sp = - styleProvider != null ? styleProvider : mAdapterParameters.mDefaultStyleProvider; - when(mFrameContext.makeStyleFor(any(StyleIdsStack.class))).thenReturn(sp); - return asElement( - TextElement.newBuilder().setParameterizedTextBinding(DEFAULT_BINDING_REF).build()); - } - - private Element getBaseTextElement() { - return getBaseTextElement(null); - } - - private Element getBaseTextElement(/*@Nullable*/ StyleProvider styleProvider) { - StyleProvider sp = - styleProvider != null ? styleProvider : mAdapterParameters.mDefaultStyleProvider; - when(mFrameContext.makeStyleFor(any(StyleIdsStack.class))).thenReturn(sp); - - return asElement(TextElement.newBuilder() - .setParameterizedText( - ParameterizedText.newBuilder().setText(TEXT_LINE_CONTENT)) - .build()); - } - - private static Element asElement(TextElement textElement) { - return Element.newBuilder().setTextElement(textElement).build(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ParameterizedTextEvaluatorTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ParameterizedTextEvaluatorTest.java deleted file mode 100644 index c27b342..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ParameterizedTextEvaluatorTest.java +++ /dev/null
@@ -1,139 +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. - -package org.chromium.chrome.browser.feed.library.piet; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.piet.host.AssetProvider; -import org.chromium.components.feed.core.proto.ui.piet.TextProto.ParameterizedText; -import org.chromium.components.feed.core.proto.ui.piet.TextProto.ParameterizedText.Parameter; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests of the {@link ParameterizedTextEvaluator} */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -// TODO: Create a test of evaluteHtml -public class ParameterizedTextEvaluatorTest { - private static final int MILLISECONDS_PER_SECOND = 1000; - private static final int SECONDS_PER_MINUTE = 60; - private static final int MILLISECONDS_PER_MINUTE = SECONDS_PER_MINUTE * MILLISECONDS_PER_SECOND; - @Mock - private AssetProvider mAssetProvider; - - private ParameterizedTextEvaluator mEvaluator; - private FakeClock mClock = new FakeClock(); - - @Before - public void setUp() throws Exception { - initMocks(this); - mEvaluator = new ParameterizedTextEvaluator(mClock); - } - - @Test - public void testEvaluate_noText() { - ParameterizedText text = ParameterizedText.getDefaultInstance(); - assertThat(mEvaluator.evaluate(mAssetProvider, text).toString()).isEmpty(); - } - - @Test - public void testEvaluate_noParameters() { - String content = "content"; - ParameterizedText text = ParameterizedText.newBuilder().setText(content).build(); - assertThat(mEvaluator.evaluate(mAssetProvider, text).toString()).isEqualTo(content); - } - - @Test - public void testEvaluate_time() { - String content = "content %s"; - String time = "10 minutes"; - when(mAssetProvider.getRelativeElapsedString(anyLong())).thenReturn(time); - long initialTime = 10; - mClock.set(initialTime * MILLISECONDS_PER_SECOND + 10 * MILLISECONDS_PER_MINUTE); - ParameterizedText text = - ParameterizedText.newBuilder() - .setText(content) - .addParameters(Parameter.newBuilder().setTimestampSeconds(initialTime)) - .build(); - - assertThat(mEvaluator.evaluate(mAssetProvider, text).toString()) - .isEqualTo(String.format(content, time)); - verify(mAssetProvider).getRelativeElapsedString(10 * MILLISECONDS_PER_MINUTE); - } - - @Test - public void testEvaluate_multipleParameters() { - String content = "content %s - %s"; - String time1 = "10 minutes"; - String time2 = "20 minutes"; - when(mAssetProvider.getRelativeElapsedString(anyLong())) - .thenReturn(time1) - .thenReturn(time2); - mClock.set(20 * MILLISECONDS_PER_MINUTE); - - ParameterizedText text = - ParameterizedText.newBuilder() - .setText(content) - .addParameters( - Parameter.newBuilder().setTimestampSeconds(10 * SECONDS_PER_MINUTE)) - .addParameters(Parameter.newBuilder().setTimestampSeconds(0)) - .build(); - - assertThat(mEvaluator.evaluate(mAssetProvider, text).toString()) - .isEqualTo(String.format(content, time1, time2)); - - verify(mAssetProvider).getRelativeElapsedString(10 * MILLISECONDS_PER_MINUTE); - verify(mAssetProvider).getRelativeElapsedString(20 * MILLISECONDS_PER_MINUTE); - } - - @Test - public void testEvaluate_html() { - String content = "<h1>content</h1>"; - ParameterizedText text = - ParameterizedText.newBuilder().setIsHtml(true).setText(content).build(); - assertThat(mEvaluator.evaluate(mAssetProvider, text).toString()).isEqualTo("content\n\n"); - } - - @Test - public void testEvaluate_htmlAndParameters() { - String content = "<h1>content %s</h1>"; - String time1 = "1 second"; - when(mAssetProvider.getRelativeElapsedString(anyLong())).thenReturn(time1); - - ParameterizedText text = - ParameterizedText.newBuilder() - .setIsHtml(true) - .setText(content) - .addParameters(Parameter.newBuilder().setTimestampSeconds(1)) - .build(); - assertThat(mEvaluator.evaluate(mAssetProvider, text).toString()) - .isEqualTo("content 1 second\n\n"); - } - - @Test - public void testTimeConversion() { - String content = "%s"; - String time = "10 minutes"; - when(mAssetProvider.getRelativeElapsedString(1000)).thenReturn(time); - mClock.set(2000); - ParameterizedText.Builder text = ParameterizedText.newBuilder(); - text.setText(content); - text.addParameters(Parameter.newBuilder().setTimestampSeconds(1).build()); - - assertThat(mEvaluator.evaluate(mAssetProvider, text.build()).toString()) - .isEqualTo(String.format(content, time)); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/PietManagerImplTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/PietManagerImplTest.java deleted file mode 100644 index 6f348349..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/PietManagerImplTest.java +++ /dev/null
@@ -1,259 +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. - -package org.chromium.chrome.browser.feed.library.piet; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.MockitoAnnotations.initMocks; - -import android.app.Activity; -import android.content.Context; -import android.graphics.Typeface; -import android.graphics.drawable.Drawable; -import android.view.View; -import android.view.ViewGroup; -import android.widget.FrameLayout; -import android.widget.LinearLayout; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.base.Consumer; -import org.chromium.base.supplier.Supplier; -import org.chromium.chrome.browser.feed.library.api.host.config.DebugBehavior; -import org.chromium.chrome.browser.feed.library.common.functional.Suppliers; -import org.chromium.chrome.browser.feed.library.common.time.Clock; -import org.chromium.chrome.browser.feed.library.common.time.SystemClockImpl; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.common.ui.LayoutUtils; -import org.chromium.chrome.browser.feed.library.piet.PietStylesHelper.PietStylesHelperFactory; -import org.chromium.chrome.browser.feed.library.piet.host.ActionHandler; -import org.chromium.chrome.browser.feed.library.piet.host.AssetProvider; -import org.chromium.chrome.browser.feed.library.piet.host.CustomElementProvider; -import org.chromium.chrome.browser.feed.library.piet.host.EventLogger; -import org.chromium.chrome.browser.feed.library.piet.host.HostBindingProvider; -import org.chromium.chrome.browser.feed.library.piet.host.ImageLoader; -import org.chromium.chrome.browser.feed.library.piet.host.LogDataCallback; -import org.chromium.chrome.browser.feed.library.piet.host.StringFormatter; -import org.chromium.chrome.browser.feed.library.piet.host.ThrowingCustomElementProvider; -import org.chromium.chrome.browser.feed.library.piet.host.TypefaceProvider; -import org.chromium.chrome.browser.feed.library.piet.ui.RoundedCornerMaskCache; -import org.chromium.components.feed.core.proto.ui.piet.ImagesProto.Image; -import org.chromium.components.feed.core.proto.ui.piet.LogDataProto.LogData; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.Frame; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.Collections; -import java.util.Locale; - -/** Tests of the {@link PietManagerImpl}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class PietManagerImplTest { - @Mock - private ActionHandler mActionHandler; - @Mock - private EventLogger mEventLogger; - @Mock - private CustomElementProvider mCustomElementProvider; - - @Mock - ImageLoader mImageLoader; - @Mock - StringFormatter mStringFormatter; - @Mock - TypefaceProvider mTypefaceProvider; - @Mock - private PietStylesHelperFactory mStylesHelpers; - - private Context mContext; - private ViewGroup mViewGroup1; - private ViewGroup mViewGroup2; - - private PietManagerImpl mPietManager; - - @Before - public void setUp() throws Exception { - initMocks(this); - mContext = Robolectric.buildActivity(Activity.class).get(); - mViewGroup1 = new LinearLayout(mContext); - mViewGroup2 = new FrameLayout(mContext); - mPietManager = (PietManagerImpl) new PietManager.Builder() - .setDebugBehavior(DebugBehavior.VERBOSE) - .setCustomElementProvider(mCustomElementProvider) - .build(); - } - - @Test - public void testCreatePietFrameAdapter() { - Supplier<ViewGroup> cardViewSupplier = Suppliers.of(mViewGroup1); - FrameAdapterImpl frameAdapter = - (FrameAdapterImpl) mPietManager.createPietFrameAdapter(cardViewSupplier, - mActionHandler, mEventLogger, mContext, /* logDataCallback= */ null); - assertThat(frameAdapter.getParameters().mParentViewSupplier) - .isSameInstanceAs(cardViewSupplier); - } - - @Test - public void testCreatePietFrameAdapter_loggingCallback() { - LogDataCallback logDataCallback = new LogDataCallback() { - @Override - public void onBind(LogData logData, View view) {} - - @Override - public void onUnbind(LogData logData, View view) {} - }; - Supplier<ViewGroup> cardViewSupplier = Suppliers.of(mViewGroup1); - FrameAdapterImpl frameAdapter = (FrameAdapterImpl) mPietManager.createPietFrameAdapter( - cardViewSupplier, mActionHandler, mEventLogger, mContext, logDataCallback); - assertThat(frameAdapter.getParameters().mHostProviders.getLogDataCallback()) - .isEqualTo(logDataCallback); - } - - @Test - public void testGetAdapterParameters() { - Supplier<ViewGroup> viewGroupProducer1 = Suppliers.of(mViewGroup1); - Supplier<ViewGroup> viewGroupProducer2 = Suppliers.of(mViewGroup2); - Context context1 = Robolectric.buildActivity(Activity.class).get(); - Context context2 = Robolectric.buildActivity(Activity.class).get(); - - AdapterParameters returnParams; - - // Get params for a context that does not exist - returnParams = mPietManager.getAdapterParameters( - context1, viewGroupProducer1, /* logDataCallback= */ null); - assertThat(returnParams.mParentViewSupplier).isEqualTo(viewGroupProducer1); - assertThat(returnParams.mContext).isEqualTo(context1); - - // Get params for the same context again (use cached value) - returnParams = mPietManager.getAdapterParameters( - context1, Suppliers.of(null), /* logDataCallback= */ null); - assertThat(returnParams.mParentViewSupplier).isEqualTo(viewGroupProducer1); - - // Get params for a different context - returnParams = mPietManager.getAdapterParameters( - context2, viewGroupProducer2, /* logDataCallback= */ null); - assertThat(returnParams.mParentViewSupplier).isEqualTo(viewGroupProducer2); - } - - @Test - public void testBuilder_defaults() { - PietManagerImpl manager = (PietManagerImpl) new PietManager.Builder().build(); - AdapterParameters parameters = manager.getAdapterParameters( - mContext, Suppliers.of(mViewGroup1), /* logDataCallback= */ null); - assertThat(parameters.mHostProviders.getCustomElementProvider()) - .isInstanceOf(ThrowingCustomElementProvider.class); - assertThat(parameters.mClock).isInstanceOf(SystemClockImpl.class); - // There's no good way to test the HostBindingProvider. - - FrameAdapterImpl frameAdapter = (FrameAdapterImpl) manager.createPietFrameAdapter( - Suppliers.of(mViewGroup1), mActionHandler, mEventLogger, mContext, - /* logDataCallback= */ null); - FrameContext frameContext = frameAdapter.createFrameContext( - Frame.getDefaultInstance(), 0, Collections.emptyList(), mViewGroup2); - assertThat(frameContext.getDebugBehavior()).isEqualTo(DebugBehavior.SILENT); - - AssetProvider assetProvider = manager.mAssetProvider; - - assertThat(assetProvider.isDarkTheme()).isFalse(); - assertThat(assetProvider.getDefaultCornerRadius()).isEqualTo(0); - assertThat(assetProvider.getFadeImageThresholdMs()).isEqualTo(Long.MAX_VALUE); - assertThat(assetProvider.isRtL()).isFalse(); - } - - @Test - public void testBuilder_rtl() { - Locale defaultLocale = Locale.getDefault(); - - Locale.setDefault(Locale.forLanguageTag("ar")); - assertThat(LayoutUtils.isDefaultLocaleRtl()).isTrue(); - - PietManagerImpl manager = (PietManagerImpl) new PietManager.Builder().build(); - - assertThat(manager.mAssetProvider.isRtL()).isTrue(); - - // Reset the Locale so it doesn't mess up other tests - // (Removing this causes failures in Kokoro/Bazel testing) - Locale.setDefault(defaultLocale); - } - - @Test - public void testBuilder_setters() { - boolean isRtL = true; - boolean isDarkTheme = true; - HostBindingProvider hostBindingProvider = new HostBindingProvider(); - Clock clock = new FakeClock(); - PietManagerImpl manager = (PietManagerImpl) new PietManager.Builder() - .setImageLoader(mImageLoader) - .setStringFormatter(mStringFormatter) - .setDefaultCornerRadius(Suppliers.of(123)) - .setIsDarkTheme(Suppliers.of(isDarkTheme)) - .setIsRtL(Suppliers.of(isRtL)) - .setFadeImageThresholdMs(Suppliers.of(456L)) - .setTypefaceProvider(mTypefaceProvider) - .setDebugBehavior(DebugBehavior.VERBOSE) - .setCustomElementProvider(mCustomElementProvider) - .setHostBindingProvider(hostBindingProvider) - .setClock(clock) - .build(); - AdapterParameters parameters = manager.getAdapterParameters( - mContext, Suppliers.of(mViewGroup1), /* logDataCallback= */ null); - assertThat(parameters.mHostProviders.getCustomElementProvider()) - .isSameInstanceAs(mCustomElementProvider); - assertThat(parameters.mHostProviders.getHostBindingProvider()) - .isSameInstanceAs(hostBindingProvider); - assertThat(parameters.mClock).isSameInstanceAs(clock); - - FrameAdapterImpl frameAdapter = (FrameAdapterImpl) manager.createPietFrameAdapter( - Suppliers.of(mViewGroup1), mActionHandler, mEventLogger, mContext, - /* logDataCallback= */ null); - FrameContext frameContext = frameAdapter.createFrameContext( - Frame.getDefaultInstance(), 0, Collections.emptyList(), mViewGroup2); - assertThat(frameContext.getDebugBehavior()).isEqualTo(DebugBehavior.VERBOSE); - - AssetProvider assetProvider = manager.mAssetProvider; - - Consumer<Drawable> drawableConsumer = drawable -> {}; - assetProvider.getImage(Image.getDefaultInstance(), 12, 34, drawableConsumer); - verify(mImageLoader).getImage(Image.getDefaultInstance(), 12, 34, drawableConsumer); - - assetProvider.getRelativeElapsedString(789); - verify(mStringFormatter).getRelativeElapsedString(789); - - Consumer<Typeface> typefaceConsumer = typeface -> {}; - assetProvider.getTypeface("blah", false, typefaceConsumer); - verify(mTypefaceProvider).getTypeface("blah", false, typefaceConsumer); - - assertThat(assetProvider.isDarkTheme()).isEqualTo(isDarkTheme); - assertThat(assetProvider.isRtL()).isEqualTo(isRtL); - - assertThat(assetProvider.getDefaultCornerRadius()).isEqualTo(123); - assertThat(assetProvider.getFadeImageThresholdMs()).isEqualTo(456); - } - - @Test - public void testPurgeRecyclerPools() { - // Test with null adapterParameters - mPietManager.purgeRecyclerPools(); - - ElementAdapterFactory mockFactory = mock(ElementAdapterFactory.class); - TemplateBinder mockTemplateBinder = mock(TemplateBinder.class); - HostProviders hostProviders = mock(HostProviders.class); - RoundedCornerMaskCache maskCache = mock(RoundedCornerMaskCache.class); - mPietManager.mAdapterParameters = new AdapterParameters(mContext, Suppliers.of(mViewGroup1), - hostProviders, null, mockFactory, mockTemplateBinder, new FakeClock(), - mStylesHelpers, maskCache, false, false); - mPietManager.purgeRecyclerPools(); - verify(mockFactory).purgeRecyclerPools(); - verify(mStylesHelpers).purge(); - verify(maskCache).purge(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/PietStylesHelperTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/PietStylesHelperTest.java deleted file mode 100644 index 740881b..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/PietStylesHelperTest.java +++ /dev/null
@@ -1,555 +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. - -package org.chromium.chrome.browser.feed.library.piet; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import static org.chromium.chrome.browser.feed.library.common.testing.RunnableSubject.assertThatRunnable; - -import android.app.Activity; -import android.content.Context; - -import com.google.common.collect.ImmutableList; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.piet.PietStylesHelper.PietStylesHelperFactory; -import org.chromium.chrome.browser.feed.library.piet.PietStylesHelper.PietStylesHelperKey; -import org.chromium.chrome.browser.feed.library.piet.host.AssetProvider; -import org.chromium.components.feed.core.proto.ui.piet.BindingRefsProto.StyleBindingRef; -import org.chromium.components.feed.core.proto.ui.piet.GradientsProto.ColorStop; -import org.chromium.components.feed.core.proto.ui.piet.GradientsProto.Fill; -import org.chromium.components.feed.core.proto.ui.piet.GradientsProto.LinearGradient; -import org.chromium.components.feed.core.proto.ui.piet.MediaQueriesProto.DarkLightCondition; -import org.chromium.components.feed.core.proto.ui.piet.MediaQueriesProto.DarkLightCondition.DarkLightMode; -import org.chromium.components.feed.core.proto.ui.piet.MediaQueriesProto.MediaQueryCondition; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.PietSharedState; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.Stylesheet; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.Stylesheets; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.Template; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.BoundStyle; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.Font; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.Style; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.StyleIdsStack; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** Tests of the {@link PietStylesHelper}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class PietStylesHelperTest { - private static final String STYLESHEET_ID_1 = "ss1"; - private static final String STYLESHEET_ID_2 = "ss2"; - private static final String STYLE_ID_1 = "s1"; - private static final String STYLE_ID_2 = "s2"; - private static final Style STYLE_1 = Style.newBuilder().setStyleId(STYLE_ID_1).build(); - private static final Style STYLE_2 = Style.newBuilder().setStyleId(STYLE_ID_2).build(); - private static final String TEMPLATE_ID_1 = "t1"; - private static final String TEMPLATE_ID_2 = "t2"; - private static final Template TEMPLATE_1 = - Template.newBuilder().setTemplateId(TEMPLATE_ID_1).build(); - private static final Template TEMPLATE_2 = - Template.newBuilder().setTemplateId(TEMPLATE_ID_2).build(); - - private static final MediaQueryCondition DARK_CONDITION = - MediaQueryCondition.newBuilder() - .setDarkLight(DarkLightCondition.newBuilder().setMode(DarkLightMode.DARK)) - .build(); - private static final MediaQueryCondition LIGHT_CONDITION = - MediaQueryCondition.newBuilder() - .setDarkLight(DarkLightCondition.newBuilder().setMode(DarkLightMode.LIGHT)) - .build(); - - private static final int FRAME_WIDTH_PX = 480; - - private List<PietSharedState> mSharedStates = new ArrayList<>(); - @Mock - FrameContext mFrameContext; - @Mock - AssetProvider mAssetProvider; - DebugLogger mDebugLogger; - - private Context mContext; - private PietStylesHelperFactory mHelperFactory; - private PietStylesHelper mHelper; - private PietSharedState mSharedState1; - - @Before - public void setUp() throws Exception { - mContext = Robolectric.buildActivity(Activity.class).get(); - initMocks(this); - Stylesheet.Builder stylesheet1 = - Stylesheet.newBuilder().setStylesheetId(STYLESHEET_ID_1).addStyles(STYLE_1); - - Stylesheet.Builder stylesheet2 = - Stylesheet.newBuilder().setStylesheetId(STYLESHEET_ID_2).addStyles(STYLE_2); - - mSharedState1 = PietSharedState.newBuilder() - .addStylesheets(stylesheet1.build()) - .addTemplates(TEMPLATE_1) - .build(); - - PietSharedState sharedState2 = PietSharedState.newBuilder() - .addStylesheets(stylesheet2.build()) - .addTemplates(TEMPLATE_2) - .build(); - mSharedStates.add(mSharedState1); - mSharedStates.add(sharedState2); - - mDebugLogger = new DebugLogger(); - - mHelperFactory = new PietStylesHelperFactory(); - mHelper = mHelperFactory.get(mSharedStates, newMediaQueryHelper()); - } - - @Test - public void testConstructorRespectsMediaQueryConditions_stylesheets() { - Stylesheet darkStylesheet = Stylesheet.newBuilder() - .setStylesheetId("DARK") - .addConditions(DARK_CONDITION) - .addStyles(STYLE_1) - .build(); - Stylesheet lightStylesheet = Stylesheet.newBuilder() - .setStylesheetId("LIGHT") - .addConditions(LIGHT_CONDITION) - .addStyles(STYLE_2) - .build(); - - Style darkStyle = Style.newBuilder().setStyleId("dark").build(); - Style lightStyle = Style.newBuilder().setStyleId("light").build(); - Stylesheet switchStylesheetDark = Stylesheet.newBuilder() - .setStylesheetId("SWITCH") - .addConditions(DARK_CONDITION) - .addStyles(darkStyle) - .build(); - Stylesheet switchStylesheetLight = Stylesheet.newBuilder() - .setStylesheetId("SWITCH") - .addConditions(LIGHT_CONDITION) - .addStyles(lightStyle) - .build(); - - PietSharedState sharedState = PietSharedState.newBuilder() - .addStylesheets(darkStylesheet) - .addStylesheets(lightStylesheet) - .addStylesheets(switchStylesheetDark) - .addStylesheets(switchStylesheetLight) - .build(); - - when(mAssetProvider.isDarkTheme()).thenReturn(true); - mHelper = mHelperFactory.get(Collections.singletonList(sharedState), newMediaQueryHelper()); - - assertThat(mHelper.getStylesheetMap( - Stylesheets.newBuilder().addStylesheetIds("DARK").build(), mDebugLogger)) - .containsExactly(STYLE_ID_1, STYLE_1); - assertThat( - mHelper.getStylesheetMap( - Stylesheets.newBuilder().addStylesheetIds("LIGHT").build(), mDebugLogger)) - .isEmpty(); - assertThat( - mHelper.getStylesheetMap( - Stylesheets.newBuilder().addStylesheetIds("SWITCH").build(), mDebugLogger)) - .containsExactly("dark", darkStyle); - - when(mAssetProvider.isDarkTheme()).thenReturn(false); - mHelper = mHelperFactory.get(Collections.singletonList(sharedState), newMediaQueryHelper()); - - assertThat(mHelper.getStylesheetMap( - Stylesheets.newBuilder().addStylesheetIds("DARK").build(), mDebugLogger)) - .isEmpty(); - assertThat( - mHelper.getStylesheetMap( - Stylesheets.newBuilder().addStylesheetIds("LIGHT").build(), mDebugLogger)) - .containsExactly(STYLE_ID_2, STYLE_2); - assertThat( - mHelper.getStylesheetMap( - Stylesheets.newBuilder().addStylesheetIds("SWITCH").build(), mDebugLogger)) - .containsExactly("light", lightStyle); - } - - @Test - public void testConstructorRespectsMediaQueryConditions_templates() { - Template darkTemplate = - Template.newBuilder().setTemplateId("DARK").addConditions(DARK_CONDITION).build(); - Template lightTemplate = - Template.newBuilder().setTemplateId("LIGHT").addConditions(LIGHT_CONDITION).build(); - Template switchTemplateDark = - Template.newBuilder().setTemplateId("SWITCH").addConditions(DARK_CONDITION).build(); - Template switchTemplateLight = Template.newBuilder() - .setTemplateId("SWITCH") - .addConditions(LIGHT_CONDITION) - .build(); - - PietSharedState sharedState = PietSharedState.newBuilder() - .addTemplates(darkTemplate) - .addTemplates(lightTemplate) - .addTemplates(switchTemplateDark) - .addTemplates(switchTemplateLight) - .build(); - - when(mAssetProvider.isDarkTheme()).thenReturn(true); - mHelper = mHelperFactory.get(Collections.singletonList(sharedState), newMediaQueryHelper()); - - assertThat(mHelper.getTemplate("DARK")).isSameInstanceAs(darkTemplate); - assertThat(mHelper.getTemplate("LIGHT")).isNull(); - assertThat(mHelper.getTemplate("SWITCH")).isSameInstanceAs(switchTemplateDark); - - when(mAssetProvider.isDarkTheme()).thenReturn(false); - mHelper = mHelperFactory.get(Collections.singletonList(sharedState), newMediaQueryHelper()); - - assertThat(mHelper.getTemplate("DARK")).isNull(); - assertThat(mHelper.getTemplate("LIGHT")).isSameInstanceAs(lightTemplate); - assertThat(mHelper.getTemplate("SWITCH")).isSameInstanceAs(switchTemplateLight); - } - - @Test - public void testGetStylesheet() { - Map<String, Style> resultMap1 = mHelper.getStylesheetMap( - Stylesheets.newBuilder().addStylesheetIds(STYLESHEET_ID_1).build(), mDebugLogger); - assertThat(resultMap1).containsExactly(STYLE_ID_1, STYLE_1); - - // Retrieve map again to test caching - assertThat(mHelper.getStylesheetMap( - Stylesheets.newBuilder().addStylesheetIds(STYLESHEET_ID_1).build(), - mDebugLogger)) - .isSameInstanceAs(resultMap1); - - Map<String, Style> resultMap2 = mHelper.getStylesheetMap( - Stylesheets.newBuilder().addStylesheetIds(STYLESHEET_ID_2).build(), mDebugLogger); - assertThat(resultMap2).containsExactly(STYLE_ID_2, STYLE_2); - assertThat(mHelper.getStylesheetMap( - Stylesheets.newBuilder().addStylesheetIds(STYLESHEET_ID_2).build(), - mDebugLogger)) - .isSameInstanceAs(resultMap2); - } - - @Test - public void testGetStylesheet_withSameStylesheetId() { - List<PietSharedState> sharedStates = new ArrayList<>(); - Stylesheet.Builder stylesheet = - Stylesheet.newBuilder().setStylesheetId(STYLESHEET_ID_1).addStyles(STYLE_2); - PietSharedState sharedState2 = PietSharedState.newBuilder() - .addStylesheets(stylesheet.build()) - .addTemplates(TEMPLATE_2) - .build(); - sharedStates.add(mSharedState1); - sharedStates.add(sharedState2); - - assertThatRunnable(() -> mHelperFactory.get(sharedStates, newMediaQueryHelper())) - .throwsAnExceptionOfType(PietFatalException.class) - .that() - .hasMessageThat() - .contains("Stylesheet key 'ss1' already defined"); - } - - @Test - public void testGetStylesheet_notExist() { - assertThat(mHelper.getStylesheetMap( - Stylesheets.newBuilder().addStylesheetIds("NOT EXIST").build(), - mDebugLogger)) - .isEmpty(); - } - - @Test - public void testCreateMapFromStylesheet() { - Stylesheet.Builder myStyles = Stylesheet.newBuilder(); - Style sixties = Style.newBuilder().setStyleId("60s").build(); - myStyles.addStyles(sixties); - Style eighties = Style.newBuilder().setStyleId("80s").build(); - myStyles.addStyles(eighties); - - assertThat(mHelper.getStylesheetMap( - Stylesheets.newBuilder().addStylesheets(myStyles.build()).build(), - mDebugLogger)) - .containsExactly("60s", sixties, "80s", eighties); - } - - @Test - public void testCreateMapFromStylesheet_throwsWhenDuplicateStyleId() { - Stylesheet.Builder myStyles = Stylesheet.newBuilder(); - Style sixties = Style.newBuilder().setStyleId("60s").build(); - myStyles.addStyles(sixties); - Style sixtiesAgain = Style.newBuilder().setStyleId("60s").build(); - myStyles.addStyles(sixtiesAgain); - - assertThatRunnable( - () - -> mHelper.getStylesheetMap( - Stylesheets.newBuilder().addStylesheets(myStyles.build()).build(), - mDebugLogger)) - .throwsAnExceptionOfType(PietFatalException.class) - .that() - .hasMessageThat() - .contains("Style key '60s' already defined"); - } - - @Test - public void testCreateMapFromStylesheet_filtersByMediaQuery() { - Stylesheet.Builder myStyles = Stylesheet.newBuilder(); - Style lightStyle = - Style.newBuilder() - .setStyleId("theme") - .addConditions(MediaQueryCondition.newBuilder().setDarkLight( - DarkLightCondition.newBuilder().setMode(DarkLightMode.LIGHT))) - .build(); - myStyles.addStyles(lightStyle); - Style darkStyle = - Style.newBuilder() - .setStyleId("theme") - .addConditions(MediaQueryCondition.newBuilder().setDarkLight( - DarkLightCondition.newBuilder().setMode(DarkLightMode.DARK))) - .build(); - myStyles.addStyles(darkStyle); - - when(mAssetProvider.isDarkTheme()).thenReturn(true); - mHelper = mHelperFactory.get(mSharedStates, newMediaQueryHelper()); - assertThat(mHelper.getStylesheetMap( - Stylesheets.newBuilder().addStylesheets(myStyles.build()).build(), - mDebugLogger)) - .containsExactly("theme", darkStyle); - - when(mAssetProvider.isDarkTheme()).thenReturn(false); - mHelper = mHelperFactory.get(mSharedStates, newMediaQueryHelper()); - assertThat(mHelper.getStylesheetMap( - Stylesheets.newBuilder().addStylesheets(myStyles.build()).build(), - mDebugLogger)) - .containsExactly("theme", lightStyle); - } - - @Test - public void testGetTemplate() { - assertThat(mHelper.getTemplate(TEMPLATE_ID_1)).isEqualTo(TEMPLATE_1); - assertThat(mHelper.getTemplate(TEMPLATE_ID_2)).isEqualTo(TEMPLATE_2); - } - - @Test - public void testGetTemplate_notExist() { - assertThat(mHelper.getTemplate("NOT EXIST")).isNull(); - } - - @Test - public void testMergeStyleIdsStack() { - // These constants are in the final output and are not overridden - int baseWidth = 999; - int style1Color = 12345; - boolean style1Italic = true; - int style2MaxLines = 22222; - int style2MinHeight = 33333; - int style2FontSize = 13; - int style1GradientColor = 1234; - int style2GradientDirection = 321; - int boundStyleColor = 5050; - Fill boundStyleBackground = - Fill.newBuilder() - .setLinearGradient( - LinearGradient.newBuilder().setDirectionDeg(boundStyleColor)) - .build(); - - Style baseStyle = Style.newBuilder() - .setWidth(baseWidth) // Not overridden - .setColor(888) // Overridden - .build(); - String styleId1 = "STYLE1"; - Style style1 = - Style.newBuilder() - .setColor(style1Color) // Not overridden - .setMaxLines(54321) // Overridden - .setFont(Font.newBuilder().setSize(11).setItalic(style1Italic)) - .setBackground(Fill.newBuilder().setLinearGradient( - LinearGradient.newBuilder().addStops( - ColorStop.newBuilder().setColor(style1GradientColor)))) - .build(); - String styleId2 = "STYLE2"; - Style style2 = - Style.newBuilder() - .setMaxLines(style2MaxLines) // Overrides - .setMinHeight(style2MinHeight) // Not an override - .setFont(Font.newBuilder().setSize(style2FontSize)) // Just override size - .setBackground(Fill.newBuilder().setLinearGradient( - LinearGradient.newBuilder().setDirectionDeg( - style2GradientDirection))) - .build(); - Map<String, Style> stylesheetMap = new HashMap<>(); - stylesheetMap.put(styleId1, style1); - stylesheetMap.put(styleId2, style2); - - // Test merging a style IDs stack - Style mergedStyle = PietStylesHelper.mergeStyleIdsStack(baseStyle, - StyleIdsStack.newBuilder().addStyleIds(styleId1).addStyleIds(styleId2).build(), - stylesheetMap, mFrameContext); - - assertThat(mergedStyle) - .isEqualTo(Style.newBuilder() - .setColor(style1Color) - .setMaxLines(style2MaxLines) - .setMinHeight(style2MinHeight) - .setFont(Font.newBuilder() - .setSize(style2FontSize) - .setItalic(style1Italic)) - .setBackground(Fill.newBuilder().setLinearGradient( - LinearGradient.newBuilder() - .addStops(ColorStop.newBuilder().setColor( - style1GradientColor)) - .setDirectionDeg(style2GradientDirection))) - .setWidth(baseWidth) - .build()); - - // Test merging a style IDs stack with a bound style - String styleBindingId = "BOUND_STYLE"; - BoundStyle boundStyle = BoundStyle.newBuilder() - .setColor(boundStyleColor) - .setBackground(boundStyleBackground) - .build(); - StyleBindingRef styleBindingRef = - StyleBindingRef.newBuilder().setBindingId(styleBindingId).build(); - when(mFrameContext.getStyleFromBinding(styleBindingRef)).thenReturn(boundStyle); - - mergedStyle = PietStylesHelper.mergeStyleIdsStack(baseStyle, - StyleIdsStack.newBuilder() - .addStyleIds(styleId1) - .addStyleIds(styleId2) - .setStyleBinding(styleBindingRef) - .build(), - stylesheetMap, mFrameContext); - assertThat(mergedStyle) - .isEqualTo(Style.newBuilder() - .setColor(boundStyleColor) - .setMaxLines(style2MaxLines) - .setMinHeight(style2MinHeight) - .setFont(Font.newBuilder() - .setSize(style2FontSize) - .setItalic(style1Italic)) - .setBackground(Fill.newBuilder().setLinearGradient( - LinearGradient.newBuilder() - .addStops(ColorStop.newBuilder().setColor( - style1GradientColor)) - .setDirectionDeg(boundStyleColor))) - .setWidth(baseWidth) - .build()); - - // Binding styles fails when frameContext is null. - assertThatRunnable(() -> { - PietStylesHelper.mergeStyleIdsStack(Style.getDefaultInstance(), - StyleIdsStack.newBuilder() - .addStyleIds(styleId1) - .addStyleIds(styleId2) - .setStyleBinding(styleBindingRef) - .build(), - stylesheetMap, null); - }) - .throwsAnExceptionOfType(NullPointerException.class) - .that() - .hasMessageThat() - .contains("Binding styles not supported when frameContext is null"); - } - - @Test - public void testHashCodeAndEquals() { - PietSharedState sharedState = PietSharedState.newBuilder() - .addStylesheets(Stylesheet.newBuilder().addStyles( - Style.newBuilder().setStyleId("style"))) - .build(); - PietSharedState equalSharedState = - PietSharedState.newBuilder() - .addStylesheets(Stylesheet.newBuilder().addStyles( - Style.newBuilder().setStyleId("style"))) - .build(); - PietSharedState differentSharedState = - PietSharedState.newBuilder() - .addStylesheets(Stylesheet.newBuilder().addStyles( - Style.newBuilder().setStyleId("NOT_SAME"))) - .build(); - - MediaQueryHelper mediaQueryHelper = new MediaQueryHelper(123, 4, false, mContext); - MediaQueryHelper equalMediaQueryHelper = new MediaQueryHelper(123, 4, false, mContext); - MediaQueryHelper differentMediaQueryHelper = new MediaQueryHelper(456, 7, false, mContext); - - // Objects that should be equal - assertThat(ImmutableList.of(sharedState).hashCode()) - .isEqualTo(ImmutableList.of(sharedState).hashCode()); - assertThat(ImmutableList.of(sharedState).hashCode()) - .isEqualTo(ImmutableList.of(equalSharedState).hashCode()); - assertThat(new PietStylesHelperKey(ImmutableList.of(sharedState), mediaQueryHelper)) - .isEqualTo( - new PietStylesHelperKey(ImmutableList.of(sharedState), mediaQueryHelper)); - assertThat(new PietStylesHelperKey(ImmutableList.of(sharedState), mediaQueryHelper)) - .isEqualTo(new PietStylesHelperKey( - ImmutableList.of(equalSharedState), equalMediaQueryHelper)); - assertThat(new PietStylesHelperKey( - ImmutableList.of(sharedState, differentSharedState), mediaQueryHelper)) - .isEqualTo( - new PietStylesHelperKey(ImmutableList.of(sharedState, differentSharedState), - equalMediaQueryHelper)); - assertThat(new PietStylesHelperKey( - ImmutableList.of(sharedState, differentSharedState), mediaQueryHelper)) - .isEqualTo(new PietStylesHelperKey( - ImmutableList.of(differentSharedState, equalSharedState), - equalMediaQueryHelper)); - assertThat(new PietStylesHelperKey( - ImmutableList.of(sharedState, differentSharedState), mediaQueryHelper)) - .isEqualTo(new PietStylesHelperKey( - Arrays.asList(sharedState, differentSharedState), equalMediaQueryHelper)); - - assertThat( - new PietStylesHelperKey(ImmutableList.of(sharedState), mediaQueryHelper).hashCode()) - .isEqualTo(new PietStylesHelperKey(ImmutableList.of(sharedState), mediaQueryHelper) - .hashCode()); - assertThat( - new PietStylesHelperKey(ImmutableList.of(sharedState), mediaQueryHelper).hashCode()) - .isEqualTo(new PietStylesHelperKey( - ImmutableList.of(equalSharedState), equalMediaQueryHelper) - .hashCode()); - assertThat(new PietStylesHelperKey( - ImmutableList.of(sharedState, differentSharedState), mediaQueryHelper) - .hashCode()) - .isEqualTo(new PietStylesHelperKey( - ImmutableList.of(sharedState, differentSharedState), equalMediaQueryHelper) - .hashCode()); - - // Objects that should be different - assertThat(new PietStylesHelperKey(ImmutableList.of(sharedState), mediaQueryHelper)) - .isNotEqualTo(new PietStylesHelperKey( - ImmutableList.of(differentSharedState), mediaQueryHelper)); - assertThat(new PietStylesHelperKey(ImmutableList.of(sharedState), mediaQueryHelper)) - .isNotEqualTo(new PietStylesHelperKey( - ImmutableList.of(equalSharedState), differentMediaQueryHelper)); - assertThat(new PietStylesHelperKey(ImmutableList.of(sharedState), mediaQueryHelper)) - .isNotEqualTo(new PietStylesHelperKey( - ImmutableList.of(sharedState, differentSharedState), mediaQueryHelper)); - - assertThat( - new PietStylesHelperKey(ImmutableList.of(sharedState), mediaQueryHelper).hashCode()) - .isNotEqualTo(new PietStylesHelperKey( - ImmutableList.of(differentSharedState), mediaQueryHelper) - .hashCode()); - assertThat( - new PietStylesHelperKey(ImmutableList.of(sharedState), mediaQueryHelper).hashCode()) - .isNotEqualTo(new PietStylesHelperKey( - ImmutableList.of(equalSharedState), differentMediaQueryHelper) - .hashCode()); - assertThat( - new PietStylesHelperKey(ImmutableList.of(sharedState), mediaQueryHelper).hashCode()) - .isNotEqualTo(new PietStylesHelperKey( - ImmutableList.of(sharedState, differentSharedState), mediaQueryHelper) - .hashCode()); - } - - private MediaQueryHelper newMediaQueryHelper() { - return new MediaQueryHelper(FRAME_WIDTH_PX, mAssetProvider, mContext); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/SingleKeyRecyclerPoolTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/SingleKeyRecyclerPoolTest.java deleted file mode 100644 index a9fd759..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/SingleKeyRecyclerPoolTest.java +++ /dev/null
@@ -1,160 +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. - -package org.chromium.chrome.browser.feed.library.piet; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.MockitoAnnotations.initMocks; - -import static org.chromium.chrome.browser.feed.library.common.testing.RunnableSubject.assertThatRunnable; - -import android.view.View; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests of the {@link SingleKeyRecyclerPool} */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class SingleKeyRecyclerPoolTest { - public static final TestRecyclerKey DEFAULT_KEY = new TestRecyclerKey("HappyKey"); - public static final TestRecyclerKey INVALID_KEY = new TestRecyclerKey("INVALID"); - public static final int DEFAULT_CAPACITY = 2; - - @Mock - ElementAdapter<View, Object> mAdapter; - @Mock - ElementAdapter<View, Object> mAdapter2; - @Mock - ElementAdapter<View, Object> mAdapter3; - - SingleKeyRecyclerPool<ElementAdapter<View, Object>> mPool; - - @Before - public void setUp() throws Exception { - initMocks(this); - mPool = new SingleKeyRecyclerPool<>(DEFAULT_KEY, DEFAULT_CAPACITY); - } - - @Test - public void testPutAndGetOneElement() { - mPool.put(DEFAULT_KEY, mAdapter); - assertThat(mPool.get(DEFAULT_KEY)).isEqualTo(mAdapter); - } - - @Test - public void testGetOnEmptyPoolReturnsNull() { - assertThat(mPool.get(DEFAULT_KEY)).isNull(); - } - - @Test - public void testGetWithDifferentKeyFails() { - assertThatRunnable(() -> mPool.get(INVALID_KEY)) - .throwsAnExceptionOfType(IllegalArgumentException.class) - .that() - .hasMessageThat() - .contains("does not match singleton key"); - } - - @Test - public void testPutWithDifferentKeyFails() { - assertThatRunnable(() -> mPool.put(INVALID_KEY, mAdapter)) - .throwsAnExceptionOfType(IllegalArgumentException.class) - .that() - .hasMessageThat() - .contains("does not match singleton key"); - } - - @Test - public void testGetWithNullKeyFails() { - assertThatRunnable(() -> mPool.get(null)) - .throwsAnExceptionOfType(IllegalArgumentException.class) - .that() - .hasMessageThat() - .contains("does not match singleton key"); - } - - @Test - public void testPutWithNullKeyFails() { - assertThatRunnable(() -> mPool.put(null, mAdapter)) - .throwsAnExceptionOfType(NullPointerException.class) - .that() - .hasMessageThat() - .contains("null key for mAdapter"); - } - - @Test - public void testPutSameElementTwiceFails() { - mPool.put(DEFAULT_KEY, mAdapter); - assertThatRunnable(() -> mPool.put(DEFAULT_KEY, mAdapter)) - .throwsAnExceptionOfType(IllegalStateException.class) - .that() - .hasMessageThat() - .contains("Already in the pool!"); - } - - @Test - public void testPutAndGetTwoElements() { - mPool.put(DEFAULT_KEY, mAdapter); - mPool.put(DEFAULT_KEY, mAdapter2); - assertThat(mPool.get(DEFAULT_KEY)).isNotNull(); - assertThat(mPool.get(DEFAULT_KEY)).isNotNull(); - assertThat(mPool.get(DEFAULT_KEY)).isNull(); - } - - @Test - public void testPoolOverflowIgnoresLastElement() { - mPool.put(DEFAULT_KEY, mAdapter); - mPool.put(DEFAULT_KEY, mAdapter2); - mPool.put(DEFAULT_KEY, mAdapter3); - assertThat(mPool.get(DEFAULT_KEY)).isNotNull(); - assertThat(mPool.get(DEFAULT_KEY)).isNotNull(); - assertThat(mPool.get(DEFAULT_KEY)).isNull(); - } - - @Test - public void testClear() { - mPool.put(DEFAULT_KEY, mAdapter); - mPool.put(DEFAULT_KEY, mAdapter2); - mPool.clear(); - assertThat(mPool.get(DEFAULT_KEY)).isNull(); - } - - private static class TestRecyclerKey extends RecyclerKey { - private final String mKey; - - TestRecyclerKey(String key) { - this.mKey = key; - } - - @Override - public int hashCode() { - return mKey.hashCode(); - } - - @Override - public boolean equals(/*@Nullable*/ Object obj) { - if (obj == this) { - return true; - } - - if (obj == null) { - return false; - } - - if (!(obj instanceof TestRecyclerKey)) { - return false; - } - - TestRecyclerKey otherKey = (TestRecyclerKey) obj; - return otherKey.mKey.equals(this.mKey); - } - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/StyleProviderTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/StyleProviderTest.java deleted file mode 100644 index fcd4289..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/StyleProviderTest.java +++ /dev/null
@@ -1,707 +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. - -package org.chromium.chrome.browser.feed.library.piet; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import static org.chromium.chrome.browser.feed.library.piet.StyleProvider.DIMENSION_NOT_SET; - -import android.app.Activity; -import android.content.Context; -import android.graphics.Color; -import android.graphics.Rect; -import android.graphics.drawable.ColorDrawable; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.ShapeDrawable; -import android.view.Gravity; -import android.view.View; -import android.view.ViewGroup.LayoutParams; -import android.view.ViewGroup.MarginLayoutParams; -import android.view.ViewOutlineProvider; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.TextView; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.common.functional.Suppliers; -import org.chromium.chrome.browser.feed.library.common.ui.LayoutUtils; -import org.chromium.chrome.browser.feed.library.piet.host.AssetProvider; -import org.chromium.chrome.browser.feed.library.piet.ui.BorderDrawable; -import org.chromium.chrome.browser.feed.library.piet.ui.GradientDrawable; -import org.chromium.chrome.browser.feed.library.piet.ui.RoundedCornerMaskCache; -import org.chromium.chrome.browser.feed.library.piet.ui.RoundedCornerWrapperView; -import org.chromium.components.feed.core.proto.ui.piet.GradientsProto.ColorStop; -import org.chromium.components.feed.core.proto.ui.piet.GradientsProto.Fill; -import org.chromium.components.feed.core.proto.ui.piet.GradientsProto.LinearGradient; -import org.chromium.components.feed.core.proto.ui.piet.ImagesProto.Image.ScaleType; -import org.chromium.components.feed.core.proto.ui.piet.RoundedCornersProto.RoundedCorners; -import org.chromium.components.feed.core.proto.ui.piet.ShadowsProto.ElevationShadow; -import org.chromium.components.feed.core.proto.ui.piet.ShadowsProto.Shadow; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.Borders; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.Borders.Edges; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.EdgeWidths; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.Font; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.GravityHorizontal; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.GravityVertical; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.ImageLoadingSettings; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.RelativeSize; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.Style; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.TextAlignmentHorizontal; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.TextAlignmentVertical; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** TODO: Test remaining methods of StyleProvider. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class StyleProviderTest { - @Mock - private AssetProvider mMockAssetProvider; - @Mock - private ElementAdapter<View, ?> mAdapter; - @Mock - private TextElementAdapter mTextAdapter; - @Mock - private RoundedCornerMaskCache mMaskCache; - - private View mView; - private View mBaseView; - private TextView mTextView; - - private Context mContext; - - @Before - public void setUp() throws Exception { - initMocks(this); - mContext = Robolectric.buildActivity(Activity.class).get(); - mView = new View(mContext); - mBaseView = new View(mContext); - mTextView = new TextView(mContext); - when(mAdapter.getView()).thenReturn(mView); - when(mAdapter.getBaseView()).thenReturn(mBaseView); - when(mAdapter.getContext()).thenReturn(mContext); - when(mTextAdapter.getView()).thenReturn(mView); - when(mTextAdapter.getBaseView()).thenReturn(mTextView); - when(mTextAdapter.getContext()).thenReturn(mContext); - when(mMockAssetProvider.isRtLSupplier()).thenReturn(Suppliers.of(false)); - } - - @Test - public void testGetters_withStyleDefined() { - Style style = - Style.newBuilder() - .setColor(1) - .setBackground(Fill.newBuilder().setColor(2)) - .setImageLoadingSettings( - ImageLoadingSettings.newBuilder() - .setPreLoadFill(Fill.newBuilder().setColor(9)) - .setFadeInImageOnLoad(true) - .build()) - .setRoundedCorners(RoundedCorners.newBuilder().setRadiusDp(3)) - .setFont(Font.newBuilder().setSize(4)) - .setMaxLines(5) - .setMinHeight(6) - .setHeight(7) - .setWidth(8) - .setScaleType(ScaleType.CENTER_CROP) - .setGravityHorizontal(GravityHorizontal.GRAVITY_END) - .setGravityVertical(GravityVertical.GRAVITY_BOTTOM) - .setTextAlignmentHorizontal(TextAlignmentHorizontal.TEXT_ALIGNMENT_CENTER) - .setTextAlignmentVertical(TextAlignmentVertical.TEXT_ALIGNMENT_BOTTOM) - .build(); - - StyleProvider styleProvider = new StyleProvider(style, mMockAssetProvider); - - assertThat(styleProvider.getColor()).isEqualTo(style.getColor()); - assertThat(styleProvider.getBackground()).isEqualTo(style.getBackground()); - assertThat(styleProvider.hasPreLoadFill()).isTrue(); - assertThat(styleProvider.getPreLoadFill()) - .isEqualTo(style.getImageLoadingSettings().getPreLoadFill()); - assertThat(styleProvider.getFadeInImageOnLoad()) - .isEqualTo(style.getImageLoadingSettings().getFadeInImageOnLoad()); - assertThat(styleProvider.getRoundedCorners()).isEqualTo(style.getRoundedCorners()); - assertThat(styleProvider.hasRoundedCorners()).isTrue(); - assertThat(styleProvider.getFont()).isEqualTo(style.getFont()); - assertThat(styleProvider.getMaxLines()).isEqualTo(style.getMaxLines()); - assertThat(styleProvider.getHeightSpecPx(mContext)) - .isEqualTo((int) LayoutUtils.dpToPx(style.getHeight(), mContext)); - assertThat(styleProvider.getWidthSpecPx(mContext)) - .isEqualTo((int) LayoutUtils.dpToPx(style.getWidth(), mContext)); - assertThat(styleProvider.hasHeight()).isTrue(); - assertThat(styleProvider.hasWidth()).isTrue(); - assertThat(styleProvider.getScaleType()).isEqualTo(ImageView.ScaleType.CENTER_CROP); - assertThat(styleProvider.hasGravityHorizontal()).isTrue(); - assertThat(styleProvider.getGravityHorizontal(Gravity.CLIP_VERTICAL)) - .isEqualTo(Gravity.END); - assertThat(styleProvider.hasGravityVertical()).isTrue(); - assertThat(styleProvider.getGravityVertical(Gravity.CLIP_HORIZONTAL)) - .isEqualTo(Gravity.BOTTOM); - assertThat(styleProvider.getGravity(Gravity.FILL)).isEqualTo(Gravity.END | Gravity.BOTTOM); - assertThat(styleProvider.getTextAlignment()) - .isEqualTo(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM); - } - - @Test - public void testGetters_withEmptyStyleDefined() { - Style style = Style.getDefaultInstance(); - - StyleProvider styleProvider = new StyleProvider(style, mMockAssetProvider); - - assertThat(styleProvider.getColor()).isEqualTo(style.getColor()); - assertThat(styleProvider.getBackground()).isEqualTo(style.getBackground()); - assertThat(styleProvider.hasPreLoadFill()).isFalse(); - assertThat(styleProvider.getPreLoadFill()).isEqualTo(Fill.getDefaultInstance()); - assertThat(styleProvider.getFadeInImageOnLoad()).isFalse(); - assertThat(styleProvider.hasRoundedCorners()).isFalse(); - assertThat(styleProvider.getRoundedCorners()) - .isEqualTo(RoundedCorners.getDefaultInstance()); - assertThat(styleProvider.getFont()).isEqualTo(Font.getDefaultInstance()); - assertThat(styleProvider.getMaxLines()).isEqualTo(style.getMaxLines()); - assertThat(styleProvider.getHeightSpecPx(mContext)).isEqualTo(DIMENSION_NOT_SET); - assertThat(styleProvider.getWidthSpecPx(mContext)).isEqualTo(DIMENSION_NOT_SET); - assertThat(styleProvider.hasHeight()).isFalse(); - assertThat(styleProvider.hasWidth()).isFalse(); - assertThat(styleProvider.getScaleType()).isEqualTo(ImageView.ScaleType.FIT_CENTER); - assertThat(styleProvider.hasGravityHorizontal()).isFalse(); - assertThat(styleProvider.getGravityHorizontal(Gravity.CLIP_VERTICAL)) - .isEqualTo(Gravity.CLIP_VERTICAL); - assertThat(styleProvider.hasGravityVertical()).isFalse(); - assertThat(styleProvider.getGravityVertical(Gravity.CLIP_HORIZONTAL)) - .isEqualTo(Gravity.CLIP_HORIZONTAL); - assertThat(styleProvider.getGravity(Gravity.FILL)).isEqualTo(Gravity.FILL); - assertThat(styleProvider.getTextAlignment()).isEqualTo(Gravity.START | Gravity.TOP); - } - - @Test - public void testNoOverlapWithAndroidConstants() { - assertThat(DIMENSION_NOT_SET).isNotEqualTo(LayoutParams.MATCH_PARENT); - assertThat(DIMENSION_NOT_SET).isNotEqualTo(LayoutParams.WRAP_CONTENT); - assertThat(DIMENSION_NOT_SET).isLessThan(0); - } - - @Test - public void testGetHeightSpecPx() { - assertThat(new StyleProvider(Style.getDefaultInstance(), mMockAssetProvider) - .getHeightSpecPx(mContext)) - .isEqualTo(DIMENSION_NOT_SET); - - assertThat(new StyleProvider(Style.newBuilder().setHeight(123).build(), mMockAssetProvider) - .getHeightSpecPx(mContext)) - .isEqualTo(123); - - assertThat(new StyleProvider( - Style.newBuilder().setRelativeHeight(RelativeSize.FILL_PARENT).build(), - mMockAssetProvider) - .getHeightSpecPx(mContext)) - .isEqualTo(LayoutParams.MATCH_PARENT); - assertThat(new StyleProvider( - Style.newBuilder().setRelativeHeight(RelativeSize.FIT_CONTENT).build(), - mMockAssetProvider) - .getHeightSpecPx(mContext)) - .isEqualTo(LayoutParams.WRAP_CONTENT); - assertThat( - new StyleProvider(Style.newBuilder() - .setRelativeHeight(RelativeSize.RELATIVE_SIZE_UNDEFINED) - .build(), - mMockAssetProvider) - .getHeightSpecPx(mContext)) - .isEqualTo(DIMENSION_NOT_SET); - } - - @Test - public void testGetWidthSpecPx() { - assertThat(new StyleProvider(Style.getDefaultInstance(), mMockAssetProvider) - .getWidthSpecPx(mContext)) - .isEqualTo(DIMENSION_NOT_SET); - - assertThat(new StyleProvider(Style.newBuilder().setWidth(123).build(), mMockAssetProvider) - .getWidthSpecPx(mContext)) - .isEqualTo(123); - - assertThat(new StyleProvider( - Style.newBuilder().setRelativeWidth(RelativeSize.FILL_PARENT).build(), - mMockAssetProvider) - .getWidthSpecPx(mContext)) - .isEqualTo(LayoutParams.MATCH_PARENT); - assertThat(new StyleProvider( - Style.newBuilder().setRelativeWidth(RelativeSize.FIT_CONTENT).build(), - mMockAssetProvider) - .getWidthSpecPx(mContext)) - .isEqualTo(LayoutParams.WRAP_CONTENT); - assertThat(new StyleProvider(Style.newBuilder() - .setRelativeWidth(RelativeSize.RELATIVE_SIZE_UNDEFINED) - .build(), - mMockAssetProvider) - .getWidthSpecPx(mContext)) - .isEqualTo(DIMENSION_NOT_SET); - } - - @Test - public void testHasBorders_falseIfWidthZero() { - StyleProvider styleProvider = new StyleProvider( - Style.newBuilder().setBorders(Borders.newBuilder().setBitmask(15)).build(), - mMockAssetProvider); - - assertThat(styleProvider.hasBorders()).isFalse(); - } - - @Test - public void testHasRoundedCornersMethod_noRoundedCorners() { - Style noRoundedCornerStyle = Style.getDefaultInstance(); - StyleProvider styleProvider = new StyleProvider(noRoundedCornerStyle, mMockAssetProvider); - when(mMockAssetProvider.getDefaultCornerRadius()).thenReturn(321); - - assertThat(styleProvider.hasRoundedCorners()).isFalse(); - } - - @Test - public void testApplyPadding() { - EdgeWidths padding = - EdgeWidths.newBuilder().setTop(1).setBottom(2).setStart(3).setEnd(4).build(); - new StyleProvider(Style.getDefaultInstance(), mMockAssetProvider) - .applyPadding(mContext, mView, padding, - TextElementAdapter.ExtraLineHeight.builder().build()); - verifyPadding(mView, padding); - } - - @Test - public void testApplyPadding_RtL() { - EdgeWidths padding = - EdgeWidths.newBuilder().setTop(1).setBottom(2).setStart(3).setEnd(4).build(); - when(mMockAssetProvider.isRtL()).thenReturn(true); - when(mMockAssetProvider.isRtLSupplier()).thenReturn(Suppliers.of(true)); - new StyleProvider(Style.getDefaultInstance(), mMockAssetProvider) - .applyPadding(mContext, mView, padding, - TextElementAdapter.ExtraLineHeight.builder().build()); - assertThat(mView.getPaddingLeft()).isEqualTo(4); - assertThat(mView.getPaddingRight()).isEqualTo(3); - } - - @Test - public void testApplyPadding_lineHeight() { - EdgeWidths padding = - EdgeWidths.newBuilder().setTop(1).setBottom(2).setStart(3).setEnd(4).build(); - TextElementAdapter.ExtraLineHeight extraLineHeightPadding = - TextElementAdapter.ExtraLineHeight.builder() - .setTopPaddingPx(50) - .setBottomPaddingPx(60) - .build(); - Style paddingStyle = Style.newBuilder().setPadding(padding).build(); - StyleProvider styleProvider = new StyleProvider(paddingStyle, mMockAssetProvider); - - styleProvider.applyPadding(mContext, mView, padding, extraLineHeightPadding); - - // line height top padding (50) + regular top padding (1) = expected final top (51) - assertThat(mView.getPaddingTop()).isEqualTo(51); - // line height bottom padding (60) + regular bottom padding (2) = expected final bottom (62) - assertThat(mView.getPaddingBottom()).isEqualTo(62); - } - - @Test - public void testApplyPadding_addsExtraForBorders_allSides() { - EdgeWidths padding = - EdgeWidths.newBuilder().setTop(1).setBottom(2).setStart(3).setEnd(4).build(); - Style bordersStyle = - Style.newBuilder().setBorders(Borders.newBuilder().setWidth(5)).build(); - new StyleProvider(bordersStyle, mMockAssetProvider) - .applyPadding(mContext, mView, padding, - TextElementAdapter.ExtraLineHeight.builder().build()); - - assertThat(mView.getPaddingTop()).isEqualTo((int) LayoutUtils.dpToPx(1 + 5, mContext)); - assertThat(mView.getPaddingBottom()).isEqualTo((int) LayoutUtils.dpToPx(2 + 5, mContext)); - assertThat(mView.getPaddingStart()).isEqualTo((int) LayoutUtils.dpToPx(3 + 5, mContext)); - assertThat(mView.getPaddingEnd()).isEqualTo((int) LayoutUtils.dpToPx(4 + 5, mContext)); - } - - @Test - public void testApplyPadding_addsExtraForBorders_someSides() { - EdgeWidths padding = - EdgeWidths.newBuilder().setTop(1).setBottom(2).setStart(3).setEnd(4).build(); - Style bordersBottomRight = - Style.newBuilder() - .setBorders(Borders.newBuilder().setWidth(5).setBitmask( - Edges.BOTTOM.getNumber() | Edges.END.getNumber())) - .build(); - new StyleProvider(bordersBottomRight, mMockAssetProvider) - .applyPadding(mContext, mView, padding, - TextElementAdapter.ExtraLineHeight.builder().build()); - - assertThat(mView.getPaddingTop()).isEqualTo((int) LayoutUtils.dpToPx(1, mContext)); - assertThat(mView.getPaddingBottom()).isEqualTo((int) LayoutUtils.dpToPx(2 + 5, mContext)); - assertThat(mView.getPaddingStart()).isEqualTo((int) LayoutUtils.dpToPx(3, mContext)); - assertThat(mView.getPaddingEnd()).isEqualTo((int) LayoutUtils.dpToPx(4 + 5, mContext)); - } - - @Test - public void testCreateBorderDrawable() { - Borders borders = Borders.newBuilder() - .setColor(Color.CYAN) - .setWidth(4) - .setBitmask(Edges.TOP.getNumber() | Edges.END.getNumber()) - .build(); - - FrameLayout view = new FrameLayout(mContext); - new StyleProvider(Style.newBuilder().setBorders(borders).build(), mMockAssetProvider) - .addBordersWithoutRoundedCorners(view, mContext); - BorderDrawable borderDrawable = (BorderDrawable) view.getForeground(); - borderDrawable.setBounds(0, 0, 0, 0); - - assertThat(borderDrawable.getPaint().getColor()).isEqualTo(Color.CYAN); - assertThat(borderDrawable.getBounds()).isEqualTo(new Rect(-4, 0, 0, 4)); - } - - @Test - public void testCreateBorderDrawable_noOp() { - FrameLayout view = new FrameLayout(mContext); - new StyleProvider(Style.newBuilder().setBorders(Borders.newBuilder().setWidth(0)).build(), - mMockAssetProvider) - .addBordersWithoutRoundedCorners(view, mContext); - - assertThat(view.getForeground()).isNull(); - } - - @Test - public void testCreateWrapperView_noRoundedCorners() { - StyleProvider styleProvider = new StyleProvider( - Style.newBuilder() - .setRoundedCorners(RoundedCorners.newBuilder().setRadiusDp(0).setBitmask(4)) - .build(), - mMockAssetProvider); - - FrameLayout wrapperView = - styleProvider.createWrapperView(mContext, mMaskCache, false, false); - - assertThat(wrapperView).isNotInstanceOf(RoundedCornerWrapperView.class); - assertThat(wrapperView.getOutlineProvider()).isEqualTo(ViewOutlineProvider.BOUNDS); - } - - @Test - public void testCreateWrapperView_roundedCorners() { - StyleProvider styleProvider = new StyleProvider( - Style.newBuilder() - .setRoundedCorners( - RoundedCorners.newBuilder().setRadiusDp(16).setBitmask(4)) - .build(), - mMockAssetProvider); - - FrameLayout wrapperView = - styleProvider.createWrapperView(mContext, mMaskCache, false, false); - - assertThat(wrapperView).isInstanceOf(RoundedCornerWrapperView.class); - assertThat(wrapperView.getOutlineProvider()).isNotEqualTo(ViewOutlineProvider.BOUNDS); - } - - @Test - public void testApplyMargins() { - EdgeWidths margins = - EdgeWidths.newBuilder().setTop(1).setBottom(2).setStart(3).setEnd(4).build(); - Style marginStyle = Style.newBuilder().setMargins(margins).build(); - - MarginLayoutParams params = new MarginLayoutParams( - MarginLayoutParams.MATCH_PARENT, MarginLayoutParams.WRAP_CONTENT); - - new StyleProvider(marginStyle, mMockAssetProvider).applyMargins(mContext, params); - verifyMargins(params, margins); - } - - @Test - public void testElementStyles_padding() { - EdgeWidths padding = - EdgeWidths.newBuilder().setTop(1).setBottom(2).setStart(3).setEnd(4).build(); - Style paddingStyle = Style.newBuilder().setPadding(padding).build(); - - new StyleProvider(paddingStyle, mMockAssetProvider).applyElementStyles(mAdapter); - verifyPadding(mBaseView, padding); - } - - @Test - public void testElementStyles_backgroundAndCorners() { - int color = 0xffffffff; - Fill background = Fill.newBuilder().setColor(color).build(); - RoundedCorners corners = RoundedCorners.newBuilder().setRadiusDp(4).setBitmask(3).build(); - - Style style = Style.newBuilder() - .setColor(color) - .setBackground(background) - .setRoundedCorners(corners) - .build(); - - StyleProvider styleProvider = new StyleProvider(style, mMockAssetProvider); - styleProvider.applyElementStyles(mAdapter); - - ColorDrawable colorDrawable = (ColorDrawable) mBaseView.getBackground(); - assertThat(colorDrawable.getColor()).isEqualTo(color); - } - - @Test - public void testElementStyles_noBackgroundInStyle() { - mBaseView.setBackground(new ColorDrawable(0xffff0000)); - - new StyleProvider(Style.getDefaultInstance(), mMockAssetProvider) - .applyElementStyles(mAdapter); - assertThat(mBaseView.getBackground()).isNull(); - } - - @Test - public void testElementStyles_noColorInFill() { - mBaseView.setBackground(new ColorDrawable(0xffff0000)); - - Style style = Style.newBuilder().setBackground(Fill.getDefaultInstance()).build(); - - new StyleProvider(style, mMockAssetProvider).applyElementStyles(mAdapter); - - assertThat(mBaseView.getBackground()).isNull(); - } - - @Test - public void testElementStyles_gradientBackground() { - mBaseView.setBackground(new ColorDrawable(0xffff0000)); - - Style style = Style.newBuilder() - .setBackground(Fill.newBuilder().setLinearGradient( - LinearGradient.newBuilder() - .setDirectionDeg(25) - .addStops(ColorStop.newBuilder() - .setColor(Color.RED) - .setPositionPercent(0)) - .addStops(ColorStop.newBuilder() - .setColor(Color.WHITE) - .setPositionPercent(25)) - .addStops(ColorStop.newBuilder() - .setColor(Color.GREEN) - .setPositionPercent(50)) - .addStops(ColorStop.newBuilder() - .setColor(Color.WHITE) - .setPositionPercent(75)) - .addStops(ColorStop.newBuilder() - .setColor(Color.BLUE) - .setPositionPercent(100)))) - .build(); - - new StyleProvider(style, mMockAssetProvider).applyElementStyles(mAdapter); - - Drawable background = mBaseView.getBackground(); - assertThat(background).isInstanceOf(GradientDrawable.class); - } - - @Test - public void testElementStyles_gradientBackground_badAngle_doesntCrash() { - mBaseView.setBackground(new ColorDrawable(0xffff0000)); - - Style style = Style.newBuilder() - .setBackground(Fill.newBuilder().setLinearGradient( - LinearGradient.newBuilder() - .setDirectionDeg(999) - .addStops(ColorStop.newBuilder() - .setColor(Color.RED) - .setPositionPercent(0)) - .addStops(ColorStop.newBuilder() - .setColor(Color.BLUE) - .setPositionPercent(100)))) - .build(); - - new StyleProvider(style, mMockAssetProvider).applyElementStyles(mAdapter); - - Drawable background = mBaseView.getBackground(); - assertThat(background).isInstanceOf(GradientDrawable.class); - } - - @Test - public void testElementStyles_gradientBackground_badPercent_doesntCrash() { - mBaseView.setBackground(new ColorDrawable(0xffff0000)); - - Style style = Style.newBuilder() - .setBackground(Fill.newBuilder().setLinearGradient( - LinearGradient.newBuilder() - .setDirectionDeg(45) - .addStops(ColorStop.newBuilder() - .setColor(Color.RED) - .setPositionPercent(200)) - .addStops(ColorStop.newBuilder() - .setColor(Color.BLUE) - .setPositionPercent(25)))) - .build(); - - new StyleProvider(style, mMockAssetProvider).applyElementStyles(mAdapter); - - Drawable background = mBaseView.getBackground(); - assertThat(background).isInstanceOf(GradientDrawable.class); - } - - @Test - public void testElementStyles_minimumHeight() { - int minHeight = 12345; - Style heightStyle = Style.newBuilder().setMinHeight(minHeight).build(); - - new StyleProvider(heightStyle, mMockAssetProvider).applyElementStyles(mAdapter); - - assertThat(mBaseView.getMinimumHeight()).isEqualTo(minHeight); - } - - @Test - public void testElementStyles_noMinimumHeight() { - Style noHeightStyle = Style.getDefaultInstance(); - mView.setMinimumHeight(12345); - - new StyleProvider(noHeightStyle, mMockAssetProvider).applyElementStyles(mAdapter); - - assertThat(mBaseView.getMinimumHeight()).isEqualTo(0); - } - - @Test - public void testElementStyles_shadow() { - int elevation = 5280; - Style shadowStyle = Style.newBuilder() - .setShadow(Shadow.newBuilder().setElevationShadow( - ElevationShadow.newBuilder().setElevation(elevation))) - .build(); - - new StyleProvider(shadowStyle, mMockAssetProvider).applyElementStyles(mAdapter); - - assertThat(mView.getElevation()).isEqualTo((float) elevation); - } - - @Test - public void testElementStyles_noShadow() { - Style shadowStyle = Style.newBuilder() - .setShadow(Shadow.newBuilder().setElevationShadow( - ElevationShadow.newBuilder().setElevation(5280))) - .build(); - Style noShadowStyle = Style.getDefaultInstance(); - - new StyleProvider(shadowStyle, mMockAssetProvider).applyElementStyles(mAdapter); - - new StyleProvider(noShadowStyle, mMockAssetProvider).applyElementStyles(mAdapter); - - assertThat(mView.getElevation()).isEqualTo(0.0f); - } - - @Test - public void testElementStyles_opacity() { - new StyleProvider(Style.newBuilder().setOpacity(0.5f).build(), mMockAssetProvider) - .applyElementStyles(mAdapter); - - assertThat(mBaseView.getAlpha()).isEqualTo(0.5f); - - new StyleProvider(Style.getDefaultInstance(), mMockAssetProvider) - .applyElementStyles(mAdapter); - - assertThat(mBaseView.getAlpha()).isEqualTo(1.0f); - } - - @Test - public void testElementStyles_overlayResets() { - mBaseView.setBackground(new ShapeDrawable()); - mBaseView.setElevation(12.3f); - - new StyleProvider(Style.newBuilder() - .setBackground(Fill.newBuilder().setColor(Color.BLUE)) - .setShadow(Shadow.newBuilder().setElevationShadow( - ElevationShadow.newBuilder().setElevation(5))) - .build(), - mMockAssetProvider) - .applyElementStyles(mAdapter); - - assertThat(mBaseView.getElevation()).isWithin(0.1f).of(0.0f); - assertThat(mView.getElevation()).isWithin(0.1f).of(5.0f); - - assertThat(mView.getBackground()).isNull(); - assertThat(mBaseView.getBackground()).isInstanceOf(ColorDrawable.class); - } - - @Test - public void testCreateBackground() { - int color = 12345; - Fill fill = Fill.newBuilder().setColor(color).build(); - RoundedCorners roundedCorners = RoundedCorners.newBuilder().setRadiusDp(4321).build(); - StyleProvider styleProvider; - - styleProvider = new StyleProvider(Style.getDefaultInstance(), mMockAssetProvider); - assertThat(styleProvider.createBackground()).isNull(); - - styleProvider = new StyleProvider( - Style.newBuilder().setBackground(fill).setRoundedCorners(roundedCorners).build(), - mMockAssetProvider); - Drawable backgroundDrawable = styleProvider.createBackground(); - assertThat(backgroundDrawable).isInstanceOf(ColorDrawable.class); - - ColorDrawable background = (ColorDrawable) backgroundDrawable; - assertThat(background.getColor()).isEqualTo(color); - } - - @Test - public void testCreatePreLoadFill() { - int color = 12345; - Fill fill = Fill.newBuilder().setColor(color).build(); - RoundedCorners roundedCorners = RoundedCorners.newBuilder().setRadiusDp(4321).build(); - StyleProvider styleProvider; - - styleProvider = new StyleProvider(Style.getDefaultInstance(), mMockAssetProvider); - assertThat(styleProvider.createPreLoadFill()).isNull(); - - styleProvider = new StyleProvider( - Style.newBuilder() - .setImageLoadingSettings( - ImageLoadingSettings.newBuilder().setPreLoadFill(fill).build()) - .setRoundedCorners(roundedCorners) - .build(), - mMockAssetProvider); - Drawable preLoadFillDrawable = styleProvider.createPreLoadFill(); - assertThat(preLoadFillDrawable).isInstanceOf(ColorDrawable.class); - - ColorDrawable background = (ColorDrawable) preLoadFillDrawable; - assertThat(background.getColor()).isEqualTo(color); - } - - @Test - public void testEqualsAndHashCode() { - Style style = Style.newBuilder().setColor(123).build(); - Style sameStyle = Style.newBuilder().setColor(123).build(); - Style differentStyle = Style.newBuilder().setHeight(456).build(); - - StyleProvider styleProvider = new StyleProvider(style, mMockAssetProvider); - StyleProvider sameStyleProvider = new StyleProvider(sameStyle, mMockAssetProvider); - StyleProvider differentStyleProvider = - new StyleProvider(differentStyle, mMockAssetProvider); - - assertThat(styleProvider).isEqualTo(sameStyleProvider); - assertThat(styleProvider.hashCode()).isEqualTo(sameStyleProvider.hashCode()); - assertThat(styleProvider).isNotEqualTo(differentStyleProvider); - } - - private void verifyPadding(View view, EdgeWidths padding) { - assertThat(view.getPaddingTop()) - .isEqualTo((int) LayoutUtils.dpToPx(padding.getTop(), mContext)); - assertThat(view.getPaddingBottom()) - .isEqualTo((int) LayoutUtils.dpToPx(padding.getBottom(), mContext)); - assertThat(view.getPaddingStart()) - .isEqualTo((int) LayoutUtils.dpToPx(padding.getStart(), mContext)); - assertThat(view.getPaddingEnd()) - .isEqualTo((int) LayoutUtils.dpToPx(padding.getEnd(), mContext)); - } - - private void verifyMargins(MarginLayoutParams params, EdgeWidths margins) { - assertThat(params.getMarginStart()) - .isEqualTo((int) LayoutUtils.dpToPx(margins.getStart(), mContext)); - assertThat(params.getMarginEnd()) - .isEqualTo((int) LayoutUtils.dpToPx(margins.getEnd(), mContext)); - assertThat(params.topMargin) - .isEqualTo((int) LayoutUtils.dpToPx(margins.getTop(), mContext)); - assertThat(params.bottomMargin) - .isEqualTo((int) LayoutUtils.dpToPx(margins.getBottom(), mContext)); - assertThat(params.leftMargin) - .isEqualTo((int) LayoutUtils.dpToPx(margins.getStart(), mContext)); - assertThat(params.rightMargin) - .isEqualTo((int) LayoutUtils.dpToPx(margins.getEnd(), mContext)); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/TemplateBinderTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/TemplateBinderTest.java deleted file mode 100644 index e1dfbe8..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/TemplateBinderTest.java +++ /dev/null
@@ -1,724 +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. - -package org.chromium.chrome.browser.feed.library.piet; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import static org.chromium.chrome.browser.feed.library.common.testing.RunnableSubject.assertThatRunnable; - -import android.app.Activity; -import android.content.Context; -import android.graphics.Color; -import android.graphics.drawable.ColorDrawable; -import android.view.View; -import android.widget.FrameLayout; -import android.widget.LinearLayout; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.config.DebugBehavior; -import org.chromium.chrome.browser.feed.library.common.functional.Suppliers; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.piet.PietStylesHelper.PietStylesHelperFactory; -import org.chromium.chrome.browser.feed.library.piet.TemplateBinder.TemplateAdapterModel; -import org.chromium.chrome.browser.feed.library.piet.TemplateBinder.TemplateKey; -import org.chromium.chrome.browser.feed.library.piet.host.ActionHandler; -import org.chromium.chrome.browser.feed.library.piet.host.AssetProvider; -import org.chromium.components.feed.core.proto.ui.piet.BindingRefsProto.ParameterizedTextBindingRef; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.BindingContext; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.BindingValue; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.Content; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.Element; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.ElementList; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.GridRow; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.TextElement; -import org.chromium.components.feed.core.proto.ui.piet.GradientsProto.Fill; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.Frame; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.PietSharedState; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.Stylesheet; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.Stylesheets; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.Template; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.Style; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.StyleIdsStack; -import org.chromium.components.feed.core.proto.ui.piet.TextProto.ParameterizedText; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** Tests for TemplateBinder methods. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class TemplateBinderTest { - private static final int FRAME_COLOR = 12345; - private static final String FRAME_STYLESHEET_ID = "coolcat"; - private static final String TEXT_STYLE_ID = "catalog"; - private static final String TEMPLATE_ID = "duplicat"; - private static final String OTHER_TEMPLATE_ID = "alleycat"; - private static final String TEXT_BINDING_ID = "ofmiceandmen"; - private static final String TEXT_CONTENTS = "afewmilessouth"; - - private static final int FRAME_WIDTH_PX = 321; - - private static final Template MODEL_TEMPLATE = - Template.newBuilder() - .setTemplateId(TEMPLATE_ID) - .setElement( - Element.newBuilder() - .setStyleReferences( - StyleIdsStack.newBuilder().addStyleIds(TEXT_STYLE_ID)) - .setTextElement( - TextElement.newBuilder().setParameterizedTextBinding( - ParameterizedTextBindingRef.newBuilder() - .setBindingId(TEXT_BINDING_ID)))) - .build(); - private static final Template OTHER_TEMPLATE = - Template.newBuilder() - .setTemplateId(OTHER_TEMPLATE_ID) - .setElement( - Element.newBuilder().setElementList(ElementList.getDefaultInstance())) - .build(); - - private static final Frame DEFAULT_FRAME = - Frame.newBuilder() - .setStylesheets(Stylesheets.newBuilder().addStylesheets( - Stylesheet.newBuilder() - .setStylesheetId(FRAME_STYLESHEET_ID) - .addStyles(Style.newBuilder() - .setStyleId(TEXT_STYLE_ID) - .setColor(FRAME_COLOR)))) - .addTemplates(MODEL_TEMPLATE) - .addTemplates(OTHER_TEMPLATE) - .build(); - - private static final BindingContext MODEL_BINDING_CONTEXT = - BindingContext.newBuilder() - .addBindingValues( - BindingValue.newBuilder() - .setBindingId(TEXT_BINDING_ID) - .setParameterizedText( - ParameterizedText.newBuilder().setText(TEXT_CONTENTS))) - .build(); - - private static final Element DEFAULT_TEMPLATE_ELEMENT = - Element.newBuilder().setElementList(ElementList.getDefaultInstance()).build(); - - @Mock - private ElementListAdapter mElementListAdapter; - @Mock - private ElementAdapter<? extends View, ?> mTemplateAdapter; - @Mock - private FrameContext mFrameContext; - @Mock - private ElementAdapterFactory mAdapterFactory; - @Mock - private ActionHandler mActionHandler; - - private KeyedRecyclerPool<ElementAdapter<? extends View, ?>> mTemplateRecyclerPool; - - private TemplateBinder mTemplateBinder; - - @Before - public void setUp() throws Exception { - initMocks(this); - - mTemplateRecyclerPool = new KeyedRecyclerPool<>(100, 100); - mTemplateBinder = new TemplateBinder(mTemplateRecyclerPool, mAdapterFactory); - } - - @Test - public void testCreateTemplateAdapter() { - // Set up data for test: template, shared states, binding context, template adapter model - String templateId = "papa"; - Template template = Template.newBuilder() - .setTemplateId(templateId) - .setElement(DEFAULT_TEMPLATE_ELEMENT) - .build(); - when(mFrameContext.getTemplate(templateId)).thenReturn(template); - PietSharedState sharedState = PietSharedState.newBuilder().addTemplates(template).build(); - List<PietSharedState> sharedStates = Collections.singletonList(sharedState); - when(mFrameContext.getPietSharedStates()).thenReturn(sharedStates); - BindingContext bindingContext = - BindingContext.newBuilder() - .addBindingValues(BindingValue.newBuilder().setBindingId("potato")) - .build(); - TemplateAdapterModel model = new TemplateAdapterModel(template, bindingContext); - - // Set frameContext to return a new frameContext when a template is bound - FrameContext templateContext = mock(FrameContext.class); - when(mFrameContext.createTemplateContext(template, bindingContext)) - .thenReturn(templateContext); - doReturn(mElementListAdapter) - .when(mAdapterFactory) - .createAdapterForElement(DEFAULT_TEMPLATE_ELEMENT, templateContext); - - ElementAdapter<? extends View, ?> adapter = - mTemplateBinder.createTemplateAdapter(model, mFrameContext); - - assertThat(adapter).isSameInstanceAs(mElementListAdapter); - verify(mElementListAdapter) - .setKey(new TemplateKey(template, sharedStates, new ArrayList<>())); - } - - @Test - public void testCreateTemplateAdapter_recycled() { - Template template = Template.newBuilder() - .setTemplateId("template") - .setElement(DEFAULT_TEMPLATE_ELEMENT) - .build(); - List<PietSharedState> sharedStates = Collections.emptyList(); - TemplateKey templateKey = new TemplateKey(template, sharedStates, new ArrayList<>()); - when(mTemplateAdapter.getKey()).thenReturn(templateKey); - when(mFrameContext.getPietSharedStates()).thenReturn(sharedStates); - - // Release adapter to populate the recycler pool - mTemplateRecyclerPool.put(templateKey, mTemplateAdapter); - - // Get a new adapter from the pool. - TemplateAdapterModel model = - new TemplateAdapterModel(template, BindingContext.getDefaultInstance()); - ElementAdapter<? extends View, ?> adapter = - mTemplateBinder.createTemplateAdapter(model, mFrameContext); - - assertThat(adapter).isSameInstanceAs(mTemplateAdapter); - // We don't need to re-create the adapter; it has already been created. - verify(mTemplateAdapter, never()).createAdapter(any(Element.class), any()); - verify(mTemplateAdapter, never()).createAdapter(any(), any(), any()); - } - - /** - * Set up a "real" environment, and ensure that styles are set from the template, not from the - * frame. - */ - @Test - public void testCreateTemplateAdapter_checkStyleSources() { - // Set up 3 styles: one on the template, one on the frame, and one on the shared state. - String templateStyleId = "templateStyle"; - String frameStyleId = "frameStyle"; - String globalStyleId = "globalStyle"; - - int templateColor = Color.GREEN; - Style templateStyle = Style.newBuilder() - .setStyleId(templateStyleId) - .setBackground(Fill.newBuilder().setColor(templateColor)) - .build(); - int frameColor = Color.RED; - Style frameStyle = Style.newBuilder() - .setStyleId(frameStyleId) - .setBackground(Fill.newBuilder().setColor(frameColor)) - .build(); - int globalColor = Color.BLUE; - Style globalStyle = Style.newBuilder() - .setStyleId(globalStyleId) - .setBackground(Fill.newBuilder().setColor(globalColor)) - .build(); - - // Style on the frame with the same ID as the template's style. - int frameTemplateColor = Color.MAGENTA; - Style frameTemplateStyle = - Style.newBuilder() - .setStyleId(templateStyleId) - .setBackground(Fill.newBuilder().setColor(frameTemplateColor)) - .build(); - - // Template: A list of 3 elements with template style, frame style, and global style, - // respectively. - Template template = - Template.newBuilder() - .setStylesheets(Stylesheets.newBuilder().addStylesheets( - Stylesheet.newBuilder().addStyles(templateStyle))) - .setElement(Element.newBuilder().setElementList( - ElementList.newBuilder() - .addContents(Content.newBuilder().setElement( - Element.newBuilder() - .setStyleReferences( - StyleIdsStack.newBuilder() - .addStyleIds( - templateStyleId)) - .setElementList( - ElementList.getDefaultInstance()))) - .addContents(Content.newBuilder().setElement( - Element.newBuilder() - .setStyleReferences( - StyleIdsStack.newBuilder() - .addStyleIds(frameStyleId)) - .setElementList( - ElementList.getDefaultInstance()))) - .addContents(Content.newBuilder().setElement( - Element.newBuilder() - .setStyleReferences( - StyleIdsStack.newBuilder() - .addStyleIds(globalStyleId)) - .setElementList( - ElementList - .getDefaultInstance()))))) - .build(); - - PietSharedState pietSharedState = - PietSharedState.newBuilder() - .addTemplates(template) - .addStylesheets(Stylesheet.newBuilder().addStyles(globalStyle)) - .build(); - - // Frame defines style IDs that are also defined in the template - Frame frame = Frame.newBuilder() - .setStylesheets(Stylesheets.newBuilder().addStylesheets( - Stylesheet.newBuilder() - .addStyles(frameStyle) - .addStyles(frameTemplateStyle))) - .build(); - - // Set up a "real" frameContext, adapterParameters, factory - Context context = Robolectric.buildActivity(Activity.class).get(); - List<PietSharedState> pietSharedStates = Collections.singletonList(pietSharedState); - HostProviders mockHostProviders = mock(HostProviders.class); - AssetProvider mockAssetProvider = mock(AssetProvider.class); - when(mockHostProviders.getAssetProvider()).thenReturn(mockAssetProvider); - MediaQueryHelper mediaQueryHelper = - new MediaQueryHelper(FRAME_WIDTH_PX, mockAssetProvider, context); - PietStylesHelper pietStylesHelper = - new PietStylesHelperFactory().get(pietSharedStates, mediaQueryHelper); - mFrameContext = FrameContext.createFrameContext(frame, pietSharedStates, pietStylesHelper, - DebugBehavior.VERBOSE, new DebugLogger(), mActionHandler, mockHostProviders, - new FrameLayout(context)); - AdapterParameters adapterParameters = new AdapterParameters( - context, Suppliers.of(null), mockHostProviders, new FakeClock(), false, false); - TemplateBinder templateBinder = adapterParameters.mTemplateBinder; - - // Create and bind adapter - TemplateAdapterModel templateModel = - new TemplateAdapterModel(template, BindingContext.getDefaultInstance()); - ElementAdapter<? extends View, ?> adapter = - templateBinder.createTemplateAdapter(templateModel, mFrameContext); - templateBinder.bindTemplateAdapter(adapter, templateModel, mFrameContext); - - // Check views to ensure that template styles get set, but not frame or global styles. - LinearLayout templateList = (LinearLayout) adapter.getView(); - assertThat(templateList.getChildCount()).isEqualTo(3); - - // Template style element gets background from template - assertThat(((ColorDrawable) templateList.getChildAt(0).getBackground()).getColor()) - .isEqualTo(templateColor); - - // Frame style element gets no background - frame styles are not in scope for template. - assertThat(templateList.getChildAt(1).getBackground()).isNull(); - - // Global style element gets no background - global styles are not in scope for template. - assertThat(templateList.getChildAt(2).getBackground()).isNull(); - } - - @Test - public void testBindTemplateAdapter_success() { - // Set up data for test: template, shared states, binding context, template adapter model - String templateId = "papa"; - Template template = Template.newBuilder() - .setTemplateId(templateId) - .setElement(Element.newBuilder().setElementList( - ElementList.getDefaultInstance())) - .build(); - when(mFrameContext.getTemplate(templateId)).thenReturn(template); - PietSharedState sharedState = PietSharedState.newBuilder().addTemplates(template).build(); - List<PietSharedState> sharedStates = Collections.singletonList(sharedState); - when(mFrameContext.getPietSharedStates()).thenReturn(sharedStates); - BindingContext bindingContext = - BindingContext.newBuilder() - .addBindingValues(BindingValue.newBuilder().setBindingId("potato")) - .build(); - TemplateAdapterModel model = new TemplateAdapterModel(template, bindingContext); - - // Set frameContext to return a new frameContext when a template is bound - FrameContext templateContext = mock(FrameContext.class); - when(mFrameContext.createTemplateContext(template, bindingContext)) - .thenReturn(templateContext); - doReturn(mElementListAdapter) - .when(mAdapterFactory) - .createAdapterForElement(DEFAULT_TEMPLATE_ELEMENT, templateContext); - - // Create adapter and ensure template key is set. - ElementAdapter<? extends View, ?> adapter = - mTemplateBinder.createTemplateAdapter(model, mFrameContext); - ArgumentCaptor<RecyclerKey> keyArgumentCaptor = ArgumentCaptor.forClass(RecyclerKey.class); - verify(mElementListAdapter).setKey(keyArgumentCaptor.capture()); - when(mElementListAdapter.getKey()).thenReturn(keyArgumentCaptor.getValue()); - - mTemplateBinder.bindTemplateAdapter(adapter, model, mFrameContext); - - // Assert that adapter is bound with the template frameContext - verify(mElementListAdapter).bindModel(model.getTemplate().getElement(), templateContext); - } - - @Test - public void testBindTemplateAdapter_nullKey() { - TemplateAdapterModel templateAdapterModel = - new TemplateAdapterModel(Template.getDefaultInstance(), null); - when(mElementListAdapter.getKey()).thenReturn(null); - - assertThatRunnable(() - -> mTemplateBinder.bindTemplateAdapter(mElementListAdapter, - templateAdapterModel, mFrameContext)) - .throwsAnExceptionOfType(NullPointerException.class) - .that() - .hasMessageThat() - .contains("Adapter key was null"); - } - - @Test - public void testBindTemplateAdapter_notATemplateAdapter() { - TemplateAdapterModel templateAdapterModel = - new TemplateAdapterModel(Template.getDefaultInstance(), null); - when(mElementListAdapter.getKey()).thenReturn(ElementListAdapter.KeySupplier.SINGLETON_KEY); - - assertThatRunnable(() - -> mTemplateBinder.bindTemplateAdapter(mElementListAdapter, - templateAdapterModel, mFrameContext)) - .throwsAnExceptionOfType(IllegalStateException.class) - .that() - .hasMessageThat() - .contains("bindTemplateAdapter only applicable for template adapters"); - } - - @Test - public void testBindTemplateAdapter_templateMismatch() { - // Set up data for test: two templates, shared states, binding context, template adapter - // model - String templateId1 = "papa"; - Template template1 = Template.newBuilder() - .setTemplateId(templateId1) - .setElement(DEFAULT_TEMPLATE_ELEMENT) - .build(); - String templateId2 = "mama"; - Template template2 = - Template.newBuilder() - .setTemplateId(templateId2) - .setElement(Element.newBuilder().setGridRow(GridRow.getDefaultInstance())) - .build(); - when(mFrameContext.getTemplate(templateId1)).thenReturn(template1); - when(mFrameContext.getTemplate(templateId2)).thenReturn(template2); - PietSharedState sharedState = PietSharedState.newBuilder() - .addTemplates(template1) - .addTemplates(template2) - .build(); - List<PietSharedState> sharedStates = Collections.singletonList(sharedState); - when(mFrameContext.getPietSharedStates()).thenReturn(sharedStates); - BindingContext bindingContext = - BindingContext.newBuilder() - .addBindingValues(BindingValue.newBuilder().setBindingId("potato")) - .build(); - TemplateAdapterModel model1 = new TemplateAdapterModel(template1, bindingContext); - TemplateAdapterModel model2 = new TemplateAdapterModel(template2, bindingContext); - assertThat(new TemplateKey(template1, sharedStates, new ArrayList<>())) - .isNotEqualTo(new TemplateKey(template2, sharedStates, new ArrayList<>())); - - // Set frameContext to return a new frameContext when a template is bound - FrameContext templateContext = mock(FrameContext.class); - when(mFrameContext.createTemplateContext(template1, bindingContext)) - .thenReturn(templateContext); - when(mFrameContext.createTemplateContext(template2, bindingContext)) - .thenReturn(templateContext); - doReturn(mElementListAdapter) - .when(mAdapterFactory) - .createAdapterForElement(DEFAULT_TEMPLATE_ELEMENT, templateContext); - - // Create adapter with first template and ensure template key is set. - ElementAdapter<? extends View, ?> adapter = - mTemplateBinder.createTemplateAdapter(model1, mFrameContext); - ArgumentCaptor<RecyclerKey> keyArgumentCaptor = ArgumentCaptor.forClass(RecyclerKey.class); - verify(mElementListAdapter).setKey(keyArgumentCaptor.capture()); - when(mElementListAdapter.getKey()).thenReturn(keyArgumentCaptor.getValue()); - - // Try to bind with a different template and fail. - assertThatRunnable( - () -> mTemplateBinder.bindTemplateAdapter(adapter, model2, mFrameContext)) - .throwsAnExceptionOfType(IllegalStateException.class) - .that() - .hasMessageThat() - .contains("Template keys did not match"); - } - - @Test - public void testCreateAndBindTemplateAdapter_newAdapter() { - // Set up data for test: template, shared states, binding context, template adapter model - String templateId = "papa"; - Template template = Template.newBuilder() - .setTemplateId(templateId) - .setElement(DEFAULT_TEMPLATE_ELEMENT) - .build(); - when(mFrameContext.getTemplate(templateId)).thenReturn(template); - PietSharedState sharedState = PietSharedState.newBuilder().addTemplates(template).build(); - List<PietSharedState> sharedStates = Collections.singletonList(sharedState); - when(mFrameContext.getPietSharedStates()).thenReturn(sharedStates); - BindingContext bindingContext = - BindingContext.newBuilder() - .addBindingValues(BindingValue.newBuilder().setBindingId("potato")) - .build(); - TemplateAdapterModel model = new TemplateAdapterModel(template, bindingContext); - - // Set frameContext to return a new frameContext when a template is bound - FrameContext templateContext = mock(FrameContext.class); - when(mFrameContext.createTemplateContext(template, bindingContext)) - .thenReturn(templateContext); - doReturn(mElementListAdapter) - .when(mAdapterFactory) - .createAdapterForElement(DEFAULT_TEMPLATE_ELEMENT, templateContext); - - // Create adapter and ensure template key is set. - ElementAdapter<? extends View, ?> adapter = - mTemplateBinder.createAndBindTemplateAdapter(model, mFrameContext); - - assertThat(adapter).isSameInstanceAs(mElementListAdapter); - verify(mElementListAdapter) - .setKey(new TemplateKey(template, sharedStates, new ArrayList<>())); - - // Assert that adapter is bound with the template frameContext - verify(mElementListAdapter).bindModel(model.getTemplate().getElement(), templateContext); - } - - @Test - public void testCreateAndBindTemplateAdapter_recycled() { - // Set up data for test: template, shared states, binding context, template adapter model - String templateId = "papa"; - Template template = Template.newBuilder() - .setTemplateId(templateId) - .setElement(DEFAULT_TEMPLATE_ELEMENT) - .build(); - when(mFrameContext.getTemplate(templateId)).thenReturn(template); - PietSharedState sharedState = PietSharedState.newBuilder().addTemplates(template).build(); - List<PietSharedState> sharedStates = Collections.singletonList(sharedState); - when(mFrameContext.getPietSharedStates()).thenReturn(sharedStates); - BindingContext bindingContext = - BindingContext.newBuilder() - .addBindingValues(BindingValue.newBuilder().setBindingId("potato")) - .build(); - TemplateAdapterModel model = new TemplateAdapterModel(template, bindingContext); - - // Set frameContext to return a new frameContext when a template is bound - FrameContext templateContext = mock(FrameContext.class); - when(mFrameContext.createTemplateContext(template, bindingContext)) - .thenReturn(templateContext); - doReturn(mElementListAdapter) - .when(mAdapterFactory) - .createAdapterForElement(DEFAULT_TEMPLATE_ELEMENT, templateContext); - - TemplateKey templateKey = new TemplateKey(template, sharedStates, new ArrayList<>()); - when(mElementListAdapter.getKey()).thenReturn(templateKey); - mTemplateRecyclerPool.put(templateKey, mElementListAdapter); - - // Create adapter and ensure template key is set. - ElementAdapter<? extends View, ?> adapter = - mTemplateBinder.createAndBindTemplateAdapter(model, mFrameContext); - assertThat(adapter).isSameInstanceAs(mElementListAdapter); - - // We don't get the adapter from the factory - verifyZeroInteractions(mAdapterFactory); - verify(mElementListAdapter, never()).setKey(any(TemplateKey.class)); - - // Assert that adapter is bound with the template frameContext - verify(mElementListAdapter).bindModel(model.getTemplate().getElement(), templateContext); - } - - @Test - public void testTemplateKey_equalWithSameObjects() { - Template template = Template.newBuilder().setTemplateId("T").build(); - Stylesheet stylesheet = Stylesheet.newBuilder().setStylesheetId("S").build(); - List<PietSharedState> sharedStates = - listOfSharedStates(PietSharedState.newBuilder().addTemplates(template).build()); - List<Stylesheet> stylesheets = Collections.singletonList(stylesheet); - TemplateKey key1 = new TemplateKey(template, sharedStates, stylesheets); - TemplateKey key2 = new TemplateKey(template, sharedStates, stylesheets); - - assertThat(key1.hashCode()).isEqualTo(key2.hashCode()); - assertThat(key1).isEqualTo(key2); - } - - @Test - public void testTemplateKey_equalWithDifferentTemplateObject() { - Template template1 = Template.newBuilder().setTemplateId("T").build(); - Template template2 = Template.newBuilder().setTemplateId("T").build(); - PietSharedState sharedState = PietSharedState.newBuilder().addTemplates(template1).build(); - TemplateKey key1 = - new TemplateKey(template1, listOfSharedStates(sharedState), new ArrayList<>()); - TemplateKey key2 = - new TemplateKey(template2, listOfSharedStates(sharedState), new ArrayList<>()); - - assertThat(key1.hashCode()).isEqualTo(key2.hashCode()); - assertThat(key1).isEqualTo(key2); - } - - @Test - public void testTemplateKey_equalWithDifferentSharedStateObject() { - Template template = Template.newBuilder().setTemplateId("T").build(); - PietSharedState sharedState1 = PietSharedState.newBuilder().addTemplates(template).build(); - PietSharedState sharedState2 = PietSharedState.newBuilder().addTemplates(template).build(); - TemplateKey key1 = - new TemplateKey(template, listOfSharedStates(sharedState1), new ArrayList<>()); - TemplateKey key2 = - new TemplateKey(template, listOfSharedStates(sharedState2), new ArrayList<>()); - - assertThat(key1.hashCode()).isEqualTo(key2.hashCode()); - assertThat(key1).isEqualTo(key2); - } - - @Test - public void testTemplateKey_equalWithDifferentStylesheetObject() { - Template template = Template.newBuilder().setTemplateId("T").build(); - PietSharedState sharedState = PietSharedState.newBuilder().addTemplates(template).build(); - Stylesheet stylesheet1 = Stylesheet.newBuilder().setStylesheetId("1").build(); - Stylesheet stylesheet2 = Stylesheet.newBuilder().setStylesheetId("1").build(); - TemplateKey key1 = new TemplateKey( - template, listOfSharedStates(sharedState), Collections.singletonList(stylesheet1)); - TemplateKey key2 = new TemplateKey( - template, listOfSharedStates(sharedState), Collections.singletonList(stylesheet2)); - - assertThat(key1.hashCode()).isEqualTo(key2.hashCode()); - assertThat(key1).isEqualTo(key2); - } - - @Test - public void testTemplateKey_differentWithDifferentLengthSharedStates() { - Template template = Template.newBuilder().setTemplateId("T").build(); - PietSharedState sharedState1 = PietSharedState.newBuilder().addTemplates(template).build(); - TemplateKey key1 = - new TemplateKey(template, listOfSharedStates(sharedState1), new ArrayList<>()); - TemplateKey key2 = new TemplateKey( - template, listOfSharedStates(sharedState1, sharedState1), new ArrayList<>()); - - assertThat(key1.hashCode()).isNotEqualTo(key2.hashCode()); - assertThat(key1).isNotEqualTo(key2); - } - - @Test - public void testTemplateKey_differentWithDifferentTemplate() { - Template template1 = Template.newBuilder().setTemplateId("T1").build(); - Template template2 = Template.newBuilder().setTemplateId("T2").build(); - List<PietSharedState> sharedStates = - listOfSharedStates(PietSharedState.newBuilder().addTemplates(template1).build()); - TemplateKey key1 = new TemplateKey(template1, sharedStates, new ArrayList<>()); - TemplateKey key2 = new TemplateKey(template2, sharedStates, new ArrayList<>()); - - assertThat(key1.hashCode()).isNotEqualTo(key2.hashCode()); - assertThat(key1).isNotEqualTo(key2); - } - - @Test - public void testTemplateKey_differentWithDifferentSharedState() { - Template template = Template.newBuilder().setTemplateId("T").build(); - PietSharedState sharedState1 = PietSharedState.newBuilder().addTemplates(template).build(); - PietSharedState sharedState2 = PietSharedState.getDefaultInstance(); - TemplateKey key1 = - new TemplateKey(template, listOfSharedStates(sharedState1), new ArrayList<>()); - TemplateKey key2 = - new TemplateKey(template, listOfSharedStates(sharedState2), new ArrayList<>()); - - assertThat(key1.hashCode()).isNotEqualTo(key2.hashCode()); - assertThat(key1).isNotEqualTo(key2); - } - - @Test - public void testTemplateKey_differentWithDifferentStylesheet() { - Template template = Template.newBuilder().setTemplateId("T").build(); - PietSharedState sharedState = PietSharedState.newBuilder().addTemplates(template).build(); - Stylesheet stylesheet1 = Stylesheet.newBuilder().setStylesheetId("1").build(); - Stylesheet stylesheet2 = Stylesheet.newBuilder().setStylesheetId("2").build(); - TemplateKey key1 = new TemplateKey( - template, listOfSharedStates(sharedState), Collections.singletonList(stylesheet1)); - TemplateKey key2 = new TemplateKey( - template, listOfSharedStates(sharedState), Collections.singletonList(stylesheet2)); - - assertThat(key1.hashCode()).isNotEqualTo(key2.hashCode()); - assertThat(key1).isNotEqualTo(key2); - } - - @Test - public void testTemplateAdapterModel_getters() { - TemplateAdapterModel model = - new TemplateAdapterModel(MODEL_TEMPLATE, MODEL_BINDING_CONTEXT); - assertThat(model.getTemplate()).isSameInstanceAs(MODEL_TEMPLATE); - assertThat(model.getBindingContext()).isSameInstanceAs(MODEL_BINDING_CONTEXT); - } - - @Test - public void testTemplateAdapterModel_lookUpTemplate() { - ActionHandler actionHandler = mock(ActionHandler.class); - List<PietSharedState> pietSharedStates = Collections.emptyList(); - Context context = Robolectric.buildActivity(Activity.class).get(); - - HostProviders mockHostProviders = mock(HostProviders.class); - AssetProvider mockAssetProvider = mock(AssetProvider.class); - when(mockHostProviders.getAssetProvider()).thenReturn(mockAssetProvider); - - MediaQueryHelper mediaQueryHelper = - new MediaQueryHelper(FRAME_WIDTH_PX, mockAssetProvider, context); - PietStylesHelper pietStylesHelper = - new PietStylesHelperFactory().get(pietSharedStates, mediaQueryHelper); - - FrameContext frameContext = FrameContext.createFrameContext( - DEFAULT_FRAME, // This defines MODEL_TEMPLATE - pietSharedStates, pietStylesHelper, DebugBehavior.VERBOSE, new DebugLogger(), - actionHandler, mockHostProviders, new FrameLayout(context)); - - TemplateAdapterModel model = new TemplateAdapterModel( - MODEL_TEMPLATE.getTemplateId(), frameContext, MODEL_BINDING_CONTEXT); - assertThat(model.getTemplate()).isSameInstanceAs(MODEL_TEMPLATE); - assertThat(model.getBindingContext()).isSameInstanceAs(MODEL_BINDING_CONTEXT); - } - - @Test - public void testTemplateAdapterModel_equalsSame() { - TemplateAdapterModel model1 = - new TemplateAdapterModel(MODEL_TEMPLATE, MODEL_BINDING_CONTEXT); - TemplateAdapterModel model2 = - new TemplateAdapterModel(MODEL_TEMPLATE, MODEL_BINDING_CONTEXT); - assertThat(model1).isEqualTo(model2); - assertThat(model1.hashCode()).isEqualTo(model2.hashCode()); - } - - @Test - public void testTemplateAdapterModel_equalsOtherInstance() { - TemplateAdapterModel model1 = - new TemplateAdapterModel(MODEL_TEMPLATE, MODEL_BINDING_CONTEXT); - TemplateAdapterModel model2 = new TemplateAdapterModel( - MODEL_TEMPLATE.toBuilder().build(), MODEL_BINDING_CONTEXT.toBuilder().build()); - assertThat(model1.getTemplate()).isNotSameInstanceAs(model2.getTemplate()); - assertThat(model1.getBindingContext()).isNotSameInstanceAs(model2.getBindingContext()); - assertThat(model1).isEqualTo(model2); - assertThat(model1.hashCode()).isEqualTo(model2.hashCode()); - } - - @Test - public void testTemplateAdapterModel_notEquals() { - TemplateAdapterModel model1 = - new TemplateAdapterModel(MODEL_TEMPLATE, MODEL_BINDING_CONTEXT); - TemplateAdapterModel model2 = new TemplateAdapterModel( - MODEL_TEMPLATE.toBuilder().clearTemplateId().build(), MODEL_BINDING_CONTEXT); - TemplateAdapterModel model3 = new TemplateAdapterModel( - MODEL_TEMPLATE, MODEL_BINDING_CONTEXT.toBuilder().clearBindingValues().build()); - assertThat(model1).isNotEqualTo(model2); - assertThat(model1.hashCode()).isNotEqualTo(model2.hashCode()); - assertThat(model1).isNotEqualTo(model3); - assertThat(model1.hashCode()).isNotEqualTo(model3.hashCode()); - } - - private List<PietSharedState> listOfSharedStates(PietSharedState... pietSharedStates) { - List<PietSharedState> sharedStates = new ArrayList<>(); - Collections.addAll(sharedStates, pietSharedStates); - return sharedStates; - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/TextElementAdapterTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/TextElementAdapterTest.java deleted file mode 100644 index 8fd5bd5f..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/TextElementAdapterTest.java +++ /dev/null
@@ -1,557 +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. - -package org.chromium.chrome.browser.feed.library.piet; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import static org.chromium.chrome.browser.feed.library.common.testing.RunnableSubject.assertThatRunnable; - -import android.app.Activity; -import android.content.Context; -import android.graphics.Color; -import android.graphics.Typeface; -import android.text.Layout; -import android.text.TextUtils.TruncateAt; -import android.view.Gravity; -import android.view.View; -import android.widget.TextView; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentMatchers; -import org.mockito.InOrder; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.base.Consumer; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.common.ui.LayoutUtils; -import org.chromium.chrome.browser.feed.library.piet.DebugLogger.MessageType; -import org.chromium.chrome.browser.feed.library.piet.TextElementAdapter.TextElementKey; -import org.chromium.chrome.browser.feed.library.piet.host.AssetProvider; -import org.chromium.chrome.browser.feed.library.piet.host.TypefaceProvider.GoogleSansTypeface; -import org.chromium.components.feed.core.proto.ui.piet.BindingRefsProto.StyleBindingRef; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.CustomElement; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.Element; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.TextElement; -import org.chromium.components.feed.core.proto.ui.piet.ErrorsProto.ErrorCode; -import org.chromium.components.feed.core.proto.ui.piet.RoundedCornersProto.RoundedCorners; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.Font; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.Style; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.StyleIdsStack; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.TextAlignmentHorizontal; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.TextAlignmentVertical; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.Typeface.CommonTypeface; -import org.chromium.components.feed.core.proto.ui.piet.TextProto.ParameterizedText; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests of the {@link TextElementAdapter}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class TextElementAdapterTest { - @Mock - private FrameContext mFrameContext; - @Mock - private StyleProvider mMockStyleProvider; - @Mock - private HostProviders mMockHostProviders; - @Mock - private AssetProvider mMockAssetProvider; - - private AdapterParameters mAdapterParameters; - - private Context mContext; - - private TextElementAdapter mAdapter; - private int mEmptyTextElementLineHeight; - - @Before - public void setUp() { - initMocks(this); - mContext = Robolectric.buildActivity(Activity.class).get(); - - when(mMockHostProviders.getAssetProvider()).thenReturn(mMockAssetProvider); - when(mMockAssetProvider.isRtL()).thenReturn(false); - when(mMockStyleProvider.getRoundedCorners()) - .thenReturn(RoundedCorners.getDefaultInstance()); - when(mMockStyleProvider.getTextAlignment()).thenReturn(Gravity.START | Gravity.TOP); - - mAdapterParameters = new AdapterParameters(null, null, mMockHostProviders, - new ParameterizedTextEvaluator(new FakeClock()), null, null, new FakeClock()); - - TextElementAdapter adapterForEmptyElement = - new TestTextElementAdapter(mContext, mAdapterParameters); - // Get emptyTextElementHeight based on a text element with no content or styles set. - Element textElement = getBaseTextElement(); - adapterForEmptyElement.createAdapter(textElement, mFrameContext); - mEmptyTextElementLineHeight = adapterForEmptyElement.getBaseView().getLineHeight(); - - mAdapter = new TestTextElementAdapter(mContext, mAdapterParameters); - } - - @Test - public void testHyphenationDisabled() { - assertThat(mAdapter.getBaseView().getBreakStrategy()) - .isEqualTo(Layout.BREAK_STRATEGY_SIMPLE); - } - - @Test - public void testCreateAdapter_setsStyles() { - Element textElement = getBaseTextElement(mMockStyleProvider); - int color = Color.RED; - int maxLines = 72; - when(mMockStyleProvider.getFont()).thenReturn(Font.getDefaultInstance()); - when(mMockStyleProvider.getColor()).thenReturn(color); - when(mMockStyleProvider.getMaxLines()).thenReturn(maxLines); - - mAdapter.createAdapter(textElement, mFrameContext); - - verify(mMockStyleProvider).applyElementStyles(mAdapter); - assertThat(mAdapter.getBaseView().getMaxLines()).isEqualTo(maxLines); - assertThat(mAdapter.getBaseView().getEllipsize()).isEqualTo(TruncateAt.END); - assertThat(mAdapter.getBaseView().getCurrentTextColor()).isEqualTo(color); - } - - @Test - public void testSetFont_usesCommonFont() { - Font font = - Font.newBuilder() - .addTypeface(StylesProto.Typeface.newBuilder().setCommonTypeface( - CommonTypeface.PLATFORM_DEFAULT_MEDIUM)) - .addTypeface(StylesProto.Typeface.newBuilder().setCustomTypeface("notused")) - .build(); - - TextElementKey key = new TextElementKey(font); - - mAdapter.setValuesUsedInRecyclerKey(key, mFrameContext); - - verify(mMockAssetProvider, never()) - .getTypeface(anyString(), anyBoolean(), ArgumentMatchers.<Consumer<Typeface>>any()); - } - - @Test - public void testSetFont_callsHost() { - Font font = Font.newBuilder() - .addTypeface( - StylesProto.Typeface.newBuilder().setCustomTypeface("goodfont")) - .build(); - TextElementKey key = new TextElementKey(font); - - mAdapter.setValuesUsedInRecyclerKey(key, mFrameContext); - - verify(mMockAssetProvider, atLeastOnce()) - .getTypeface(eq("goodfont"), eq(false), ArgumentMatchers.<Consumer<Typeface>>any()); - } - - @Test - public void testSetFont_callsHostWithItalic() { - Font font = - Font.newBuilder() - .addTypeface( - StylesProto.Typeface.newBuilder().setCustomTypeface("goodfont")) - .addTypeface(StylesProto.Typeface.newBuilder().setCustomTypeface("badfont")) - .setItalic(true) - .build(); - TextElementKey key = new TextElementKey(font); - - mAdapter.setValuesUsedInRecyclerKey(key, mFrameContext); - - verify(mMockAssetProvider, atLeastOnce()) - .getTypeface(eq("goodfont"), eq(true), ArgumentMatchers.<Consumer<Typeface>>any()); - } - - @Test - public void testSetFont_callsHostWithFallback() { - Font font = - Font.newBuilder() - .addTypeface(StylesProto.Typeface.newBuilder().setCustomTypeface("badfont")) - .addTypeface( - StylesProto.Typeface.newBuilder().setCustomTypeface("goodfont")) - .build(); - TextElementKey key = new TextElementKey(font); - // Consumer accepts null for badfont - doAnswer(answer -> { - Consumer<Typeface> typefaceConsumer = answer.getArgument(2); - typefaceConsumer.accept(null); - return null; - }) - .when(mMockAssetProvider) - .getTypeface(eq("badfont"), eq(false), ArgumentMatchers.<Consumer<Typeface>>any()); - // Consumer accepts hosttypeface for goodfont - Typeface hostTypeface = Typeface.create("host", Typeface.BOLD_ITALIC); - doAnswer(answer -> { - Consumer<Typeface> typefaceConsumer = answer.getArgument(2); - typefaceConsumer.accept(hostTypeface); - return null; - }) - .when(mMockAssetProvider) - .getTypeface(eq("goodfont"), eq(false), ArgumentMatchers.<Consumer<Typeface>>any()); - - mAdapter.setValuesUsedInRecyclerKey(key, mFrameContext); - - Typeface typeface = mAdapter.getBaseView().getTypeface(); - assertThat(typeface).isEqualTo(hostTypeface); - InOrder inOrder = inOrder(mMockAssetProvider); - inOrder.verify(mMockAssetProvider, atLeastOnce()) - .getTypeface(eq("badfont"), eq(false), ArgumentMatchers.<Consumer<Typeface>>any()); - inOrder.verify(mMockAssetProvider, atLeastOnce()) - .getTypeface(eq("goodfont"), eq(false), ArgumentMatchers.<Consumer<Typeface>>any()); - } - - @Test - public void testSetFont_hostReturnsNull() { - Font font = Font.newBuilder() - .addTypeface( - StylesProto.Typeface.newBuilder().setCustomTypeface("notvalid")) - .build(); - doAnswer(answer -> { - Consumer<Typeface> typefaceConsumer = answer.getArgument(2); - typefaceConsumer.accept(null); - return null; - }) - .when(mMockAssetProvider) - .getTypeface(eq("notvalid"), eq(false), ArgumentMatchers.<Consumer<Typeface>>any()); - TextElementKey key = new TextElementKey(font); - - mAdapter.setValuesUsedInRecyclerKey(key, mFrameContext); - Typeface typeface = mAdapter.getBaseView().getTypeface(); - - verify(mFrameContext) - .reportMessage(MessageType.WARNING, ErrorCode.ERR_MISSING_FONTS, - "Could not load specified typefaces."); - assertThat(typeface).isEqualTo(new TextView(mContext).getTypeface()); - } - - @Test - public void testSetFont_callsHostForGoogleSans() { - Font font = Font.newBuilder() - .addTypeface(StylesProto.Typeface.newBuilder().setCommonTypeface( - CommonTypeface.GOOGLE_SANS_MEDIUM)) - .build(); - TextElementKey key = new TextElementKey(font); - - mAdapter.setValuesUsedInRecyclerKey(key, mFrameContext); - - verify(mMockAssetProvider, atLeastOnce()) - .getTypeface(eq(GoogleSansTypeface.GOOGLE_SANS_MEDIUM), eq(false), - ArgumentMatchers.<Consumer<Typeface>>any()); - } - - @Test - public void testSetFont_italics() { - Font font = Font.newBuilder().setItalic(true).build(); - TextElementKey key = new TextElementKey(font); - - mAdapter.setValuesUsedInRecyclerKey(key, mFrameContext); - Typeface typeface = mAdapter.getBaseView().getTypeface(); - // Typeface.isBold and Typeface.isItalic don't work properly in roboelectric. - assertThat(typeface.getStyle() & Typeface.BOLD).isEqualTo(0); - assertThat(typeface.getStyle() & Typeface.ITALIC).isGreaterThan(0); - } - - @Test - public void testGoogleSansEnumToStringDef() { - assertThat(TextElementAdapter.googleSansEnumToStringDef(CommonTypeface.GOOGLE_SANS_REGULAR)) - .isEqualTo(GoogleSansTypeface.GOOGLE_SANS_REGULAR); - assertThat(TextElementAdapter.googleSansEnumToStringDef(CommonTypeface.GOOGLE_SANS_MEDIUM)) - .isEqualTo(GoogleSansTypeface.GOOGLE_SANS_MEDIUM); - assertThat(TextElementAdapter.googleSansEnumToStringDef( - CommonTypeface.PLATFORM_DEFAULT_MEDIUM)) - .isEqualTo(GoogleSansTypeface.UNDEFINED); - } - - @Test - public void testSetLineHeight() { - int lineHeightToSetSp = 18; - Style lineHeightStyle1 = - Style.newBuilder() - .setFont(Font.newBuilder().setLineHeight(lineHeightToSetSp)) - .build(); - StyleProvider styleProvider1 = new StyleProvider(lineHeightStyle1, mMockAssetProvider); - Element textElement = getBaseTextElement(styleProvider1); - - mAdapter.createAdapter(textElement, mFrameContext); - TextView textView = mAdapter.getBaseView(); - float actualLineHeightPx = textView.getLineHeight(); - int actualLineHeightSp = - (int) LayoutUtils.pxToSp(actualLineHeightPx, textView.getContext()); - assertThat(actualLineHeightSp).isEqualTo(lineHeightToSetSp); - } - - @Test - public void testGetExtraLineHeight_roundDown() { - // Extra height is 40.2px. This gets rounded down between the lines (to 40) and rounded up - // for top and bottom padding (for 21 + 20 = 41). - initializeAdapterWithExtraLineHeightPx(40.2f); - - TextElementAdapter.ExtraLineHeight extraLineHeight = mAdapter.getExtraLineHeight(); - - assertThat(extraLineHeight.betweenLinesExtraPx()).isEqualTo(40); - assertThat(extraLineHeight.bottomPaddingPx()).isEqualTo(21); - assertThat(extraLineHeight.topPaddingPx()).isEqualTo(20); - } - - @Test - public void testGetExtraLineHeight_noRound() { - // Extra height is 40px. 40 pixels will be added between each line, and that amount is split - // (20 and 20) to be added to the top and bottom of the text element. - initializeAdapterWithExtraLineHeightPx(40.0f); - - TextElementAdapter.ExtraLineHeight extraLineHeight = mAdapter.getExtraLineHeight(); - - assertThat(extraLineHeight.betweenLinesExtraPx()).isEqualTo(40); - assertThat(extraLineHeight.bottomPaddingPx()).isEqualTo(20); - assertThat(extraLineHeight.topPaddingPx()).isEqualTo(20); - } - - @Test - public void testGetExtraLineHeight_roundUp() { - // Extra height is 40.8px. This gets rounded up between the lines (to 41) and rounded down - // for top and bottom padding (for 20 + 20 = 40). - initializeAdapterWithExtraLineHeightPx(40.8f); - - TextElementAdapter.ExtraLineHeight extraLineHeight = mAdapter.getExtraLineHeight(); - - assertThat(extraLineHeight.betweenLinesExtraPx()).isEqualTo(41); - assertThat(extraLineHeight.bottomPaddingPx()).isEqualTo(20); - assertThat(extraLineHeight.topPaddingPx()).isEqualTo(20); - } - - private void initializeAdapterWithExtraLineHeightPx(float lineHeightPx) { - // Line height is specified in sp, so line height px = scaledDensity x line height sp - // These tests set display density because, in order to test the rounding behavior of - // extraLineHeight, we need a lineHeight integer (in sp) that results in a decimal value in - // px. - int lineHeightSp = 10; - float totalLineHeightPx = mEmptyTextElementLineHeight + lineHeightPx; - mContext.getResources().getDisplayMetrics().scaledDensity = - totalLineHeightPx / lineHeightSp; - Style lineHeightStyle1 = - Style.newBuilder().setFont(Font.newBuilder().setLineHeight(lineHeightSp)).build(); - StyleProvider styleProvider1 = new StyleProvider(lineHeightStyle1, mMockAssetProvider); - Element textElement = getBaseTextElement(styleProvider1); - mAdapter.createAdapter(textElement, mFrameContext); - } - - @Test - public void testBind_setsTextAlignment_horizontal() { - Style style = - Style.newBuilder() - .setTextAlignmentHorizontal(TextAlignmentHorizontal.TEXT_ALIGNMENT_CENTER) - .build(); - StyleProvider styleProvider = new StyleProvider(style, mMockAssetProvider); - Element textElement = getBaseTextElement(styleProvider); - mAdapter.createAdapter(textElement, mFrameContext); - mAdapter.bindModel(textElement, mFrameContext); - - assertThat(mAdapter.getBaseView().getGravity()) - .isEqualTo(Gravity.CENTER_HORIZONTAL | Gravity.TOP); - } - - @Test - public void testBind_setsTextAlignment_vertical() { - Style style = Style.newBuilder() - .setTextAlignmentVertical(TextAlignmentVertical.TEXT_ALIGNMENT_BOTTOM) - .build(); - StyleProvider styleProvider = new StyleProvider(style, mMockAssetProvider); - Element textElement = getBaseTextElement(styleProvider); - mAdapter.createAdapter(textElement, mFrameContext); - mAdapter.bindModel(textElement, mFrameContext); - - assertThat(mAdapter.getBaseView().getGravity()).isEqualTo(Gravity.START | Gravity.BOTTOM); - } - - @Test - public void testBind_setsTextAlignment_both() { - Style style = - Style.newBuilder() - .setTextAlignmentHorizontal(TextAlignmentHorizontal.TEXT_ALIGNMENT_END) - .setTextAlignmentVertical(TextAlignmentVertical.TEXT_ALIGNMENT_MIDDLE) - .build(); - StyleProvider styleProvider = new StyleProvider(style, mMockAssetProvider); - Element textElement = getBaseTextElement(styleProvider); - mAdapter.createAdapter(textElement, mFrameContext); - mAdapter.bindModel(textElement, mFrameContext); - - assertThat(mAdapter.getBaseView().getGravity()) - .isEqualTo(Gravity.END | Gravity.CENTER_VERTICAL); - } - - @Test - public void testBind_setsTextAlignment_default() { - Style style = Style.getDefaultInstance(); - StyleProvider styleProvider = new StyleProvider(style, mMockAssetProvider); - Element textElement = getBaseTextElement(styleProvider); - mAdapter.getBaseView().setGravity(Gravity.BOTTOM | Gravity.RIGHT); - mAdapter.createAdapter(textElement, mFrameContext); - mAdapter.bindModel(textElement, mFrameContext); - - assertThat(mAdapter.getBaseView().getGravity()).isEqualTo(Gravity.START | Gravity.TOP); - } - - @Test - public void testBind_setsStylesOnlyIfBindingIsDefined() { - int maxLines = 2; - Style style = Style.newBuilder().setMaxLines(maxLines).build(); - StyleProvider styleProvider = new StyleProvider(style, mMockAssetProvider); - Element textElement = getBaseTextElement(styleProvider); - mAdapter.createAdapter(textElement, mFrameContext); - mAdapter.bindModel(textElement, mFrameContext); - assertThat(mAdapter.getBaseView().getMaxLines()).isEqualTo(maxLines); - - // Styles should not change on a re-bind - mAdapter.unbindModel(); - StyleIdsStack otherStyle = StyleIdsStack.newBuilder().addStyleIds("ignored").build(); - textElement = getBaseTextElement().toBuilder().setStyleReferences(otherStyle).build(); - mAdapter.bindModel(textElement, mFrameContext); - - assertThat(mAdapter.getBaseView().getMaxLines()).isEqualTo(maxLines); - verify(mFrameContext, never()).makeStyleFor(otherStyle); - - // Styles only change if new model has style bindings - mAdapter.unbindModel(); - StyleIdsStack otherStyleWithBinding = - StyleIdsStack.newBuilder() - .setStyleBinding(StyleBindingRef.newBuilder().setBindingId("prionailurus")) - .build(); - textElement = - getBaseTextElement().toBuilder().setStyleReferences(otherStyleWithBinding).build(); - mAdapter.bindModel(textElement, mFrameContext); - - verify(mFrameContext).makeStyleFor(otherStyleWithBinding); - } - - @Test - public void bindWithUpdatedDensity_shouldUpdateLineHeight() { - final int lineHeightInTextElement = 50; - mContext.getResources().getDisplayMetrics().scaledDensity = 1; - Style style = Style.newBuilder() - .setFont(Font.newBuilder().setLineHeight(lineHeightInTextElement)) - .build(); - StyleProvider styleProvider = new StyleProvider(style, mMockAssetProvider); - Element textElement = getBaseTextElement(styleProvider); - - mAdapter.createAdapter(textElement, mFrameContext); - mAdapter.bindModel(textElement, mFrameContext); - assertThat(mAdapter.getBaseView().getLineHeight()).isEqualTo(lineHeightInTextElement); - - mAdapter.unbindModel(); - // Change line height by changing the scale density - mContext.getResources().getDisplayMetrics().scaledDensity = 2; - mAdapter.bindModel(textElement, mFrameContext); - // getLineHeight() still returns pixels. The number of pixels should have been updated to - // reflect the new density. - assertThat(mAdapter.getBaseView().getLineHeight()).isEqualTo(lineHeightInTextElement * 2); - - mAdapter.unbindModel(); - // Make sure the line height is updated again when the scale density is changed back. - mContext.getResources().getDisplayMetrics().scaledDensity = 1; - mAdapter.bindModel(textElement, mFrameContext); - assertThat(mAdapter.getBaseView().getLineHeight()).isEqualTo(lineHeightInTextElement); - } - - @Test - public void testUnbind() { - Element textElement = getBaseTextElement(null); - mAdapter.createAdapter(textElement, mFrameContext); - mAdapter.bindModel(textElement, mFrameContext); - - TextView adapterView = mAdapter.getBaseView(); - adapterView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START); - adapterView.setText("OLD TEXT"); - - mAdapter.unbindModel(); - - assertThat(mAdapter.getBaseView()).isSameInstanceAs(adapterView); - assertThat(adapterView.getTextAlignment()).isEqualTo(View.TEXT_ALIGNMENT_GRAVITY); - assertThat(adapterView.getText().toString()).isEmpty(); - } - - @Test - public void testGetStyles() { - StyleIdsStack elementStyles = StyleIdsStack.newBuilder().addStyleIds("hair").build(); - when(mMockStyleProvider.getFont()).thenReturn(Font.getDefaultInstance()); - Element textElement = getBaseTextElement(mMockStyleProvider) - .toBuilder() - .setStyleReferences(elementStyles) - .build(); - - mAdapter.createAdapter(textElement, mFrameContext); - - assertThat(mAdapter.getElementStyleIdsStack()).isSameInstanceAs(elementStyles); - } - - @Test - public void testGetModelFromElement() { - TextElement model = - TextElement.newBuilder() - .setParameterizedText(ParameterizedText.newBuilder().setText("text")) - .build(); - - Element elementWithModel = - Element.newBuilder() - .setStyleReferences(StyleIdsStack.newBuilder().addStyleIds("spacer")) - .setTextElement(model) - .build(); - assertThat(mAdapter.getModelFromElement(elementWithModel)) - .isSameInstanceAs(elementWithModel); - - Element elementWithWrongModel = - Element.newBuilder().setCustomElement(CustomElement.getDefaultInstance()).build(); - assertThatRunnable(() -> mAdapter.getModelFromElement(elementWithWrongModel)) - .throwsAnExceptionOfType(PietFatalException.class) - .that() - .hasMessageThat() - .contains("Missing TextElement"); - - Element emptyElement = Element.getDefaultInstance(); - assertThatRunnable(() -> mAdapter.getModelFromElement(emptyElement)) - .throwsAnExceptionOfType(PietFatalException.class) - .that() - .hasMessageThat() - .contains("Missing TextElement"); - } - - private Element getBaseTextElement() { - return getBaseTextElement(null); - } - - private Element getBaseTextElement(/*@Nullable*/ StyleProvider styleProvider) { - StyleProvider sp = - styleProvider != null ? styleProvider : mAdapterParameters.mDefaultStyleProvider; - when(mFrameContext.makeStyleFor(any(StyleIdsStack.class))).thenReturn(sp); - - return Element.newBuilder().setTextElement(TextElement.getDefaultInstance()).build(); - } - - private static class TestTextElementAdapter extends TextElementAdapter { - TestTextElementAdapter(Context mContext, AdapterParameters parameters) { - super(mContext, parameters); - } - - @Override - void setTextOnView(FrameContext mFrameContext, TextElement textElement) {} - - @Override - TextElementKey createKey(Font font) { - return new TextElementKey(font); - } - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ViewUtilsTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ViewUtilsTest.java deleted file mode 100644 index 2839761..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ViewUtilsTest.java +++ /dev/null
@@ -1,469 +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. - -package org.chromium.chrome.browser.feed.library.piet; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import android.app.Activity; -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.PorterDuff.Mode; -import android.graphics.PorterDuffColorFilter; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.RippleDrawable; -import android.view.View; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; -import org.robolectric.shadow.api.Shadow; - -import org.chromium.chrome.browser.feed.library.piet.host.ActionHandler; -import org.chromium.chrome.browser.feed.library.piet.host.ActionHandler.ActionType; -import org.chromium.chrome.browser.feed.library.testing.shadows.ExtendedShadowView; -import org.chromium.components.feed.core.proto.ui.piet.ActionsProto.Action; -import org.chromium.components.feed.core.proto.ui.piet.ActionsProto.Actions; -import org.chromium.components.feed.core.proto.ui.piet.ActionsProto.VisibilityAction; -import org.chromium.components.feed.core.proto.ui.piet.LogDataProto.LogData; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.Frame; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.HashSet; -import java.util.Set; - -/** Tests of the {@link ViewUtils}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE, shadows = {ExtendedShadowView.class}) -public class ViewUtilsTest { - private final Context mContext = Robolectric.buildActivity(Activity.class).get(); - - private static final Frame DEFAULT_FRAME = Frame.newBuilder().setTag("Frame").build(); - private static final Action DEFAULT_ACTION = Action.getDefaultInstance(); - private static final Actions DEFAULT_ACTIONS = - Actions.newBuilder().setOnClickAction(DEFAULT_ACTION).build(); - private static final Actions LONG_CLICK_ACTIONS = - Actions.newBuilder().setOnLongClickAction(DEFAULT_ACTION).build(); - private static final Action PARTIAL_VIEW_ACTION = Action.newBuilder().build(); - private static final Action FULL_VIEW_ACTION = Action.newBuilder().build(); - private static final Actions VIEW_ACTIONS = - Actions.newBuilder() - .addOnViewActions( - VisibilityAction.newBuilder().setProportionVisible(0.01f).setAction( - PARTIAL_VIEW_ACTION)) - .addOnViewActions( - VisibilityAction.newBuilder().setProportionVisible(1.00f).setAction( - FULL_VIEW_ACTION)) - .build(); - - // Triggers when more than 1% of the view is visible - private static final VisibilityAction VIEW_ACTION = - VisibilityAction.newBuilder() - .setProportionVisible(0.01f) - .setAction(Action.newBuilder().build()) - .build(); - // Triggers when more than 1% of the view is hidden - private static final VisibilityAction HIDE_ACTION = - VisibilityAction.newBuilder() - .setProportionVisible(0.99f) - .setAction(Action.newBuilder().build()) - .build(); - private static final Actions VIEW_AND_HIDE_ACTIONS = Actions.newBuilder() - .addOnViewActions(VIEW_ACTION) - .addOnHideActions(HIDE_ACTION) - .build(); - - @Mock - private ActionHandler mMockActionHandler; - @Mock - private FrameContext mMockFrameContext; - @Mock - private View.OnClickListener mMockListener; - @Mock - private View.OnLongClickListener mMockLongClickListener; - - private final View mView = new View(mContext); - private final View mViewport = new View(mContext); - - private final ExtendedShadowView mViewShadow = Shadow.extract(mView); - private final ExtendedShadowView mViewportShadow = Shadow.extract(mViewport); - - private final Set<VisibilityAction> mActiveActions = new HashSet<>(); - - @Before - public void setUp() { - initMocks(this); - when(mMockFrameContext.getFrame()).thenReturn(DEFAULT_FRAME); - when(mMockFrameContext.getActionHandler()).thenReturn(mMockActionHandler); - } - - @Test - public void testSetOnClickActions_success() { - LogData logData = LogData.newBuilder().build(); - ViewUtils.setOnClickActions(DEFAULT_ACTIONS, mView, mMockFrameContext, logData); - - assertThat(mView.hasOnClickListeners()).isTrue(); - - mView.callOnClick(); - verify(mMockActionHandler) - .handleAction(eq(DEFAULT_ACTION), eq(ActionType.CLICK), eq(DEFAULT_FRAME), - eq(mView), same(logData)); - assertThat(mView.getForeground()).isInstanceOf(RippleDrawable.class); - } - - @Test - public void testSetOnLongClickActions_success() { - LogData logData = LogData.newBuilder().build(); - ViewUtils.setOnClickActions(LONG_CLICK_ACTIONS, mView, mMockFrameContext, logData); - - mView.performLongClick(); - verify(mMockActionHandler) - .handleAction(eq(DEFAULT_ACTION), eq(ActionType.LONG_CLICK), eq(DEFAULT_FRAME), - eq(mView), same(logData)); - assertThat(mView.getForeground()).isInstanceOf(RippleDrawable.class); - } - - @Test - public void testSetOnClickActions_noOnClickActionsDefinedClearsActions() { - mView.setOnClickListener(mMockListener); - assertThat(mView.hasOnClickListeners()).isTrue(); - - ViewUtils.setOnClickActions(Actions.getDefaultInstance(), mView, mMockFrameContext, - LogData.getDefaultInstance()); - - assertViewNotClickable(); - assertThat(mView.getForeground()).isNull(); - } - - @Test - public void testSetOnClickActions_noOnLongClickActionsDefinedClearsActions() { - mView.setOnLongClickListener(mMockLongClickListener); - assertThat(mView.isLongClickable()).isTrue(); - - ViewUtils.setOnClickActions(Actions.getDefaultInstance(), mView, mMockFrameContext, - LogData.getDefaultInstance()); - - assertThat(mView.isLongClickable()).isFalse(); - assertThat(mView.getForeground()).isNull(); - } - - @Test - public void testClearOnClickActions_success() { - mView.setOnClickListener(mMockListener); - assertThat(mView.hasOnClickListeners()).isTrue(); - - ViewUtils.clearOnClickActions(mView); - - assertViewNotClickable(); - } - - @Test - public void testClearOnLongClickActions_success() { - mView.setOnLongClickListener(mMockLongClickListener); - assertThat(mView.isLongClickable()).isTrue(); - - ViewUtils.clearOnLongClickActions(mView); - - assertThat(mView.isLongClickable()).isFalse(); - } - - @Test - public void testSetAndClearClickActions() { - ViewUtils.setOnClickActions(Actions.newBuilder() - .setOnClickAction(DEFAULT_ACTION) - .setOnLongClickAction(DEFAULT_ACTION) - .build(), - mView, mMockFrameContext, LogData.getDefaultInstance()); - ViewUtils.setOnClickActions(Actions.getDefaultInstance(), mView, mMockFrameContext, - LogData.getDefaultInstance()); - - assertViewNotClickable(); - assertThat(mView.isLongClickable()).isFalse(); - assertThat(mView.getForeground()).isNull(); - } - - @Test - public void testViewActions_notVisible() { - setupFullViewScenario(); - mView.setVisibility(View.INVISIBLE); - ViewUtils.maybeTriggerViewActions( - mView, mViewport, VIEW_ACTIONS, mMockActionHandler, DEFAULT_FRAME, mActiveActions); - verifyZeroInteractions(mMockActionHandler); - } - - @Test - public void testViewActions_notAttached() { - setupFullViewScenario(); - mViewShadow.setAttachedToWindow(false); - ViewUtils.maybeTriggerViewActions( - mView, mViewport, VIEW_ACTIONS, mMockActionHandler, DEFAULT_FRAME, mActiveActions); - verifyZeroInteractions(mMockActionHandler); - } - - @Test - public void testViewActions_notIntersecting() { - setupFullViewScenario(); - mViewportShadow.setLocationOnScreen(0, 0); - mViewportShadow.setHeight(100); - mViewportShadow.setWidth(100); - mViewShadow.setLocationOnScreen(1000, 1000); - ViewUtils.maybeTriggerViewActions( - mView, mViewport, VIEW_ACTIONS, mMockActionHandler, DEFAULT_FRAME, mActiveActions); - verifyZeroInteractions(mMockActionHandler); - } - - @Test - public void testViewActions_intersectionTriggersPartialView() { - setupPartialViewScenario(); - ViewUtils.maybeTriggerViewActions( - mView, mViewport, VIEW_ACTIONS, mMockActionHandler, DEFAULT_FRAME, mActiveActions); - verify(mMockActionHandler) - .handleAction(same(PARTIAL_VIEW_ACTION), eq(ActionType.VIEW), same(DEFAULT_FRAME), - same(mView), eq(LogData.getDefaultInstance())); - } - - @Test - public void testViewActions_fullyOverlappingTriggersFullViewAndPartialView() { - setupFullViewScenario(); - ViewUtils.maybeTriggerViewActions( - mView, mViewport, VIEW_ACTIONS, mMockActionHandler, DEFAULT_FRAME, mActiveActions); - verify(mMockActionHandler) - .handleAction(same(FULL_VIEW_ACTION), eq(ActionType.VIEW), same(DEFAULT_FRAME), - same(mView), eq(LogData.getDefaultInstance())); - verify(mMockActionHandler) - .handleAction(same(PARTIAL_VIEW_ACTION), eq(ActionType.VIEW), same(DEFAULT_FRAME), - same(mView), eq(LogData.getDefaultInstance())); - } - - @Test - public void testViewActions_fullOverlapTriggersActions() { - setupFullViewScenario(); - mViewShadow.setLocationOnScreen(0, 0); - mViewShadow.setWidth(100); - mViewShadow.setHeight(100); - mViewportShadow.setLocationOnScreen(0, 0); - mViewportShadow.setWidth(100); - mViewportShadow.setHeight(100); - - ViewUtils.maybeTriggerViewActions( - mView, mViewport, VIEW_ACTIONS, mMockActionHandler, DEFAULT_FRAME, mActiveActions); - verify(mMockActionHandler) - .handleAction(same(FULL_VIEW_ACTION), eq(ActionType.VIEW), same(DEFAULT_FRAME), - same(mView), eq(LogData.getDefaultInstance())); - verify(mMockActionHandler) - .handleAction(same(PARTIAL_VIEW_ACTION), eq(ActionType.VIEW), same(DEFAULT_FRAME), - same(mView), eq(LogData.getDefaultInstance())); - } - - @Test - public void testViewActions_noPartialViewAction() { - setupFullViewScenario(); - ViewUtils.maybeTriggerViewActions(mView, mViewport, - Actions.newBuilder() - .addOnViewActions( - VisibilityAction.newBuilder().setProportionVisible(1.00f).setAction( - FULL_VIEW_ACTION)) - .build(), - mMockActionHandler, DEFAULT_FRAME, mActiveActions); - verify(mMockActionHandler) - .handleAction(same(FULL_VIEW_ACTION), eq(ActionType.VIEW), same(DEFAULT_FRAME), - same(mView), eq(LogData.getDefaultInstance())); - } - - @Test - public void testViewActions_noFullViewAction() { - setupFullViewScenario(); - ViewUtils.maybeTriggerViewActions(mView, mViewport, - Actions.newBuilder() - .addOnViewActions( - VisibilityAction.newBuilder().setProportionVisible(0.01f).setAction( - PARTIAL_VIEW_ACTION)) - .build(), - mMockActionHandler, DEFAULT_FRAME, mActiveActions); - verify(mMockActionHandler) - .handleAction(same(PARTIAL_VIEW_ACTION), eq(ActionType.VIEW), same(DEFAULT_FRAME), - same(mView), eq(LogData.getDefaultInstance())); - } - - @Test - public void testViewActions_hideActionsNotTriggered() { - setupFullViewScenario(); - ViewUtils.maybeTriggerViewActions(mView, mViewport, - Actions.newBuilder() - .addOnHideActions( - VisibilityAction.newBuilder().setProportionVisible(0.01f).setAction( - PARTIAL_VIEW_ACTION)) - .build(), - mMockActionHandler, DEFAULT_FRAME, mActiveActions); - verifyZeroInteractions(mMockActionHandler); - } - - @Test - public void testViewActions_hideActionsTriggered() { - setupPartialViewScenario(); - ViewUtils.maybeTriggerViewActions(mView, mViewport, - Actions.newBuilder() - .addOnHideActions( - VisibilityAction.newBuilder().setProportionVisible(0.90f).setAction( - PARTIAL_VIEW_ACTION)) - .build(), - mMockActionHandler, DEFAULT_FRAME, mActiveActions); - verify(mMockActionHandler) - .handleAction(same(PARTIAL_VIEW_ACTION), eq(ActionType.VIEW), same(DEFAULT_FRAME), - same(mView), eq(LogData.getDefaultInstance())); - } - - @Test - public void testViewActions_activeActionsPreventsTriggering_notVisible() { - mActiveActions.add(VIEW_ACTION); - mActiveActions.add(HIDE_ACTION); - - setupFullViewScenario(); - mViewShadow.setLocationOnScreen(1000, 1000); - ViewUtils.maybeTriggerViewActions(mView, mViewport, VIEW_AND_HIDE_ACTIONS, - mMockActionHandler, DEFAULT_FRAME, mActiveActions); - verifyZeroInteractions(mMockActionHandler); - } - - @Test - public void testViewActions_activeActionsPreventsTriggering_partiallyVisible() { - setupPartialViewScenario(); - mActiveActions.add(VIEW_ACTION); - mActiveActions.add(HIDE_ACTION); - - ViewUtils.maybeTriggerViewActions(mView, mViewport, VIEW_AND_HIDE_ACTIONS, - mMockActionHandler, DEFAULT_FRAME, mActiveActions); - verifyZeroInteractions(mMockActionHandler); - } - - @Test - public void testViewActions_activeActionsPreventsTriggering_fullyVisible() { - setupFullViewScenario(); - mActiveActions.add(VIEW_ACTION); - mActiveActions.add(HIDE_ACTION); - - ViewUtils.maybeTriggerViewActions(mView, mViewport, VIEW_AND_HIDE_ACTIONS, - mMockActionHandler, DEFAULT_FRAME, mActiveActions); - verifyZeroInteractions(mMockActionHandler); - } - - @Test - public void testViewActions_notAttachedUnsetsActiveActions() { - setupFullViewScenario(); - mViewShadow.setAttachedToWindow(false); - mActiveActions.add(VIEW_ACTION); - - ViewUtils.maybeTriggerViewActions(mView, mViewport, VIEW_AND_HIDE_ACTIONS, - mMockActionHandler, DEFAULT_FRAME, mActiveActions); - assertThat(mActiveActions).containsExactly(HIDE_ACTION); - } - - @Test - public void testViewActions_notVisibleUnsetsActiveActions() { - setupFullViewScenario(); - mView.setVisibility(View.INVISIBLE); - mActiveActions.add(VIEW_ACTION); - - ViewUtils.maybeTriggerViewActions(mView, mViewport, VIEW_AND_HIDE_ACTIONS, - mMockActionHandler, DEFAULT_FRAME, mActiveActions); - assertThat(mActiveActions).containsExactly(HIDE_ACTION); - } - - @Test - public void testHideActions() { - ViewUtils.triggerHideActions( - mView, VIEW_AND_HIDE_ACTIONS, mMockActionHandler, DEFAULT_FRAME, mActiveActions); - assertThat(mActiveActions).containsExactly(HIDE_ACTION); - verify(mMockActionHandler) - .handleAction(HIDE_ACTION.getAction(), ActionType.VIEW, DEFAULT_FRAME, mView, - LogData.getDefaultInstance()); - } - - @Test - public void testHideActions_deduplicates() { - ViewUtils.triggerHideActions( - mView, VIEW_AND_HIDE_ACTIONS, mMockActionHandler, DEFAULT_FRAME, mActiveActions); - verify(mMockActionHandler) - .handleAction(HIDE_ACTION.getAction(), ActionType.VIEW, DEFAULT_FRAME, mView, - LogData.getDefaultInstance()); - - assertThat(mActiveActions).containsExactly(HIDE_ACTION); - - // Hide action is not triggered again. - ViewUtils.triggerHideActions( - mView, VIEW_AND_HIDE_ACTIONS, mMockActionHandler, DEFAULT_FRAME, mActiveActions); - verify(mMockActionHandler, times(1)) - .handleAction(HIDE_ACTION.getAction(), ActionType.VIEW, DEFAULT_FRAME, mView, - LogData.getDefaultInstance()); - } - - @Test - public void testApplyOverlayColor_setsColorFilter() { - int overlayColor1 = 0xFFEEDDCC; - int overlayColor2 = 0xCCDDEEFF; - Drawable original = - new BitmapDrawable(Bitmap.createBitmap(12, 34, Bitmap.Config.ARGB_8888)); - - Drawable result1 = ViewUtils.applyOverlayColor(original, overlayColor1); - Drawable result2 = ViewUtils.applyOverlayColor(original, overlayColor2); - - assertThat(result1).isNotSameInstanceAs(original); - assertThat(result1.getColorFilter()) - .isEqualTo(new PorterDuffColorFilter(overlayColor1, Mode.SRC_IN)); - - assertThat(result2).isNotSameInstanceAs(original); - assertThat(result2.getColorFilter()) - .isEqualTo(new PorterDuffColorFilter(overlayColor2, Mode.SRC_IN)); - } - - @Test - public void testApplyOverlayColor_nullIsNoOp() { - Drawable original = - new BitmapDrawable(Bitmap.createBitmap(12, 34, Bitmap.Config.ARGB_8888)); - - Drawable result1 = ViewUtils.applyOverlayColor(original, null); - - assertThat(result1).isSameInstanceAs(original); - assertThat(result1.getColorFilter()).isNull(); - } - - /** Sets up view and viewport so that view should be fully visible. */ - private void setupFullViewScenario() { - mView.setVisibility(View.VISIBLE); - mViewShadow.setAttachedToWindow(true); - mViewShadow.setLocationOnScreen(10, 10); - mViewShadow.setWidth(10); - mViewShadow.setHeight(10); - - mViewport.setVisibility(View.VISIBLE); - mViewportShadow.setAttachedToWindow(true); - mViewportShadow.setLocationOnScreen(0, 0); - mViewportShadow.setWidth(100); - mViewportShadow.setHeight(100); - - mActiveActions.clear(); - } - - private void setupPartialViewScenario() { - setupFullViewScenario(); - mViewShadow.setHeight(1000); - } - - private void assertViewNotClickable() { - assertThat(mView.hasOnClickListeners()).isFalse(); - assertThat(mView.isClickable()).isFalse(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/host/AssetProviderTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/host/AssetProviderTest.java deleted file mode 100644 index d120bfc0..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/host/AssetProviderTest.java +++ /dev/null
@@ -1,95 +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. - -package org.chromium.chrome.browser.feed.library.piet.host; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.MockitoAnnotations.initMocks; - -import android.app.Activity; -import android.content.Context; -import android.graphics.Color; -import android.graphics.drawable.ColorDrawable; -import android.widget.ImageView; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.common.functional.Suppliers; -import org.chromium.components.feed.core.proto.ui.piet.ImagesProto.Image; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link AssetProvider}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class AssetProviderTest { - @Mock - ImageLoader mImageLoader; - @Mock - StringFormatter mStringFormatter; - @Mock - TypefaceProvider mTypefaceProvider; - - private Context mContext; - - @Before - public void setUp() { - initMocks(this); - - mContext = Robolectric.buildActivity(Activity.class).get(); - } - - @Test - public void testBuilder_setsFields() { - AssetProvider assetProvider = new AssetProvider(mImageLoader, mStringFormatter, - Suppliers.of(123), Suppliers.of(456L), Suppliers.of(true), Suppliers.of(true), - mTypefaceProvider); - - assertThat(assetProvider.mImageLoader).isSameInstanceAs(mImageLoader); - assertThat(assetProvider.mStringFormatter).isSameInstanceAs(mStringFormatter); - assertThat(assetProvider.mTypefaceProvider).isSameInstanceAs(mTypefaceProvider); - assertThat(assetProvider.getDefaultCornerRadius()).isEqualTo(123); - assertThat(assetProvider.getFadeImageThresholdMs()).isEqualTo(456); - assertThat(assetProvider.isDarkTheme()).isTrue(); - assertThat(assetProvider.isRtL()).isTrue(); - } - - @Test - public void testNullImageLoader() { - ImageLoader imageLoader = new NullImageLoader(); - ImageView imageView = new ImageView(mContext); - imageView.setImageDrawable(new ColorDrawable(Color.RED)); - - imageLoader.getImage( - Image.getDefaultInstance(), 1, 2, drawable -> imageView.setImageDrawable(drawable)); - - assertThat(imageView.getDrawable()).isNull(); - } - - @Test - public void testNullTypefaceProvider() { - TypefaceProvider typefaceProvider = new NullTypefaceProvider(); - final Object[] consumedObject = {""}; - - // Make sure the object isn't already null, or we'll get a false positive. - assertThat(consumedObject[0]).isNotNull(); - // The consumer passed in just saves the value that is consumed, so we can check that it's - // null. - typefaceProvider.getTypeface( - "GOOGLE_SANS_MEDIUM", false, typeface -> consumedObject[0] = typeface); - assertThat(consumedObject[0]).isNull(); - } - - @Test - public void testEmptyStringFormatter() { - StringFormatter stringFormatter = new EmptyStringFormatter(); - - assertThat(stringFormatter.getRelativeElapsedString(123456)).isEmpty(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ui/AspectRatioScalingImageViewTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ui/AspectRatioScalingImageViewTest.java deleted file mode 100644 index 45e061f..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ui/AspectRatioScalingImageViewTest.java +++ /dev/null
@@ -1,230 +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. - -package org.chromium.chrome.browser.feed.library.piet.ui; - -import static com.google.common.truth.Truth.assertThat; - -import android.app.Activity; -import android.graphics.Bitmap; -import android.graphics.Color; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.ColorDrawable; -import android.graphics.drawable.Drawable; -import android.view.View.MeasureSpec; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link AspectRatioScalingImageView}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class AspectRatioScalingImageViewTest { - private static final int DRAWABLE_WIDTH = 80; - private static final int DRAWABLE_HEIGHT = 40; - private static final int DRAWABLE_ASPECT_RATIO = 2; - - private static final int CONTAINER_WIDTH = 90; - private static final int CONTAINER_HEIGHT = 30; - - private AspectRatioScalingImageView mView; - private Drawable mDrawable; - - @Before - public void setUp() { - mView = new AspectRatioScalingImageView(Robolectric.buildActivity(Activity.class).get()); - mDrawable = new BitmapDrawable( - Bitmap.createBitmap(DRAWABLE_WIDTH, DRAWABLE_HEIGHT, Bitmap.Config.RGB_565)); - } - - @Test - public void testScaling_noDrawable_exactly() { - int heightSpec = MeasureSpec.makeMeasureSpec(CONTAINER_HEIGHT, MeasureSpec.EXACTLY); - int widthSpec = MeasureSpec.makeMeasureSpec(CONTAINER_WIDTH, MeasureSpec.EXACTLY); - - mView.measure(widthSpec, heightSpec); - - assertThat(mView.getMeasuredHeight()).isEqualTo(CONTAINER_HEIGHT); - assertThat(mView.getMeasuredWidth()).isEqualTo(CONTAINER_WIDTH); - } - - @Test - public void testScaling_noDrawable_unspecified() { - int heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); - int widthSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); - - mView.measure(widthSpec, heightSpec); - - assertThat(mView.getMeasuredHeight()).isEqualTo(0); - assertThat(mView.getMeasuredWidth()).isEqualTo(0); - } - - @Test - public void testScaling_noDrawable_defaultAspectRatio() { - int heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); - int widthSpec = MeasureSpec.makeMeasureSpec(CONTAINER_WIDTH, MeasureSpec.EXACTLY); - float aspectRatio = 2.0f; - - mView.setDefaultAspectRatio(aspectRatio); - - mView.measure(widthSpec, heightSpec); - - assertThat(mView.getMeasuredHeight()).isEqualTo((int) (CONTAINER_WIDTH / aspectRatio)); - assertThat(mView.getMeasuredWidth()).isEqualTo(CONTAINER_WIDTH); - } - - @Test - public void testScaling_drawableBadDims_defaultAspectRatio() { - int heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); - int widthSpec = MeasureSpec.makeMeasureSpec(CONTAINER_WIDTH, MeasureSpec.EXACTLY); - float aspectRatio = 2.0f; - - mDrawable = new ColorDrawable(Color.RED); - - mView.setDefaultAspectRatio(aspectRatio); - mView.setImageDrawable(mDrawable); - - mView.measure(widthSpec, heightSpec); - - assertThat(mView.getMeasuredHeight()).isEqualTo((int) (CONTAINER_WIDTH / aspectRatio)); - assertThat(mView.getMeasuredWidth()).isEqualTo(CONTAINER_WIDTH); - } - - @Test - public void testScaling_bothExactly() { - mView.setImageDrawable(mDrawable); - - int heightSpec = MeasureSpec.makeMeasureSpec(CONTAINER_HEIGHT, MeasureSpec.EXACTLY); - int widthSpec = MeasureSpec.makeMeasureSpec(CONTAINER_WIDTH, MeasureSpec.EXACTLY); - - mView.measure(widthSpec, heightSpec); - - assertThat(mView.getMeasuredHeight()).isEqualTo(CONTAINER_HEIGHT); - assertThat(mView.getMeasuredWidth()).isEqualTo(CONTAINER_WIDTH); - } - - @Test - public void testScaling_exactlyWidth_unspecifiedHeight() { - mView.setImageDrawable(mDrawable); - - int heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); - int widthSpec = MeasureSpec.makeMeasureSpec(CONTAINER_WIDTH, MeasureSpec.EXACTLY); - - mView.measure(widthSpec, heightSpec); - - assertThat(mView.getMeasuredHeight()).isEqualTo(CONTAINER_WIDTH / DRAWABLE_ASPECT_RATIO); - assertThat(mView.getMeasuredWidth()).isEqualTo(CONTAINER_WIDTH); - } - - @Test - public void testScaling_exactlyHeight_unspecifiedWidth() { - mView.setImageDrawable(mDrawable); - - int heightSpec = MeasureSpec.makeMeasureSpec(CONTAINER_HEIGHT, MeasureSpec.EXACTLY); - int widthSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); - - mView.measure(widthSpec, heightSpec); - - assertThat(mView.getMeasuredHeight()).isEqualTo(CONTAINER_HEIGHT); - assertThat(mView.getMeasuredWidth()).isEqualTo(CONTAINER_HEIGHT * DRAWABLE_ASPECT_RATIO); - } - - @Test - public void testScaling_exactlyWidth_atMostHeight() { - mView.setImageDrawable(mDrawable); - - int heightSpec = MeasureSpec.makeMeasureSpec(CONTAINER_HEIGHT, MeasureSpec.AT_MOST); - int widthSpec = MeasureSpec.makeMeasureSpec(CONTAINER_WIDTH, MeasureSpec.EXACTLY); - - mView.measure(widthSpec, heightSpec); - - assertThat(mView.getMeasuredHeight()).isEqualTo(CONTAINER_HEIGHT); - assertThat(mView.getMeasuredWidth()).isEqualTo(CONTAINER_WIDTH); - } - - @Test - public void testScaling_exactlyHeight_atMostWidth() { - mView.setImageDrawable(mDrawable); - - int heightSpec = MeasureSpec.makeMeasureSpec(CONTAINER_HEIGHT, MeasureSpec.EXACTLY); - int widthSpec = MeasureSpec.makeMeasureSpec(CONTAINER_WIDTH, MeasureSpec.AT_MOST); - - mView.measure(widthSpec, heightSpec); - - assertThat(mView.getMeasuredHeight()).isEqualTo(CONTAINER_HEIGHT); - assertThat(mView.getMeasuredWidth()).isEqualTo(CONTAINER_HEIGHT * DRAWABLE_ASPECT_RATIO); - } - - @Test - public void testScaling_atMostHeightAndWidth_widerContainer() { - mDrawable = new BitmapDrawable(Bitmap.createBitmap(50, 100, Bitmap.Config.RGB_565)); - mView.setImageDrawable(mDrawable); - - int heightSpec = MeasureSpec.makeMeasureSpec(200, MeasureSpec.AT_MOST); - int widthSpec = MeasureSpec.makeMeasureSpec(400, MeasureSpec.AT_MOST); - - mView.measure(widthSpec, heightSpec); - - assertThat(mView.getMeasuredHeight()).isEqualTo(200); - assertThat(mView.getMeasuredWidth()).isEqualTo(100); - } - - @Test - public void testScaling_atMostHeightAndWidth_tallerContainer() { - mDrawable = new BitmapDrawable(Bitmap.createBitmap(100, 50, Bitmap.Config.RGB_565)); - mView.setImageDrawable(mDrawable); - - int heightSpec = MeasureSpec.makeMeasureSpec(400, MeasureSpec.AT_MOST); - int widthSpec = MeasureSpec.makeMeasureSpec(200, MeasureSpec.AT_MOST); - - mView.measure(widthSpec, heightSpec); - - assertThat(mView.getMeasuredHeight()).isEqualTo(100); - assertThat(mView.getMeasuredWidth()).isEqualTo(200); - } - - @Test - public void testScaling_atMostWidth_unspecifiedHeight() { - mView.setImageDrawable(mDrawable); - - int heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); - int widthSpec = MeasureSpec.makeMeasureSpec(CONTAINER_WIDTH, MeasureSpec.AT_MOST); - - mView.measure(widthSpec, heightSpec); - - assertThat(mView.getMeasuredHeight()).isEqualTo(CONTAINER_WIDTH / DRAWABLE_ASPECT_RATIO); - assertThat(mView.getMeasuredWidth()).isEqualTo(CONTAINER_WIDTH); - } - - @Test - public void testScaling_atMostHeight_unspecifiedWidth() { - mView.setImageDrawable(mDrawable); - - int heightSpec = MeasureSpec.makeMeasureSpec(CONTAINER_HEIGHT, MeasureSpec.AT_MOST); - int widthSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); - - mView.measure(widthSpec, heightSpec); - - assertThat(mView.getMeasuredHeight()).isEqualTo(CONTAINER_HEIGHT); - assertThat(mView.getMeasuredWidth()).isEqualTo(CONTAINER_HEIGHT * DRAWABLE_ASPECT_RATIO); - } - - @Test - public void testScaling_bothUnspecified() { - mView.setImageDrawable(mDrawable); - - int heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); - int widthSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); - - mView.measure(widthSpec, heightSpec); - - assertThat(mView.getMeasuredHeight()).isEqualTo(0xFFFFFF); - assertThat(mView.getMeasuredWidth()).isEqualTo(0xFFFFFF); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ui/BitmapMaskingRoundedCornerDelegateTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ui/BitmapMaskingRoundedCornerDelegateTest.java deleted file mode 100644 index 28a3099..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ui/BitmapMaskingRoundedCornerDelegateTest.java +++ /dev/null
@@ -1,152 +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. - -package org.chromium.chrome.browser.feed.library.piet.ui; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyFloat; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import android.app.Activity; -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Paint; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.base.supplier.Supplier; -import org.chromium.chrome.browser.feed.library.common.functional.Suppliers; -import org.chromium.chrome.browser.feed.library.piet.ui.RoundedCornerMaskCache.Corner; -import org.chromium.chrome.browser.feed.library.piet.ui.RoundedCornerMaskCache.RoundedCornerBitmaps; -import org.chromium.components.feed.core.proto.ui.piet.RoundedCornersProto.RoundedCorners; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.Borders; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for the {@link BitmapMaskingRoundedCornerDelegate}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class BitmapMaskingRoundedCornerDelegateTest { - @Mock - private Canvas mMockCanvas; - @Mock - private RoundedCornerMaskCache mCache; - - private static final Supplier<Boolean> IS_RTL_SUPPLIER = Suppliers.of(false); - private RoundedCornerWrapperView mRoundedCornerWrapperView; - private Context mContext; - private static final int RADIUS = 10; - - private Bitmap mTopLeft; - private Bitmap mTopRight; - private Bitmap mBottomLeft; - private Bitmap mBottomRight; - private RoundedCornerBitmaps mBitmaps; - - @Before - public void setUp() { - initMocks(this); - mContext = Robolectric.buildActivity(Activity.class).get(); - mRoundedCornerWrapperView = - new RoundedCornerWrapperView(mContext, RoundedCorners.getDefaultInstance(), mCache, - IS_RTL_SUPPLIER, 0, Borders.getDefaultInstance(), true, true); - - RoundedCornerMaskCache realCache = new RoundedCornerMaskCache(); - mBitmaps = realCache.getMasks(16); - mTopLeft = realCache.getMasks(16).get(Corner.TOP_LEFT); - mTopRight = realCache.getMasks(16).get(Corner.TOP_RIGHT); - mBottomLeft = realCache.getMasks(16).get(Corner.BOTTOM_LEFT); - mBottomRight = realCache.getMasks(16).get(Corner.BOTTOM_RIGHT); - - when(mCache.getMasks(anyInt())).thenReturn(mBitmaps); - when(mCache.getMaskPaint()).thenReturn(new Paint()); - } - - @Test - public void maskCorners_radiusZero() { - BitmapMaskingRoundedCornerDelegate bitmapMaskingDelegate = - new BitmapMaskingRoundedCornerDelegate( - mCache, /* bitmask= */ 15, /* isRtL= */ false, mMockCanvas); - - mRoundedCornerWrapperView.layout(0, 0, 100, 100); - - bitmapMaskingDelegate.onLayout(/* radius= */ 0, /* isRtL= */ false, 100, 100); - bitmapMaskingDelegate.draw(mRoundedCornerWrapperView, new Canvas()); - - verify(mMockCanvas, never()) - .drawBitmap(any(Bitmap.class), anyFloat(), anyFloat(), any(Paint.class)); - } - - @Test - public void maskAndDrawCorners_allCorners() { - int all_corner_bitmask = 15; - boolean isRtL = false; - BitmapMaskingRoundedCornerDelegate bitmapMaskingDelegate = - new BitmapMaskingRoundedCornerDelegate( - mCache, all_corner_bitmask, isRtL, mMockCanvas); - - mRoundedCornerWrapperView.layout(0, 0, 100, 100); - - bitmapMaskingDelegate.onLayout(RADIUS, isRtL, 100, 100); - bitmapMaskingDelegate.draw(mRoundedCornerWrapperView, new Canvas()); - - verify(mMockCanvas).drawBitmap(eq(mTopLeft), anyFloat(), anyFloat(), any(Paint.class)); - verify(mMockCanvas).drawBitmap(eq(mTopRight), anyFloat(), anyFloat(), any(Paint.class)); - verify(mMockCanvas).drawBitmap(eq(mBottomRight), anyFloat(), anyFloat(), any(Paint.class)); - verify(mMockCanvas).drawBitmap(eq(mBottomLeft), anyFloat(), anyFloat(), any(Paint.class)); - } - - @Test - public void maskCorners_topStart_bottomEnd() { - int topStart_bottomEnd_bitmask = 5; - boolean isRtL = false; - - BitmapMaskingRoundedCornerDelegate bitmapMaskingDelegate = - new BitmapMaskingRoundedCornerDelegate( - mCache, topStart_bottomEnd_bitmask, isRtL, mMockCanvas); - - mRoundedCornerWrapperView.layout(0, 0, 100, 100); - - bitmapMaskingDelegate.onLayout(RADIUS, isRtL, 100, 100); - bitmapMaskingDelegate.draw(mRoundedCornerWrapperView, new Canvas()); - - verify(mMockCanvas).drawBitmap(eq(mTopLeft), anyFloat(), anyFloat(), any(Paint.class)); - verify(mMockCanvas, never()) - .drawBitmap(eq(mTopRight), anyFloat(), anyFloat(), any(Paint.class)); - verify(mMockCanvas).drawBitmap(eq(mBottomRight), anyFloat(), anyFloat(), any(Paint.class)); - verify(mMockCanvas, never()) - .drawBitmap(eq(mBottomLeft), anyFloat(), anyFloat(), any(Paint.class)); - } - - @Test - public void maskCorners_topStart_bottomEnd_rtl() { - int topStart_bottomEnd_bitmask = 5; - boolean isRtL = true; - BitmapMaskingRoundedCornerDelegate bitmapMaskingDelegate = - new BitmapMaskingRoundedCornerDelegate( - mCache, topStart_bottomEnd_bitmask, isRtL, mMockCanvas); - - mRoundedCornerWrapperView.layout(0, 0, 100, 100); - - bitmapMaskingDelegate.onLayout(RADIUS, isRtL, 100, 100); - bitmapMaskingDelegate.draw(mRoundedCornerWrapperView, new Canvas()); - - verify(mMockCanvas, never()) - .drawBitmap(eq(mTopLeft), anyFloat(), anyFloat(), any(Paint.class)); - verify(mMockCanvas).drawBitmap(eq(mTopRight), anyFloat(), anyFloat(), any(Paint.class)); - verify(mMockCanvas, never()) - .drawBitmap(eq(mBottomRight), anyFloat(), anyFloat(), any(Paint.class)); - verify(mMockCanvas).drawBitmap(eq(mBottomLeft), anyFloat(), anyFloat(), any(Paint.class)); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ui/BorderDrawableTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ui/BorderDrawableTest.java deleted file mode 100644 index f411c8c..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ui/BorderDrawableTest.java +++ /dev/null
@@ -1,149 +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. - -package org.chromium.chrome.browser.feed.library.piet.ui; - -import static com.google.common.truth.Truth.assertThat; - -import android.app.Activity; -import android.content.Context; -import android.graphics.Paint; -import android.graphics.Rect; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.common.ui.LayoutUtils; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.Borders; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.Borders.Edges; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for the {@link BorderDrawable}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class BorderDrawableTest { - private static final float[] ZERO_RADII = new float[] {0, 0, 0, 0, 0, 0, 0, 0}; - private static final boolean LEFT_TO_RIGHT = false; - private static final boolean RIGHT_TO_LEFT = true; - - private static final int COLOR = 0xFFFF0000; - private static final int WIDTH_DP = 8; - private int mWidthPx; - - private static final Borders DEFAULT_BORDER = - Borders.newBuilder().setWidth(WIDTH_DP).setColor(COLOR).build(); - - private Context mContext; - - @Before - public void setUp() { - mContext = Robolectric.buildActivity(Activity.class).get(); - mWidthPx = (int) LayoutUtils.dpToPx(WIDTH_DP, mContext); - } - - @Test - public void testBorders_setsPaintParams() { - BorderDrawable borderDrawable = - new BorderDrawable(mContext, DEFAULT_BORDER, ZERO_RADII, LEFT_TO_RIGHT); - - assertThat(borderDrawable.getPaint().getStyle()).isEqualTo(Paint.Style.STROKE); - assertThat(borderDrawable.getPaint().getStrokeWidth()).isEqualTo((float) mWidthPx * 2); - assertThat(borderDrawable.getPaint().getColor()).isEqualTo(COLOR); - } - - @Test - public void testBorders_allSides_default() { - BorderDrawable borderDrawable = - new BorderDrawable(mContext, DEFAULT_BORDER, ZERO_RADII, LEFT_TO_RIGHT); - - assertThat(borderDrawable.getPaint().getStyle()).isEqualTo(Paint.Style.STROKE); - assertThat(borderDrawable.getPaint().getStrokeWidth()).isEqualTo((float) mWidthPx * 2); - assertThat(borderDrawable.getPaint().getColor()).isEqualTo(COLOR); - - borderDrawable.setBounds(1, 2, 3, 4); - Rect bounds = borderDrawable.getBounds(); - assertThat(bounds).isEqualTo(new Rect(1, 2, 3, 4)); - } - - @Test - public void testBorders_allSides_explicit() { - BorderDrawable borderDrawable = new BorderDrawable(mContext, - DEFAULT_BORDER.toBuilder() - .setBitmask(Edges.BOTTOM.getNumber() | Edges.TOP.getNumber() - | Edges.START.getNumber() | Edges.END.getNumber()) - .build(), - ZERO_RADII, LEFT_TO_RIGHT); - - borderDrawable.setBounds(1, 2, 3, 4); - Rect bounds = borderDrawable.getBounds(); - assertThat(bounds).isEqualTo(new Rect(1, 2, 3, 4)); - } - - @Test - public void testBorders_topLeft() { - BorderDrawable borderDrawable = new BorderDrawable(mContext, - DEFAULT_BORDER.toBuilder() - .setBitmask(Edges.TOP.getNumber() | Edges.START.getNumber()) - .build(), - ZERO_RADII, LEFT_TO_RIGHT); - - borderDrawable.setBounds(1, 2, 3, 4); - Rect bounds = borderDrawable.getBounds(); - assertThat(bounds).isEqualTo(new Rect(1, 2, 3 + mWidthPx, 4 + mWidthPx)); - } - - @Test - public void testBorders_bottomRight() { - BorderDrawable borderDrawable = new BorderDrawable(mContext, - DEFAULT_BORDER.toBuilder() - .setBitmask(Edges.BOTTOM.getNumber() | Edges.END.getNumber()) - .build(), - ZERO_RADII, LEFT_TO_RIGHT); - - borderDrawable.setBounds(1, 2, 3, 4); - Rect bounds = borderDrawable.getBounds(); - assertThat(bounds).isEqualTo(new Rect(1 - mWidthPx, 2 - mWidthPx, 3, 4)); - } - - @Test - public void testBorders_someSides_RtL() { - BorderDrawable borderDrawable = new BorderDrawable(mContext, - DEFAULT_BORDER.toBuilder() - .setBitmask(Edges.TOP.getNumber() | Edges.BOTTOM.getNumber() - | Edges.END.getNumber()) - .build(), - ZERO_RADII, RIGHT_TO_LEFT); - - borderDrawable.setBounds(1, 2, 3, 4); - Rect bounds = borderDrawable.getBounds(); - assertThat(bounds).isEqualTo(new Rect(1, 2, 3 + mWidthPx, 4)); - - borderDrawable = new BorderDrawable(mContext, - DEFAULT_BORDER.toBuilder() - .setBitmask(Edges.TOP.getNumber() | Edges.BOTTOM.getNumber() - | Edges.START.getNumber()) - .build(), - ZERO_RADII, RIGHT_TO_LEFT); - - borderDrawable.setBounds(1, 2, 3, 4); - bounds = borderDrawable.getBounds(); - assertThat(bounds).isEqualTo(new Rect(1 - mWidthPx, 2, 3, 4)); - } - - @Test - public void testSetBoundsRect() { - BorderDrawable borderDrawable = new BorderDrawable(mContext, - DEFAULT_BORDER.toBuilder() - .setBitmask(Edges.TOP.getNumber() | Edges.END.getNumber()) - .build(), - ZERO_RADII, LEFT_TO_RIGHT); - - borderDrawable.setBounds(new Rect(1, 2, 3, 4)); - Rect bounds = borderDrawable.getBounds(); - assertThat(bounds).isEqualTo(new Rect(1 - mWidthPx, 2, 3, 4 + mWidthPx)); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ui/GradientDrawableTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ui/GradientDrawableTest.java deleted file mode 100644 index ba5df788..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ui/GradientDrawableTest.java +++ /dev/null
@@ -1,82 +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. - -package org.chromium.chrome.browser.feed.library.piet.ui; - -import static com.google.common.truth.Truth.assertThat; - -import android.graphics.Color; -import android.graphics.drawable.shapes.RectShape; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.common.functional.Suppliers; -import org.chromium.components.feed.core.proto.ui.piet.GradientsProto.ColorStop; -import org.chromium.components.feed.core.proto.ui.piet.GradientsProto.LinearGradient; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for the {@link GradientDrawable}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class GradientDrawableTest { - @Test - public void testCreatesShader() { - GradientDrawable drawable = new GradientDrawable( - LinearGradient.newBuilder() - .setDirectionDeg(123) - .addStops(ColorStop.newBuilder().setPositionPercent(0).setColor(Color.BLUE)) - .addStops( - ColorStop.newBuilder().setPositionPercent(100).setColor(Color.RED)) - .build(), - Suppliers.of(true)); - assertThat(drawable.getShape()).isInstanceOf(RectShape.class); - assertThat(drawable.getShaderFactory()).isInstanceOf(GradientShader.class); - } - - @Test - public void testCreatesShader_noRtlSupport() { - GradientDrawable drawable = new GradientDrawable( - LinearGradient.newBuilder() - .setDirectionDeg(123) - .addStops(ColorStop.newBuilder().setPositionPercent(0).setColor(Color.BLUE)) - .addStops( - ColorStop.newBuilder().setPositionPercent(100).setColor(Color.RED)) - .build(), - Suppliers.of(true)); - - assertThat(((GradientShader) drawable.getShaderFactory()).mRtLSupplier).isNull(); - } - - @Test - public void testCreatesShader_rtl() { - GradientDrawable drawable = new GradientDrawable( - LinearGradient.newBuilder() - .setDirectionDeg(123) - .addStops(ColorStop.newBuilder().setPositionPercent(0).setColor(Color.BLUE)) - .addStops( - ColorStop.newBuilder().setPositionPercent(100).setColor(Color.RED)) - .setReverseForRtl(true) - .build(), - Suppliers.of(true)); - - assertThat(((GradientShader) drawable.getShaderFactory()).mRtLSupplier.get()).isTrue(); - } - - @Test - public void testCreatesShader_ltr() { - GradientDrawable drawable = new GradientDrawable( - LinearGradient.newBuilder() - .setDirectionDeg(123) - .addStops(ColorStop.newBuilder().setPositionPercent(0).setColor(Color.BLUE)) - .addStops( - ColorStop.newBuilder().setPositionPercent(100).setColor(Color.RED)) - .setReverseForRtl(true) - .build(), - Suppliers.of(false)); - - assertThat(((GradientShader) drawable.getShaderFactory()).mRtLSupplier.get()).isFalse(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ui/GradientShaderTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ui/GradientShaderTest.java deleted file mode 100644 index 767af3ff..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ui/GradientShaderTest.java +++ /dev/null
@@ -1,151 +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. - -package org.chromium.chrome.browser.feed.library.piet.ui; - -import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth.assertWithMessage; - -import static org.chromium.chrome.browser.feed.library.common.testing.RunnableSubject.assertThatRunnable; - -import android.graphics.Color; -import android.graphics.RectF; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.common.functional.Suppliers; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** - * Tests for the {@link GradientShader}. - * - * <p>Note that on Android, the Y axis starts at the top and increases to the bottom, so some of the - * math is backward. - */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class GradientShaderTest { - private static final boolean RTL = true; - private static final boolean LTR = false; - - @Test - public void testGradientLine_leftToRight() { - RectF points = GradientShader.calculateGradientLine(12, 12, Math.toRadians(90), 0, LTR); - checkGradientLine(points, 0, 6, 12, 6); - } - - @Test - public void testGradientLine_bottomToTop() { - RectF points = GradientShader.calculateGradientLine(12, 12, 0, 0, LTR); - checkGradientLine(points, 6, 12, 6, 0); - } - - @Test - public void testGradientLine_bottomLeftToTopRight() { - RectF points = GradientShader.calculateGradientLine( - 12, 12, Math.toRadians(45), Math.toRadians(45), LTR); - checkGradientLine(points, 0, 12, 12, 0); - } - - @Test - public void testGradientLine_bottomRightToTopLeft() { - RectF points = GradientShader.calculateGradientLine( - 12, 12, Math.toRadians(315), Math.toRadians(315 % 90), LTR); - checkGradientLine(points, 12, 12, 0, 0); - } - - @Test - public void testGradientLine_thirtyDegrees() { - RectF points = GradientShader.calculateGradientLine( - 12, 12, Math.toRadians(30), Math.toRadians(30), LTR); - checkGradientLine(points, 1.9019f, 13.0981f, 10.0981f, -1.0981f); - } - - @Test - public void testGradientLine_threeThirtyDegrees() { - RectF points = GradientShader.calculateGradientLine( - 12, 12, Math.toRadians(330), Math.toRadians(330 % 90), LTR); - checkGradientLine(points, 10.0981f, 13.0981f, 1.9019f, -1.0981f); - } - - @Test - public void testGradientLine_horizontalRtL() { - RectF points = GradientShader.calculateGradientLine(12, 12, Math.toRadians(90), 0, RTL); - checkGradientLine(points, 12, 6, 0, 6); - - // Flip the angle 180; should be the same as the RtL version - RectF pointsLtR = GradientShader.calculateGradientLine(12, 12, Math.toRadians(270), 0, LTR); - checkGradientLine(points, pointsLtR.left, pointsLtR.top, pointsLtR.right, pointsLtR.bottom); - } - - @Test - public void testGradientLine_verticalRtL() { - RectF points = GradientShader.calculateGradientLine(12, 12, 0, 0, LTR); - checkGradientLine(points, 6, 12, 6, 0); - - // RtL should not change the points for a vertical line - RectF pointsLtR = GradientShader.calculateGradientLine(12, 12, 0, 0, LTR); - checkGradientLine(points, pointsLtR.left, pointsLtR.top, pointsLtR.right, pointsLtR.bottom); - } - - @Test - public void testGradientLine_angleRtL() { - RectF points = GradientShader.calculateGradientLine( - 12, 12, Math.toRadians(45), Math.toRadians(45), RTL); - checkGradientLine(points, 12, 12, 0, 0); - - RectF pointsLtR = GradientShader.calculateGradientLine( - 12, 12, Math.toRadians(360 - 45), Math.toRadians(45), LTR); - checkGradientLine(points, pointsLtR.left, pointsLtR.top, pointsLtR.right, pointsLtR.bottom); - } - - @Test - public void testGradientLine_invalidDegrees() { - GradientShader shader = new GradientShader( - new int[] {Color.BLUE, Color.RED}, new float[] {0, 1}, 999, Suppliers.of(LTR)); - assertThat(shader.mAngleRadians).isEqualTo(Math.toRadians(999 % 360)); - assertThat(shader.mAngleRadiansSmall).isEqualTo(Math.toRadians(999 % 90)); - } - - @Test - public void testGradientLine_invalidStops() { - GradientShader shader = new GradientShader( - new int[] {Color.BLUE, Color.RED}, new float[] {999, -1}, 45, Suppliers.of(LTR)); - shader.resize(123, 456); - - // assert no failures - } - - @Test - public void testGradientLine_lengthMismatch() { - assertThatRunnable(() - -> new GradientShader(new int[] {Color.BLUE, Color.RED}, - new float[] {1}, 45, Suppliers.of(LTR))) - .throwsAnExceptionOfType(IllegalStateException.class) - .that() - .hasMessageThat() - .contains("Mismatch: got 2 colors and 1 stops"); - } - - @Test - public void testGradientLine_nullLtRSupplier() { - GradientShader shader = - new GradientShader(new int[] {Color.BLUE, Color.RED}, new float[] {0, 1}, 45, null); - shader.resize(123, 456); - - // assert no failures - } - - private void checkGradientLine( - RectF result, float startx, float starty, float endx, float endy) { - String testFailOutput = String.format( - "expected: %s\nbut was : %s", new RectF(startx, starty, endx, endy), result); - assertWithMessage(testFailOutput).that(result.left).isWithin(0.01f).of(startx); - assertWithMessage(testFailOutput).that(result.top).isWithin(0.01f).of(starty); - assertWithMessage(testFailOutput).that(result.right).isWithin(0.01f).of(endx); - assertWithMessage(testFailOutput).that(result.bottom).isWithin(0.01f).of(endy); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ui/GridRowViewTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ui/GridRowViewTest.java deleted file mode 100644 index ea63e1d..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ui/GridRowViewTest.java +++ /dev/null
@@ -1,1011 +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. - -package org.chromium.chrome.browser.feed.library.piet.ui; - -import static com.google.common.truth.Truth.assertThat; - -import static org.chromium.chrome.browser.feed.library.common.testing.RunnableSubject.assertThatRunnable; - -import android.app.Activity; -import android.content.Context; -import android.view.View; -import android.view.View.MeasureSpec; -import android.view.ViewGroup; -import android.widget.LinearLayout; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.common.functional.Suppliers; -import org.chromium.chrome.browser.feed.library.piet.ui.GridRowView.LayoutParams; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for the {@link GridRowView}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class GridRowViewTest { - private static final int WIDTH = 100; - private static final int WRAP_CONTENT_WIDTH = 75; - private static final int COLLAPSIBLE_WIDTH = 80; - private static final int HEIGHT = 1234; - private static final int LARGE_HEIGHT = 10000; - - private int mUnspecifiedSpec; - - private Context mContext; - - private TestView mCollapsibleView; - private TestView mCollapsibleView2; - private TestView mWrapContentView; - private TestView mWidthView; - private TestView mWeightView; - private TestView mWeightView2; - private TestView mGoneView; - - private GridRowView mGridRowView; - - @Before - public void setUp() { - mContext = Robolectric.buildActivity(Activity.class).get(); - - mUnspecifiedSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); - - mGridRowView = new GridRowView(mContext, Suppliers.of(false)); - - mCollapsibleView = new TestView(mContext, COLLAPSIBLE_WIDTH, HEIGHT); - mCollapsibleView.setLayoutParams( - new LayoutParams(LayoutParams.WRAP_CONTENT, HEIGHT, 0.0f, true)); - - mCollapsibleView2 = new TestView(mContext, COLLAPSIBLE_WIDTH, HEIGHT); - mCollapsibleView2.setLayoutParams( - new LayoutParams(LayoutParams.WRAP_CONTENT, HEIGHT, 0.0f, true)); - - mWrapContentView = new TestView(mContext, WRAP_CONTENT_WIDTH, HEIGHT); - mWrapContentView.setLayoutParams( - new LayoutParams(LayoutParams.WRAP_CONTENT, HEIGHT, 0.0f, false)); - // Not sure how to get the wrap content width - - mWidthView = new TestView(mContext, WIDTH, HEIGHT); - mWidthView.setLayoutParams(new LayoutParams(WIDTH, HEIGHT, 0.0f, false)); - - mWeightView = new TestView(mContext, 0, HEIGHT); - mWeightView.setLayoutParams(new LayoutParams(0, HEIGHT, 1.0f, false)); - - mWeightView2 = new TestView(mContext, 0, HEIGHT); - mWeightView2.setLayoutParams(new LayoutParams(0, HEIGHT, 1.0f, false)); - - mGoneView = new TestView(mContext, WIDTH, LARGE_HEIGHT); - mGoneView.setMinimumHeight(LARGE_HEIGHT); - mGoneView.setMinimumWidth(WIDTH); - mGoneView.setVisibility(View.GONE); - } - - @Test - public void testOnlyHorizontal() { - assertThat(mGridRowView.getOrientation()).isEqualTo(LinearLayout.HORIZONTAL); - assertThatRunnable(() -> mGridRowView.setOrientation(LinearLayout.VERTICAL)) - .throwsAnExceptionOfType(IllegalArgumentException.class) - .that() - .hasMessageThat() - .contains("GridRowView can only be horizontal"); - } - - @Test - public void testCollapsibleIgnoresWeight() { - LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, HEIGHT, 0.0f, true); - assertThat(params.getIsCollapsible()).isTrue(); - - params = new LayoutParams(123, HEIGHT, 0.0f, true); - assertThat(params.getIsCollapsible()).isTrue(); - - params = new LayoutParams(0, HEIGHT, 1.0f, true); - assertThat(params.getIsCollapsible()).isFalse(); - } - - @Test - public void testGenerateDefaultLayoutParams() { - LayoutParams layoutParams = mGridRowView.generateDefaultLayoutParams(); - assertThat(layoutParams.width).isEqualTo(0); - assertThat(layoutParams.height).isEqualTo(LayoutParams.WRAP_CONTENT); - assertThat(layoutParams.weight).isEqualTo(1.0f); - assertThat(layoutParams.getIsCollapsible()).isFalse(); - } - - @Test - public void testGenerateLayoutParams() { - LayoutParams result; - - // not LinearLayout - ViewGroup.LayoutParams viewGroupLayoutParams = new ViewGroup.LayoutParams(12, 34); - result = mGridRowView.generateLayoutParams(viewGroupLayoutParams); - assertThat(result.width).isEqualTo(12); - assertThat(result.height).isEqualTo(34); - - // LinearLayout - LinearLayout.LayoutParams linearLayoutParams = new LinearLayout.LayoutParams(12, 34, 56); - result = mGridRowView.generateLayoutParams(linearLayoutParams); - assertThat(result.width).isEqualTo(12); - assertThat(result.height).isEqualTo(34); - assertThat(result.weight).isEqualTo(56.0f); - - // GridRowView - GridRowView.LayoutParams gridRowParams = - new LayoutParams(LayoutParams.WRAP_CONTENT, 34, 0, true); - result = mGridRowView.generateLayoutParams(gridRowParams); - assertThat(result.width).isEqualTo(LayoutParams.WRAP_CONTENT); - assertThat(result.height).isEqualTo(34); - assertThat(result.weight).isEqualTo(0.0f); - assertThat(result.getIsCollapsible()).isTrue(); - } - - @Test - public void testCheckLayoutParams() { - // not LinearLayout - ViewGroup.LayoutParams viewGroupLayoutParams = new ViewGroup.LayoutParams(12, 34); - assertThat(mGridRowView.checkLayoutParams(viewGroupLayoutParams)).isFalse(); - - // LinearLayout - LinearLayout.LayoutParams linearLayoutParams = new LinearLayout.LayoutParams(12, 34, 56); - assertThat(mGridRowView.checkLayoutParams(linearLayoutParams)).isFalse(); - - // GridRowView - GridRowView.LayoutParams gridRowParams = - new LayoutParams(LayoutParams.WRAP_CONTENT, 34, 0, true); - assertThat(mGridRowView.checkLayoutParams(gridRowParams)).isTrue(); - } - - @Test - public void testOnMeasure_noCollapsible() { - // No special processing - - mGridRowView.addView(mWidthView); - mGridRowView.addView(mWeightView); - mGridRowView.addView(mWeightView2); - // Verify views which are gone are not considered in the layout. - mGridRowView.addView(mGoneView); - - int widthSpec = MeasureSpec.makeMeasureSpec(400, MeasureSpec.EXACTLY); - mGridRowView.measure(widthSpec, mUnspecifiedSpec); - - assertThat(mWidthView.mRequestedWidth).isEqualTo(100); // WIDTH - assertThat(mWeightView.mRequestedWidth).isEqualTo(150); // (400 - WIDTH) / 2 - assertThat(mWeightView2.mRequestedWidth).isEqualTo(150); - assertThat(mGridRowView.getMeasuredWidth()).isEqualTo(400); - } - - @Test - public void testOnMeasure_unspecifiedWidth() { - // No special processing; collapsible cell is WRAP_CONTENT - - mGridRowView.addView(mWidthView); - mGridRowView.addView(mCollapsibleView); - mGridRowView.addView(mWrapContentView); - // Verify views which are gone are not considered in the layout. - mGridRowView.addView(mGoneView); - - mGridRowView.measure(mUnspecifiedSpec, mUnspecifiedSpec); - - assertThat(mWidthView.mRequestedWidth).isEqualTo(100); // WIDTH - assertThat(mCollapsibleView.mRequestedWidth).isEqualTo(COLLAPSIBLE_WIDTH); - assertThat(mWrapContentView.mRequestedWidth).isEqualTo(WRAP_CONTENT_WIDTH); - assertThat(mGridRowView.getMeasuredWidth()).isEqualTo(255); // 100 + 80 + 75 - } - - @Test - public void testOnMeasure_moreSpaceThanNecessary() { - // DP, Collapsible, WRAP_CONTENT - // Extra space is left over - - mGridRowView.addView(mWidthView); - mGridRowView.addView(mCollapsibleView); - mGridRowView.addView(mWrapContentView); - // Verify views which are gone are not considered in the layout. - mGridRowView.addView(mGoneView); - - int widthSpec = MeasureSpec.makeMeasureSpec(400, MeasureSpec.EXACTLY); - mGridRowView.measure(widthSpec, mUnspecifiedSpec); - - assertThat(mWidthView.mRequestedWidth).isEqualTo(WIDTH); - assertThat(mCollapsibleView.mRequestedWidth).isEqualTo(COLLAPSIBLE_WIDTH); - assertThat(mWrapContentView.mRequestedWidth).isEqualTo(WRAP_CONTENT_WIDTH); - assertThat(mGridRowView.getMeasuredWidth()).isEqualTo(400); - } - - @Test - public void testOnMeasure_notEnoughSpace() { - // DP, Collapsible, WRAP_CONTENT - // Collapsible cell is truncated - - mGridRowView.addView(mWidthView); - mGridRowView.addView(mCollapsibleView); - mGridRowView.addView(mWrapContentView); - // Verify views which are gone are not considered in the layout. - mGridRowView.addView(mGoneView); - - int widthSpec = MeasureSpec.makeMeasureSpec(200, MeasureSpec.EXACTLY); - mGridRowView.measure(widthSpec, mUnspecifiedSpec); - - assertThat(mWidthView.mRequestedWidth).isEqualTo(WIDTH); - assertThat(mCollapsibleView.mRequestedWidth).isEqualTo(200 - WIDTH - WRAP_CONTENT_WIDTH); - assertThat(mWrapContentView.mRequestedWidth).isEqualTo(WRAP_CONTENT_WIDTH); - assertThat(mGridRowView.getMeasuredWidth()).isEqualTo(200); - } - - @Test - public void testOnMeasure_noSpace() { - // DP, Collapsible, WRAP_CONTENT - // Collapsible cell is completely gone - - mGridRowView.addView(mWidthView); - mGridRowView.addView(mCollapsibleView); - mGridRowView.addView(mWrapContentView); - // Verify views which are gone are not considered in the layout. - mGridRowView.addView(mGoneView); - - int widthSpec = MeasureSpec.makeMeasureSpec(160, MeasureSpec.EXACTLY); - mGridRowView.measure(widthSpec, mUnspecifiedSpec); - - assertThat(mWidthView.mRequestedWidth).isEqualTo(WIDTH); - assertThat(mCollapsibleView.mRequestedWidth).isEqualTo(0); - assertThat(mWrapContentView.mRequestedWidth).isEqualTo(160 - WIDTH); - assertThat(mGridRowView.getMeasuredWidth()).isEqualTo(160); - } - - @Test - public void testOnMeasure_twoCollapsible_spaceForBoth() { - // Both cells WRAP_CONTENT and there is space left over - - mGridRowView.addView(mCollapsibleView); - mGridRowView.addView(mCollapsibleView2); - // Verify views which are gone are not considered in the layout. - mGridRowView.addView(mGoneView); - - int widthSpec = MeasureSpec.makeMeasureSpec(200, MeasureSpec.EXACTLY); - mGridRowView.measure(widthSpec, mUnspecifiedSpec); - - assertThat(mCollapsibleView.mRequestedWidth).isEqualTo(COLLAPSIBLE_WIDTH); - assertThat(mCollapsibleView2.mRequestedWidth).isEqualTo(COLLAPSIBLE_WIDTH); - assertThat(mGridRowView.getMeasuredWidth()).isEqualTo(200); - } - - @Test - public void testOnMeasure_twoCollapsible_spaceForFirst() { - // First cell should WRAP_CONTENT, second cell shrinks - - mGridRowView.addView(mCollapsibleView); - mGridRowView.addView(mCollapsibleView2); - // Verify views which are gone are not considered in the layout. - mGridRowView.addView(mGoneView); - - int widthSpec = MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY); - mGridRowView.measure(widthSpec, mUnspecifiedSpec); - - assertThat(mCollapsibleView.mRequestedWidth).isEqualTo(COLLAPSIBLE_WIDTH); - assertThat(mCollapsibleView2.mRequestedWidth).isEqualTo(100 - COLLAPSIBLE_WIDTH); - assertThat(mGridRowView.getMeasuredWidth()).isEqualTo(100); - } - - @Test - public void testOnMeasure_twoCollapsible_spaceForNeither() { - // First cell fills row, and second gets no space - - mGridRowView.addView(mCollapsibleView); - mGridRowView.addView(mCollapsibleView2); - // Verify views which are gone are not considered in the layout. - mGridRowView.addView(mGoneView); - - int widthSpec = MeasureSpec.makeMeasureSpec(50, MeasureSpec.EXACTLY); - mGridRowView.measure(widthSpec, mUnspecifiedSpec); - - assertThat(mCollapsibleView.mRequestedWidth).isEqualTo(50); - assertThat(mCollapsibleView2.mRequestedWidth).isEqualTo(0); - assertThat(mGridRowView.getMeasuredWidth()).isEqualTo(50); - } - - @Test - public void testOnMeasure_collapsibleWithWeight_enoughSpace() { - // Collapsible cell should WRAP_CONTENT, and weight fills the rest - - mGridRowView.addView(mCollapsibleView); - mGridRowView.addView(mWeightView); - mGridRowView.addView(mWeightView2); - // Verify views which are gone are not considered in the layout. - mGridRowView.addView(mGoneView); - - int widthSpec = MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY); - mGridRowView.measure(widthSpec, mUnspecifiedSpec); - - assertThat(mCollapsibleView.mRequestedWidth).isEqualTo(COLLAPSIBLE_WIDTH); - assertThat(mWeightView.mRequestedWidth).isEqualTo((100 - COLLAPSIBLE_WIDTH) / 2); - assertThat(mWeightView2.mRequestedWidth).isEqualTo((100 - COLLAPSIBLE_WIDTH) / 2); - assertThat(mGridRowView.getMeasuredWidth()).isEqualTo(100); - } - - @Test - public void testOnMeasure_collapsibleWithWeight_notEnoughSpace() { - // Collapsible cell should take up the entire row - - mGridRowView.addView(mCollapsibleView); - mGridRowView.addView(mWeightView); - // Verify views which are gone are not considered in the layout. - mGridRowView.addView(mGoneView); - - int widthSpec = MeasureSpec.makeMeasureSpec(50, MeasureSpec.EXACTLY); - mGridRowView.measure(widthSpec, mUnspecifiedSpec); - - assertThat(mCollapsibleView.mRequestedWidth).isEqualTo(50); - assertThat(mWeightView.mRequestedWidth).isEqualTo(0); - assertThat(mGridRowView.getMeasuredWidth()).isEqualTo(50); - } - - @Test - public void testOnMeasure_widthCollapsible_enoughSpace() { - // DP, Collapsible, WRAP - // Extra space is left over - - mCollapsibleView.setLayoutParams(new LayoutParams(COLLAPSIBLE_WIDTH, HEIGHT, 0.0f, true)); - - mGridRowView.addView(mWidthView); - mGridRowView.addView(mCollapsibleView); - mGridRowView.addView(mWrapContentView); - // Verify views which are gone are not considered in the layout. - mGridRowView.addView(mGoneView); - - int widthSpec = MeasureSpec.makeMeasureSpec(400, MeasureSpec.EXACTLY); - mGridRowView.measure(widthSpec, mUnspecifiedSpec); - - assertThat(mWidthView.mRequestedWidth).isEqualTo(WIDTH); - assertThat(mCollapsibleView.mRequestedWidth).isEqualTo(COLLAPSIBLE_WIDTH); - assertThat(mWrapContentView.mRequestedWidth).isEqualTo(WRAP_CONTENT_WIDTH); - assertThat(mGridRowView.getMeasuredWidth()).isEqualTo(400); - } - - @Test - public void testOnMeasure_widthCollapsible_notEnoughSpace() { - // DP, Collapsible, WRAP - // Collapsible cell is truncated - - mCollapsibleView.setLayoutParams(new LayoutParams(COLLAPSIBLE_WIDTH, HEIGHT, 0.0f, true)); - - mGridRowView.addView(mWidthView); - mGridRowView.addView(mCollapsibleView); - mGridRowView.addView(mWrapContentView); - // Verify views which are gone are not considered in the layout. - mGridRowView.addView(mGoneView); - - int widthSpec = MeasureSpec.makeMeasureSpec(200, MeasureSpec.EXACTLY); - mGridRowView.measure(widthSpec, mUnspecifiedSpec); - - assertThat(mWidthView.mRequestedWidth).isEqualTo(WIDTH); - assertThat(mCollapsibleView.mRequestedWidth).isEqualTo(200 - WIDTH - WRAP_CONTENT_WIDTH); - assertThat(mWrapContentView.mRequestedWidth).isEqualTo(WRAP_CONTENT_WIDTH); - assertThat(mGridRowView.getMeasuredWidth()).isEqualTo(200); - } - - @Test - public void testOnMeasure_cellThatGetsTallerWithWidth() { - // Make a cell where width = height and weight = 1 and ensure it behaves with a collapsible - - mCollapsibleView = new TestView(mContext, COLLAPSIBLE_WIDTH, 20); - mCollapsibleView.setLayoutParams( - new LayoutParams(LayoutParams.WRAP_CONTENT, 20, 0.0f, true)); - - SquareView squareView = new SquareView(mContext); - squareView.setLayoutParams(new LayoutParams(0, LayoutParams.WRAP_CONTENT, 1.0f, false)); - - mGridRowView.addView(mCollapsibleView); - mGridRowView.addView(squareView); - // Verify views which are gone are not considered in the layout. - mGridRowView.addView(mGoneView); - - mGridRowView.setLayoutParams( - new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); - - int widthSpec = MeasureSpec.makeMeasureSpec(130, MeasureSpec.EXACTLY); - mGridRowView.measure(widthSpec, mUnspecifiedSpec); - - int squareSize = 130 - COLLAPSIBLE_WIDTH; - assertThat(mCollapsibleView.mRequestedWidth).isEqualTo(COLLAPSIBLE_WIDTH); - assertThat(squareView.getMeasuredWidth()).isEqualTo(squareSize); - assertThat(squareView.getMeasuredHeight()).isEqualTo(squareSize); - assertThat(mGridRowView.getMeasuredWidth()).isEqualTo(130); - assertThat(mGridRowView.getMeasuredHeight()).isEqualTo(squareSize); - } - - @Test - public void testOnMeasure_wrapContentMatchesCellHeight() { - // Several different sizes of cells; ensure that height of GridRowView is same as tallest - // cell. - - TestView square1 = new TestView(mContext, 20, 20); - square1.setLayoutParams(new LayoutParams(20, 20, 0.0f, true)); - TestView square2 = new TestView(mContext, 40, 40); - square2.setLayoutParams(new LayoutParams(40, 40, 0.0f, true)); - TestView square3 = new TestView(mContext, 30, 30); - square3.setLayoutParams(new LayoutParams(30, 30, 0.0f, true)); - - mGridRowView.addView(square1); - mGridRowView.addView(square2); - mGridRowView.addView(square3); - // Verify views which are gone are not considered in the layout. - mGridRowView.addView(mGoneView); - - mGridRowView.setLayoutParams( - new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); - - int sizeSpec = MeasureSpec.makeMeasureSpec(100, MeasureSpec.AT_MOST); - mGridRowView.measure(sizeSpec, sizeSpec); - - assertThat(mGridRowView.getMeasuredWidth()).isEqualTo(100); - assertThat(mGridRowView.getMeasuredHeight()).isEqualTo(40); - } - - @Test - public void testOnMeasure_doesNotWrapHeightWhenMeasureExactly() { - // Several different sizes of cells; ensure that height of GridRowView is same as tallest - // cell. - - TestView square1 = new TestView(mContext, 20, 20); - square1.setLayoutParams(new LayoutParams(20, 20, 0.0f, true)); - TestView square2 = new TestView(mContext, 40, 40); - square2.setLayoutParams(new LayoutParams(40, 40, 0.0f, true)); - TestView square3 = new TestView(mContext, 30, 30); - square3.setLayoutParams(new LayoutParams(30, 30, 0.0f, true)); - - mGridRowView.addView(square1); - mGridRowView.addView(square2); - mGridRowView.addView(square3); - // Verify views which are gone are not considered in the layout. - mGridRowView.addView(mGoneView); - - mGridRowView.setLayoutParams(new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, 100)); - - int sizeSpec = MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY); - mGridRowView.measure(sizeSpec, sizeSpec); - - assertThat(mGridRowView.getMeasuredHeight()).isEqualTo(100); - } - - @Test - public void testOnMeasure_shrinksCellThatWantsToBeTooTall() { - // Several different sizes of cells; ensure that height of GridRowView is same as tallest - // cell. - - TestView view = new TestView(mContext, 150, 200); - view.setLayoutParams(new LayoutParams(150, 200, 0.0f, true)); - - mGridRowView.addView(view); - - mGridRowView.setLayoutParams(new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, 100)); - - int sizeSpec = MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY); - mGridRowView.measure(sizeSpec, sizeSpec); - - assertThat(mGridRowView.getMeasuredHeight()).isEqualTo(100); - assertThat(view.mRequestedWidth).isEqualTo(100); - assertThat(view.mRequestedHeight).isEqualTo(100); - } - - @Test - public void testOnMeasure_respectsMinHeight() { - // Several different sizes of cells; ensure that height of GridRowView is the min height. - - TestView square1 = new TestView(mContext, 20, 20); - square1.setLayoutParams(new LayoutParams(20, 20, 0.0f, true)); - TestView square2 = new TestView(mContext, 40, 40); - square2.setLayoutParams(new LayoutParams(40, 40, 0.0f, true)); - TestView square3 = new TestView(mContext, 30, 30); - square3.setLayoutParams(new LayoutParams(30, 30, 0.0f, true)); - - mGridRowView.addView(square1); - mGridRowView.addView(square2); - mGridRowView.addView(square3); - // Verify views which are gone are not considered in the layout. - mGridRowView.addView(mGoneView); - - mGridRowView.setLayoutParams( - new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); - - mGridRowView.setMinimumHeight(95); - - int sizeSpec = MeasureSpec.makeMeasureSpec(100, MeasureSpec.AT_MOST); - mGridRowView.measure(sizeSpec, sizeSpec); - - assertThat(mGridRowView.getMeasuredWidth()).isEqualTo(100); - assertThat(mGridRowView.getMeasuredHeight()).isEqualTo(95); - } - - @Test - public void testOnMeasure_respectsMinHeightUpToAtMost() { - // Several different sizes of cells; ensure that height of GridRowView is the min height. - - TestView square1 = new TestView(mContext, 20, 20); - square1.setLayoutParams(new LayoutParams(20, 20, 0.0f, true)); - TestView square2 = new TestView(mContext, 40, 40); - square2.setLayoutParams(new LayoutParams(40, 40, 0.0f, true)); - TestView square3 = new TestView(mContext, 30, 30); - square3.setLayoutParams(new LayoutParams(30, 30, 0.0f, true)); - - mGridRowView.addView(square1); - mGridRowView.addView(square2); - mGridRowView.addView(square3); - // Verify views which are gone are not considered in the layout. - mGridRowView.addView(mGoneView); - - mGridRowView.setLayoutParams( - new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); - - mGridRowView.setMinimumHeight(1234); - - int sizeSpec = MeasureSpec.makeMeasureSpec(100, MeasureSpec.AT_MOST); - mGridRowView.measure(sizeSpec, sizeSpec); - - assertThat(mGridRowView.getMeasuredWidth()).isEqualTo(100); - assertThat(mGridRowView.getMeasuredHeight()).isEqualTo(100); - } - - @Test - public void testOnMeasure_respectsChildLayoutParams_weight() { - // Several different sizes of cells; ensure that width of each cell is set by the style - - int styleWidth = 30; - LayoutParams cellLayoutParams = - new LayoutParams(styleWidth, LayoutParams.WRAP_CONTENT, 0.0f, true); - TestView square1 = new TestView(mContext, 20, 20); - square1.setLayoutParams(cellLayoutParams); - TestView square2 = new TestView(mContext, 40, 40); - square2.setLayoutParams(cellLayoutParams); - TestView square3 = new TestView(mContext, 30, 30); - square3.setLayoutParams(cellLayoutParams); - - mGridRowView.addView(square1); - mGridRowView.addView(square2); - mGridRowView.addView(square3); - // Verify views which are gone are not considered in the layout. - mGridRowView.addView(mGoneView); - - mGridRowView.setLayoutParams( - new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); - - int sizeSpec = MeasureSpec.makeMeasureSpec(200, MeasureSpec.AT_MOST); - mGridRowView.measure(sizeSpec, sizeSpec); - - assertThat(square1.mRequestedWidth).isEqualTo(styleWidth); - assertThat(square2.mRequestedWidth).isEqualTo(styleWidth); - assertThat(square3.mRequestedWidth).isEqualTo(styleWidth); - - assertThat(mGridRowView.getMeasuredWidth()).isEqualTo(200); - } - - @Test - public void testOnMeasure_respectsChildLayoutParams_height() { - // Several different sizes of cells; ensure that height of GridRowView is same as tallest - // cell. - - int styleHeight = 30; - LayoutParams cellLayoutParams = - new LayoutParams(LayoutParams.WRAP_CONTENT, styleHeight, 0.0f, true); - TestView square1 = new TestView(mContext, 20, 20); - square1.setLayoutParams(cellLayoutParams); - TestView square2 = new TestView(mContext, 40, 40); - square2.setLayoutParams(cellLayoutParams); - TestView square3 = new TestView(mContext, 30, 30); - square3.setLayoutParams(cellLayoutParams); - - mGridRowView.addView(square1); - mGridRowView.addView(square2); - mGridRowView.addView(square3); - // Verify views which are gone are not considered in the layout. - mGridRowView.addView(mGoneView); - - mGridRowView.setLayoutParams( - new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); - - int sizeSpec = MeasureSpec.makeMeasureSpec(100, MeasureSpec.AT_MOST); - mGridRowView.measure(sizeSpec, sizeSpec); - - assertThat(square1.mRequestedHeight).isEqualTo(styleHeight); - assertThat(square2.mRequestedHeight).isEqualTo(styleHeight); - assertThat(square3.mRequestedHeight).isEqualTo(styleHeight); - - assertThat(mGridRowView.getMeasuredWidth()).isEqualTo(100); - assertThat(mGridRowView.getMeasuredHeight()).isEqualTo(styleHeight); - } - - @Test - public void testOnMeasure_rowHeightIsMaxCellHeightWithMargins() { - // Several different sizes of cells; ensure that height of GridRowView is same as tallest - // cell. - - TestView view1 = new TestView(mContext, 40, 40); - view1.setLayoutParams(new LayoutParams(40, 40)); - - TestView view2 = new TestView(mContext, 30, 30); - LayoutParams params = new LayoutParams(30, 30); - params.topMargin = 5; - params.bottomMargin = 15; - view2.setLayoutParams(params); - - mGridRowView.addView(view1); - mGridRowView.addView(view2); - // Verify views which are gone are not considered in the layout. - mGridRowView.addView(mGoneView); - - mGridRowView.setLayoutParams( - new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); - - int sizeSpec = MeasureSpec.makeMeasureSpec(100, MeasureSpec.AT_MOST); - mGridRowView.measure(sizeSpec, sizeSpec); - - assertThat(mGridRowView.getMeasuredWidth()).isEqualTo(100); - assertThat(mGridRowView.getMeasuredHeight()).isEqualTo(50); - } - - @Test - public void testOnMeasure_cellWithMarginsClippedByHeightConstraint() { - // Row is 100 high, cell is set to 90 high, but has 5 + 15 margins, so cell is only 80 high. - - TestView view = new TestView(mContext, 123, 90); - LayoutParams params = new LayoutParams(123, 90); - params.topMargin = 5; - params.bottomMargin = 15; - view.setLayoutParams(params); - - mGridRowView.addView(view); - // Verify views which are gone are not considered in the layout. - mGridRowView.addView(mGoneView); - - int widthSpec = MeasureSpec.makeMeasureSpec(500, MeasureSpec.AT_MOST); - int heightSpec = MeasureSpec.makeMeasureSpec(100, MeasureSpec.AT_MOST); - - mGridRowView.measure(widthSpec, heightSpec); - - assertThat(view.mRequestedHeight).isEqualTo(80); - } - - @Test - public void testOnMeasure_respectsGridRowPadding() { - // DP, Collapsible, WRAP_CONTENT - // Collapsible cell is truncated - - mGridRowView.addView(mWidthView); - mGridRowView.addView(mCollapsibleView); - mGridRowView.addView(mWrapContentView); - // Verify views which are gone are not considered in the layout. - mGridRowView.addView(mGoneView); - - int paddingLeft = 10; - int paddingTop = 20; - int paddingRight = 30; - int paddingBottom = 40; - mGridRowView.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom); - - int sizeSpec = MeasureSpec.makeMeasureSpec(250, MeasureSpec.EXACTLY); - mGridRowView.measure(sizeSpec, sizeSpec); - - assertThat(mWidthView.mRequestedWidth).isEqualTo(WIDTH); - assertThat(mCollapsibleView.mRequestedWidth) - .isEqualTo(250 - WIDTH - WRAP_CONTENT_WIDTH - paddingLeft - paddingRight); - assertThat(mWrapContentView.mRequestedWidth).isEqualTo(WRAP_CONTENT_WIDTH); - assertThat(mGridRowView.getMeasuredWidth()).isEqualTo(250); - - int cellHeight = 250 - paddingTop - paddingBottom; - assertThat(mWidthView.mRequestedHeight).isEqualTo(cellHeight); - assertThat(mCollapsibleView.mRequestedHeight).isEqualTo(cellHeight); - assertThat(mWrapContentView.mRequestedHeight).isEqualTo(cellHeight); - assertThat(mGridRowView.getMeasuredHeight()).isEqualTo(250); - } - - @Test - public void testOnMeasure_fillParentCellsWithFitContentRow() { - TestView tallView = new TestView(mContext, 11, 100); - tallView.setLayoutParams(new LayoutParams(11, ViewGroup.LayoutParams.MATCH_PARENT)); - TestView shortView = new TestView(mContext, 12, 20); - shortView.setLayoutParams(new LayoutParams(12, ViewGroup.LayoutParams.MATCH_PARENT)); - - mGridRowView.addView(tallView); - mGridRowView.addView(shortView); - // Verify views which are gone are not considered in the layout. - mGridRowView.addView(mGoneView); - - mGridRowView.setLayoutParams(new LayoutParams(50, ViewGroup.LayoutParams.WRAP_CONTENT)); - - int widthSpec = MeasureSpec.makeMeasureSpec(500, MeasureSpec.AT_MOST); - int heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); - - mGridRowView.measure(widthSpec, heightSpec); - - assertThat(tallView.mRequestedHeight).isEqualTo(100); - assertThat(shortView.mRequestedHeight).isEqualTo(100); - } - - @Test - public void testOnMeasure_fitContentCellsWithFitContentRow_minHeight() { - TestView tallView = new TestView(mContext, 11, 50); - tallView.setLayoutParams(new LayoutParams(11, ViewGroup.LayoutParams.WRAP_CONTENT)); - TestView shortView = new TestView(mContext, 12, 20); - shortView.setLayoutParams(new LayoutParams(12, ViewGroup.LayoutParams.WRAP_CONTENT)); - shortView.setMinimumHeight(30); - - mGridRowView.addView(tallView); - mGridRowView.addView(shortView); - // Verify views which are gone are not considered in the layout. - mGridRowView.addView(mGoneView); - - mGridRowView.setLayoutParams(new LayoutParams(50, ViewGroup.LayoutParams.WRAP_CONTENT)); - - int widthSpec = MeasureSpec.makeMeasureSpec(500, MeasureSpec.AT_MOST); - int heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); - - mGridRowView.measure(widthSpec, heightSpec); - - assertThat(tallView.mRequestedHeight).isEqualTo(50); - assertThat(shortView.mRequestedHeight).isEqualTo(30); - } - - @Test - public void testOnMeasure_fitContentWidthRowIsTotalOfCells() { - TestView view1 = new TestView(mContext, 11, 100); - view1.setLayoutParams(new LayoutParams(11, 100)); - TestView view2 = new TestView(mContext, 22, 100); - view2.setLayoutParams(new LayoutParams(22, 100)); - - mGridRowView.addView(view1); - mGridRowView.addView(view2); - // Verify views which are gone are not considered in the layout. - mGridRowView.addView(mGoneView); - - mGridRowView.setLayoutParams( - new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); - - int widthSpec = MeasureSpec.makeMeasureSpec(400, MeasureSpec.AT_MOST); - mGridRowView.measure(widthSpec, mUnspecifiedSpec); - - assertThat(view1.mRequestedWidth).isEqualTo(11); - assertThat(view2.mRequestedWidth).isEqualTo(22); - assertThat(mGridRowView.getMeasuredWidth()).isEqualTo(33); - } - - @Test - public void testOnMeasure_fitContentWidthRowWithWeightCellsTakesAllSpace() { - mGridRowView.addView(mWidthView); - mGridRowView.addView(mWeightView); - // Verify views which are gone are not considered in the layout. - mGridRowView.addView(mGoneView); - - mGridRowView.setLayoutParams( - new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); - - int widthSpec = MeasureSpec.makeMeasureSpec(400, MeasureSpec.AT_MOST); - mGridRowView.measure(widthSpec, mUnspecifiedSpec); - - assertThat(mWidthView.mRequestedWidth).isEqualTo(WIDTH); - assertThat(mWeightView.mRequestedWidth).isEqualTo(400 - WIDTH); - assertThat(mGridRowView.getMeasuredWidth()).isEqualTo(400); - } - - @Test - public void testOnMeasure_fitContentWidthRowWithMargins() { - TestView view1 = new TestView(mContext, 11, 100); - LayoutParams view1Params = new LayoutParams(11, 100); - view1Params.leftMargin = 2; - view1Params.rightMargin = 3; - view1.setLayoutParams(view1Params); - - TestView view2 = new TestView(mContext, 22, 100); - LayoutParams view2Params = new LayoutParams(22, 100); - view2Params.leftMargin = 4; - view2Params.rightMargin = 5; - view2.setLayoutParams(view2Params); - - mGridRowView.addView(view1); - mGridRowView.addView(view2); - // Verify views which are gone are not considered in the layout. - mGridRowView.addView(mGoneView); - - mGridRowView.setLayoutParams( - new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); - - int widthSpec = MeasureSpec.makeMeasureSpec(400, MeasureSpec.AT_MOST); - mGridRowView.measure(widthSpec, mUnspecifiedSpec); - - assertThat(view1.mRequestedWidth).isEqualTo(11); - assertThat(view2.mRequestedWidth).isEqualTo(22); - assertThat(mGridRowView.getMeasuredWidth()).isEqualTo(33 + 14); - } - - @Test - public void testOnMeasure_fitContentWidthRowIsTotalOfCells_collapsibleAndMargins() { - TestView view1 = new TestView(mContext, 11, 100); - LayoutParams view1Params = new LayoutParams(11, 100); - view1Params.leftMargin = 2; - view1Params.rightMargin = 3; - view1.setLayoutParams(view1Params); - - TestView view2 = new TestView(mContext, 22, 100); - LayoutParams view2Params = new LayoutParams(22, 100); - view2Params.leftMargin = 4; - view2Params.rightMargin = 5; - view2.setLayoutParams(view2Params); - - TestView view3 = new TestView(mContext, 33, 100); - LayoutParams view3Params = new LayoutParams(LayoutParams.WRAP_CONTENT, 100, 0.0f, true); - view3Params.leftMargin = 6; - view3Params.rightMargin = 7; - view3.setLayoutParams(view3Params); - - mGridRowView.addView(view1); - mGridRowView.addView(view2); - mGridRowView.addView(view3); - mGridRowView.setLayoutParams( - new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); - - int widthSpec = MeasureSpec.makeMeasureSpec(400, MeasureSpec.AT_MOST); - mGridRowView.measure(widthSpec, mUnspecifiedSpec); - - assertThat(view1.mRequestedWidth).isEqualTo(11); - assertThat(view2.mRequestedWidth).isEqualTo(22); - assertThat(view3.mRequestedWidth).isEqualTo(33); - assertThat(mGridRowView.getMeasuredWidth()).isEqualTo(11 + 22 + 33 + 2 + 3 + 4 + 5 + 6 + 7); - } - - @Test - public void testOnMeasure_truncatesCellsWithMarginsAndPadding() { - // Cells will fit in the space, but margins push the second cell outside the row - - TestView view1 = new TestView(mContext, 11, 100); - LayoutParams view1Params = new LayoutParams(11, 100); - view1Params.leftMargin = 2; - view1Params.rightMargin = 3; - view1.setLayoutParams(view1Params); - - TestView view2 = new TestView(mContext, 22, 100); - LayoutParams view2Params = new LayoutParams(22, 100); - view2Params.leftMargin = 4; - view2Params.rightMargin = 5; - view2.setLayoutParams(view2Params); - - mGridRowView.addView(view1); - mGridRowView.addView(view2); - - mGridRowView.setPadding(1, 0, 1, 0); - - int widthSpec = MeasureSpec.makeMeasureSpec(33, MeasureSpec.AT_MOST); - mGridRowView.measure(widthSpec, mUnspecifiedSpec); - - assertThat(view1.mRequestedWidth).isEqualTo(11); - assertThat(view2.mRequestedWidth).isEqualTo(33 - 11 - 1 - 1 - 2 - 3 - 4); // 11 - assertThat(mGridRowView.getMeasuredWidth()).isEqualTo(33); - } - - @Test - public void testCalculatesTotalWidth_noWeightCells() { - TestView view1 = new TestView(mContext, 11, 100); - LayoutParams view1Params = new LayoutParams(11, 100); - view1Params.leftMargin = 2; - view1Params.rightMargin = 3; - view1.setLayoutParams(view1Params); - - TestView view2 = new TestView(mContext, 22, 100); - LayoutParams view2Params = new LayoutParams(22, 100); - view2Params.leftMargin = 4; - view2Params.rightMargin = 5; - view2.setLayoutParams(view2Params); - - mGridRowView.addView(view1); - mGridRowView.addView(view2); - - mGridRowView.setPadding(6, 0, 7, 0); - - int widthSpec = MeasureSpec.makeMeasureSpec(100, MeasureSpec.AT_MOST); - mGridRowView.measure(widthSpec, mUnspecifiedSpec); - - assertThat(mGridRowView.mTotalContentWidth).isEqualTo(11 + 2 + 3 + 22 + 4 + 5 + 6 + 7); - } - - @Test - public void testCalculatesTotalWidth_weightCells() { - TestView view1 = new TestView(mContext, 11, 100); - LayoutParams view1Params = new LayoutParams(11, 100); - view1Params.leftMargin = 2; - view1Params.rightMargin = 3; - view1.setLayoutParams(view1Params); - - TestView view2 = new TestView(mContext, 22, 100); - LayoutParams view2Params = new LayoutParams(0, 100, 1); - view2Params.leftMargin = 4; - view2Params.rightMargin = 5; - view2.setLayoutParams(view2Params); - - mGridRowView.addView(view1); - mGridRowView.addView(view2); - - mGridRowView.setPadding(6, 0, 7, 0); - - int widthSpec = MeasureSpec.makeMeasureSpec(100, MeasureSpec.AT_MOST); - mGridRowView.measure(widthSpec, mUnspecifiedSpec); - - assertThat(mGridRowView.mTotalContentWidth).isEqualTo(100); - } - - private static class TestView extends View { - private final int mDesiredWidth; - private final int mDesiredHeight; - - int mRequestedWidth = -3; - int mRequestedHeight = -3; - - TestView(Context context, int desiredWidth, int desiredHeight) { - super(context); - this.mDesiredWidth = desiredWidth; - this.mDesiredHeight = desiredHeight; - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - if (MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED) { - mRequestedWidth = MeasureSpec.getSize(widthMeasureSpec); - } else { - mRequestedWidth = mDesiredWidth; - } - if (MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.UNSPECIFIED) { - mRequestedHeight = MeasureSpec.getSize(heightMeasureSpec); - } else { - mRequestedHeight = mDesiredHeight; - } - - int measuredWidth; - int measuredHeight; - switch (MeasureSpec.getMode(widthMeasureSpec)) { - case MeasureSpec.UNSPECIFIED: - measuredWidth = mDesiredWidth; - break; - case MeasureSpec.EXACTLY: - measuredWidth = mRequestedWidth; - break; - case MeasureSpec.AT_MOST: - measuredWidth = Math.min(mRequestedWidth, mDesiredWidth); - break; - default: - measuredWidth = 999999; - } - switch (MeasureSpec.getMode(heightMeasureSpec)) { - case MeasureSpec.UNSPECIFIED: - measuredHeight = mDesiredHeight; - break; - case MeasureSpec.EXACTLY: - measuredHeight = mRequestedHeight; - break; - case MeasureSpec.AT_MOST: - measuredHeight = Math.min(mRequestedHeight, mDesiredHeight); - break; - default: - measuredHeight = 999999; - } - - setMeasuredDimension(measuredWidth, measuredHeight); - } - } - - private static class SquareView extends View { - SquareView(Context context) { - super(context); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int width; - if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.UNSPECIFIED) { - width = 999999; - } else { - width = MeasureSpec.getSize(widthMeasureSpec); - } - setMeasuredDimension(width, width); - } - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ui/RoundedCornerMaskCacheTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ui/RoundedCornerMaskCacheTest.java deleted file mode 100644 index 61af8b4..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ui/RoundedCornerMaskCacheTest.java +++ /dev/null
@@ -1,103 +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. - -package org.chromium.chrome.browser.feed.library.piet.ui; - -import static com.google.common.truth.Truth.assertThat; - -import static org.chromium.chrome.browser.feed.library.common.testing.RunnableSubject.assertThatRunnable; - -import android.graphics.Bitmap; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.piet.ui.RoundedCornerMaskCache.Corner; -import org.chromium.chrome.browser.feed.library.piet.ui.RoundedCornerMaskCache.RoundedCornerBitmaps; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for the {@link RoundedCornerMaskCache}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class RoundedCornerMaskCacheTest { - private RoundedCornerMaskCache mCache; - - @Before - public void setUp() { - mCache = new RoundedCornerMaskCache(); - } - - @Test - public void testGetBitmaps_createsNewInstance() { - RoundedCornerBitmaps masks = mCache.getMasks(16); - - for (int i = 0; i < 4; i++) { - Bitmap mask = masks.get(i); - assertThat(mask.getWidth()).isEqualTo(16); - assertThat(mask.getHeight()).isEqualTo(16); - } - } - - @Test - public void testGetBitmaps_differentRadii() { - RoundedCornerBitmaps masksFive = mCache.getMasks(5); - RoundedCornerBitmaps masksTen = mCache.getMasks(10); - - assertThat(masksFive).isNotEqualTo(masksTen); - - Bitmap maskFive = masksFive.get(Corner.TOP_LEFT); - Bitmap maskTen = masksTen.get(Corner.TOP_LEFT); - - assertThat(maskFive).isNotEqualTo(maskTen); - assertThat(maskFive.getWidth()).isEqualTo(5); - assertThat(maskTen.getWidth()).isEqualTo(10); - } - - @Test - public void testGetBitmaps_cachesInstance() { - RoundedCornerBitmaps masks1 = mCache.getMasks(16); - - RoundedCornerBitmaps masks2 = mCache.getMasks(16); - - assertThat(masks1).isSameInstanceAs(masks2); - } - - @Test - public void testPurge() { - RoundedCornerBitmaps masks1 = mCache.getMasks(16); - - mCache.purge(); - - RoundedCornerBitmaps masks2 = mCache.getMasks(16); - - assertThat(masks1).isNotSameInstanceAs(masks2); - } - - @Test - public void testBadCornerException() { - RoundedCornerBitmaps masks = mCache.getMasks(16); - - assertThatRunnable(() -> masks.get(999)) - .throwsAnExceptionOfType(IllegalArgumentException.class); - } - - @Test - public void testCreatesOnlyRequestedCorners() { - RoundedCornerBitmaps masks = mCache.getMasks(123); - - assertThat(masks.mMasks[Corner.TOP_LEFT]).isNull(); - assertThat(masks.mMasks[Corner.TOP_RIGHT]).isNull(); - assertThat(masks.mMasks[Corner.BOTTOM_LEFT]).isNull(); - assertThat(masks.mMasks[Corner.BOTTOM_RIGHT]).isNull(); - - masks.get(Corner.TOP_RIGHT); - - assertThat(masks.mMasks[Corner.TOP_LEFT]).isNull(); - assertThat(masks.mMasks[Corner.TOP_RIGHT]).isNotNull(); - assertThat(masks.mMasks[Corner.BOTTOM_LEFT]).isNull(); - assertThat(masks.mMasks[Corner.BOTTOM_RIGHT]).isNull(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ui/RoundedCornerViewHelperTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ui/RoundedCornerViewHelperTest.java deleted file mode 100644 index 1913ff0..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ui/RoundedCornerViewHelperTest.java +++ /dev/null
@@ -1,81 +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. - -package org.chromium.chrome.browser.feed.library.piet.ui; - -import static com.google.common.truth.Truth.assertThat; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.components.feed.core.proto.ui.piet.RoundedCornersProto.RoundedCorners; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for the {@link RoundedCornerViewHelper}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class RoundedCornerViewHelperTest { - @Test - public void hasNoValidRoundedCorners_noRadiusSet() { - RoundedCorners roundedCorners = RoundedCorners.getDefaultInstance(); - - boolean calculatedValidity = RoundedCornerViewHelper.hasValidRoundedCorners( - roundedCorners, /* radiusOverride= */ 0); - - assertThat(calculatedValidity).isFalse(); - } - - @Test - public void hasNoValidRoundedCorners_zeroRadius() { - RoundedCorners roundedCorners = RoundedCorners.newBuilder().setRadiusDp(0).build(); - - boolean calculatedValidity = RoundedCornerViewHelper.hasValidRoundedCorners( - roundedCorners, /* radiusOverride= */ 0); - - assertThat(calculatedValidity).isFalse(); - } - - @Test - public void hasValidRoundedCorners_radiusDp() { - RoundedCorners roundedCorners = RoundedCorners.newBuilder().setRadiusDp(10).build(); - - boolean calculatedValidity = RoundedCornerViewHelper.hasValidRoundedCorners( - roundedCorners, /* radiusOverride= */ 0); - - assertThat(calculatedValidity).isTrue(); - } - - @Test - public void hasValidRoundedCorners_radiusPercentageOfHeight() { - RoundedCorners roundedCorners = - RoundedCorners.newBuilder().setRadiusPercentageOfHeight(20).build(); - - boolean calculatedValidity = RoundedCornerViewHelper.hasValidRoundedCorners( - roundedCorners, /* radiusOverride= */ 0); - - assertThat(calculatedValidity).isTrue(); - } - - @Test - public void hasValidRoundedCorners_radiusPercentageOfWidth() { - RoundedCorners roundedCorners = - RoundedCorners.newBuilder().setRadiusPercentageOfWidth(30).build(); - - boolean calculatedValidity = RoundedCornerViewHelper.hasValidRoundedCorners( - roundedCorners, /* radiusOverride= */ 0); - - assertThat(calculatedValidity).isTrue(); - } - - @Test - public void hasValidRoundedCorners_radiusOverride() { - RoundedCorners roundedCorners = RoundedCorners.getDefaultInstance(); - - boolean calculatedValidity = RoundedCornerViewHelper.hasValidRoundedCorners( - roundedCorners, /* radiusOverride= */ 10); - - assertThat(calculatedValidity).isTrue(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ui/RoundedCornerWrapperViewTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ui/RoundedCornerWrapperViewTest.java deleted file mode 100644 index 73a3a03..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/piet/ui/RoundedCornerWrapperViewTest.java +++ /dev/null
@@ -1,593 +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. - -package org.chromium.chrome.browser.feed.library.piet.ui; - -import static com.google.common.truth.Truth.assertThat; - -import android.app.Activity; -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Canvas; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.base.supplier.Supplier; -import org.chromium.chrome.browser.feed.library.common.functional.Suppliers; -import org.chromium.chrome.browser.feed.library.piet.ui.RoundedCornerDelegateFactory.RoundingStrategy; -import org.chromium.components.feed.core.proto.ui.piet.RoundedCornersProto.RoundedCorners; -import org.chromium.components.feed.core.proto.ui.piet.StylesProto.Borders; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for the {@link RoundedCornerWrapperView}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class RoundedCornerWrapperViewTest { - private static final int TOP_CORNERS_BITMASK = 3; - private static final int LEFT_CORNERS_BITMASK = 9; - private static final int ALL_CORNERS_BITMASK = 15; - - private Canvas mCanvas; - private Bitmap mBitmap; - - @Before - public void setUp() { - mBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); - mCanvas = new Canvas(mBitmap); - } - - @Test - public void layoutZeroDimensions_notRounded() { - RoundedCornerWrapperView view = CommonRoundedCornerWrapperView.getDefaultInstance(); - - view.layout(0, 0, 0, 100); - assertThat(view.getWidth()).isEqualTo(0); - view.draw(mCanvas); - // Assert nothing fails - - view.layout(0, 0, 100, 0); - assertThat(view.getHeight()).isEqualTo(0); - view.draw(mCanvas); - // Assert nothing fails - - view.layout(0, 0, 0, 0); - assertThat(view.getWidth()).isEqualTo(0); - assertThat(view.getHeight()).isEqualTo(0); - view.draw(mCanvas); - // Assert nothing fails - } - - @Test - public void layoutZeroDimensions_rounded() { - RoundedCorners roundedCorners = - RoundedCorners.newBuilder().setBitmask(7).setRadiusDp(10).build(); - RoundedCornerWrapperView view = - CommonRoundedCornerWrapperView.builder().setRoundedCorners(roundedCorners).build(); - - view.layout(0, 0, 0, 100); - assertThat(view.getWidth()).isEqualTo(0); - view.draw(mCanvas); - // Assert nothing fails - - view.layout(0, 0, 100, 0); - assertThat(view.getHeight()).isEqualTo(0); - view.draw(mCanvas); - // Assert nothing fails - - view.layout(0, 0, 0, 0); - assertThat(view.getWidth()).isEqualTo(0); - assertThat(view.getHeight()).isEqualTo(0); - view.draw(mCanvas); - // Assert nothing fails - } - - @Test - public void roundCorners_bordersAdded() { - // The width, height, and radius don't really matter for this test. As long as they exist, a - // BorderDrawable should be set on the view. - Borders borders = Borders.newBuilder().setWidth(10).build(); - - RoundedCorners roundedCorners = RoundedCorners.newBuilder().setRadiusDp(10).build(); - RoundedCornerWrapperView view = CommonRoundedCornerWrapperView.builder() - .setRoundedCorners(roundedCorners) - .setBorders(borders) - .build(); - - view.layout(0, 0, 100, 100); - view.draw(mCanvas); - - // Assert that borders are created. - assertThat(view.getForeground()).isInstanceOf(BorderDrawable.class); - // The specifics of how the borders look are difficult to test here, and so are tested in a - // screendiff test instead. - } - - @Test - public void setRoundedCorners_bordersWidthZero() { - Borders borders = Borders.newBuilder().setWidth(0).build(); - - RoundedCorners roundedCorners = RoundedCorners.newBuilder().setRadiusDp(10).build(); - RoundedCornerWrapperView view = CommonRoundedCornerWrapperView.builder() - .setRoundedCorners(roundedCorners) - .setBorders(borders) - .build(); - - // Set a width and height on the view so that the only thing stopping borders from being - // created is the border width of 0. - view.layout(0, 0, 100, 100); - view.draw(mCanvas); - - // Assert that borders are not created. - assertThat(view.getForeground()).isNull(); - } - - @Test - public void getRadius_usesOverride() { - int viewWidth = 100; - int viewHeight = 100; - int radiusToSet = 10; - int radiusOverride = 20; - RoundedCorners roundedCorners = - RoundedCorners.newBuilder().setRadiusDp(radiusToSet).build(); - RoundedCornerWrapperView view = CommonRoundedCornerWrapperView.builder() - .setRoundedCorners(roundedCorners) - .setRadiusOverride(radiusOverride) - .build(); - - int calculatedRadius = view.getRadius(viewWidth, viewHeight); - - // Make sure it's using the override value, NOT the radius from RoundedCorners. - assertThat(calculatedRadius).isEqualTo(radiusOverride); - } - - @Test - public void getRadius_radiusDp() { - int viewWidth = 100; - int viewHeight = 100; - int radiusToSet = 10; - RoundedCorners roundedCorners = - RoundedCorners.newBuilder().setRadiusDp(radiusToSet).build(); - RoundedCornerWrapperView view = - CommonRoundedCornerWrapperView.builder().setRoundedCorners(roundedCorners).build(); - - int calculatedRadius = view.getRadius(viewWidth, viewHeight); - - assertThat(calculatedRadius).isEqualTo(radiusToSet); - } - - @Test - public void getRadius_radiusPercentageOfHeight() { - int viewWidth = 60; - int viewHeight = 100; - int radiusPercentageOfHeight = 25; - RoundedCorners roundedCorners = - RoundedCorners.newBuilder() - .setRadiusPercentageOfHeight(radiusPercentageOfHeight) - .build(); - RoundedCornerWrapperView view = - CommonRoundedCornerWrapperView.builder().setRoundedCorners(roundedCorners).build(); - - int calculatedRadius = view.getRadius(viewWidth, viewHeight); - - // 25% of the height is 25. .25 * 100 = 25 - assertThat(calculatedRadius).isEqualTo(25); - } - - @Test - public void getRadius_radiusPercentageOfWidth() { - int viewWidth = 60; - int viewHeight = 100; - int radiusPercentageOfWidth = 25; - RoundedCorners roundedCorners = RoundedCorners.newBuilder() - .setRadiusPercentageOfWidth(radiusPercentageOfWidth) - .build(); - RoundedCornerWrapperView view = - CommonRoundedCornerWrapperView.builder().setRoundedCorners(roundedCorners).build(); - - int calculatedRadius = view.getRadius(viewWidth, viewHeight); - - // 25% of the width is 15. .25 * 60 = 15 - assertThat(calculatedRadius).isEqualTo(15); - } - - @Test - public void getRadius_smallWidth_RadiusDpShouldAdjust() { - int viewWidth = 30; - int viewHeight = 40; - int radiusToSet = 20; - RoundedCorners roundedCorners = - RoundedCorners.newBuilder().setRadiusDp(radiusToSet).build(); - RoundedCornerWrapperView view = - CommonRoundedCornerWrapperView.builder().setRoundedCorners(roundedCorners).build(); - - int calculatedRadius = view.getRadius(viewWidth, viewHeight); - - // A radius of 20 on each corner will add up to 40, which is bigger than the width. The - // radius should be adjusted to be 15. - assertThat(calculatedRadius).isEqualTo(15); - } - - @Test - public void getRadius_smallWidth_RadiusDpShouldNotAdjust() { - int viewWidth = 30; - int viewHeight = 40; - int radiusToSet = 20; - RoundedCorners roundedCorners = RoundedCorners.newBuilder() - .setBitmask(LEFT_CORNERS_BITMASK) - .setRadiusDp(radiusToSet) - .build(); - RoundedCornerWrapperView view = - CommonRoundedCornerWrapperView.builder().setRoundedCorners(roundedCorners).build(); - - int calculatedRadius = view.getRadius(viewWidth, viewHeight); - - // The radius of 20 is more than half the width. However, since only the left corners are - // rounded, the radius should not be adjusted, since 20dp is only half the height. - assertThat(calculatedRadius).isEqualTo(20); - } - - @Test - public void getRadius_smallHeight_RadiusDpShouldAdjust() { - int viewWidth = 40; - int viewHeight = 30; - int radiusToSet = 20; - RoundedCorners roundedCorners = - RoundedCorners.newBuilder().setRadiusDp(radiusToSet).build(); - RoundedCornerWrapperView view = - CommonRoundedCornerWrapperView.builder().setRoundedCorners(roundedCorners).build(); - - int calculatedRadius = view.getRadius(viewWidth, viewHeight); - - // A radius of 20 on each corner will add up to 40, which is bigger than the height. The - // radius should be adjusted to be 15. - assertThat(calculatedRadius).isEqualTo(15); - } - - @Test - public void getRadius_smallHeight_RadiusDpShouldNotAdjust() { - int viewWidth = 40; - int viewHeight = 30; - int radiusToSet = 20; - RoundedCorners roundedCorners = RoundedCorners.newBuilder() - .setBitmask(TOP_CORNERS_BITMASK) - .setRadiusDp(radiusToSet) - .build(); - RoundedCornerWrapperView view = - CommonRoundedCornerWrapperView.builder().setRoundedCorners(roundedCorners).build(); - - int calculatedRadius = view.getRadius(viewWidth, viewHeight); - - // The radius of 20 is more than half the height. However, since only the top corners are - // rounded, the radius should not be adjusted, since 20dp is only half the width. - assertThat(calculatedRadius).isEqualTo(20); - } - - @Test - public void getRadius_radiusPercentageOfHeight_100Percent_shouldAdjust() { - int viewWidth = 60; - int viewHeight = 100; - int radiusPercentageOfHeight = 100; - RoundedCorners roundedCorners = - RoundedCorners.newBuilder() - .setRadiusPercentageOfHeight(radiusPercentageOfHeight) - .build(); - RoundedCornerWrapperView view = - CommonRoundedCornerWrapperView.builder().setRoundedCorners(roundedCorners).build(); - - int calculatedRadius = view.getRadius(viewWidth, viewHeight); - - // Since all corners are rounded, the radius should shrink to 30, half the width. - assertThat(calculatedRadius).isEqualTo(30); - } - - @Test - public void getRadius_radiusPercentageOfHeight_100Percent_topCorners_shouldAdjust() { - int viewWidth = 60; - int viewHeight = 100; - int radiusPercentageOfHeight = 100; - RoundedCorners roundedCorners = - RoundedCorners.newBuilder() - .setBitmask(TOP_CORNERS_BITMASK) - .setRadiusPercentageOfHeight(radiusPercentageOfHeight) - .build(); - RoundedCornerWrapperView view = - CommonRoundedCornerWrapperView.builder().setRoundedCorners(roundedCorners).build(); - - int calculatedRadius = view.getRadius(viewWidth, viewHeight); - - // Only top corners are rounded, but the radius should still shrink to 30, half the width, - // since the width is small. - assertThat(calculatedRadius).isEqualTo(30); - } - - @Test - public void getRadius_radiusPercentageOfHeight_100Percent_topCorners_shouldNotAdjust() { - int viewWidth = 100; - int viewHeight = 40; - int radiusPercentageOfHeight = 100; - RoundedCorners roundedCorners = - RoundedCorners.newBuilder() - .setBitmask(TOP_CORNERS_BITMASK) - .setRadiusPercentageOfHeight(radiusPercentageOfHeight) - .build(); - RoundedCornerWrapperView view = - CommonRoundedCornerWrapperView.builder().setRoundedCorners(roundedCorners).build(); - - int calculatedRadius = view.getRadius(viewWidth, viewHeight); - - // Only top corners are rounded, and 40*2=80 is still less than the width (100), so we don't - // need to shrink the radius. - assertThat(calculatedRadius).isEqualTo(40); - } - - @Test - public void getRadius_radiusPercentageOfWidth_100Percent_shouldAdjust() { - int viewWidth = 100; - int viewHeight = 60; - int radiusPercentageOfWidth = 100; - RoundedCorners roundedCorners = RoundedCorners.newBuilder() - .setRadiusPercentageOfWidth(radiusPercentageOfWidth) - .build(); - RoundedCornerWrapperView view = - CommonRoundedCornerWrapperView.builder().setRoundedCorners(roundedCorners).build(); - - int calculatedRadius = view.getRadius(viewWidth, viewHeight); - - // Since all corners are rounded, the radius should shrink to 30, half the height, instead - // of 100% of 100 = 100. - assertThat(calculatedRadius).isEqualTo(30); - } - - @Test - public void getRadius_radiusPercentageOfWidth_100Percent_leftCorners_shouldAdjust() { - int viewWidth = 100; - int viewHeight = 60; - int radiusPercentageOfWidth = 100; - RoundedCorners roundedCorners = RoundedCorners.newBuilder() - .setBitmask(LEFT_CORNERS_BITMASK) - .setRadiusPercentageOfWidth(radiusPercentageOfWidth) - .build(); - RoundedCornerWrapperView view = - CommonRoundedCornerWrapperView.builder().setRoundedCorners(roundedCorners).build(); - - int calculatedRadius = view.getRadius(viewWidth, viewHeight); - - // Only left corners are rounded, but the radius should still shrink to 30, half the height, - // since the height is small. 100% of 100 = 100, which is greater than the height. - assertThat(calculatedRadius).isEqualTo(30); - } - - @Test - public void getRadius_radiusPercentageOfWidth_100Percent_topCorners_shouldNotAdjust() { - int viewWidth = 40; - int viewHeight = 100; - int radiusPercentageOfWidth = 100; - RoundedCorners roundedCorners = RoundedCorners.newBuilder() - .setBitmask(LEFT_CORNERS_BITMASK) - .setRadiusPercentageOfWidth(radiusPercentageOfWidth) - .build(); - RoundedCornerWrapperView view = - CommonRoundedCornerWrapperView.builder().setRoundedCorners(roundedCorners).build(); - - int calculatedRadius = view.getRadius(viewWidth, viewHeight); - - // Only left corners are rounded, and 40*2=80 is still less than the height (100), so we - // don't need to shrink the radius. - assertThat(calculatedRadius).isEqualTo(40); - } - - @Test - public void useMaskingStrategy_notAllCornersRounded() { - int radius = 16; - RoundedCorners roundedCorners = RoundedCorners.newBuilder() - .setBitmask(LEFT_CORNERS_BITMASK) - .setRadiusDp(radius) - .build(); - CommonRoundedCornerWrapperView view = - CommonRoundedCornerWrapperView.builder().setRoundedCorners(roundedCorners).build(); - - // When not all corners are rounded, the outline provider strategy doesn't work, so it - // should use bitmap masking - assertThat(view.getRoundingStrategy()).isEqualTo(RoundingStrategy.BITMAP_MASKING); - } - - @Test - public void useOutlineProviderStrategy_hardwareAcceleration() { - int width = 100; - int height = 100; - int radius = 16; - RoundedCorners roundedCorners = RoundedCorners.newBuilder() - .setBitmask(ALL_CORNERS_BITMASK) - .setRadiusDp(radius) - .build(); - CommonRoundedCornerWrapperView view = CommonRoundedCornerWrapperView.builder() - .setRoundedCorners(roundedCorners) - .setHardwareAccelerated(true) - .build(); - - // Lay out the view, because that's when the view would know if it's hardware accelerated. - view.layout(0, 0, width, height); - - assertThat(view.getClipToOutline()).isTrue(); - assertThat(view.getClipChildren()).isTrue(); - assertThat(view.getRoundingStrategy()).isEqualTo(RoundingStrategy.OUTLINE_PROVIDER); - } - - @Test - public void useClipPathStrategy_noHardwareAcceleration() { - int width = 100; - int height = 100; - int radius = 16; - RoundedCorners roundedCorners = RoundedCorners.newBuilder() - .setBitmask(ALL_CORNERS_BITMASK) - .setRadiusDp(radius) - .build(); - CommonRoundedCornerWrapperView view = CommonRoundedCornerWrapperView.builder() - .setRoundedCorners(roundedCorners) - .setHardwareAccelerated(false) - .build(); - - view.layout(0, 0, width, height); - - assertThat(view.getClipToOutline()).isFalse(); - assertThat(view.getClipChildren()).isFalse(); - - assertThat(view.getRoundingStrategy()).isEqualTo(RoundingStrategy.CLIP_PATH); - } - - @Test - public void useMaskingStrategy_noHardwareAcceleration_noClipPathAllowed() { - int width = 100; - int height = 100; - int radius = 16; - RoundedCorners roundedCorners = RoundedCorners.newBuilder() - .setBitmask(ALL_CORNERS_BITMASK) - .setRadiusDp(radius) - .build(); - CommonRoundedCornerWrapperView view = CommonRoundedCornerWrapperView.builder() - .setRoundedCorners(roundedCorners) - .setHardwareAccelerated(false) - .setAllowClipPath(false) - .build(); - - view.layout(0, 0, width, height); - - assertThat(view.getRoundingStrategy()).isEqualTo(RoundingStrategy.BITMAP_MASKING); - } - - @Test - public void useMaskingStrategy_withHwAcceleration_noClipPathAllowed_noOutlineProviderAllowed() { - int width = 100; - int height = 100; - int radius = 16; - RoundedCorners roundedCorners = RoundedCorners.newBuilder() - .setBitmask(ALL_CORNERS_BITMASK) - .setRadiusDp(radius) - .build(); - CommonRoundedCornerWrapperView view = CommonRoundedCornerWrapperView.builder() - .setRoundedCorners(roundedCorners) - .setHardwareAccelerated(true) - .setAllowClipPath(false) - .setAllowOutlineRounding(false) - .build(); - - view.layout(0, 0, width, height); - - assertThat(view.getRoundingStrategy()).isEqualTo(RoundingStrategy.BITMAP_MASKING); - } - - @Test - public void allowAllRoundingStrategies_shouldChooseOutlineProvider() { - int width = 100; - int height = 100; - int radius = 16; - RoundedCorners roundedCorners = RoundedCorners.newBuilder() - .setBitmask(ALL_CORNERS_BITMASK) - .setRadiusDp(radius) - .build(); - CommonRoundedCornerWrapperView view = CommonRoundedCornerWrapperView.builder() - .setRoundedCorners(roundedCorners) - .setHardwareAccelerated(true) - .setAllowClipPath(true) - .setAllowOutlineRounding(true) - .build(); - - view.layout(0, 0, width, height); - - assertThat(view.getClipToOutline()).isTrue(); - assertThat(view.getClipChildren()).isTrue(); - - assertThat(view.getRoundingStrategy()).isEqualTo(RoundingStrategy.OUTLINE_PROVIDER); - } - - static class CommonRoundedCornerWrapperView extends RoundedCornerWrapperView { - private static final Supplier<Boolean> IS_RTL_SUPPLIER = Suppliers.of(false); - private static final Context CONTEXT = Robolectric.buildActivity(Activity.class).get(); - private final boolean mHardwareAccelerated; - private RoundingStrategy mRoundingStrategy; - - @Override - public boolean isHardwareAccelerated() { - return mHardwareAccelerated; - } - - @Override - public boolean isAttachedToWindow() { - return true; - } - - @Override - void setRoundingDelegate(RoundingStrategy roundingStrategy) { - super.setRoundingDelegate(roundingStrategy); - this.mRoundingStrategy = roundingStrategy; - } - - RoundingStrategy getRoundingStrategy() { - return mRoundingStrategy; - } - - private CommonRoundedCornerWrapperView(Builder builder) { - super(CONTEXT, builder.mRoundedCorners, new RoundedCornerMaskCache(), IS_RTL_SUPPLIER, - builder.mRadiusOverride, builder.mBorders, builder.mAllowClipPath, - builder.mAllowOutlineRounding); - this.mHardwareAccelerated = builder.mHardwareAccelerated; - } - - static CommonRoundedCornerWrapperView getDefaultInstance() { - return new CommonRoundedCornerWrapperView(new CommonRoundedCornerWrapperView.Builder()); - } - - static Builder builder() { - return new CommonRoundedCornerWrapperView.Builder(); - } - - static class Builder { - private boolean mHardwareAccelerated; - - RoundedCorners mRoundedCorners = RoundedCorners.getDefaultInstance(); - int mRadiusOverride; - Borders mBorders = Borders.getDefaultInstance(); - boolean mAllowClipPath = true; - boolean mAllowOutlineRounding = true; - - Builder setHardwareAccelerated(boolean value) { - mHardwareAccelerated = value; - return this; - } - - Builder setRoundedCorners(RoundedCorners value) { - mRoundedCorners = value; - return this; - } - - Builder setRadiusOverride(int value) { - mRadiusOverride = value; - return this; - } - - Builder setBorders(Borders value) { - mBorders = value; - return this; - } - - Builder setAllowClipPath(boolean value) { - mAllowClipPath = value; - return this; - } - - Builder setAllowOutlineRounding(boolean value) { - mAllowOutlineRounding = value; - return this; - } - - CommonRoundedCornerWrapperView build() { - return new CommonRoundedCornerWrapperView(this); - } - } - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/contentchanged/StreamContentChangedListenerTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/contentchanged/StreamContentChangedListenerTest.java deleted file mode 100644 index 763e8972..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/contentchanged/StreamContentChangedListenerTest.java +++ /dev/null
@@ -1,55 +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. - -package org.chromium.chrome.browser.feed.library.sharedstream.contentchanged; - -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.shared.stream.Stream.ContentChangedListener; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** - * Tests for {@link StreamContentChangedListener}. - */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class StreamContentChangedListenerTest { - @Mock - ContentChangedListener mContentChangedListener; - - StreamContentChangedListener mStreamContentChangedListener; - - @Before - public void setup() { - initMocks(this); - mStreamContentChangedListener = new StreamContentChangedListener(); - } - - @Test - public void testOnContentChanged() { - mStreamContentChangedListener.addContentChangedListener(mContentChangedListener); - - mStreamContentChangedListener.onContentChanged(); - - verify(mContentChangedListener).onContentChanged(); - } - - @Test - public void testRemoveContentChangedListener() { - mStreamContentChangedListener.addContentChangedListener(mContentChangedListener); - mStreamContentChangedListener.removeContentChangedListener(mContentChangedListener); - - mStreamContentChangedListener.onContentChanged(); - - verify(mContentChangedListener, never()).onContentChanged(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/contextmenumanager/ContextMenuManagerImplTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/contextmenumanager/ContextMenuManagerImplTest.java deleted file mode 100644 index 36b0a11..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/contextmenumanager/ContextMenuManagerImplTest.java +++ /dev/null
@@ -1,163 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.feed.library.sharedstream.contextmenumanager; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; -import static org.robolectric.Shadows.shadowOf; - -import android.app.Activity; -import android.view.View; -import android.view.View.MeasureSpec; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.FrameLayout; -import android.widget.ListView; -import android.widget.PopupWindow; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentMatchers; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.sharedstream.contextmenumanager.ContextMenuManager.ContextMenuClickHandler; -import org.chromium.chrome.browser.feed.library.sharedstream.publicapi.menumeasurer.MenuMeasurer; -import org.chromium.chrome.browser.feed.library.sharedstream.publicapi.menumeasurer.Size; -import org.chromium.chrome.R; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.ArrayList; -import java.util.List; - -/** Tests for {@link ContextMenuManagerImpl}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ContextMenuManagerImplTest { - private static final int NO_ID = -1; - - @Mock - private MenuMeasurer mMenuMeasurer; - @Mock - private ContextMenuClickHandler mClickHandler; - - private Activity mContext; - private ContextMenuManagerImpl mContextMenuManager; - private FrameLayout mParentView; - private View mAnchorView; - private List<String> mAdapterItems; - - @Before - public void setup() { - initMocks(this); - - mContext = Robolectric.buildActivity(Activity.class).get(); - mContext.setTheme(R.style.Light); - mParentView = new FrameLayout(mContext); - mAnchorView = new View(mContext); - mParentView.addView(mAnchorView); - mContextMenuManager = new ContextMenuManagerImpl(mMenuMeasurer, mContext); - mContextMenuManager.setView(mParentView); - mAdapterItems = mCreateAdapterItems(); - when(mMenuMeasurer.measureAdapterContent(any(ViewGroup.class), - ArgumentMatchers.<ArrayAdapter<? extends Object>>any(), anyInt(), anyInt(), - anyInt())) - .thenReturn(new Size(1, 2)); - } - - @Test - public void testGetHeight() { - mParentView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); - - int top = 25; - int bottom = 150; - mParentView.layout(0, top, 0, bottom); - - assertThat(mContextMenuManager.getStreamHeight()).isEqualTo(bottom - top); - } - - @Test - public void testOpenContextMenu() { - mContextMenuManager.openContextMenu(mAnchorView, mAdapterItems, mClickHandler); - assertThat(shadowOf(mParentView).getDisallowInterceptTouchEvent()).isTrue(); - - PopupWindow popupWindow = shadowOf(mContext.getApplication()).getLatestPopupWindow(); - ListView listView = (ListView) popupWindow.getContentView(); - - assertThat(listView.getAdapter().getItem(0)).isSameInstanceAs(mAdapterItems.get(0)); - assertThat(listView.getAdapter().getItem(1)).isSameInstanceAs(mAdapterItems.get(1)); - assertThat(listView.getAdapter().getItem(2)).isSameInstanceAs(mAdapterItems.get(2)); - - assertThat(popupWindow.isShowing()).isTrue(); - listView.performItemClick(null, /* position= */ 1, NO_ID); - - verify(mClickHandler).handleClick(1); - assertThat(popupWindow.isShowing()).isFalse(); - } - - @Test - public void testOnlyOpensOneMenu() { - // Opens first context menu. - assertThat(mContextMenuManager.openContextMenu(mAnchorView, mAdapterItems, mClickHandler)) - .isTrue(); - - // Won't open a second one while the first one is open. - assertThat(mContextMenuManager.openContextMenu(mAnchorView, mAdapterItems, mClickHandler)) - .isFalse(); - - shadowOf(mContext.getApplication()).getLatestPopupWindow().dismiss(); - - // After the menu is dismissed another can be opened - assertThat(mContextMenuManager.openContextMenu(mAnchorView, mAdapterItems, mClickHandler)) - .isTrue(); - } - - @Test - public void testDismiss_fromLockingPhone() { - mContextMenuManager.openContextMenu(mAnchorView, mAdapterItems, mClickHandler); - - assertThat(shadowOf(mContext.getApplication()).getLatestPopupWindow().isShowing()).isTrue(); - - mContextMenuManager.dismissPopup(); - - assertThat(shadowOf(mContext.getApplication()).getLatestPopupWindow().isShowing()) - .isFalse(); - } - - @Test - public void testClosesMenuWhenDimensionsChange() { - mContextMenuManager.openContextMenu(mAnchorView, mAdapterItems, mClickHandler); - - PopupWindow popupWindow = shadowOf(mContext.getApplication()).getLatestPopupWindow(); - assertThat(popupWindow.isShowing()).isTrue(); - - mContextMenuManager.dismissPopup(); - - assertThat(popupWindow.isShowing()).isFalse(); - } - - @Test - public void testOpenContextMenu_hasShadow() { - mContextMenuManager.openContextMenu(mAnchorView, mAdapterItems, mClickHandler); - - PopupWindow popupWindow = shadowOf(mContext.getApplication()).getLatestPopupWindow(); - assertThat(popupWindow.getBackground()).isNotNull(); - } - - private List<String> mCreateAdapterItems() { - List<String> adapter = new ArrayList<>(); - for (int i = 0; i < 3; i++) { - adapter.add(String.valueOf(i)); - } - return adapter; - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/contextmenumanager/FloatingContextMenuManagerTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/contextmenumanager/FloatingContextMenuManagerTest.java deleted file mode 100644 index 70543e82..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/contextmenumanager/FloatingContextMenuManagerTest.java +++ /dev/null
@@ -1,126 +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. - -package org.chromium.chrome.browser.feed.library.sharedstream.contextmenumanager; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.verify; -import static org.mockito.MockitoAnnotations.initMocks; -import static org.robolectric.Shadows.shadowOf; - -import android.app.Activity; -import android.app.AlertDialog; -import android.content.Context; -import android.content.DialogInterface.OnClickListener; -import android.view.View; -import android.widget.FrameLayout; -import android.widget.ListAdapter; -import android.widget.ListView; - -import com.google.common.collect.ImmutableList; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; -import org.robolectric.shadows.ShadowAlertDialog; - -import org.chromium.chrome.browser.feed.library.sharedstream.contextmenumanager.ContextMenuManager.ContextMenuClickHandler; -import org.chromium.chrome.R; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link ContextMenuManagerImpl}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class FloatingContextMenuManagerTest { - private static final ImmutableList<String> ITEMS = ImmutableList.of("1", "2", "3"); - - private Context mContext; - private FloatingContextMenuManager mContextMenuManager; - @Mock - private ContextMenuClickHandler mHandler; - private View mAnchorView; - - @Before - public void createContextMenuManager() { - initMocks(this); - mContext = Robolectric.buildActivity(Activity.class).get(); - mContext.setTheme(R.style.Light); - mContextMenuManager = new FloatingContextMenuManager(mContext); - mAnchorView = new View(mContext); - } - - @Test - public void openContextMenu_opensContextMenu() { - mContextMenuManager.openContextMenu(mAnchorView, ITEMS, mHandler); - - assertThat(ShadowAlertDialog.getLatestAlertDialog()).isNotNull(); - } - - @Test - public void performClick_triggersClickHandler() { - mContextMenuManager.openContextMenu(mAnchorView, ITEMS, mHandler); - - performClick(0); - - verify(mHandler).handleClick(0); - } - - @Test - public void performClick_dismissesMenu() { - mContextMenuManager.openContextMenu(mAnchorView, ITEMS, mHandler); - - // Should dismiss the menu. - performClick(1); - - // Should open a new menu, as the old one has been dismissed. - assertThat(mContextMenuManager.openContextMenu(mAnchorView, ITEMS, mHandler)).isTrue(); - } - - @Test - public void openContextMenu_multipleTimes_onlyOpensFirstMenu() { - mContextMenuManager.openContextMenu(mAnchorView, ITEMS, mHandler); - - // Fails to open as another menu is showing. - assertThat(mContextMenuManager.openContextMenu(mAnchorView, ImmutableList.of(), mHandler)) - .isFalse(); - } - - @Test - public void openContextMenu_disallowsInterceptTouchEvent() { - FrameLayout parent = new FrameLayout(mContext); - parent.addView(mAnchorView); - - mContextMenuManager.openContextMenu(mAnchorView, ITEMS, mHandler); - - assertThat(shadowOf(parent).getDisallowInterceptTouchEvent()).isTrue(); - } - - @Test - public void dismissPopup_dismissesPopup() { - mContextMenuManager.openContextMenu(mAnchorView, ITEMS, mHandler); - - mContextMenuManager.dismissPopup(); - - assertThat(mContextMenuManager.openContextMenu(mAnchorView, ITEMS, mHandler)).isTrue(); - } - - /** - * Utility method to perform click on an index. Using the normal methods didn't seem to work, - * probably because we set the {@link ListView} via {@link AlertDialog.Builder#setView(View)} - * instead of {@link AlertDialog.Builder#setAdapter(ListAdapter, OnClickListener)} so it doesn't - * know that the view is a {@link ListView} - */ - private void performClick(int index) { - AlertDialog dialog = ShadowAlertDialog.getLatestAlertDialog(); - - // Can't just use shadowAlertDialog.getListView, which returns null, as does performing the - // click on the shadow. - ListView listView = (ListView) shadowOf(dialog).getView(); - listView.performItemClick(/* view= */ null, index, /* id= */ -1); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/deepestcontenttracker/DeepestContentTrackerTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/deepestcontenttracker/DeepestContentTrackerTest.java deleted file mode 100644 index be02622c..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/deepestcontenttracker/DeepestContentTrackerTest.java +++ /dev/null
@@ -1,120 +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. - -package org.chromium.chrome.browser.feed.library.sharedstream.deepestcontenttracker; - -import static com.google.common.truth.Truth.assertThat; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link DeepestContentTracker}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class DeepestContentTrackerTest { - private static final String CONTENT_ID_1 = "CONTENT_ID_1"; - private static final String CONTENT_ID_2 = "CONTENT_ID_2"; - private static final String CONTENT_ID_3 = "CONTENT_ID_3"; - - private DeepestContentTracker mDeepestContentTracker; - - @Before - public void setUp() { - mDeepestContentTracker = new DeepestContentTracker(); - } - - @Test - public void testUpdateDeepestContentTracker() { - mDeepestContentTracker.updateDeepestContentTracker(0, CONTENT_ID_1); - - assertThat(mDeepestContentTracker.getChildViewDepth()).isEqualTo(CONTENT_ID_1); - } - - @Test - public void testUpdateDeepestContentTracker_updatesFromDeeperContent() { - mDeepestContentTracker.updateDeepestContentTracker(0, CONTENT_ID_1); - mDeepestContentTracker.updateDeepestContentTracker(1, CONTENT_ID_2); - - assertThat(mDeepestContentTracker.getChildViewDepth()).isEqualTo(CONTENT_ID_2); - } - - @Test - public void testUpdateDeepestContentTracker_doesNotAddContentIdIfAlreadyTracked() { - mDeepestContentTracker.updateDeepestContentTracker(0, CONTENT_ID_2); - mDeepestContentTracker.updateDeepestContentTracker(1, CONTENT_ID_1); - mDeepestContentTracker.updateDeepestContentTracker(0, CONTENT_ID_2); - - assertThat(mDeepestContentTracker.getChildViewDepth()).isEqualTo(CONTENT_ID_1); - } - - @Test - public void testUpdateDeepestContentTracker_ignoresNullContentId() { - mDeepestContentTracker.updateDeepestContentTracker(0, CONTENT_ID_1); - mDeepestContentTracker.updateDeepestContentTracker(1, /* contentId= */ null); - - assertThat(mDeepestContentTracker.getChildViewDepth()).isEqualTo(CONTENT_ID_1); - } - - @Test - public void testUpdateDeepestContentTracker_updatingPreviousKnownPosition() { - mDeepestContentTracker.updateDeepestContentTracker(0, CONTENT_ID_1); - mDeepestContentTracker.updateDeepestContentTracker(1, CONTENT_ID_2); - mDeepestContentTracker.updateDeepestContentTracker(0, CONTENT_ID_3); - - assertThat(mDeepestContentTracker.getContentItAtPosition(0)).isEqualTo(CONTENT_ID_3); - } - - @Test - public void testUpdateDeepestContentTracker_sparsePopulate() { - mDeepestContentTracker.updateDeepestContentTracker(1, CONTENT_ID_2); - - assertThat(mDeepestContentTracker.getContentItAtPosition(0)).isNull(); - assertThat(mDeepestContentTracker.getContentItAtPosition(1)).isEqualTo(CONTENT_ID_2); - - mDeepestContentTracker.updateDeepestContentTracker(0, CONTENT_ID_1); - assertThat(mDeepestContentTracker.getContentItAtPosition(0)).isEqualTo(CONTENT_ID_1); - } - - @Test - public void testRemoveContentId() { - mDeepestContentTracker.updateDeepestContentTracker(0, CONTENT_ID_1); - mDeepestContentTracker.updateDeepestContentTracker(1, CONTENT_ID_2); - - mDeepestContentTracker.removeContentId(1); - - assertThat(mDeepestContentTracker.getChildViewDepth()).isEqualTo(CONTENT_ID_1); - } - - @Test - public void testRemoveContentId_removingShallowerContentIdRetainsDeeperId() { - mDeepestContentTracker.updateDeepestContentTracker(0, CONTENT_ID_1); - mDeepestContentTracker.updateDeepestContentTracker(1, CONTENT_ID_2); - - mDeepestContentTracker.removeContentId(0); - - assertThat(mDeepestContentTracker.getChildViewDepth()).isEqualTo(CONTENT_ID_2); - } - - @Test - public void testRemoveContentId_doesNotRemoveContentId() { - mDeepestContentTracker.updateDeepestContentTracker(0, CONTENT_ID_1); - - mDeepestContentTracker.removeContentId(1); - - assertThat(mDeepestContentTracker.getChildViewDepth()).isEqualTo(CONTENT_ID_1); - } - - @Test - public void testReset() { - mDeepestContentTracker.updateDeepestContentTracker(0, CONTENT_ID_1); - - mDeepestContentTracker.reset(); - - assertThat(mDeepestContentTracker.getChildViewDepth()).isNull(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/logging/OneShotVisibilityLoggingListenerTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/logging/OneShotVisibilityLoggingListenerTest.java deleted file mode 100644 index 1a47944..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/logging/OneShotVisibilityLoggingListenerTest.java +++ /dev/null
@@ -1,58 +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. - -package org.chromium.chrome.browser.feed.library.sharedstream.logging; - -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.verify; -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link OneShotVisibilityLoggingListener}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class OneShotVisibilityLoggingListenerTest { - @Mock - private LoggingListener mLoggingListener; - - private OneShotVisibilityLoggingListener mOneShotVisibilityLoggingListener; - - @Before - public void setUp() { - initMocks(this); - mOneShotVisibilityLoggingListener = new OneShotVisibilityLoggingListener(mLoggingListener); - } - - @Test - public void testOnViewVisible() { - mOneShotVisibilityLoggingListener.onViewVisible(); - - verify(mLoggingListener).onViewVisible(); - } - - @Test - public void testOnViewVisible_onlyNotifiesListenerOnce() { - mOneShotVisibilityLoggingListener.onViewVisible(); - reset(mLoggingListener); - - mOneShotVisibilityLoggingListener.onViewVisible(); - - verify(mLoggingListener, never()).onViewVisible(); - } - - @Test - public void testOnContentClicked() { - mOneShotVisibilityLoggingListener.onContentClicked(); - - verify(mLoggingListener).onContentClicked(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/logging/SpinnerLoggerTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/logging/SpinnerLoggerTest.java deleted file mode 100644 index 4ad3fde0..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/logging/SpinnerLoggerTest.java +++ /dev/null
@@ -1,113 +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. - -package org.chromium.chrome.browser.feed.library.sharedstream.logging; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.verify; -import static org.mockito.MockitoAnnotations.initMocks; - -import static org.chromium.chrome.browser.feed.library.common.testing.RunnableSubject.assertThatRunnable; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.logging.BasicLoggingApi; -import org.chromium.chrome.browser.feed.library.api.host.logging.SpinnerType; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link SpinnerLogger}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class SpinnerLoggerTest { - private static final long START_TIME = 1000; - private static final int SPINNER_TIME = 500; - - @Mock - private BasicLoggingApi mBasicLoggingApi; - private FakeClock mClock; - private SpinnerLogger mSpinnerLogger; - - @Before - public void setUp() { - initMocks(this); - mClock = new FakeClock(); - mClock.set(START_TIME); - - mSpinnerLogger = new SpinnerLogger(mBasicLoggingApi, mClock); - } - - @Test - public void spinnerStarted_logsSpinnerStarted() { - mSpinnerLogger.spinnerStarted(SpinnerType.INITIAL_LOAD); - - verify(mBasicLoggingApi).onSpinnerStarted(SpinnerType.INITIAL_LOAD); - } - - @Test - public void spinnerStarted_twice_throwsException() { - mSpinnerLogger.spinnerStarted(SpinnerType.INITIAL_LOAD); - - assertThatRunnable(() -> mSpinnerLogger.spinnerStarted(SpinnerType.INITIAL_LOAD)) - .throwsAnExceptionOfType(RuntimeException.class); - } - - @Test - public void spinnerFinished_logsOnSpinnerFinished_ifSpinnerStartedCalledBefore() { - mSpinnerLogger.spinnerStarted(SpinnerType.INITIAL_LOAD); - mClock.advance(SPINNER_TIME); - - mSpinnerLogger.spinnerFinished(); - - verify(mBasicLoggingApi).onSpinnerFinished(SPINNER_TIME, SpinnerType.INITIAL_LOAD); - } - - @Test - public void spinnerFinished_beforeStarting_throwsException() { - assertThatRunnable(() -> mSpinnerLogger.spinnerFinished()) - .throwsAnExceptionOfType(RuntimeException.class); - } - - @Test - public void spinnerDestroyedWithoutCompleting_logsOnSpinnerDestroyedWithoutCompleting() { - mSpinnerLogger.spinnerStarted(SpinnerType.MORE_BUTTON); - mClock.advance(SPINNER_TIME); - - mSpinnerLogger.spinnerDestroyedWithoutCompleting(); - - verify(mBasicLoggingApi) - .onSpinnerDestroyedWithoutCompleting(SPINNER_TIME, SpinnerType.MORE_BUTTON); - } - - @Test - public void spinnerDestroyed_beforeStarting_throwsException() { - assertThatRunnable(() -> mSpinnerLogger.spinnerDestroyedWithoutCompleting()) - .throwsAnExceptionOfType(RuntimeException.class); - } - - @Test - public void isSpinnerActive_returnsTrue_ifSpinnerStartedCalledBefore() { - mSpinnerLogger.spinnerStarted(SpinnerType.INITIAL_LOAD); - - assertThat(mSpinnerLogger.isSpinnerActive()).isTrue(); - } - - @Test - public void isSpinnerActive_returnsFalseInitially() { - assertThat(mSpinnerLogger.isSpinnerActive()).isFalse(); - } - - @Test - public void isSpinnerActive_returnsFalse_ifSpinnerFinishedCalledBefore() { - mSpinnerLogger.spinnerStarted(SpinnerType.INITIAL_LOAD); - mSpinnerLogger.spinnerFinished(); - - assertThat(mSpinnerLogger.isSpinnerActive()).isFalse(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/logging/UiSessionRequestLoggerTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/logging/UiSessionRequestLoggerTest.java deleted file mode 100644 index ea32966..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/logging/UiSessionRequestLoggerTest.java +++ /dev/null
@@ -1,147 +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. - -package org.chromium.chrome.browser.feed.library.sharedstream.logging; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.verify; -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.InOrder; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.logging.BasicLoggingApi; -import org.chromium.chrome.browser.feed.library.api.host.logging.SessionEvent; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelError; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelError.ErrorType; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.testing.modelprovider.FakeModelFeature; -import org.chromium.chrome.browser.feed.library.testing.modelprovider.FakeModelProvider; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link UiSessionRequestLogger}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class UiSessionRequestLoggerTest { - private static final long SESSION_EVENT_DELAY = 123L; - private static final ModelError MODEL_ERROR = - new ModelError(ErrorType.UNKNOWN, /* continuationToken= */ null); - private static final FakeModelFeature MODEL_FEATURE = FakeModelFeature.newBuilder().build(); - - @Mock - private BasicLoggingApi mBasicLoggingApi; - - private FakeClock mClock; - private UiSessionRequestLogger mUiSessionRequestLogger; - private FakeModelProvider mModelProvider; - - @Before - public void setUp() { - initMocks(this); - mClock = new FakeClock(); - mModelProvider = new FakeModelProvider(); - mUiSessionRequestLogger = new UiSessionRequestLogger(mClock, mBasicLoggingApi); - } - - @Test - public void testOnSessionRequested_onSessionStart_logsSessionStart() { - mUiSessionRequestLogger.onSessionRequested(mModelProvider); - mClock.advance(SESSION_EVENT_DELAY); - - mModelProvider.triggerOnSessionStart(MODEL_FEATURE); - - verify(mBasicLoggingApi) - .onInitialSessionEvent( - SessionEvent.STARTED, (int) SESSION_EVENT_DELAY, /* sessionCount= */ 1); - assertThat(mModelProvider.getObservers()).isEmpty(); - } - - @Test - public void testOnSessionRequested_onSessionFinished_logsSessionStart() { - mUiSessionRequestLogger.onSessionRequested(mModelProvider); - mClock.advance(SESSION_EVENT_DELAY); - - mModelProvider.triggerOnSessionFinished(); - - verify(mBasicLoggingApi) - .onInitialSessionEvent(SessionEvent.FINISHED_IMMEDIATELY, (int) SESSION_EVENT_DELAY, - /* sessionCount= */ 1); - assertThat(mModelProvider.getObservers()).isEmpty(); - } - - @Test - public void testOnSessionRequested_onSessionError_logsSessionStart() { - mUiSessionRequestLogger.onSessionRequested(mModelProvider); - mClock.advance(SESSION_EVENT_DELAY); - - mModelProvider.triggerOnError(MODEL_ERROR); - - verify(mBasicLoggingApi) - .onInitialSessionEvent( - SessionEvent.ERROR, (int) SESSION_EVENT_DELAY, /* sessionCount= */ 1); - assertThat(mModelProvider.getObservers()).isEmpty(); - } - - @Test - public void testOnSessionRequested_onDestroy_logsDestroy() { - mUiSessionRequestLogger.onSessionRequested(mModelProvider); - mClock.advance(SESSION_EVENT_DELAY); - - mUiSessionRequestLogger.onDestroy(); - - verify(mBasicLoggingApi) - .onInitialSessionEvent(SessionEvent.USER_ABANDONED, (int) SESSION_EVENT_DELAY, - /* sessionCount= */ 1); - assertThat(mModelProvider.getObservers()).isEmpty(); - } - - @Test - public void testMultipleSessions_incrementsSessionCount() { - mUiSessionRequestLogger.onSessionRequested(mModelProvider); - mModelProvider.triggerOnSessionStart(MODEL_FEATURE); - - mUiSessionRequestLogger.onSessionRequested(mModelProvider); - mModelProvider.triggerOnSessionFinished(); - - mUiSessionRequestLogger.onSessionRequested(mModelProvider); - mModelProvider.triggerOnError(MODEL_ERROR); - - InOrder inOrder = inOrder(mBasicLoggingApi); - - inOrder.verify(mBasicLoggingApi) - .onInitialSessionEvent(eq(SessionEvent.STARTED), anyInt(), eq(1)); - inOrder.verify(mBasicLoggingApi) - .onInitialSessionEvent(eq(SessionEvent.FINISHED_IMMEDIATELY), anyInt(), eq(2)); - inOrder.verify(mBasicLoggingApi) - .onInitialSessionEvent(eq(SessionEvent.ERROR), anyInt(), eq(3)); - } - - @Test - public void testOnSessionRequested_immediatelyTriggerSessionStart_logsSessionStart() { - mModelProvider.triggerOnSessionStartImmediately(MODEL_FEATURE); - - mUiSessionRequestLogger.onSessionRequested(mModelProvider); - - // The ModelProvider will sometimes trigger onSessionStart() immediately when a listener is - // registered. This tests that that situation is appropriately logged. - verify(mBasicLoggingApi).onInitialSessionEvent(SessionEvent.STARTED, 0, 1); - } - - @Test - public void testOnSessionRequested_twice_deregistersFromFirstModelProvider() { - mUiSessionRequestLogger.onSessionRequested(mModelProvider); - - mUiSessionRequestLogger.onSessionRequested(new FakeModelProvider()); - - assertThat(mModelProvider.getObservers()).isEmpty(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/logging/VisibilityMonitorTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/logging/VisibilityMonitorTest.java deleted file mode 100644 index 1b400f35..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/logging/VisibilityMonitorTest.java +++ /dev/null
@@ -1,142 +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. - -package org.chromium.chrome.browser.feed.library.sharedstream.logging; - -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.verify; -import static org.mockito.MockitoAnnotations.initMocks; - -import android.app.Activity; -import android.graphics.Point; -import android.graphics.Rect; -import android.view.View; -import android.view.ViewGroup; -import android.widget.FrameLayout; -import android.widget.FrameLayout.LayoutParams; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration.ConfigKey; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link VisibilityMonitor}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class VisibilityMonitorTest { - private static final Configuration CONFIGURATION = - new Configuration.Builder().put(ConfigKey.VIEW_LOG_THRESHOLD, .50).build(); - private static final int VIEW_HEIGHT = 100; - private static final int VIEW_WIDTH = 50; - - @Mock - private VisibilityListener mVisibilityListener; - - private Activity mContext; - private ViewGroup mParentView; - private View mView; - private VisibilityMonitor mVisibilityMonitor; - - @Before - public void setUp() { - initMocks(this); - mContext = Robolectric.setupActivity(Activity.class); - - setUpViews(((child, r, offset) -> { - r.set(0, 0, VIEW_WIDTH, VIEW_HEIGHT); - return true; - })); - } - - @Test - public void testPreDraw_notifiesListener() { - mContext.setContentView(mParentView); - - mVisibilityMonitor.onPreDraw(); - - verify(mVisibilityListener).onViewVisible(); - } - - @Test - public void testPreDraw_notifiesListenerIfVisibleViewHeightIsAtThreshold() { - setUpViews((child, r, offset) -> { - r.set(0, 0, VIEW_WIDTH, 50); - return true; - }); - mContext.setContentView(mParentView); - - mVisibilityMonitor.onPreDraw(); - - verify(mVisibilityListener).onViewVisible(); - } - - @Test - public void testPreDraw_doesNotNotifyListenerIfAlreadyVisible() { - mContext.setContentView(mParentView); - mVisibilityMonitor.onPreDraw(); - reset(mVisibilityListener); - - mVisibilityMonitor.onPreDraw(); - - verify(mVisibilityListener, never()).onViewVisible(); - } - - @Test - public void testPreDraw_doesNotNotifyListenerIfVisibleViewHeightIsBelowThreshold() { - setUpViews((child, r, offset) -> { - r.set(0, 0, VIEW_WIDTH, 49); - return true; - }); - mContext.setContentView(mParentView); - - mVisibilityMonitor.onPreDraw(); - - verify(mVisibilityListener, never()).onViewVisible(); - } - - @Test - public void testPreDraw_doesNotNotifyListenerIfViewNotAttached() { - setUpViews((child, r, offset) -> false); - - mVisibilityMonitor.onPreDraw(); - - verify(mVisibilityListener, never()).onViewVisible(); - } - - @Test - public void testPreDraw_doesNotNotifyListenerIfParentIsNull() { - mVisibilityMonitor = new VisibilityMonitor(new FrameLayout(mContext), CONFIGURATION); - mVisibilityMonitor.setListener(null); - - mVisibilityMonitor.onPreDraw(); - - verify(mVisibilityListener, never()).onViewVisible(); - } - - private void setUpViews(ChildVisibleRectMock childVisibleRectMock) { - mView = new FrameLayout(mContext); - mView.setLayoutParams(new LayoutParams(VIEW_WIDTH, VIEW_HEIGHT)); - mParentView = new FrameLayout(mContext) { - @Override - public boolean getChildVisibleRect(View child, Rect r, Point offset) { - return childVisibleRectMock.getChildVisibleRect(child, r, offset); - } - }; - - mParentView.addView(mView); - mVisibilityMonitor = new VisibilityMonitor(mView, CONFIGURATION); - mVisibilityMonitor.setListener(mVisibilityListener); - } - - interface ChildVisibleRectMock { - boolean getChildVisibleRect(View child, Rect r, Point offset); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/offlinemonitor/StreamOfflineMonitorTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/offlinemonitor/StreamOfflineMonitorTest.java deleted file mode 100644 index 9fa629f2..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/offlinemonitor/StreamOfflineMonitorTest.java +++ /dev/null
@@ -1,177 +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. - -package org.chromium.chrome.browser.feed.library.sharedstream.offlinemonitor; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.ArgumentMatchers; -import org.mockito.Captor; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.base.Consumer; -import org.chromium.chrome.browser.feed.library.api.host.offlineindicator.OfflineIndicatorApi; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -/** Tests for {@link StreamOfflineMonitor}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class StreamOfflineMonitorTest { - private static final String URL = "google.com"; - - @Mock - private Consumer<Boolean> mOfflineStatusConsumer1; - @Mock - private Consumer<Boolean> mOfflineStatusConsumer2; - @Mock - private OfflineIndicatorApi mOfflineIndicatorApi; - @Captor - private ArgumentCaptor<List<String>> mListArgumentCaptor; - - private StreamOfflineMonitor mStreamOfflineMonitor; - - @Before - public void setup() { - initMocks(this); - mStreamOfflineMonitor = new StreamOfflineMonitor(mOfflineIndicatorApi); - } - - @Test - public void testIsAvailableOffline() { - assertThat(mStreamOfflineMonitor.isAvailableOffline(URL)).isFalse(); - mStreamOfflineMonitor.updateOfflineStatus(URL, true); - assertThat(mStreamOfflineMonitor.isAvailableOffline(URL)).isTrue(); - mStreamOfflineMonitor.updateOfflineStatus(URL, false); - assertThat(mStreamOfflineMonitor.isAvailableOffline(URL)).isFalse(); - } - - @Test - public void testNotifyListeners() { - mStreamOfflineMonitor.addOfflineStatusConsumer(URL, mOfflineStatusConsumer1); - - mStreamOfflineMonitor.updateOfflineStatus(URL, true); - - verify(mOfflineStatusConsumer1).accept(true); - - mStreamOfflineMonitor.updateOfflineStatus(URL, false); - - verify(mOfflineStatusConsumer1).accept(false); - } - - @Test - public void testNotify_multipleListeners() { - mStreamOfflineMonitor.addOfflineStatusConsumer(URL, mOfflineStatusConsumer1); - mStreamOfflineMonitor.addOfflineStatusConsumer(URL, mOfflineStatusConsumer2); - mStreamOfflineMonitor.updateOfflineStatus(URL, true); - - verify(mOfflineStatusConsumer1).accept(true); - verify(mOfflineStatusConsumer2).accept(true); - } - - @Test - public void testRemoveConsumer() { - mStreamOfflineMonitor.addOfflineStatusConsumer(URL, mOfflineStatusConsumer1); - - mStreamOfflineMonitor.removeOfflineStatusConsumer(URL, mOfflineStatusConsumer1); - - mStreamOfflineMonitor.updateOfflineStatus(URL, true); - - verify(mOfflineStatusConsumer1, never()).accept(anyBoolean()); - } - - @Test - public void testNotifyOnlyOnce() { - mStreamOfflineMonitor.addOfflineStatusConsumer(URL, mOfflineStatusConsumer1); - - mStreamOfflineMonitor.updateOfflineStatus(URL, true); - mStreamOfflineMonitor.updateOfflineStatus(URL, true); - mStreamOfflineMonitor.updateOfflineStatus(URL, false); - mStreamOfflineMonitor.updateOfflineStatus(URL, false); - - verify(mOfflineStatusConsumer1, times(1)).accept(true); - verify(mOfflineStatusConsumer1, times(1)).accept(false); - } - - @Test - public void testRequestOfflineStatusForNewContent() { - String url1 = "gmail.com"; - String url2 = "mail.google.com"; - - // Checking if they are offline adds them to the list of articles the StreamOfflineMonitor - // will ask about. - mStreamOfflineMonitor.isAvailableOffline(URL); - mStreamOfflineMonitor.isAvailableOffline(url1); - mStreamOfflineMonitor.isAvailableOffline(url2); - - mStreamOfflineMonitor.requestOfflineStatusForNewContent(); - verify(mOfflineIndicatorApi) - .getOfflineStatus(mListArgumentCaptor.capture(), - ArgumentMatchers.<Consumer<List<String>>>any()); - - assertThat(mListArgumentCaptor.getValue()) - .containsExactlyElementsIn(Arrays.asList(URL, url1, url2)); - } - - @Test - public void testRequestOfflineStatusForNewContent_onlyRequestsOnce() { - // Checking if it is offline adds it to the list of articles the StreamOfflineMonitor will - // ask about. - mStreamOfflineMonitor.isAvailableOffline(URL); - - mStreamOfflineMonitor.requestOfflineStatusForNewContent(); - reset(mOfflineIndicatorApi); - - mStreamOfflineMonitor.requestOfflineStatusForNewContent(); - - verify(mOfflineIndicatorApi, never()) - .getOfflineStatus(eq(Collections.emptyList()), - ArgumentMatchers.<Consumer<List<String>>>any()); - } - - @Test - public void testRequestOfflineStatusForNewContent_noUrls() { - mStreamOfflineMonitor.requestOfflineStatusForNewContent(); - - verify(mOfflineIndicatorApi, never()) - .getOfflineStatus(eq(Collections.emptyList()), - ArgumentMatchers.<Consumer<List<String>>>any()); - } - - @Test - public void testOnDestroy_clearsConsumersMap() { - mStreamOfflineMonitor.addOfflineStatusConsumer(URL, mOfflineStatusConsumer1); - - // Should clear out all listeners - mStreamOfflineMonitor.onDestroy(); - - mStreamOfflineMonitor.updateOfflineStatus(URL, true); - - verifyZeroInteractions(mOfflineStatusConsumer1); - } - - @Test - public void testOnDestroy_detachesFromApi() { - mStreamOfflineMonitor.onDestroy(); - - verify(mOfflineIndicatorApi).removeOfflineStatusListener(mStreamOfflineMonitor); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/piet/PietCustomElementProviderTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/piet/PietCustomElementProviderTest.java deleted file mode 100644 index 406b12cf..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/piet/PietCustomElementProviderTest.java +++ /dev/null
@@ -1,84 +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. - -package org.chromium.chrome.browser.feed.library.sharedstream.piet; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import android.app.Activity; -import android.content.Context; -import android.view.View; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.piet.host.CustomElementProvider; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.CustomElementData; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link PietCustomElementProvider}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class PietCustomElementProviderTest { - @Mock - private CustomElementProvider mHostCustomElementProvider; - - private Context mContext; - private View mHostCreatedView; - private PietCustomElementProvider mCustomElementProvider; - private PietCustomElementProvider mDelegatingCustomElementProvider; - - @Before - public void setUp() { - initMocks(this); - - mContext = Robolectric.buildActivity(Activity.class).get(); - mHostCreatedView = new View(mContext); - mCustomElementProvider = - new PietCustomElementProvider(mContext, /* customElementProvider */ null); - mDelegatingCustomElementProvider = - new PietCustomElementProvider(mContext, mHostCustomElementProvider); - } - - @Test - public void testCreateCustomElement_noHostDelegate() { - View view = - mCustomElementProvider.createCustomElement(CustomElementData.getDefaultInstance()); - assertThat(view).isNotNull(); - } - - @Test - public void testCreateCustomElement_hostDelegate() { - CustomElementData customElementData = CustomElementData.getDefaultInstance(); - when(mHostCustomElementProvider.createCustomElement(customElementData)) - .thenReturn(mHostCreatedView); - - View view = mDelegatingCustomElementProvider.createCustomElement(customElementData); - assertThat(view).isEqualTo(mHostCreatedView); - } - - @Test - public void testReleaseView_noHostDelegate() { - mCustomElementProvider.releaseCustomView( - new View(mContext), CustomElementData.getDefaultInstance()); - - // Above call should not throw - } - - @Test - public void testReleaseView_hostDelegate() { - CustomElementData customElementData = CustomElementData.newBuilder().build(); - mDelegatingCustomElementProvider.releaseCustomView(mHostCreatedView, customElementData); - - verify(mHostCustomElementProvider).releaseCustomView(mHostCreatedView, customElementData); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/piet/PietEventLoggerTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/piet/PietEventLoggerTest.java deleted file mode 100644 index 335f849..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/piet/PietEventLoggerTest.java +++ /dev/null
@@ -1,34 +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. -package org.chromium.chrome.browser.feed.library.sharedstream.piet; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.logging.BasicLoggingApi; -import org.chromium.components.feed.core.proto.ui.piet.ErrorsProto.ErrorCode; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.Collections; - -/** Tests for {@link PietEventLogger}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class PietEventLoggerTest { - @Test - public void testLogging() { - BasicLoggingApi basicLoggingApi = mock(BasicLoggingApi.class); - PietEventLogger logger = new PietEventLogger(basicLoggingApi); - - logger.logEvents(Collections.singletonList(ErrorCode.ERR_MISSING_BINDING_VALUE)); - - verify(basicLoggingApi) - .onPietFrameRenderingEvent( - Collections.singletonList(ErrorCode.ERR_MISSING_BINDING_VALUE_VALUE)); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/piet/PietHostBindingProviderTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/piet/PietHostBindingProviderTest.java deleted file mode 100644 index c4dea35..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/piet/PietHostBindingProviderTest.java +++ /dev/null
@@ -1,255 +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. - -package org.chromium.chrome.browser.feed.library.sharedstream.piet; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.piet.host.HostBindingProvider; -import org.chromium.chrome.browser.feed.library.sharedstream.offlinemonitor.StreamOfflineMonitor; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.BindingValue; -import org.chromium.components.feed.core.proto.ui.piet.ElementsProto.HostBindingData; -import org.chromium.components.feed.core.proto.ui.piet.TextProto.ParameterizedText; -import org.chromium.components.feed.core.proto.ui.stream.StreamOfflineExtensionProto.OfflineExtension; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link PietHostBindingProvider}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class PietHostBindingProviderTest { - private static final String URL = "url"; - private static final BindingValue OFFLINE_BINDING_VISIBILITY = - BindingValue.newBuilder().setBindingId("offline").build(); - private static final BindingValue NOT_OFFLINE_BINDING_VISIBILITY = - BindingValue.newBuilder().setBindingId("not-offline").build(); - public static final BindingValue OFFLINE_INDICATOR_BINDING = - BindingValue.newBuilder() - .setHostBindingData(HostBindingData.newBuilder().setExtension( - OfflineExtension.offlineExtension, - OfflineExtension.newBuilder() - .setUrl(URL) - .setOfflineBinding(OFFLINE_BINDING_VISIBILITY) - .setNotOfflineBinding(NOT_OFFLINE_BINDING_VISIBILITY) - .build())) - .build(); - - @Mock - private HostBindingProvider mHostHostBindingProvider; - @Mock - private StreamOfflineMonitor mOfflineMonitor; - - private static final ParameterizedText TEXT_PAYLOAD = - ParameterizedText.newBuilder().setText("foo").build(); - - private static final BindingValue BINDING_WITH_HOST_DATA = - BindingValue.newBuilder() - .setHostBindingData(HostBindingData.newBuilder()) - .setParameterizedText(TEXT_PAYLOAD) - .build(); - private static final BindingValue BINDING_WITHOUT_HOST_DATA = - BindingValue.newBuilder().setParameterizedText(TEXT_PAYLOAD).build(); - - private PietHostBindingProvider mHostBindingProvider; - private PietHostBindingProvider mDelegatingHostBindingProvider; - - @Before - public void setUp() { - initMocks(this); - - mHostBindingProvider = - new PietHostBindingProvider(/* hostBindingProvider */ null, mOfflineMonitor); - mDelegatingHostBindingProvider = - new PietHostBindingProvider(mHostHostBindingProvider, mOfflineMonitor); - } - - @Test - public void testGetCustomElementDataBindingForValue() { - assertThat(mHostBindingProvider.getCustomElementDataBindingForValue(BINDING_WITH_HOST_DATA)) - .isEqualTo(BINDING_WITHOUT_HOST_DATA); - } - - @Test - public void testGetCustomElementDataBindingForValue_delegating() { - BindingValue hostBinding = BindingValue.newBuilder().setBindingId("custom-element").build(); - when(mHostHostBindingProvider.getCustomElementDataBindingForValue(BINDING_WITH_HOST_DATA)) - .thenReturn(hostBinding); - - assertThat(mDelegatingHostBindingProvider.getCustomElementDataBindingForValue( - BINDING_WITH_HOST_DATA)) - .isEqualTo(hostBinding); - } - - @Test - public void testGetParameterizedTextBindingForValue() { - assertThat(mHostBindingProvider.getParameterizedTextBindingForValue(BINDING_WITH_HOST_DATA)) - .isEqualTo(BINDING_WITHOUT_HOST_DATA); - } - - @Test - public void testGetParameterizedTextBindingForValue_delegating() { - BindingValue hostBinding = - BindingValue.newBuilder().setBindingId("parameterized-text").build(); - when(mHostHostBindingProvider.getParameterizedTextBindingForValue(BINDING_WITH_HOST_DATA)) - .thenReturn(hostBinding); - - assertThat(mDelegatingHostBindingProvider.getParameterizedTextBindingForValue( - BINDING_WITH_HOST_DATA)) - .isEqualTo(hostBinding); - } - - @Test - public void testGetChunkedTextBindingForValue() { - assertThat(mHostBindingProvider.getChunkedTextBindingForValue(BINDING_WITH_HOST_DATA)) - .isEqualTo(BINDING_WITHOUT_HOST_DATA); - } - - @Test - public void testGetChunkedTextBindingForValue_delegating() { - BindingValue hostBinding = BindingValue.newBuilder().setBindingId("chunked-text").build(); - when(mHostHostBindingProvider.getChunkedTextBindingForValue(BINDING_WITH_HOST_DATA)) - .thenReturn(hostBinding); - - assertThat(mDelegatingHostBindingProvider.getChunkedTextBindingForValue( - BINDING_WITH_HOST_DATA)) - .isEqualTo(hostBinding); - } - - @Test - public void testGetImageBindingForValue() { - assertThat(mHostBindingProvider.getChunkedTextBindingForValue(BINDING_WITH_HOST_DATA)) - .isEqualTo(BINDING_WITHOUT_HOST_DATA); - } - - @Test - public void testGetImageBindingForValue_delegating() { - BindingValue hostBinding = BindingValue.newBuilder().setBindingId("image").build(); - when(mHostHostBindingProvider.getImageBindingForValue(BINDING_WITH_HOST_DATA)) - .thenReturn(hostBinding); - - assertThat(mDelegatingHostBindingProvider.getImageBindingForValue(BINDING_WITH_HOST_DATA)) - .isEqualTo(hostBinding); - } - - @Test - public void testGetActionsBindingForValue() { - assertThat(mHostBindingProvider.getActionsBindingForValue(BINDING_WITH_HOST_DATA)) - .isEqualTo(BINDING_WITHOUT_HOST_DATA); - } - - @Test - public void testGetActionsBindingForValue_delegating() { - BindingValue hostBinding = BindingValue.newBuilder().setBindingId("actions").build(); - when(mHostHostBindingProvider.getActionsBindingForValue(BINDING_WITH_HOST_DATA)) - .thenReturn(hostBinding); - - assertThat(mDelegatingHostBindingProvider.getActionsBindingForValue(BINDING_WITH_HOST_DATA)) - .isEqualTo(hostBinding); - } - - @Test - public void testGetGridCellWidthBindingForValue() { - assertThat(mHostBindingProvider.getGridCellWidthBindingForValue(BINDING_WITH_HOST_DATA)) - .isEqualTo(BINDING_WITHOUT_HOST_DATA); - } - - @Test - public void testGetGridCellWidthBindingForValue_delegating() { - BindingValue hostBinding = BindingValue.newBuilder().setBindingId("gridcell").build(); - when(mHostHostBindingProvider.getGridCellWidthBindingForValue(BINDING_WITH_HOST_DATA)) - .thenReturn(hostBinding); - - assertThat(mDelegatingHostBindingProvider.getGridCellWidthBindingForValue( - BINDING_WITH_HOST_DATA)) - .isEqualTo(hostBinding); - } - - @Test - public void testGetLogDataBindingForValue() { - assertThat(mHostBindingProvider.getLogDataBindingForValue(BINDING_WITH_HOST_DATA)) - .isEqualTo(BINDING_WITHOUT_HOST_DATA); - } - - @Test - public void testGetLogDataBindingForValue_delegating() { - BindingValue hostBinding = BindingValue.newBuilder().setBindingId("ved").build(); - when(mHostHostBindingProvider.getLogDataBindingForValue(BINDING_WITH_HOST_DATA)) - .thenReturn(hostBinding); - - assertThat(mDelegatingHostBindingProvider.getLogDataBindingForValue(BINDING_WITH_HOST_DATA)) - .isEqualTo(hostBinding); - } - - @Test - public void testGetTemplateBindingForValue() { - assertThat(mHostBindingProvider.getTemplateBindingForValue(BINDING_WITH_HOST_DATA)) - .isEqualTo(BINDING_WITHOUT_HOST_DATA); - } - - @Test - public void testGetTemplateBindingForValue_delegating() { - BindingValue hostBinding = BindingValue.newBuilder().setBindingId("ved").build(); - when(mHostHostBindingProvider.getTemplateBindingForValue(BINDING_WITH_HOST_DATA)) - .thenReturn(hostBinding); - - assertThat( - mDelegatingHostBindingProvider.getTemplateBindingForValue(BINDING_WITH_HOST_DATA)) - .isEqualTo(hostBinding); - } - - @Test - public void testGetStyleBindingForValue() { - assertThat(mHostBindingProvider.getTemplateBindingForValue(BINDING_WITH_HOST_DATA)) - .isEqualTo(BINDING_WITHOUT_HOST_DATA); - } - - @Test - public void testGetStyleBindingForValue_delegating() { - BindingValue hostBinding = BindingValue.newBuilder().setBindingId("ved").build(); - when(mHostHostBindingProvider.getStyleBindingForValue(BINDING_WITH_HOST_DATA)) - .thenReturn(hostBinding); - - assertThat(mDelegatingHostBindingProvider.getStyleBindingForValue(BINDING_WITH_HOST_DATA)) - .isEqualTo(hostBinding); - } - - @Test - public void testGetVisibilityBindingForValue_delegating() { - BindingValue hostBinding = BindingValue.newBuilder().setBindingId("ved").build(); - when(mHostHostBindingProvider.getVisibilityBindingForValue(BINDING_WITH_HOST_DATA)) - .thenReturn(hostBinding); - - assertThat( - mDelegatingHostBindingProvider.getVisibilityBindingForValue(BINDING_WITH_HOST_DATA)) - .isEqualTo(hostBinding); - } - - @Test - public void testGetVisibilityBindingForValue_noOfflineExtension() { - assertThat(mHostBindingProvider.getVisibilityBindingForValue(BINDING_WITH_HOST_DATA)) - .isEqualTo(BINDING_WITHOUT_HOST_DATA); - } - - @Test - public void testGetVisibilityBindingForValue_offlineExtension_notOffline() { - when(mOfflineMonitor.isAvailableOffline(URL)).thenReturn(false); - assertThat(mHostBindingProvider.getVisibilityBindingForValue(OFFLINE_INDICATOR_BINDING)) - .isEqualTo(NOT_OFFLINE_BINDING_VISIBILITY); - } - - @Test - public void testGetVisibilityBindingForValue_offlineExtension_offline() { - when(mOfflineMonitor.isAvailableOffline(URL)).thenReturn(true); - assertThat(mHostBindingProvider.getVisibilityBindingForValue(OFFLINE_INDICATOR_BINDING)) - .isEqualTo(OFFLINE_BINDING_VISIBILITY); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/piet/PietImageLoaderTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/piet/PietImageLoaderTest.java deleted file mode 100644 index 488cb587..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/piet/PietImageLoaderTest.java +++ /dev/null
@@ -1,74 +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. - -package org.chromium.chrome.browser.feed.library.sharedstream.piet; - -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import android.graphics.drawable.Drawable; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.base.Consumer; -import org.chromium.chrome.browser.feed.library.api.host.imageloader.ImageLoaderApi; -import org.chromium.chrome.browser.feed.library.api.host.stream.CardConfiguration; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.components.feed.core.proto.ui.piet.ImagesProto.Image; -import org.chromium.components.feed.core.proto.ui.piet.ImagesProto.ImageSource; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.TimeUnit; - -/** Tests for {@link PietImageLoader}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class PietImageLoaderTest { - private static final int DEFAULT_CORNER_RADIUS = 10; - private static final int WIDTH_PX = 50; - private static final int HEIGHT_PX = 150; - - @Mock - private CardConfiguration mCardConfiguration; - @Mock - private ImageLoaderApi mImageLoaderApi; - - private FakeClock mClock; - private PietImageLoader mPietImageLoader; - - @Before - public void setUp() { - initMocks(this); - - when(mCardConfiguration.getDefaultCornerRadius()).thenReturn(DEFAULT_CORNER_RADIUS); - - mClock = new FakeClock(); - mClock.set(TimeUnit.MINUTES.toMillis(1)); - mPietImageLoader = new PietImageLoader(mImageLoaderApi); - } - - @Test - public void testGetImage() { - List<String> urls = Arrays.asList("url0", "url1", "url2"); - Image.Builder imageBuilder = Image.newBuilder(); - for (String url : urls) { - imageBuilder.addSources(ImageSource.newBuilder().setUrl(url).build()); - } - - Consumer<Drawable> consumer = value - -> { - // Do nothing. - }; - - mPietImageLoader.getImage(imageBuilder.build(), WIDTH_PX, HEIGHT_PX, consumer); - verify(mImageLoaderApi).loadDrawable(urls, WIDTH_PX, HEIGHT_PX, consumer); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/piet/PietRequiredContentAdapterTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/piet/PietRequiredContentAdapterTest.java deleted file mode 100644 index a71de17..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/piet/PietRequiredContentAdapterTest.java +++ /dev/null
@@ -1,77 +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. - -package org.chromium.chrome.browser.feed.library.sharedstream.piet; - -import static com.google.common.truth.Truth.assertThat; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import org.chromium.components.feed.core.proto.ui.stream.StreamStructureProto.Content; -import org.chromium.components.feed.core.proto.ui.stream.StreamStructureProto.PietContent; -import org.chromium.components.feed.core.proto.wire.ContentIdProto.ContentId; -import org.chromium.components.feed.core.proto.wire.DataOperationProto.DataOperation; -import org.chromium.components.feed.core.proto.wire.DataOperationProto.DataOperation.Operation; -import org.chromium.components.feed.core.proto.wire.FeatureProto.Feature; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link PietRequiredContentAdapter}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class PietRequiredContentAdapterTest { - private static final ContentId CONTENT_ID_1 = ContentId.newBuilder().setId(1).build(); - private static final ContentId CONTENT_ID_2 = ContentId.newBuilder().setId(2).build(); - private static final Feature FEATURE = - Feature.newBuilder() - .setExtension(Content.contentExtension, - Content.newBuilder() - .setExtension(PietContent.pietContentExtension, - PietContent.newBuilder() - .addPietSharedStates(CONTENT_ID_1) - .addPietSharedStates(CONTENT_ID_2) - .build()) - .build()) - .build(); - - private final PietRequiredContentAdapter mAdapter = new PietRequiredContentAdapter(); - - @Test - public void testDetermineRequiredContentIds() { - assertThat(mAdapter.determineRequiredContentIds( - DataOperation.newBuilder() - .setOperation(Operation.UPDATE_OR_APPEND) - .setFeature(FEATURE) - .build())) - .containsExactly(CONTENT_ID_1, CONTENT_ID_2); - } - - @Test - public void testDetermineRequiredContentIds_removeDoesNotRequireContent() { - assertThat(mAdapter.determineRequiredContentIds(DataOperation.newBuilder() - .setOperation(Operation.REMOVE) - .setFeature(FEATURE) - .build())) - .isEmpty(); - } - - @Test - public void testDetermineRequiredContentIds_clearAllDoesNotRequireContent() { - assertThat(mAdapter.determineRequiredContentIds(DataOperation.newBuilder() - .setOperation(Operation.CLEAR_ALL) - .setFeature(FEATURE) - .build())) - .isEmpty(); - } - - @Test - public void testDetermineRequiredContentIds_defaultInstanceDoesNotRequireContent() { - assertThat(mAdapter.determineRequiredContentIds( - DataOperation.newBuilder() - .setOperation(Operation.UPDATE_OR_APPEND) - .build())) - .isEmpty(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/piet/PietStringFormatterTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/piet/PietStringFormatterTest.java deleted file mode 100644 index 8af60399..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/piet/PietStringFormatterTest.java +++ /dev/null
@@ -1,26 +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. - -package org.chromium.chrome.browser.feed.library.sharedstream.piet; - -import static com.google.common.truth.Truth.assertThat; - -import org.junit.Test; - -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; - -import java.util.concurrent.TimeUnit; - -/** Tests the {@link PietStringFormatter} */ -public class PietStringFormatterTest { - @Test - public void testGetRelativeElapsedString() { - FakeClock clock = new FakeClock(); - clock.set(TimeUnit.MINUTES.toMillis(1)); - - PietStringFormatter pietStringFormatter = new PietStringFormatter(clock); - assertThat(pietStringFormatter.getRelativeElapsedString(TimeUnit.MINUTES.toMillis(1))) - .isEqualTo("1 minute ago"); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/publicapi/menumeasurer/MenuMeasurerTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/publicapi/menumeasurer/MenuMeasurerTest.java deleted file mode 100644 index 9147b56..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/publicapi/menumeasurer/MenuMeasurerTest.java +++ /dev/null
@@ -1,66 +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. - -package org.chromium.chrome.browser.feed.library.sharedstream.publicapi.menumeasurer; - -import static com.google.common.truth.Truth.assertThat; - -import static org.chromium.chrome.browser.feed.library.sharedstream.publicapi.menumeasurer.MenuMeasurer.NO_MAX_HEIGHT; -import static org.chromium.chrome.browser.feed.library.sharedstream.publicapi.menumeasurer.MenuMeasurer.NO_MAX_WIDTH; - -import android.app.Activity; - -import com.google.common.collect.Lists; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.R; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link MenuMeasurer}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class MenuMeasurerTest { - private static final int NO_PADDING = 0; - - private MenuMeasurer mMenuMeasurer; - private int mWidthUnit; - - @Before - public void setup() { - Activity activity = Robolectric.buildActivity(Activity.class).create().visible().get(); - mMenuMeasurer = new MenuMeasurer(activity); - mWidthUnit = activity.getResources().getDimensionPixelSize(R.dimen.menu_width_multiple); - } - - @Test - public void testCalculateSize() { - assertThat( - mMenuMeasurer.calculateSize(Lists.newArrayList(new Size(10, 20), new Size(10, 20)), - NO_PADDING, NO_MAX_WIDTH, NO_MAX_HEIGHT)) - .isEqualTo(new Size(roundToWidthUnit(10), 40)); - } - - @Test - public void testCalculateSize_maxWidth() { - assertThat(mMenuMeasurer.calculateSize( - Lists.newArrayList(new Size(100, 100)), NO_PADDING, 70, NO_MAX_HEIGHT)) - .isEqualTo(new Size(70, 100)); - } - - @Test - public void testCalculateSize_maxHeight() { - assertThat(mMenuMeasurer.calculateSize( - Lists.newArrayList(new Size(100, 100)), NO_PADDING, NO_MAX_WIDTH, 60)) - .isEqualTo(new Size(roundToWidthUnit(100), 60)); - } - - private int roundToWidthUnit(int measuredWidth) { - return Math.round((((float) measuredWidth / (float) mWidthUnit) + 0.5f)) * mWidthUnit; - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/removetrackingfactory/StreamRemoveTrackingFactoryTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/removetrackingfactory/StreamRemoveTrackingFactoryTest.java deleted file mode 100644 index 0ee992b..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/removetrackingfactory/StreamRemoveTrackingFactoryTest.java +++ /dev/null
@@ -1,128 +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. - -package org.chromium.chrome.browser.feed.library.sharedstream.removetrackingfactory; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.client.knowncontent.ContentRemoval; -import org.chromium.chrome.browser.feed.library.api.client.knowncontent.KnownContent; -import org.chromium.chrome.browser.feed.library.api.common.MutationContext; -import org.chromium.chrome.browser.feed.library.api.internal.knowncontent.FeedKnownContent; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.ModelProvider; -import org.chromium.chrome.browser.feed.library.api.internal.modelprovider.RemoveTracking; -import org.chromium.components.feed.core.proto.libraries.api.internal.StreamDataProto.StreamFeature; -import org.chromium.components.feed.core.proto.ui.stream.StreamStructureProto.Content; -import org.chromium.components.feed.core.proto.ui.stream.StreamStructureProto.RepresentationData; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -import java.util.List; - -/** Tests for {@link StreamRemoveTrackingFactory}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class StreamRemoveTrackingFactoryTest { - private static final String SESSION_ID = "sessionId"; - private static final String URL1 = "url1"; - private static final String URL2 = "url2"; - - @Mock - private FeedKnownContent mFeedKnownContent; - @Mock - private ModelProvider mModelProvider; - @Mock - private KnownContent.Listener mKnownContentListener; - - private StreamRemoveTrackingFactory mStreamRemoveTrackingFactory; - - @Before - public void setup() { - initMocks(this); - when(mModelProvider.getSessionId()).thenReturn(SESSION_ID); - when(mFeedKnownContent.getKnownContentHostNotifier()).thenReturn(mKnownContentListener); - mStreamRemoveTrackingFactory = - new StreamRemoveTrackingFactory(mModelProvider, mFeedKnownContent); - } - - @Test - public void testCreate_nullRequestingSession() { - assertThat(mStreamRemoveTrackingFactory.create(MutationContext.EMPTY_CONTEXT)).isNull(); - } - - @Test - public void testCreate_otherSessionId() { - assertThat(mStreamRemoveTrackingFactory.create( - new MutationContext.Builder().setRequestingSessionId("otherId").build())) - .isNull(); - } - - @Test - public void testRemoveTracking_userInitiated() { - List<ContentRemoval> removedContents = triggerConsumerUpdatesFor( - /* isUserInitiated= */ true, buildStreamFeatureForUrl(URL2), - StreamFeature.getDefaultInstance(), buildStreamFeatureForUrl(URL1), - StreamFeature.getDefaultInstance()); - - assertThat(removedContents).hasSize(2); - assertThat(removedContents.get(0).getUrl()).isEqualTo(URL2); - assertThat(removedContents.get(1).getUrl()).isEqualTo(URL1); - assertThat(removedContents.get(0).isRequestedByUser()).isTrue(); - } - - @Test - public void testRemoveTracking_notUserInitiated() { - List<ContentRemoval> removedContents = triggerConsumerUpdatesFor( - /* isUserInitiated= */ false, buildStreamFeatureForUrl(URL1), - buildStreamFeatureForUrl(URL2), StreamFeature.getDefaultInstance()); - - assertThat(removedContents).hasSize(2); - assertThat(removedContents.get(0).getUrl()).isEqualTo(URL1); - assertThat(removedContents.get(1).getUrl()).isEqualTo(URL2); - assertThat(removedContents.get(0).isRequestedByUser()).isFalse(); - } - - @SuppressWarnings("unchecked") - private List<ContentRemoval> triggerConsumerUpdatesFor( - boolean isUserInitiated, StreamFeature... streamFeatures) { - RemoveTracking<ContentRemoval> contentRemovalRemoveTracking = - mStreamRemoveTrackingFactory.create(createMutationContext(isUserInitiated)); - - for (StreamFeature streamFeature : streamFeatures) { - contentRemovalRemoveTracking.filterStreamFeature(streamFeature); - } - - contentRemovalRemoveTracking.triggerConsumerUpdate(); - - ArgumentCaptor<List<ContentRemoval>> removedContentCaptor = - (ArgumentCaptor<List<ContentRemoval>>) (Object) ArgumentCaptor.forClass(List.class); - - verify(mKnownContentListener).onContentRemoved(removedContentCaptor.capture()); - return removedContentCaptor.getValue(); - } - - private StreamFeature buildStreamFeatureForUrl(String url) { - return StreamFeature.newBuilder() - .setContent(Content.newBuilder().setRepresentationData( - RepresentationData.newBuilder().setUri(url))) - .build(); - } - - private MutationContext createMutationContext(boolean isUserInitiated) { - return new MutationContext.Builder() - .setRequestingSessionId(SESSION_ID) - .setUserInitiated(isUserInitiated) - .build(); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/scroll/PietScrollObserverTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/scroll/PietScrollObserverTest.java deleted file mode 100644 index 81e72917..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/scroll/PietScrollObserverTest.java +++ /dev/null
@@ -1,135 +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. - -package org.chromium.chrome.browser.feed.library.sharedstream.scroll; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import android.app.Activity; -import android.widget.FrameLayout; -import android.widget.LinearLayout; -import android.widget.LinearLayout.LayoutParams; - -import androidx.recyclerview.widget.RecyclerView; - -import com.google.common.collect.ImmutableList; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.piet.FrameAdapter; -import org.chromium.chrome.browser.feed.library.piet.host.ActionHandler; -import org.chromium.chrome.browser.feed.library.piet.host.ActionHandler.ActionType; -import org.chromium.chrome.browser.feed.library.piet.testing.FakeFrameAdapter; -import org.chromium.chrome.browser.feed.library.sharedstream.publicapi.scroll.ScrollObservable; -import org.chromium.components.feed.core.proto.ui.piet.ActionsProto.Action; -import org.chromium.components.feed.core.proto.ui.piet.PietProto.Frame; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link PietScrollObserverTest}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class PietScrollObserverTest { - @Mock - private ScrollObservable mScrollObservable; - @Mock - private ActionHandler mActionHandler; - - // .newBuilder().build() creates a unique instance we can check same() against. - private static final Action VIEW_ACTION = Action.newBuilder().build(); - - private FrameAdapter mFrameAdapter; - private FrameLayout mViewport; - private LinearLayout mFrameView; - private PietScrollObserver mPietScrollObserver; - - @Before - public void setUp() { - initMocks(this); - Activity activity = Robolectric.setupActivity(Activity.class); - mViewport = new FrameLayout(activity); - activity.getWindow().addContentView(mViewport, new LayoutParams(100, 100)); - - mFrameAdapter = FakeFrameAdapter.builder(activity) - .setActionHandler(mActionHandler) - .addViewAction(VIEW_ACTION) - .build(); - mFrameAdapter.bindModel(Frame.getDefaultInstance(), 0, null, ImmutableList.of()); - mFrameView = mFrameAdapter.getFrameContainer(); - - mPietScrollObserver = new PietScrollObserver(mFrameAdapter, mViewport, mScrollObservable); - } - - @Test - public void testTriggersActionsWhenIdle() { - mPietScrollObserver.onScrollStateChanged( - mViewport, "", RecyclerView.SCROLL_STATE_IDLE, 123L); - - verify(mActionHandler) - .handleAction(same(VIEW_ACTION), eq(ActionType.VIEW), - eq(Frame.getDefaultInstance()), eq(mFrameAdapter.getFrameContainer()), - any() /* LogData */); - } - - @Test - public void testDoesNotTriggerWhenScrolling() { - mPietScrollObserver.onScrollStateChanged( - mViewport, "", RecyclerView.SCROLL_STATE_DRAGGING, 123L); - - verifyZeroInteractions(mActionHandler); - } - - @Test - public void testTriggersOnFirstDraw() { - mPietScrollObserver.installFirstDrawTrigger(); - when(mScrollObservable.getCurrentScrollState()).thenReturn(RecyclerView.SCROLL_STATE_IDLE); - - mFrameView.getViewTreeObserver().dispatchOnGlobalLayout(); - - verify(mActionHandler) - .handleAction(same(VIEW_ACTION), eq(ActionType.VIEW), - eq(Frame.getDefaultInstance()), eq(mFrameView), any() /* LogData */); - } - - @Test - public void testDoesNotTriggerOnSecondDraw() { - mPietScrollObserver.installFirstDrawTrigger(); - when(mScrollObservable.getCurrentScrollState()) - .thenReturn(RecyclerView.SCROLL_STATE_DRAGGING); - - // trigger on global layout - actions will not trigger because scrolling is not IDLE - mFrameView.getViewTreeObserver().dispatchOnGlobalLayout(); - - when(mScrollObservable.getCurrentScrollState()).thenReturn(RecyclerView.SCROLL_STATE_IDLE); - - // trigger on global layout - actions will not trigger because observer has been removed. - mFrameView.getViewTreeObserver().dispatchOnGlobalLayout(); - - verifyZeroInteractions(mActionHandler); - } - - @Test - public void testTriggersOnAttach() { - // Actions will not fire before attached to window - mFrameView.getViewTreeObserver().dispatchOnGlobalLayout(); - verifyZeroInteractions(mActionHandler); - - // Now attach to window and actions should fire - mViewport.addView(mFrameView); - mFrameView.getViewTreeObserver().dispatchOnGlobalLayout(); - verify(mActionHandler) - .handleAction(same(VIEW_ACTION), eq(ActionType.VIEW), - eq(Frame.getDefaultInstance()), eq(mFrameView), any() /* LogData */); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/scroll/ScrollListenerNotifierTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/scroll/ScrollListenerNotifierTest.java deleted file mode 100644 index dd81b30..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/scroll/ScrollListenerNotifierTest.java +++ /dev/null
@@ -1,174 +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. - -package org.chromium.chrome.browser.feed.library.sharedstream.scroll; - -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.MockitoAnnotations.initMocks; - -import static org.chromium.chrome.browser.feed.library.common.testing.RunnableSubject.assertThatRunnable; -import static org.chromium.chrome.browser.feed.shared.stream.Stream.ScrollListener.UNKNOWN_SCROLL_DELTA; - -import android.app.Activity; -import android.content.Context; - -import androidx.recyclerview.widget.RecyclerView; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.common.concurrent.testing.FakeMainThreadRunner; -import org.chromium.chrome.browser.feed.library.common.time.testing.FakeClock; -import org.chromium.chrome.browser.feed.library.sharedstream.publicapi.scroll.ScrollObservable; -import org.chromium.chrome.browser.feed.shared.stream.Stream.ContentChangedListener; -import org.chromium.chrome.browser.feed.shared.stream.Stream.ScrollListener; -import org.chromium.chrome.browser.feed.shared.stream.Stream.ScrollListener.ScrollState; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link ScrollListenerNotifier}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ScrollListenerNotifierTest { - private static final String FEATURE_ID = "feature"; - private static final long TIME = 12345L; - - @Mock - private ScrollListener mScrollListener1; - @Mock - private ScrollListener mScrollListener2; - @Mock - private ContentChangedListener mContentChangedListener; - @Mock - private ScrollObservable mScrollObservable; - - private ScrollListenerNotifier mScrollListenerNotifier; - private RecyclerView mRecyclerView; - private FakeMainThreadRunner mMainThreadRunner; - private FakeClock mClock; - - @Before - public void setUp() { - initMocks(this); - - Context context = Robolectric.buildActivity(Activity.class).get(); - mRecyclerView = new RecyclerView(context); - mMainThreadRunner = FakeMainThreadRunner.queueAllTasks(); - mClock = new FakeClock(); - mClock.set(TIME); - - mScrollListenerNotifier = new ScrollListenerNotifier( - mContentChangedListener, mScrollObservable, mMainThreadRunner); - mScrollListenerNotifier.addScrollListener(mScrollListener1); - } - - @Test - public void testConstructor() { - ScrollListenerNotifier notifier = new ScrollListenerNotifier( - mContentChangedListener, mScrollObservable, mMainThreadRunner); - - verify(mScrollObservable).addScrollObserver(notifier); - } - - @Test - public void testScrollStateOutputs() { - mScrollListenerNotifier.onScrollStateChanged( - mRecyclerView, FEATURE_ID, RecyclerView.SCROLL_STATE_IDLE, TIME); - verify(mScrollListener1).onScrollStateChanged(ScrollState.IDLE); - - mScrollListenerNotifier.onScrollStateChanged( - mRecyclerView, FEATURE_ID, RecyclerView.SCROLL_STATE_DRAGGING, TIME); - verify(mScrollListener1).onScrollStateChanged(ScrollState.DRAGGING); - - mScrollListenerNotifier.onScrollStateChanged( - mRecyclerView, FEATURE_ID, RecyclerView.SCROLL_STATE_SETTLING, TIME); - verify(mScrollListener1).onScrollStateChanged(ScrollState.SETTLING); - - assertThatRunnable(() - -> mScrollListenerNotifier.onScrollStateChanged( - mRecyclerView, FEATURE_ID, -42, TIME)) - .throwsAnExceptionOfType(RuntimeException.class); - } - - @Test - public void testOnScrollStateChanged() { - mScrollListenerNotifier.onScrollStateChanged( - mRecyclerView, FEATURE_ID, RecyclerView.SCROLL_STATE_IDLE, TIME); - - verify(mScrollListener1).onScrollStateChanged(ScrollState.IDLE); - } - - @Test - public void testOnScrollStateChanged_notifiesObserverOnIdle() { - mScrollListenerNotifier.onScrollStateChanged( - mRecyclerView, FEATURE_ID, RecyclerView.SCROLL_STATE_IDLE, TIME); - - verify(mContentChangedListener).onContentChanged(); - } - - @Test - public void testOnScrollStateChanged_multipleListeners() { - mScrollListenerNotifier.addScrollListener(mScrollListener2); - - mScrollListenerNotifier.onScrollStateChanged( - mRecyclerView, FEATURE_ID, RecyclerView.SCROLL_STATE_IDLE, TIME); - - verify(mScrollListener1).onScrollStateChanged(ScrollState.IDLE); - verify(mScrollListener2).onScrollStateChanged(ScrollState.IDLE); - } - - @Test - public void testOnScrollStateChanged_removedListener() { - mScrollListenerNotifier.addScrollListener(mScrollListener2); - mScrollListenerNotifier.removeScrollListener(mScrollListener1); - - mScrollListenerNotifier.onScrollStateChanged( - mRecyclerView, FEATURE_ID, RecyclerView.SCROLL_STATE_IDLE, TIME); - - verify(mScrollListener1, never()).onScrollStateChanged(anyInt()); - verify(mScrollListener2).onScrollStateChanged(ScrollState.IDLE); - } - - @Test - public void testOnScrolled() { - mScrollListenerNotifier.onScroll(mRecyclerView, FEATURE_ID, 1, 2); - - verify(mScrollListener1).onScrolled(1, 2); - } - - @Test - public void testOnScrolled_multipleListeners() { - mScrollListenerNotifier.addScrollListener(mScrollListener2); - mScrollListenerNotifier.onScroll(mRecyclerView, FEATURE_ID, 1, 2); - - verify(mScrollListener1).onScrolled(1, 2); - verify(mScrollListener2).onScrolled(1, 2); - } - - @Test - public void testOnScrolled_removedListener() { - mScrollListenerNotifier.addScrollListener(mScrollListener2); - mScrollListenerNotifier.removeScrollListener(mScrollListener1); - - mScrollListenerNotifier.onScroll(mRecyclerView, FEATURE_ID, 1, 2); - - verify(mScrollListener1, never()).onScrolled(anyInt(), anyInt()); - verify(mScrollListener2).onScrolled(1, 2); - } - - @Test - public void onProgrammaticScroll() { - mScrollListenerNotifier.onProgrammaticScroll(mRecyclerView); - - verify(mScrollListener1, never()).onScrolled(anyInt(), anyInt()); - - mMainThreadRunner.runAllTasks(); - verify(mScrollListener1).onScrolled(UNKNOWN_SCROLL_DELTA, UNKNOWN_SCROLL_DELTA); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/scroll/ScrollLoggerTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/scroll/ScrollLoggerTest.java deleted file mode 100644 index 8b37c58..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/scroll/ScrollLoggerTest.java +++ /dev/null
@@ -1,48 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.feed.library.sharedstream.scroll; - -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.logging.BasicLoggingApi; -import org.chromium.chrome.browser.feed.library.api.host.logging.ScrollType; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -/** Tests for {@link ScrollLogger}. */ -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public final class ScrollLoggerTest { - @Mock - private BasicLoggingApi mBasicLoggingApi; - private ScrollLogger mScrollLogger; - - @Before - public void setUp() { - initMocks(this); - mScrollLogger = new ScrollLogger(mBasicLoggingApi); - } - - @Test - public void testLogsScroll() { - int scrollAmount = 100; - mScrollLogger.handleScroll(ScrollType.STREAM_SCROLL, scrollAmount); - verify(mBasicLoggingApi).onScroll(ScrollType.STREAM_SCROLL, scrollAmount); - } - - @Test - public void testLogsNoScroll_tooSmall() { - int scrollAmount = 1; - mScrollLogger.handleScroll(ScrollType.STREAM_SCROLL, scrollAmount); - verify(mBasicLoggingApi, never()).onScroll(ScrollType.STREAM_SCROLL, scrollAmount); - } -}
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/scroll/ScrollRestoreHelperTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/scroll/ScrollRestoreHelperTest.java deleted file mode 100644 index e00f81d..0000000 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/sharedstream/scroll/ScrollRestoreHelperTest.java +++ /dev/null
@@ -1,111 +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. - -package org.chromium.chrome.browser.feed.library.sharedstream.scroll; - -import static com.google.common.truth.Truth.assertThat; - -import android.app.Activity; -import android.content.Context; -import android.view.View; - -import androidx.recyclerview.widget.RecyclerView; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.Robolectric; -import org.robolectric.annotation.Config; - -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration; -import org.chromium.chrome.browser.feed.library.api.host.config.Configuration.ConfigKey; -import org.chromium.chrome.browser.feed.library.testing.android.LinearLayoutManagerForTest; -import org.chromium.components.feed.core.proto.libraries.sharedstream.ScrollStateProto.ScrollState; -import org.chromium.testing.local.LocalRobolectricTestRunner; - -@RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public final class ScrollRestoreHelperTest { - private static final int HEADER_COUNT = 10; - private static final int ABANDON_RESTORE_BELOW_FOLD_THRESHOLD = 5; - private static final int FIRST_VISIBLE_ITEM_POSITION = 3; - private static final int FIRST_VISIBLE_ITEM_OFFSET = 14; - - private LinearLayoutManagerForTest mLinearLayoutManager; - private Context mContext; - - @Before - public void setUp() { - mContext = Robolectric.buildActivity(Activity.class).get(); - mLinearLayoutManager = new LinearLayoutManagerForTest(mContext); - mLinearLayoutManager.firstVisibleItemPosition = FIRST_VISIBLE_ITEM_POSITION; - mLinearLayoutManager.firstVisibleViewOffset = FIRST_VISIBLE_ITEM_OFFSET; - } - - @Test - public void testGetScrollStateForScrollRestore_noFirstPosition_returnsNull() { - mLinearLayoutManager.firstVisibleItemPosition = RecyclerView.NO_POSITION; - - assertThat(ScrollRestoreHelper.getScrollStateForScrollRestore( - mLinearLayoutManager, new Configuration.Builder().build(), HEADER_COUNT)) - .isNull(); - } - - @Test - public void testGetScrollStateForScrollRestore_noLastPosition_returnsNull() { - // configurationMap.put(ConfigKey.ABANDON_RESTORE_BELOW_FOLD, true); - - mLinearLayoutManager.lastVisibleItemPosition = RecyclerView.NO_POSITION; - - assertThat(ScrollRestoreHelper.getScrollStateForScrollRestore( - mLinearLayoutManager, new Configuration.Builder().build(), HEADER_COUNT)) - .isNull(); - } - - @Test - public void testGetScrollStateForScrollRestore_scrolledTooFar_returnsNull() { - Configuration configuration = new Configuration.Builder() - .put(ConfigKey.ABANDON_RESTORE_BELOW_FOLD, true) - .put(ConfigKey.ABANDON_RESTORE_BELOW_FOLD_THRESHOLD, - (long) ABANDON_RESTORE_BELOW_FOLD_THRESHOLD) - .build(); - - setUpForRestoringBelowTheFold(); - View view = new View(mContext); - view.setTop(FIRST_VISIBLE_ITEM_OFFSET); - mLinearLayoutManager.addChildToPosition(FIRST_VISIBLE_ITEM_POSITION, view); - - // With ABANDON_RESTORE_BELOW_FOLD true, we should not restore below the fold. - assertThat(ScrollRestoreHelper.getScrollStateForScrollRestore( - mLinearLayoutManager, configuration, HEADER_COUNT)) - .isNull(); - } - - @Test - public void testGetScrollStateForScrollRestore_dontAbandonScrollRestore_returnsScrollState() { - Configuration configuration = new Configuration.Builder() - .put(ConfigKey.ABANDON_RESTORE_BELOW_FOLD, false) - .put(ConfigKey.ABANDON_RESTORE_BELOW_FOLD_THRESHOLD, - (long) ABANDON_RESTORE_BELOW_FOLD_THRESHOLD) - .build(); - - setUpForRestoringBelowTheFold(); - View view = new View(mContext); - view.setTop(FIRST_VISIBLE_ITEM_OFFSET); - mLinearLayoutManager.addChildToPosition(FIRST_VISIBLE_ITEM_POSITION, view); - - // With ABANDON_RESTORE_BELOW_FOLD false, we should restore below the fold. - assertThat(ScrollRestoreHelper.getScrollStateForScrollRestore( - mLinearLayoutManager, configuration, HEADER_COUNT)) - .isEqualTo(ScrollState.newBuilder() - .setPosition(FIRST_VISIBLE_ITEM_POSITION) - .setOffset(FIRST_VISIBLE_ITEM_OFFSET) - .build()); - } - - private void setUpForRestoringBelowTheFold() { - mLinearLayoutManager.lastVisibleItemPosition = - HEADER_COUNT + ABANDON_RESTORE_BELOW_FOLD_THRESHOLD + 1; - } -}
diff --git a/chrome/android/feed/merging.md b/chrome/android/feed/merging.md deleted file mode 100644 index d6ce70a..0000000 --- a/chrome/android/feed/merging.md +++ /dev/null
@@ -1,11 +0,0 @@ -# Manual Merges - -[Piet code](https://cs.chromium.org/chromium/src/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/library/piet/) -and [feed wire protos](https://cs.chromium.org/chromium/src/components/feed/core/proto/wire/) -are hand-merged from https://chromium.googlesource.com/feed git repo regularly. -Commits that don't touch these files do not cause changes here. - -The hash below represents the last commit from that repo that was reviewed for -the potential need to merge here. - -Last checked commit ID: c6eb65cc4e080d96c453c677df9bf58b3abcb9b8
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml index 23702226..49c743b9 100644 --- a/chrome/android/java/AndroidManifest.xml +++ b/chrome/android/java/AndroidManifest.xml
@@ -1046,6 +1046,15 @@ <receiver android:name="org.chromium.chrome.browser.notifications.NotificationIntentInterceptor$Receiver" android:exported="false"/> + <activity + android:name="org.chromium.chrome.browser.notifications.NotificationIntentInterceptor$TrampolineActivity" + android:theme="@android:style/Theme.NoDisplay" + android:exported="false" + android:autoRemoveFromRecents="true" + android:excludeFromRecents="true" + android:documentLaunchMode="always" + android:noHistory="true"/> + <receiver android:name="org.chromium.chrome.browser.notifications.scheduler.DisplayAgent$Receiver" android:exported="false"/>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java index 9660219..f50192d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -407,7 +407,7 @@ public ChromeTabbedActivity() { mMainIntentMetrics = new MainIntentBehaviorMetrics(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - mMultiInstanceManager = new MultiInstanceManager(this, mTabModelSelectorSupplier, + mMultiInstanceManager = new MultiInstanceManager(this, getTabModelSelectorSupplier(), getMultiWindowModeStateDispatcher(), getLifecycleDispatcher(), this); } else { mMultiInstanceManager = null; @@ -1508,7 +1508,7 @@ getActivityTabProvider(), mEphemeralTabCoordinatorSupplier, mTabModelProfileSupplier, mBookmarkBridgeSupplier, getOverviewModeBehaviorSupplier(), this::getContextualSearchManager, - mTabModelSelectorSupplier, mStartSurfaceSupplier, + getTabModelSelectorSupplier(), mStartSurfaceSupplier, mLayoutStateProviderOneshotSupplier, mStartSurfaceParentTabSupplier); } @@ -1691,7 +1691,7 @@ mRootUiCoordinator.getBottomSheetController(), /* ChromeActivityNativeDelegate */ this, /* isCustomTab= */ false, getBrowserControlsManager(), getFullscreenManager(), - /* TabCreatorManager */ this, mTabModelSelectorSupplier, + /* TabCreatorManager */ this, getTabModelSelectorSupplier(), this::getCompositorViewHolder, getModalDialogManagerSupplier()); } return mTabDelegateFactory;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/DEPS b/chrome/android/java/src/org/chromium/chrome/browser/DEPS index 13efedb5..ca3d1a11 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/DEPS +++ b/chrome/android/java/src/org/chromium/chrome/browser/DEPS
@@ -139,9 +139,6 @@ "ExploreSitesIPH\.java": [ "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java", ], - "ExternalNavigationDelegateImpl\.java": [ - "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java", - ], "ScreenshotTask\.java": [ "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java", ],
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java index cd0ffc0..08a32a15 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
@@ -152,6 +152,7 @@ import org.chromium.chrome.browser.tabmodel.TabModel; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tabmodel.TabModelSelectorProfileSupplier; +import org.chromium.chrome.browser.tabmodel.TabModelSelectorSupplier; import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver; import org.chromium.chrome.browser.tabmodel.TabModelUtils; import org.chromium.chrome.browser.toolbar.ControlContainer; @@ -241,9 +242,14 @@ private C mComponent; - protected ObservableSupplierImpl<TabModelSelector> mTabModelSelectorSupplier = - new ObservableSupplierImpl<>(); - protected ObservableSupplier<Profile> mTabModelProfileSupplier = + /** Used to access the {@link ShareDelegate} from {@link WindowAndroid}. */ + private final UnownedUserDataSupplier<ShareDelegate> mShareDelegateSupplier = + new ShareDelegateSupplier(); + /** Used to access the {@link TabModelSelector} from {@link WindowAndroid}. */ + private final UnownedUserDataSupplier<TabModelSelector> mTabModelSelectorSupplier = + new TabModelSelectorSupplier(); + + protected TabModelSelectorProfileSupplier mTabModelProfileSupplier = new TabModelSelectorProfileSupplier(mTabModelSelectorSupplier); protected ObservableSupplierImpl<BookmarkBridge> mBookmarkBridgeSupplier = new ObservableSupplierImpl<>(); @@ -341,11 +347,6 @@ private List<MenuOrKeyboardActionController.MenuOrKeyboardActionHandler> mMenuActionHandlers = new ArrayList<>(); - // UnownedUserDataSuppliers - /** Allows accessing {@link ShareDelegate} from classes created from native. */ - private UnownedUserDataSupplier<ShareDelegate> mShareDelegateSupplier = - new ShareDelegateSupplier(); - protected ChromeActivity() { mIntentHandler = new IntentHandler(this, createIntentHandlerDelegate()); } @@ -358,8 +359,7 @@ @Override public void performPreInflationStartup() { - // Setup UnownedUserData suppliers before they're used. - mShareDelegateSupplier.attach(getWindowAndroid().getUnownedUserDataHost()); + setupUnownedUserDataSuppliers(); // Make sure the root coordinator is created prior to calling super to ensure all // the activity lifecycle events are called. @@ -403,6 +403,11 @@ getWindow().setBackgroundDrawable(getBackgroundDrawable()); } + private void setupUnownedUserDataSuppliers() { + mShareDelegateSupplier.attach(getWindowAndroid().getUnownedUserDataHost()); + mTabModelSelectorSupplier.attach(getWindowAndroid().getUnownedUserDataHost()); + } + protected RootUiCoordinator createRootUiCoordinator() { // TODO(https://crbug.com/931496): Remove dependency on ChromeActivity in favor of passing // in direct dependencies on needed classes. While migrating code from Chrome*Activity @@ -411,7 +416,7 @@ // a recommended pattern. return new RootUiCoordinator(this, null, getShareDelegateSupplier(), getActivityTabProvider(), mTabModelProfileSupplier, mBookmarkBridgeSupplier, - this::getContextualSearchManager, mTabModelSelectorSupplier, + this::getContextualSearchManager, getTabModelSelectorSupplier(), new OneshotSupplierImpl<>(), new OneshotSupplierImpl<>(), new OneshotSupplierImpl<>(), () -> null); } @@ -426,7 +431,7 @@ ChromeActivityCommonsModule commonsModule = overridenCommonsFactory == null ? new ChromeActivityCommonsModule(this, - mRootUiCoordinator::getBottomSheetController, mTabModelSelectorSupplier, + mRootUiCoordinator::getBottomSheetController, getTabModelSelectorSupplier(), getBrowserControlsManager(), getBrowserControlsManager(), getBrowserControlsManager(), getFullscreenManager(), getLayoutManagerSupplier(), getLifecycleDispatcher(), @@ -440,7 +445,7 @@ /* ChromeActivityNativeDelegate */ this, getModalDialogManagerSupplier(), getBrowserControlsManager()) : overridenCommonsFactory.create(this, mRootUiCoordinator::getBottomSheetController, - mTabModelSelectorSupplier, getBrowserControlsManager(), + getTabModelSelectorSupplier(), getBrowserControlsManager(), getBrowserControlsManager(), getBrowserControlsManager(), getFullscreenManager(), getLayoutManagerSupplier(), getLifecycleDispatcher(), this::getSnackbarManager, mActivityTabProvider, @@ -1358,7 +1363,10 @@ if (mShareDelegateSupplier != null) { mShareDelegateSupplier.destroy(); - mShareDelegateSupplier = null; + } + + if (mTabModelSelectorSupplier != null) { + mTabModelSelectorSupplier.destroy(); } mActivityTabProvider.destroy(); @@ -1640,7 +1648,9 @@ * {@link TabModelSelector} no longer implements TabModel. Use getTabModelSelector() or * getCurrentTabModel() depending on your needs. * @return The {@link TabModelSelector}, possibly null. + * @deprecated in favor of getTabModelSelectorSupplier. */ + @Deprecated public TabModelSelector getTabModelSelector() { if (!mTabModelOrchestrator.areTabModelsInitialized()) { throw new IllegalStateException( @@ -1650,6 +1660,14 @@ } /** + * Returns an {@link ObservableSupplier} for {@link TabModelSelector}. Prefer this method over + * using {@link #getTabModelSelector()} directly. + */ + public final ObservableSupplier<TabModelSelector> getTabModelSelectorSupplier() { + return mTabModelSelectorSupplier; + } + + /** * @return The provider of the visible tab in the current activity. */ public ActivityTabProvider getActivityTabProvider() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/content/TabContentManager.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/content/TabContentManager.java index 7c086882..f07d1cb 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/content/TabContentManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/content/TabContentManager.java
@@ -73,7 +73,7 @@ // Whether to allow to refetch tab thumbnail if the aspect ratio is not matching. public static final BooleanCachedFieldTrialParameter ALLOW_TO_REFETCH_TAB_THUMBNAIL_VARIATION = new BooleanCachedFieldTrialParameter( - ChromeFeatureList.TAB_GRID_LAYOUT_ANDROID, "allow_to_refetch", false); + ChromeFeatureList.TAB_GRID_LAYOUT_ANDROID, "allow_to_refetch", true); @VisibleForTesting public static final String UMA_THUMBNAIL_FETCHING_RESULT =
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java index a3a0eb41..d976e5a5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
@@ -688,6 +688,8 @@ * @param searchUrlFull The URL for the full search to present in the overlay, or empty. * @param searchUrlPreload The URL for the search to preload into the overlay, or empty. * @param cocaCardTag The primary internal Coca card tag for the response, or {@code 0} if none. + * @param relatedSearches The queries known as Related Searches. These are suggested searches + * related to the context. */ @CalledByNative public void onSearchTermResolutionResponse(boolean isNetworkUnavailable, int responseCode, @@ -697,7 +699,7 @@ final String caption, final String quickActionUri, @QuickActionCategory final int quickActionCategory, final long loggedEventId, final String searchUrlFull, final String searchUrlPreload, - @CardTag final int cocaCardTag) { + @CardTag final int cocaCardTag, final String[] relatedSearches) { ContextualSearchUma.logResolveReceived(mSelectionController.isTapSelection()); ResolvedSearchTerm resolvedSearchTerm = new ResolvedSearchTerm @@ -705,7 +707,7 @@ alternateTerm, mid, doPreventPreload, selectionStartAdjust, selectionEndAdjust, contextLanguage, thumbnailUrl, caption, quickActionUri, quickActionCategory, loggedEventId, searchUrlFull, - searchUrlPreload, cocaCardTag) + searchUrlPreload, cocaCardTag, relatedSearches) .build(); mNetworkCommunicator.handleSearchTermResolutionResponse(resolvedSearchTerm); } @@ -738,6 +740,7 @@ || !TextUtils.isEmpty(resolvedSearchTerm.thumbnailUrl()); assert mSearchPanel != null; + // TODO(donnd): Pass Related Searches into the Panel for display. mSearchPanel.onSearchTermResolved(message, resolvedSearchTerm.thumbnailUrl(), resolvedSearchTerm.quickActionUri(), resolvedSearchTerm.quickActionCategory(), resolvedSearchTerm.cardTagEnum());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ResolvedSearchTerm.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ResolvedSearchTerm.java index f3c35330..e8494a3 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ResolvedSearchTerm.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ResolvedSearchTerm.java
@@ -59,6 +59,7 @@ private final String mSearchUrlPreload; @CardTag private final int mCardTagEnum; + private final String mRelatedSearches[]; /** * Called in response to the @@ -88,6 +89,7 @@ * @param searchUrlPreload The URL for the search to preload into the overlay, or empty. * @param cardTagEnum A {@link CardTag} enumeration indicating what kind of card was returned, * or {@code 0} if no card was returned. + * @param relatedSearches An array of searches that may be related to the content. */ private ResolvedSearchTerm(boolean isNetworkUnavailable, int responseCode, final String searchTerm, final String displayText, final String alternateTerm, @@ -96,7 +98,7 @@ final String caption, final String quickActionUri, @QuickActionCategory final int quickActionCategory, final long loggedEventId, final String searchUrlFull, final String searchUrlPreload, - @CardTag final int cardTagEnum) { + @CardTag final int cardTagEnum, final String[] relatedSearches) { mIsNetworkUnavailable = isNetworkUnavailable; mResponseCode = responseCode; mSearchTerm = searchTerm; @@ -115,6 +117,7 @@ mSearchUrlFull = searchUrlFull; mSearchUrlPreload = searchUrlPreload; mCardTagEnum = cardTagEnum; + mRelatedSearches = relatedSearches; } public boolean isNetworkUnavailable() { @@ -218,6 +221,10 @@ } } + public String[] relatedSearches() { + return mRelatedSearches; + } + @Override public String toString() { List<String> sections = buildTextSections(); @@ -230,6 +237,8 @@ sections.add("Network unavailable!"); } else if (mResponseCode != HttpURLConnection.HTTP_OK) { sections.add("ResponseCode:" + mResponseCode); + } else if (relatedSearches().length > 0) { + sections.add("Related Searches: [" + TextUtils.join(", ", mRelatedSearches) + "]"); } else { if (mDoPreventPreload) sections.add("Preventing preload!"); if (!TextUtils.isEmpty(mSearchTerm)) sections.add("Search for '" + mSearchTerm + "'"); @@ -284,7 +293,9 @@ private String mSearchUrlPreload; @CardTag private int mCardTagEnum; + private String[] mRelatedSearches; + /** Starts building using the given {@link ResolvedSearchTerm}. */ public Builder(ResolvedSearchTerm resolvedSearchTerm) { mIsNetworkUnavailable = resolvedSearchTerm.mIsNetworkUnavailable; mResponseCode = resolvedSearchTerm.mResponseCode; @@ -304,6 +315,7 @@ mSearchUrlFull = resolvedSearchTerm.mSearchUrlFull; mSearchUrlPreload = resolvedSearchTerm.mSearchUrlPreload; mCardTagEnum = resolvedSearchTerm.mCardTagEnum; + mRelatedSearches = resolvedSearchTerm.mRelatedSearches; } /** @@ -337,7 +349,7 @@ final String displayText, final String alternateTerm, boolean doPreventPreload) { this(isNetworkUnavailable, responseCode, searchTerm, displayText, alternateTerm, "", doPreventPreload, 0, 0, "", "", "", "", QuickActionCategory.NONE, 0L, "", "", - 0); + CardTag.CT_NONE, new String[0]); } /** @@ -368,6 +380,7 @@ * @param searchUrlPreload The URL for the search to preload into the overlay, or empty. * @param cardTag The primary internal Coca card tag for the resolution, or {@code 0} if * none. + * @param relatedSearches An array of searches that may be related to the content. */ public Builder(boolean isNetworkUnavailable, int responseCode, final String searchTerm, final String displayText, final String alternateTerm, final String mid, @@ -375,7 +388,7 @@ final String contextLanguage, final String thumbnailUrl, final String caption, final String quickActionUri, @QuickActionCategory final int quickActionCategory, final long loggedEventId, final String searchUrlFull, final String searchUrlPreload, - final int cardTag) { + @CardTag final int cardTag, final String[] relatedSearches) { mIsNetworkUnavailable = isNetworkUnavailable; mResponseCode = responseCode; mSearchTerm = searchTerm; @@ -394,6 +407,7 @@ mSearchUrlFull = searchUrlFull; mSearchUrlPreload = searchUrlPreload; mCardTagEnum = fromCocaCardTag(cardTag); + mRelatedSearches = relatedSearches; } /** @@ -522,6 +536,15 @@ } /** + * @param relatedSearches The list of related searches generated from the context. +. + */ + public Builder setRelatedSearches(String[] relatedSearches) { + mRelatedSearches = relatedSearches; + return this; + } + + /** * Builds the {@link ResolvedSearchTerm} based on the params passed into the constructor * of this builder, plus whatever settings have been established. * @return The {@link ResolvedSearchTerm}, which represents all the results sent back by @@ -532,7 +555,7 @@ mDisplayText, mAlternateTerm, mMid, mDoPreventPreload, mSelectionStartAdjust, mSelectionEndAdjust, mContextLanguage, mThumbnailUrl, mCaption, mQuickActionUri, mQuickActionCategory, mLoggedEventId, mSearchUrlFull, mSearchUrlPreload, - mCardTagEnum); + mCardTagEnum, mRelatedSearches); } } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/SimpleSearchTermResolver.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/SimpleSearchTermResolver.java index 7df18f7..d0e4f6a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/SimpleSearchTermResolver.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/SimpleSearchTermResolver.java
@@ -99,6 +99,8 @@ * @param searchUrlFull The URL for the full search to present in the overlay, or empty. * @param searchUrlPreload The URL for the search to preload into the overlay, or empty. * @param cocaCardTag The primary internal Coca card tag for the response, or {@code 0} if none. + * @param relatedSearches The query suggestions known as Related Searches returned from the + * Claire backend through GoC. These are suggested searches based on the URL or content. */ @CalledByNative public void onSearchTermResolutionResponse(boolean isNetworkUnavailable, int responseCode, @@ -108,14 +110,14 @@ final String caption, final String quickActionUri, @QuickActionCategory final int quickActionCategory, final long loggedEventId, final String searchUrlFull, final String searchUrlPreload, - @CardTag final int cocaCardTag) { + @CardTag final int cocaCardTag, final String[] relatedSearches) { ResolvedSearchTerm resolvedSearchTerm = new ResolvedSearchTerm .Builder(isNetworkUnavailable, responseCode, searchTerm, displayText, alternateTerm, mid, doPreventPreload, selectionStartAdjust, selectionEndAdjust, contextLanguage, thumbnailUrl, caption, quickActionUri, quickActionCategory, loggedEventId, searchUrlFull, - searchUrlPreload, cocaCardTag) + searchUrlPreload, cocaCardTag, relatedSearches) .build(); Log.v(TAG, "onSearchTermResolutionResponse received with " + resolvedSearchTerm); if (!TextUtils.isEmpty(resolvedSearchTerm.searchTerm())) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java index 0f6c4ee..d97e2630 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java
@@ -147,7 +147,7 @@ () -> mNavigationController, getActivityTabProvider(), mTabModelProfileSupplier, mBookmarkBridgeSupplier, - this::getContextualSearchManager, mTabModelSelectorSupplier); + this::getContextualSearchManager, getTabModelSelectorSupplier()); } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java index e9944f07..633b674 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java
@@ -20,10 +20,10 @@ import org.chromium.base.ContextUtils; import org.chromium.base.IntentUtils; import org.chromium.base.PackageManagerUtils; +import org.chromium.base.supplier.Supplier; import org.chromium.chrome.browser.ChromeTabbedActivity2; import org.chromium.chrome.browser.IntentHandler; import org.chromium.chrome.browser.LaunchIntentDispatcher; -import org.chromium.chrome.browser.app.ChromeActivity; import org.chromium.chrome.browser.autofill_assistant.AutofillAssistantFacade; import org.chromium.chrome.browser.document.ChromeLauncherActivity; import org.chromium.chrome.browser.instantapps.AuthenticatedProxyActivity; @@ -33,6 +33,8 @@ import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabObserver; import org.chromium.chrome.browser.tab.TabUtils; +import org.chromium.chrome.browser.tabmodel.TabModelSelector; +import org.chromium.chrome.browser.tabmodel.TabModelSelectorSupplier; import org.chromium.components.external_intents.ExternalNavigationDelegate; import org.chromium.components.external_intents.ExternalNavigationDelegate.StartActivityIfNeededResult; import org.chromium.components.external_intents.ExternalNavigationHandler; @@ -53,10 +55,13 @@ protected final Context mApplicationContext; private final Tab mTab; private final TabObserver mTabObserver; + private final Supplier<TabModelSelector> mTabModelSelectorSupplier; + private boolean mIsTabDestroyed; public ExternalNavigationDelegateImpl(Tab tab) { mTab = tab; + mTabModelSelectorSupplier = TabModelSelectorSupplier.from(tab.getWindowAndroid()); mApplicationContext = ContextUtils.getApplicationContext(); mTabObserver = new EmptyTabObserver() { @Override @@ -202,10 +207,8 @@ @Override public void closeTab() { if (!hasValidTab()) return; - Context context = mTab.getWindowAndroid().getContext().get(); - if (context instanceof ChromeActivity) { - ((ChromeActivity) context).getTabModelSelector().closeTab(mTab); - } + if (!mTabModelSelectorSupplier.hasValue()) return; + mTabModelSelectorSupplier.get().closeTab(mTab); } @Override @@ -299,8 +302,8 @@ */ protected void startAutofillAssistantWithIntent( Intent targetIntent, String browserFallbackUrl) { - AutofillAssistantFacade.start((ChromeActivity) TabUtils.getActivity(mTab), - targetIntent.getExtras(), browserFallbackUrl); + AutofillAssistantFacade.start( + TabUtils.getActivity(mTab), targetIntent.getExtras(), browserFallbackUrl); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java index aad9a873..d67011ce 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
@@ -15,7 +15,6 @@ import org.chromium.base.CommandLine; import org.chromium.base.ContentUriUtils; import org.chromium.base.ContextUtils; -import org.chromium.base.LocaleUtils; import org.chromium.base.Log; import org.chromium.base.SysUtils; import org.chromium.base.ThreadUtils; @@ -28,7 +27,6 @@ import org.chromium.base.task.PostTask; import org.chromium.base.task.TaskTraits; import org.chromium.chrome.browser.AppHooks; -import org.chromium.chrome.browser.ChromeLocalizationUtils; import org.chromium.chrome.browser.ChromeStrictMode; import org.chromium.chrome.browser.FileProviderHelper; import org.chromium.chrome.browser.app.flags.ChromeCachedFlags; @@ -47,7 +45,6 @@ import org.chromium.content_public.browser.SpeechRecognition; import org.chromium.content_public.browser.UiThreadTaskTraits; import org.chromium.net.NetworkChangeNotifier; -import org.chromium.ui.resources.ResourceExtractor; import java.io.File; import java.util.ArrayList; @@ -171,7 +168,7 @@ */ private void onInflationComplete(final BrowserParts parts) { if (parts.isActivityFinishingOrDestroyed()) return; - postInflationStartup(); + mPostInflationStartupComplete = true; parts.postInflationStartup(); } @@ -225,20 +222,6 @@ mPreInflationStartupComplete = true; } - private void postInflationStartup() { - ThreadUtils.assertOnUiThread(); - if (mPostInflationStartupComplete) return; - - // Check to see if we need to extract any new resources from the APK. This could - // be on first run when we need to extract all the .pak files we need, or after - // the user has switched locale, in which case we want new locale resources. - ResourceExtractor.get().setResultTraits(UiThreadTaskTraits.BOOTSTRAP); - ResourceExtractor.get().startExtractingResources( - LocaleUtils.toLanguage(ChromeLocalizationUtils.getJavaUiLocale())); - - mPostInflationStartupComplete = true; - } - /** * Execute startup tasks that require native libraries to be loaded. See {@link BrowserParts} * for a list of calls to be implemented.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationIntentInterceptor.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationIntentInterceptor.java index c33dd7d..0b4a7c4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationIntentInterceptor.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationIntentInterceptor.java
@@ -4,12 +4,14 @@ package org.chromium.chrome.browser.notifications; +import android.app.Activity; import android.app.Notification; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.os.Build; +import android.os.Bundle; import androidx.annotation.IntDef; import androidx.annotation.Nullable; @@ -57,42 +59,59 @@ } /** - * Receives the event when the user taps on the notification body, notification action, or - * dismiss notification. + * Deprecated, now we use {@link TrampolineActivity} to do the logging. Temporarily kept or + * existing notification will crash. Receives the event when the user taps on the notification + * body, notification action, or dismiss notification. * {@link Notification#contentIntent}, {@link Notification#deleteIntent} * {@link Notification.Action#actionIntent} will be delivered to this broadcast receiver. */ public static final class Receiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { - @IntentType - int intentType = intent.getIntExtra(EXTRA_INTENT_TYPE, IntentType.UNKNOWN); - @NotificationUmaTracker.SystemNotificationType - int notificationType = intent.getIntExtra( - EXTRA_NOTIFICATION_TYPE, NotificationUmaTracker.SystemNotificationType.UNKNOWN); + processIntent(context, intent); + } + } - long createTime = intent.getLongExtra(EXTRA_CREATE_TIME, INVALID_CREATE_TIME); + private static void processIntent(Context context, Intent intent) { + @IntentType + int intentType = intent.getIntExtra(EXTRA_INTENT_TYPE, IntentType.UNKNOWN); + @NotificationUmaTracker.SystemNotificationType + int notificationType = intent.getIntExtra( + EXTRA_NOTIFICATION_TYPE, NotificationUmaTracker.SystemNotificationType.UNKNOWN); - switch (intentType) { - case IntentType.UNKNOWN: - break; - case IntentType.CONTENT_INTENT: - NotificationUmaTracker.getInstance().onNotificationContentClick( - notificationType, createTime); - break; - case IntentType.DELETE_INTENT: - NotificationUmaTracker.getInstance().onNotificationDismiss( - notificationType, createTime); - break; - case IntentType.ACTION_INTENT: - int actionType = intent.getIntExtra( - EXTRA_ACTION_TYPE, NotificationUmaTracker.ActionType.UNKNOWN); - NotificationUmaTracker.getInstance().onNotificationActionClick( - actionType, notificationType, createTime); - break; - } + long createTime = intent.getLongExtra(EXTRA_CREATE_TIME, INVALID_CREATE_TIME); - forwardPendingIntent(intent); + switch (intentType) { + case IntentType.UNKNOWN: + break; + case IntentType.CONTENT_INTENT: + NotificationUmaTracker.getInstance().onNotificationContentClick( + notificationType, createTime); + break; + case IntentType.DELETE_INTENT: + NotificationUmaTracker.getInstance().onNotificationDismiss( + notificationType, createTime); + break; + case IntentType.ACTION_INTENT: + int actionType = intent.getIntExtra( + EXTRA_ACTION_TYPE, NotificationUmaTracker.ActionType.UNKNOWN); + NotificationUmaTracker.getInstance().onNotificationActionClick( + actionType, notificationType, createTime); + break; + } + + forwardPendingIntent(intent); + } + + /** + * A trampoline activity that handles notification events logging. + */ + public static class TrampolineActivity extends Activity { + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + processIntent(getApplicationContext(), getIntent()); + finish(); } } @@ -118,7 +137,8 @@ flags = pendingIntentProvider.getFlags(); } Context applicationContext = ContextUtils.getApplicationContext(); - Intent intent = new Intent(applicationContext, Receiver.class); + Intent intent = new Intent(applicationContext, TrampolineActivity.class); + intent.setAction(INTENT_ACTION); intent.putExtra(EXTRA_PENDING_INTENT, pendingIntent); intent.putExtra(EXTRA_INTENT_TYPE, intentType); @@ -137,7 +157,8 @@ int originalRequestCode = pendingIntentProvider != null ? pendingIntentProvider.getRequestCode() : 0; int requestCode = computeHashCode(metadata, intentType, intentId, originalRequestCode); - return PendingIntent.getBroadcast(applicationContext, requestCode, intent, flags); + + return PendingIntent.getActivity(applicationContext, requestCode, intent, flags); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileRenderer.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileRenderer.java index 62489c34..d535b38 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileRenderer.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileRenderer.java
@@ -115,7 +115,8 @@ for (Tile tile : sectionTiles) { SuggestionsTileView tileView = oldTileViews.get(tile.getData()); if (tileView == null || tileView.mIconView == null - || tileView.mIconView.getDrawable() == null) { + || tileView.mIconView.getDrawable() == null + || tile.getSource() == TileSource.EXPLORE) { tileView = buildTileView(tile, parent, setupDelegate); } @@ -155,19 +156,16 @@ VectorDrawableCompat.create(mResources, R.drawable.ic_apps_blue_24dp, mTheme)); tile.setType(TileVisualType.ICON_DEFAULT); - if (!LibraryLoader.getInstance().isInitialized()) { - tileView.initialize(tile, mTitleLinesCount); - return tileView; + if (LibraryLoader.getInstance().isInitialized()) { + // One task to load actual icon. + LargeIconBridge.LargeIconCallback bridgeCallback = + setupDelegate.createIconLoadCallback(tile); + ExploreSitesBridge.getSummaryImage(Profile.getLastUsedRegularProfile(), + mDesiredIconSize, + (Bitmap img) + -> bridgeCallback.onLargeIconAvailable( + img, Color.BLACK, false, IconType.FAVICON)); } - - // One task to load actual icon. - LargeIconBridge.LargeIconCallback bridgeCallback = - setupDelegate.createIconLoadCallback(tile); - ExploreSitesBridge.getSummaryImage(Profile.getLastUsedRegularProfile(), - mDesiredIconSize, - (Bitmap img) - -> bridgeCallback.onLargeIconAvailable( - img, Color.BLACK, false, IconType.FAVICON)); } else { tileView = (SuggestionsTileView) LayoutInflater.from(parentView.getContext()) .inflate(mLayout, parentView, false);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TabSwitcherModeTTCoordinatorPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TabSwitcherModeTTCoordinatorPhone.java index e7265bc..3ed9096 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TabSwitcherModeTTCoordinatorPhone.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TabSwitcherModeTTCoordinatorPhone.java
@@ -188,10 +188,10 @@ private boolean isNewTabVariationEnabled() { return mIsGridTabSwitcherEnabled && ChromeFeatureList.isInitialized() && IncognitoUtils.isIncognitoModeEnabled() - && ChromeFeatureList - .getFieldTrialParamByFeature(ChromeFeatureList.TAB_GRID_LAYOUT_ANDROID, - "tab_grid_layout_android_new_tab") - .equals("NewTabVariation"); + && !ChromeFeatureList + .getFieldTrialParamByFeature(ChromeFeatureList.TAB_GRID_LAYOUT_ANDROID, + "tab_grid_layout_android_new_tab") + .equals("false"); } /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java index 2ee104f..2c61912 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
@@ -2465,9 +2465,13 @@ @Feature({"ContextualSearch"}) @ParameterAnnotations.UseMethodParameter(FeatureParamProvider.class) public void testExternalNavigationWithUserGesture(@EnabledFeature int enabledFeature) { + final ExternalNavigationDelegateImpl delegate = + TestThreadUtils.runOnUiThreadBlockingNoException( + () + -> new ExternalNavigationDelegateImpl( + sActivityTestRule.getActivity().getActivityTab())); final ExternalNavigationHandler externalNavHandler = - new ExternalNavigationHandler(new ExternalNavigationDelegateImpl( - sActivityTestRule.getActivity().getActivityTab())); + new ExternalNavigationHandler(delegate); final NavigationParams navigationParams = new NavigationParams( "intent://test/#Intent;scheme=test;package=com.chrome.test;end", "", 0 /* navigationId */, false /* isPost */, true /* hasUserGesture */, @@ -2495,9 +2499,13 @@ @ParameterAnnotations.UseMethodParameter(FeatureParamProvider.class) public void testRedirectedExternalNavigationWithUserGesture( @EnabledFeature int enabledFeature) { + final ExternalNavigationDelegateImpl delegate = + TestThreadUtils.runOnUiThreadBlockingNoException( + () + -> new ExternalNavigationDelegateImpl( + sActivityTestRule.getActivity().getActivityTab())); final ExternalNavigationHandler externalNavHandler = - new ExternalNavigationHandler(new ExternalNavigationDelegateImpl( - sActivityTestRule.getActivity().getActivityTab())); + new ExternalNavigationHandler(delegate); final NavigationParams initialNavigationParams = new NavigationParams("http://test.com", "", 0 /* navigationId */, false /* isPost */, true /* hasUserGesture */, @@ -2534,9 +2542,13 @@ @Feature({"ContextualSearch"}) @ParameterAnnotations.UseMethodParameter(FeatureParamProvider.class) public void testExternalNavigationWithoutUserGesture(@EnabledFeature int enabledFeature) { + final ExternalNavigationDelegateImpl delegate = + TestThreadUtils.runOnUiThreadBlockingNoException( + () + -> new ExternalNavigationDelegateImpl( + sActivityTestRule.getActivity().getActivityTab())); final ExternalNavigationHandler externalNavHandler = - new ExternalNavigationHandler(new ExternalNavigationDelegateImpl( - sActivityTestRule.getActivity().getActivityTab())); + new ExternalNavigationHandler(delegate); final NavigationParams navigationParams = new NavigationParams( "intent://test/#Intent;scheme=test;package=com.chrome.test;end", "", 0 /* navigationId */, false /* isPost */, false /* hasUserGesture */,
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java index b61ee37..ff39f74b 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java
@@ -129,7 +129,7 @@ public void startSearchTermResolutionRequest(String selection, boolean isExactResolve) { // Skip native calls and immediately "resolve" the search term. onSearchTermResolutionResponse(true, 200, selection, selection, "", "", false, 0, 10, - "", "", "", "", QuickActionCategory.NONE, 0, "", "", 0); + "", "", "", "", QuickActionCategory.NONE, 0, "", "", 0, new String[0]); } /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImplTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImplTest.java index d51b8ff1..fb44936 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImplTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImplTest.java
@@ -20,11 +20,13 @@ import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.instantapps.InstantAppsHandler; +import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.chrome.test.ChromeTabbedActivityTestRule; import org.chromium.chrome.test.util.browser.Features; import org.chromium.components.external_intents.ExternalNavigationHandler; import org.chromium.components.external_intents.ExternalNavigationParams; +import org.chromium.content_public.browser.test.util.TestThreadUtils; import org.chromium.url.Origin; /** @@ -48,8 +50,8 @@ private static final boolean IS_GOOGLE_REFERRER = true; class ExternalNavigationDelegateImplForTesting extends ExternalNavigationDelegateImpl { - public ExternalNavigationDelegateImplForTesting() { - super(mActivityTestRule.getActivity().getActivityTab()); + public ExternalNavigationDelegateImplForTesting(Tab activityTab) { + super(activityTab); } @Override @@ -99,22 +101,29 @@ @Rule public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule(); + private ExternalNavigationDelegateImpl mExternalNavigationDelegateImpl; + private ExternalNavigationDelegateImplForTesting mExternalNavigationDelegateImplForTesting; + @Before public void setUp() throws InterruptedException { mActivityTestRule.startMainActivityOnBlankPage(); + Tab tab = TestThreadUtils.runOnUiThreadBlockingNoException( + () -> mActivityTestRule.getActivity().getActivityTab()); + mExternalNavigationDelegateImpl = TestThreadUtils.runOnUiThreadBlockingNoException( + () -> new ExternalNavigationDelegateImpl(tab)); + mExternalNavigationDelegateImplForTesting = + TestThreadUtils.runOnUiThreadBlockingNoException( + () -> new ExternalNavigationDelegateImplForTesting(tab)); } @Test @SmallTest public void testMaybeSetPendingIncognitoUrl() { - ExternalNavigationDelegateImpl delegate = new ExternalNavigationDelegateImpl( - mActivityTestRule.getActivity().getActivityTab()); - String url = "http://www.example.com"; Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(Uri.parse(url)); - delegate.maybeSetPendingIncognitoUrl(intent); + mExternalNavigationDelegateImpl.maybeSetPendingIncognitoUrl(intent); Assert.assertTrue( intent.getBooleanExtra(IntentHandler.EXTRA_OPEN_NEW_INCOGNITO_TAB, false)); @@ -124,9 +133,6 @@ @Test @SmallTest public void testIsIntentToInstantApp() { - ExternalNavigationDelegateImpl delegate = new ExternalNavigationDelegateImpl( - mActivityTestRule.getActivity().getActivityTab()); - // Check that the delegate correctly distinguishes instant app intents from others. String vanillaUrl = "http://www.example.com"; Intent vanillaIntent = new Intent(Intent.ACTION_VIEW); @@ -147,8 +153,8 @@ return; } - Assert.assertFalse(delegate.isIntentToInstantApp(vanillaIntent)); - Assert.assertTrue(delegate.isIntentToInstantApp(instantAppIntent)); + Assert.assertFalse(mExternalNavigationDelegateImpl.isIntentToInstantApp(vanillaIntent)); + Assert.assertTrue(mExternalNavigationDelegateImpl.isIntentToInstantApp(instantAppIntent)); // Check that Supervisor is detected by action even without package. for (String action : SUPERVISOR_START_ACTIONS) { @@ -165,59 +171,54 @@ Assert.assertTrue(false); return; } - Assert.assertTrue(delegate.isIntentToInstantApp(instantAppIntent)); + Assert.assertTrue( + mExternalNavigationDelegateImpl.isIntentToInstantApp(instantAppIntent)); } } @Test @SmallTest public void testMaybeAdjustInstantAppExtras() { - ExternalNavigationDelegateImpl delegate = new ExternalNavigationDelegateImpl( - mActivityTestRule.getActivity().getActivityTab()); - String url = "http://www.example.com"; Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(Uri.parse(url)); - delegate.maybeAdjustInstantAppExtras(intent, /*isIntentToInstantApp=*/true); + mExternalNavigationDelegateImpl.maybeAdjustInstantAppExtras( + intent, /*isIntentToInstantApp=*/true); Assert.assertTrue(intent.hasExtra(InstantAppsHandler.IS_GOOGLE_SEARCH_REFERRER)); - delegate.maybeAdjustInstantAppExtras(intent, /*isIntentToInstantApp=*/false); + mExternalNavigationDelegateImpl.maybeAdjustInstantAppExtras( + intent, /*isIntentToInstantApp=*/false); Assert.assertFalse(intent.hasExtra(InstantAppsHandler.IS_GOOGLE_SEARCH_REFERRER)); } @Test @SmallTest public void maybeSetRequestMetadata() { - ExternalNavigationDelegateImpl delegate = new ExternalNavigationDelegateImpl( - mActivityTestRule.getActivity().getActivityTab()); - String url = "http://www.example.com"; Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(Uri.parse(url)); - delegate.maybeSetRequestMetadata(intent, false, false, null); + mExternalNavigationDelegateImpl.maybeSetRequestMetadata(intent, false, false, null); Assert.assertNull( IntentWithRequestMetadataHandler.getInstance().getRequestMetadataAndClear(intent)); - maybeSetAndGetRequestMetadata(delegate, intent, true, true, null); - maybeSetAndGetRequestMetadata(delegate, intent, true, false, null); - maybeSetAndGetRequestMetadata(delegate, intent, false, true, null); - maybeSetAndGetRequestMetadata(delegate, intent, false, false, new MockOrigin()); + maybeSetAndGetRequestMetadata(mExternalNavigationDelegateImpl, intent, true, true, null); + maybeSetAndGetRequestMetadata(mExternalNavigationDelegateImpl, intent, true, false, null); + maybeSetAndGetRequestMetadata(mExternalNavigationDelegateImpl, intent, false, true, null); + maybeSetAndGetRequestMetadata( + mExternalNavigationDelegateImpl, intent, false, false, new MockOrigin()); } @Test @SmallTest public void testMaybeSetPendingReferrer() { - ExternalNavigationDelegateImpl delegate = new ExternalNavigationDelegateImpl( - mActivityTestRule.getActivity().getActivityTab()); - String url = "http://www.example.com"; Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(Uri.parse(url)); String referrerUrl = "http://www.example-referrer.com"; - delegate.maybeSetPendingReferrer(intent, referrerUrl); + mExternalNavigationDelegateImpl.maybeSetPendingReferrer(intent, referrerUrl); Assert.assertEquals( Uri.parse(referrerUrl), intent.getParcelableExtra(Intent.EXTRA_REFERRER)); @@ -231,16 +232,14 @@ ChromeFeatureList.AUTOFILL_ASSISTANT_CHROME_ENTRY}) public void testHandleWithAutofillAssistant_TriggersFromSearch() { - ExternalNavigationDelegateImplForTesting delegate = - new ExternalNavigationDelegateImplForTesting(); - ExternalNavigationParams params = new ExternalNavigationParams .Builder(AUTOFILL_ASSISTANT_INTENT_URL, /*isIncognito=*/false) .build(); - Assert.assertTrue(delegate.handleWithAutofillAssistant(params, IS_GOOGLE_REFERRER)); - Assert.assertTrue(delegate.wasAutofillAssistantStarted()); + Assert.assertTrue(mExternalNavigationDelegateImplForTesting.handleWithAutofillAssistant( + params, IS_GOOGLE_REFERRER)); + Assert.assertTrue(mExternalNavigationDelegateImplForTesting.wasAutofillAssistantStarted()); } @Test @@ -249,16 +248,14 @@ ChromeFeatureList.AUTOFILL_ASSISTANT_CHROME_ENTRY}) public void testHandleWithAutofillAssistant_DoesNotTriggerFromSearchInIncognito() { - ExternalNavigationDelegateImplForTesting delegate = - new ExternalNavigationDelegateImplForTesting(); - ExternalNavigationParams params = new ExternalNavigationParams .Builder(AUTOFILL_ASSISTANT_INTENT_URL, /*isIncognito=*/true) .build(); - Assert.assertFalse(delegate.handleWithAutofillAssistant(params, IS_GOOGLE_REFERRER)); - Assert.assertFalse(delegate.wasAutofillAssistantStarted()); + Assert.assertFalse(mExternalNavigationDelegateImplForTesting.handleWithAutofillAssistant( + params, IS_GOOGLE_REFERRER)); + Assert.assertFalse(mExternalNavigationDelegateImplForTesting.wasAutofillAssistantStarted()); } @Test @@ -267,16 +264,14 @@ ChromeFeatureList.AUTOFILL_ASSISTANT_CHROME_ENTRY}) public void testHandleWithAutofillAssistant_DoesNotTriggerFromDifferentOrigin() { - ExternalNavigationDelegateImplForTesting delegate = - new ExternalNavigationDelegateImplForTesting(); - ExternalNavigationParams params = new ExternalNavigationParams .Builder(AUTOFILL_ASSISTANT_INTENT_URL, /*isIncognito=*/false) .build(); - Assert.assertFalse(delegate.handleWithAutofillAssistant(params, !IS_GOOGLE_REFERRER)); - Assert.assertFalse(delegate.wasAutofillAssistantStarted()); + Assert.assertFalse(mExternalNavigationDelegateImplForTesting.handleWithAutofillAssistant( + params, !IS_GOOGLE_REFERRER)); + Assert.assertFalse(mExternalNavigationDelegateImplForTesting.wasAutofillAssistantStarted()); } @Test @@ -285,15 +280,13 @@ ChromeFeatureList.AUTOFILL_ASSISTANT_CHROME_ENTRY}) public void testHandleWithAutofillAssistant_DoesNotTriggerWhenFeatureDisabled() { - ExternalNavigationDelegateImplForTesting delegate = - new ExternalNavigationDelegateImplForTesting(); - ExternalNavigationParams params = new ExternalNavigationParams .Builder(AUTOFILL_ASSISTANT_INTENT_URL, /*isIncognito=*/false) .build(); - Assert.assertFalse(delegate.handleWithAutofillAssistant(params, IS_GOOGLE_REFERRER)); - Assert.assertFalse(delegate.wasAutofillAssistantStarted()); + Assert.assertFalse(mExternalNavigationDelegateImplForTesting.handleWithAutofillAssistant( + params, IS_GOOGLE_REFERRER)); + Assert.assertFalse(mExternalNavigationDelegateImplForTesting.wasAutofillAssistantStarted()); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediatorUnitTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediatorUnitTest.java index beeb149..3c2bff24 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediatorUnitTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediatorUnitTest.java
@@ -4,7 +4,6 @@ package org.chromium.chrome.browser.omnibox.suggestions; -import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.anyInt; @@ -19,7 +18,9 @@ import static org.mockito.Mockito.when; import android.os.Handler; +import android.os.Looper; import android.os.Message; +import android.os.SystemClock; import android.util.SparseArray; import android.view.View; @@ -32,16 +33,13 @@ import org.junit.rules.TestRule; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.Mockito; import org.mockito.MockitoAnnotations; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; import org.chromium.base.ContextUtils; import org.chromium.base.test.BaseJUnit4ClassRunner; import org.chromium.base.test.UiThreadTest; import org.chromium.base.test.util.Batch; -import org.chromium.base.test.util.DisabledTest; +import org.chromium.base.test.util.CriteriaHelper; import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; import org.chromium.chrome.browser.omnibox.LocationBarDataProvider; @@ -67,6 +65,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; /** * Tests for {@link AutocompleteMediator}. @@ -78,8 +77,10 @@ private static final int SUGGESTION_MIN_HEIGHT = 20; private static final int HEADER_MIN_HEIGHT = 15; - // Empty AutocompleteDelegate implementation for test. This is to work around an issue that - // mock doesn't work on inherited methods in some builds. + /** + * Empty AutocompleteDelegate implementation for test. This is to work around an issue that + * mock doesn't work on inherited methods in some builds. + */ static class AutocompleteDelegateForTest implements AutocompleteDelegate { @Override public void setOmniboxEditingText(String text) {} @@ -124,6 +125,42 @@ } } + /** + * A variant of Handler, that schedules all delayed tasks for an immediate execution. + * The handler does not invoke the calls right away; instead, the test method should call + * `runQueuedTasks()` to flush the queue. + */ + static class ImmediatePostingHandler extends Handler { + ImmediatePostingHandler() { + super(Looper.getMainLooper()); + } + + /** + * Schedule message for execution. + * Unlike normal loopers, this will place a supplied Message for immediate execution + * removing the need to wait for an arbitrary amount of time until all the delayed actions + * complete. + * + * @param msg Message to be scheduled. + * @param uptimeMillis The absolute time at which the message should be delivered. This + * parameter is ignored and replaced with current time. + */ + @Override + public boolean sendMessageAtTime(Message msg, long uptimeMillis) { + return super.sendMessageAtTime(msg, SystemClock.uptimeMillis()); + } + + /** + * Executes all tasks posted on this Handler and returns. + * Must be called from UI Thread. + */ + public void runQueuedTasks() { + AtomicBoolean ranQueuedTasks = new AtomicBoolean(false); + post(() -> ranQueuedTasks.set(true)); + CriteriaHelper.pollUiThreadNested(() -> ranQueuedTasks.get(), 100, 0); + } + } + @Rule public TestRule mProcessor = new Features.JUnitProcessor(); @@ -152,8 +189,9 @@ ModalDialogManager mModalDialogManager; @Mock - Handler mHandler; + Profile mProfile; + private ImmediatePostingHandler mHandler; private PropertyModel mListModel; private AutocompleteMediator mMediator; private List<AutocompleteMatch> mSuggestionsList; @@ -164,6 +202,8 @@ MockitoAnnotations.initMocks(this); NativeLibraryTestUtils.loadNativeLibraryNoBrowserProcess(); + mHandler = new ImmediatePostingHandler(); + mSuggestionModels = new ModelList(); mListModel = new PropertyModel(SuggestionListProperties.ALL_KEYS); mListModel.set(SuggestionListProperties.SUGGESTION_MODELS, mSuggestionModels); @@ -192,14 +232,6 @@ doReturn(HEADER_MIN_HEIGHT).when(mMockHeaderProcessor).getMinimumViewHeight(); doReturn(OmniboxSuggestionUiType.HEADER).when(mMockHeaderProcessor).getViewTypeId(); - doAnswer(new Answer<Void>() { - @Override - public Void answer(InvocationOnMock invocation) { - ((Message) invocation.getArguments()[0]).getCallback().run(); - return null; - } - }).when(mHandler).sendMessageAtTime(any(Message.class), anyLong()); - mSuggestionsList = buildDummySuggestionsList(10, "Suggestion"); doReturn(true).when(mAutocompleteDelegate).isKeyboardActive(); } @@ -240,6 +272,21 @@ return headers; } + /** + * Set up LocationBarDataProvider to report supplied values. + * + * @param url The URL to report as a current URL. + * @param title The Page Title to report. + * @param pageClassification The Page classification to report. + */ + void setUpLocationBarDataProvider(String url, String title, int pageClassification) { + when(mLocationBarDataProvider.hasTab()).thenReturn(true); + when(mLocationBarDataProvider.getProfile()).thenReturn(mProfile); + when(mLocationBarDataProvider.getCurrentUrl()).thenReturn(url); + when(mLocationBarDataProvider.getTitle()).thenReturn(title); + when(mLocationBarDataProvider.getPageClassification(false)).thenReturn(pageClassification); + } + @Test @SmallTest @UiThreadTest @@ -398,22 +445,17 @@ when(mAutocompleteDelegate.isUrlBarFocused()).thenReturn(true); when(mAutocompleteDelegate.didFocusUrlFromFakebox()).thenReturn(false); - Profile profile = Mockito.mock(Profile.class); String url = "http://www.example.com"; String title = "Title"; int pageClassification = PageClassification.BLANK_VALUE; - when(mLocationBarDataProvider.getProfile()).thenReturn(profile); - when(mLocationBarDataProvider.getCurrentUrl()).thenReturn(url); - when(mLocationBarDataProvider.getTitle()).thenReturn(title); - when(mLocationBarDataProvider.hasTab()).thenReturn(true); - when(mLocationBarDataProvider.getPageClassification(false)).thenReturn(pageClassification); + setUpLocationBarDataProvider(url, title, pageClassification); when(mTextStateProvider.getTextWithAutocomplete()).thenReturn(""); mMediator.onNativeInitialized(); mMediator.onTextChanged("", ""); verify(mAutocompleteController) - .startZeroSuggest(profile, "", url, pageClassification, title); + .startZeroSuggest(mProfile, "", url, pageClassification, title); } @Test @@ -421,13 +463,9 @@ @UiThreadTest @DisableFeatures(ChromeFeatureList.OMNIBOX_ADAPTIVE_SUGGESTIONS_COUNT) public void onTextChanged_nonEmptyTextTriggersSuggestions() { - Profile profile = Mockito.mock(Profile.class); String url = "http://www.example.com"; int pageClassification = PageClassification.BLANK_VALUE; - when(mLocationBarDataProvider.getProfile()).thenReturn(profile); - when(mLocationBarDataProvider.getCurrentUrl()).thenReturn(url); - when(mLocationBarDataProvider.hasTab()).thenReturn(true); - when(mLocationBarDataProvider.getPageClassification(false)).thenReturn(pageClassification); + setUpLocationBarDataProvider(url, url, pageClassification); when(mTextStateProvider.shouldAutocomplete()).thenReturn(true); when(mTextStateProvider.getSelectionStart()).thenReturn(4); @@ -435,23 +473,19 @@ mMediator.onNativeInitialized(); mMediator.onTextChanged("test", "testing"); + mHandler.runQueuedTasks(); verify(mAutocompleteController) - .start(profile, url, pageClassification, "test", 4, false, null, false); + .start(mProfile, url, pageClassification, "test", 4, false, null, false); } - @DisabledTest(message = "Does not test what it says: http://crbug.com/1147443") @Test @SmallTest @UiThreadTest @DisableFeatures(ChromeFeatureList.OMNIBOX_ADAPTIVE_SUGGESTIONS_COUNT) public void onTextChanged_cancelsPendingRequests() { - Profile profile = Mockito.mock(Profile.class); String url = "http://www.example.com"; int pageClassification = PageClassification.BLANK_VALUE; - when(mLocationBarDataProvider.getProfile()).thenReturn(profile); - when(mLocationBarDataProvider.getCurrentUrl()).thenReturn(url); - when(mLocationBarDataProvider.hasTab()).thenReturn(true); - when(mLocationBarDataProvider.getPageClassification(false)).thenReturn(pageClassification); + setUpLocationBarDataProvider(url, url, pageClassification); when(mTextStateProvider.shouldAutocomplete()).thenReturn(true); when(mTextStateProvider.getSelectionStart()).thenReturn(4); @@ -460,8 +494,11 @@ mMediator.onNativeInitialized(); mMediator.onTextChanged("test", "testing"); mMediator.onTextChanged("nottest", "nottesting"); - verify(mAutocompleteController) - .start(profile, url, pageClassification, "nottest", 4, false, null, false); + mHandler.runQueuedTasks(); + verify(mAutocompleteController, times(1)) + .start(mProfile, url, pageClassification, "nottest", 4, false, null, false); + verify(mAutocompleteController, times(1)) + .start(any(), any(), anyInt(), any(), anyInt(), anyBoolean(), any(), anyBoolean()); } @Test @@ -533,22 +570,18 @@ when(mAutocompleteDelegate.isUrlBarFocused()).thenReturn(true); when(mAutocompleteDelegate.didFocusUrlFromFakebox()).thenReturn(false); - Profile profile = Mockito.mock(Profile.class); String url = "http://www.example.com"; String title = "Title"; int pageClassification = PageClassification.BLANK_VALUE; - when(mLocationBarDataProvider.getProfile()).thenReturn(profile); - when(mLocationBarDataProvider.getCurrentUrl()).thenReturn(url); - when(mLocationBarDataProvider.getTitle()).thenReturn(title); - when(mLocationBarDataProvider.hasTab()).thenReturn(true); - when(mLocationBarDataProvider.getPageClassification(false)).thenReturn(pageClassification); + setUpLocationBarDataProvider(url, title, pageClassification); when(mTextStateProvider.getTextWithAutocomplete()).thenReturn(url); mMediator.onNativeInitialized(); mMediator.onUrlFocusChange(true); + mHandler.runQueuedTasks(); verify(mAutocompleteController) - .startZeroSuggest(profile, url, url, pageClassification, title); + .startZeroSuggest(mProfile, url, url, pageClassification, title); } @Test @@ -559,25 +592,24 @@ when(mAutocompleteDelegate.isUrlBarFocused()).thenReturn(true); when(mAutocompleteDelegate.didFocusUrlFromFakebox()).thenReturn(false); - Profile profile = Mockito.mock(Profile.class); String url = "http://www.example.com"; String title = "Title"; int pageClassification = PageClassification.BLANK_VALUE; - when(mLocationBarDataProvider.getProfile()).thenReturn(profile); - when(mLocationBarDataProvider.getCurrentUrl()).thenReturn(url); - when(mLocationBarDataProvider.getTitle()).thenReturn(title); - when(mLocationBarDataProvider.hasTab()).thenReturn(true); - when(mLocationBarDataProvider.getPageClassification(false)).thenReturn(pageClassification); + setUpLocationBarDataProvider(url, title, pageClassification); when(mTextStateProvider.getTextWithAutocomplete()).thenReturn(""); - // Signal focus prior to initializing native. + // Signal focus prior to initializing native; confirm that zero suggest is not triggered. mMediator.onUrlFocusChange(true); + mHandler.runQueuedTasks(); + verify(mAutocompleteController, never()) + .startZeroSuggest(any(), any(), any(), anyInt(), any()); // Initialize native and ensure zero suggest is triggered. mMediator.onNativeInitialized(); + mHandler.runQueuedTasks(); verify(mAutocompleteController) - .startZeroSuggest(profile, "", url, pageClassification, title); + .startZeroSuggest(mProfile, "", url, pageClassification, title); } @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetTest.java index e90fc04f..1a7eb58 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetTest.java
@@ -303,8 +303,8 @@ @MediumTest public void testAccountDisappearedOnCollapsedSheet() { buildAndShowCollapsedBottomSheet(); - mAccountManagerTestRule.removeAccountAndWaitForSeeding(PROFILE_DATA1.getAccountEmail()); - mAccountManagerTestRule.removeAccountAndWaitForSeeding(PROFILE_DATA2.getAccountEmail()); + mAccountManagerTestRule.removeAccount(PROFILE_DATA1.getAccountEmail()); + mAccountManagerTestRule.removeAccount(PROFILE_DATA2.getAccountEmail()); CriteriaHelper.pollUiThread(() -> { return !mCoordinator.getBottomSheetViewForTesting() .findViewById(R.id.account_picker_selected_account) @@ -317,8 +317,8 @@ @MediumTest public void testAccountDisappearedOnExpandedSheet() { buildAndShowExpandedBottomSheet(); - mAccountManagerTestRule.removeAccountAndWaitForSeeding(PROFILE_DATA1.getAccountEmail()); - mAccountManagerTestRule.removeAccountAndWaitForSeeding(PROFILE_DATA2.getAccountEmail()); + mAccountManagerTestRule.removeAccount(PROFILE_DATA1.getAccountEmail()); + mAccountManagerTestRule.removeAccount(PROFILE_DATA2.getAccountEmail()); CriteriaHelper.pollUiThread(() -> { return !mCoordinator.getBottomSheetViewForTesting() .findViewById(R.id.account_picker_account_list) @@ -330,8 +330,8 @@ @Test @MediumTest public void testAccountReappearedOnCollapsedSheet() { - mAccountManagerTestRule.removeAccountAndWaitForSeeding(PROFILE_DATA1.getAccountEmail()); - mAccountManagerTestRule.removeAccountAndWaitForSeeding(PROFILE_DATA2.getAccountEmail()); + mAccountManagerTestRule.removeAccount(PROFILE_DATA1.getAccountEmail()); + mAccountManagerTestRule.removeAccount(PROFILE_DATA2.getAccountEmail()); TestThreadUtils.runOnUiThreadBlocking(() -> { mCoordinator = new AccountPickerBottomSheetCoordinator(sActivityTestRule.getActivity(), getBottomSheetController(), mAccountPickerDelegateMock, @@ -348,7 +348,7 @@ public void testOtherAccountsChangeOnCollapsedSheet() { buildAndShowCollapsedBottomSheet(); checkCollapsedAccountList(PROFILE_DATA1); - mAccountManagerTestRule.removeAccountAndWaitForSeeding(PROFILE_DATA2.getAccountEmail()); + mAccountManagerTestRule.removeAccount(PROFILE_DATA2.getAccountEmail()); checkCollapsedAccountList(PROFILE_DATA1); } @@ -356,7 +356,7 @@ @MediumTest public void testSelectedAccountChangeOnCollapsedSheet() { buildAndShowCollapsedBottomSheet(); - mAccountManagerTestRule.removeAccountAndWaitForSeeding(PROFILE_DATA1.getAccountEmail()); + mAccountManagerTestRule.removeAccount(PROFILE_DATA1.getAccountEmail()); checkCollapsedAccountList(PROFILE_DATA2); }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/notifications/NotificationIntentInterceptorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/notifications/NotificationIntentInterceptorTest.java index 126b687..b65c7160 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/notifications/NotificationIntentInterceptorTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/notifications/NotificationIntentInterceptorTest.java
@@ -6,8 +6,6 @@ import static org.robolectric.Shadows.shadowOf; -import static org.chromium.chrome.browser.notifications.NotificationIntentInterceptor.INTENT_ACTION; - import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; @@ -24,6 +22,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; +import org.robolectric.Shadows; import org.robolectric.annotation.Config; import org.robolectric.shadows.ShadowLog; import org.robolectric.shadows.ShadowNotificationManager; @@ -86,8 +85,6 @@ ContextUtils.initApplicationContextForTests(mContext); mShadowNotificationManager = shadowOf( (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE)); - mContext.registerReceiver( - new NotificationIntentInterceptor.Receiver(), new IntentFilter(INTENT_ACTION)); mReceiver = new TestReceiver(); mContext.registerReceiver(mReceiver, new IntentFilter(TestReceiver.TEST_ACTION)); } @@ -131,6 +128,15 @@ return builder.buildNotificationWrapper(); } + private void sendPendingIntent(PendingIntent pendingIntent) { + // Simulate to send a PendingIntent by manually starting the TrampolineActivity. + ShadowPendingIntent shadowPendingIntent = Shadows.shadowOf(pendingIntent); + Robolectric + .buildActivity(NotificationIntentInterceptor.TrampolineActivity.class, + shadowPendingIntent.getSavedIntent()) + .create(); + } + /** * Verifies {@link Notification#contentIntent} can be intercepted by {@link * NotificationIntentInterceptor}. @@ -145,8 +151,7 @@ Notification notification = mShadowNotificationManager.getAllNotifications().get(0); Assert.assertEquals(TEST_NOTIFICATION_TITLE, notification.extras.getCharSequence(Notification.EXTRA_TITLE).toString()); - notification.contentIntent.send(); - Robolectric.flushForegroundThreadScheduler(); + sendPendingIntent(notification.contentIntent); // Verify the intent and histograms recorded. Intent receivedIntent = mReceiver.intentReceived(); @@ -172,8 +177,7 @@ Notification notification = mShadowNotificationManager.getAllNotifications().get(0); Assert.assertEquals(TEST_NOTIFICATION_TITLE, notification.extras.getCharSequence(Notification.EXTRA_TITLE).toString()); - notification.deleteIntent.send(); - Robolectric.flushForegroundThreadScheduler(); + sendPendingIntent(notification.deleteIntent); // Verify the histogram. Assert.assertEquals(1, @@ -200,9 +204,7 @@ Assert.assertEquals(1, notification.actions.length); Notification.Action action = notification.actions[0]; Assert.assertNotNull(action.actionIntent); - action.actionIntent.send(); - - Robolectric.flushForegroundThreadScheduler(); + sendPendingIntent(action.actionIntent); // Verify the intent and histograms recorded. Intent receivedIntent = mReceiver.intentReceived();
diff --git a/chrome/android/monochrome/BUILD.gn b/chrome/android/monochrome/BUILD.gn index aa43fd6..33da361 100644 --- a/chrome/android/monochrome/BUILD.gn +++ b/chrome/android/monochrome/BUILD.gn
@@ -11,6 +11,11 @@ data_deps = [ "//android_webview:system_webview_apk", "//build/android:devil_chromium_py", + + # Depending on logdog_wrapper here is a hack to allow all isolated scripts + # to be wrapped, otherwise some python dependencies are missing, since + # this target doesn't depend on test_runner_py like others + "//build/android:logdog_wrapper_py", "//chrome/android:chrome_public_apk", "//chrome/android:monochrome_public_apk", "//testing:run_isolated_script_test",
diff --git a/chrome/app/chrome_command_ids.h b/chrome/app/chrome_command_ids.h index dfce54a..085d480 100644 --- a/chrome/app/chrome_command_ids.h +++ b/chrome/app/chrome_command_ids.h
@@ -443,6 +443,7 @@ // Views debug commands. #define IDC_DEBUG_TOGGLE_TABLET_MODE 52510 #define IDC_DEBUG_PRINT_VIEW_TREE 52511 +#define IDC_DEBUG_PRINT_VIEW_TREE_DETAILS 52512 // Please leave a gap here for new debug commands. // NOTE: The last valid command value is 57343 (0xDFFF)
diff --git a/chrome/app/os_settings_search_tag_strings.grdp b/chrome/app/os_settings_search_tag_strings.grdp index 1c28610..f0fc212 100644 --- a/chrome/app/os_settings_search_tag_strings.grdp +++ b/chrome/app/os_settings_search_tag_strings.grdp
@@ -1174,12 +1174,21 @@ <message name="IDS_OS_SETTINGS_TAG_ABOUT_TERMS_OF_SERVICE" desc="Text for search result item which, when clicked, navigates the user to 'About Chrome OS' settings, with a link to the Terms of Service."> Terms of Service </message> - <message name="IDS_OS_SETTINGS_TAG_ABOUT_DIAGNOSTICS" desc="Text for search result item which, when clicked, navigates the user to 'Diagnostics' settings, with a link which opens the Diagnostics App. Alternate phrase for 'Troubleshooting'"> + <message name="IDS_OS_SETTINGS_TAG_ABOUT_DIAGNOSTICS" desc="Text for search result item which, when clicked, navigates the user to 'Diagnostics' settings, with a link which opens the Diagnostics App. Alternate phrase for 'Troubleshooting', 'Battery Health', 'CPU Usage', 'Memory Usage'"> Diagnostics </message> - <message name="IDS_OS_SETTINGS_TAG_ABOUT_DIAGNOSTICS_ALT1" desc="Text for search result item which, when clicked, navigates the user to 'Diagnostics' settings, with a link which opens the Diagnostics App. Alternate phrase for 'Diagnostics'"> + <message name="IDS_OS_SETTINGS_TAG_ABOUT_DIAGNOSTICS_ALT1" desc="Text for search result item which, when clicked, navigates the user to 'Diagnostics' settings, with a link which opens the Diagnostics App. Alternate phrase for 'Diagnostics', 'Battery Health', 'CPU Usage', 'Memory Usage'"> Troubleshooting </message> + <message name="IDS_OS_SETTINGS_TAG_ABOUT_DIAGNOSTICS_ALT2" desc="Text for search result item which, when clicked, navigates the user to 'Diagnostics' settings, with a link which opens the Diagnostics App. Alternate phrase for 'Diagnostics', 'Troubleshooting', 'CPU Usage', 'Memory Usage'"> + Battery Health + </message> + <message name="IDS_OS_SETTINGS_TAG_ABOUT_DIAGNOSTICS_ALT3" desc="Text for search result item which, when clicked, navigates the user to 'Diagnostics' settings, with a link which opens the Diagnostics App. Alternate phrase for 'Diagnostics', 'Troubleshooting', 'Battery Health', 'Memory Usage'"> + CPU Usage + </message> + <message name="IDS_OS_SETTINGS_TAG_ABOUT_DIAGNOSTICS_ALT4" desc="Text for search result item which, when clicked, navigates the user to 'Diagnostics' settings, with a link which opens the Diagnostics App. Alternate phrase for 'Diagnostics', 'Troubleshooting', 'Battery Health', 'CPU Usage'"> + Memory Usage + </message> <!-- On Startup section. --> <message name="IDS_OS_SETTINGS_TAG_ON_STARTUP" desc="Text for search result item which, when clicked, navigates the user to On Startup settings, with a radio group to configure the restore apps and pages options">
diff --git a/chrome/app/os_settings_search_tag_strings_grdp/IDS_OS_SETTINGS_TAG_ABOUT_DIAGNOSTICS_ALT2.png.sha1 b/chrome/app/os_settings_search_tag_strings_grdp/IDS_OS_SETTINGS_TAG_ABOUT_DIAGNOSTICS_ALT2.png.sha1 new file mode 100644 index 0000000..701f4039 --- /dev/null +++ b/chrome/app/os_settings_search_tag_strings_grdp/IDS_OS_SETTINGS_TAG_ABOUT_DIAGNOSTICS_ALT2.png.sha1
@@ -0,0 +1 @@ +c1d89b2f357083a5cb2e791e65847d7ed89d7bfc \ No newline at end of file
diff --git a/chrome/app/os_settings_search_tag_strings_grdp/IDS_OS_SETTINGS_TAG_ABOUT_DIAGNOSTICS_ALT3.png.sha1 b/chrome/app/os_settings_search_tag_strings_grdp/IDS_OS_SETTINGS_TAG_ABOUT_DIAGNOSTICS_ALT3.png.sha1 new file mode 100644 index 0000000..fda7d552 --- /dev/null +++ b/chrome/app/os_settings_search_tag_strings_grdp/IDS_OS_SETTINGS_TAG_ABOUT_DIAGNOSTICS_ALT3.png.sha1
@@ -0,0 +1 @@ +3e5f92a6e48386c10f5b48f1b424be9a00e2bfcb \ No newline at end of file
diff --git a/chrome/app/os_settings_search_tag_strings_grdp/IDS_OS_SETTINGS_TAG_ABOUT_DIAGNOSTICS_ALT4.png.sha1 b/chrome/app/os_settings_search_tag_strings_grdp/IDS_OS_SETTINGS_TAG_ABOUT_DIAGNOSTICS_ALT4.png.sha1 new file mode 100644 index 0000000..e1b2edaa --- /dev/null +++ b/chrome/app/os_settings_search_tag_strings_grdp/IDS_OS_SETTINGS_TAG_ABOUT_DIAGNOSTICS_ALT4.png.sha1
@@ -0,0 +1 @@ +f477a69ea1b255572da09472a0e470d16dc748d8 \ No newline at end of file
diff --git a/chrome/app/settings_google_chrome_strings.grdp b/chrome/app/settings_google_chrome_strings.grdp index 739cba6..cf37bc6 100644 --- a/chrome/app/settings_google_chrome_strings.grdp +++ b/chrome/app/settings_google_chrome_strings.grdp
@@ -97,7 +97,7 @@ </if> <!-- Main Page --> - <if expr="chromeos"> + <if expr="chromeos or lacros"> <!-- No target="_blank" because OS settings opens its own window. --> <message name="IDS_SETTINGS_OS_SETTINGS_BANNER" desc="Banner displayed in browser settings page that links to OS settings."> If a setting doesn't show on this page, look in your <ph name="LINK_BEGIN"><a href="$1<ex>https://google.com/</ex>"></ph>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 2fbbc05..0666cf8 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -802,8 +802,6 @@ "metrics/authenticator_utility.h", "metrics/bluetooth_available_utility.cc", "metrics/bluetooth_available_utility.h", - "metrics/browser_window_histogram_helper.cc", - "metrics/browser_window_histogram_helper.h", "metrics/chrome_browser_main_extra_parts_metrics.cc", "metrics/chrome_browser_main_extra_parts_metrics.h", "metrics/chrome_feature_list_creator.cc", @@ -1067,6 +1065,8 @@ "page_load_metrics/observers/translate_page_load_metrics_observer.h", "page_load_metrics/page_load_metrics_initialize.cc", "page_load_metrics/page_load_metrics_initialize.h", + "page_load_metrics/page_load_metrics_memory_tracker_factory.cc", + "page_load_metrics/page_load_metrics_memory_tracker_factory.h", "password_manager/account_password_store_factory.cc", "password_manager/account_password_store_factory.h", "password_manager/affiliation_service_factory.cc", @@ -4003,6 +4003,8 @@ "signin/signin_promo.h", "signin/signin_ui_util.cc", "signin/signin_ui_util.h", + "speech/chrome_speech_recognition_service.cc", + "speech/chrome_speech_recognition_service.h", "speech/extension_api/tts_extension_api_constants.cc", # Should be moved # to extensions # section ? @@ -4011,7 +4013,6 @@ "speech/speech_recognition_client_browser_interface.h", "speech/speech_recognition_client_browser_interface_factory.cc", "speech/speech_recognition_client_browser_interface_factory.h", - "speech/speech_recognition_service.cc", "speech/speech_recognition_service.h", "speech/speech_recognition_service_factory.cc", "speech/speech_recognition_service_factory.h", @@ -4208,6 +4209,16 @@ ] if (is_chromeos_ash) { sources += [ + "speech/cros_speech_recognition_service.cc", + "speech/cros_speech_recognition_service.h", + "speech/cros_speech_recognition_service_factory.cc", + "speech/cros_speech_recognition_service_factory.h", + ] + + deps += [ "//chrome/services/speech:lib" ] + } + if (is_chromeos_ash) { + sources += [ "sharing/webrtc/ice_config_fetcher.cc", "sharing/webrtc/ice_config_fetcher.h", "sharing/webrtc/sharing_mojo_service.cc",
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS index e4a9555b..a9d34ba3 100644 --- a/chrome/browser/DEPS +++ b/chrome/browser/DEPS
@@ -404,7 +404,7 @@ "+third_party/widevine/cdm/buildflags.h", "+third_party/widevine/cdm/widevine_cdm_common.h", "+chrome/services/machine_learning", - + "+chrome/services/speech", # Code under //ash should be accessed via its public API. See //ash/README.md. "-ash", "+ash/components",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index f82532f..32f588f5 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -1459,6 +1459,25 @@ {"B", kTabHoverCardsSettingB, base::size(kTabHoverCardsSettingB), nullptr}, {"C", kTabHoverCardsSettingC, base::size(kTabHoverCardsSettingC), nullptr}}; +const FeatureEntry::FeatureParam kMinimumTabWidthSettingPinned[] = { + {features::kMinimumTabWidthFeatureParameterName, "54"}}; +const FeatureEntry::FeatureParam kMinimumTabWidthSettingMedium[] = { + {features::kMinimumTabWidthFeatureParameterName, "72"}}; +const FeatureEntry::FeatureParam kMinimumTabWidthSettingLarge[] = { + {features::kMinimumTabWidthFeatureParameterName, "140"}}; +const FeatureEntry::FeatureParam kMinimumTabWidthSettingFull[] = { + {features::kMinimumTabWidthFeatureParameterName, "256"}}; + +const FeatureEntry::FeatureVariation kTabScrollingVariations[] = { + {" - tabs shrink to pinned tab width", kMinimumTabWidthSettingPinned, + base::size(kMinimumTabWidthSettingPinned), nullptr}, + {" - tabs shrink to a medium width", kMinimumTabWidthSettingMedium, + base::size(kMinimumTabWidthSettingMedium), nullptr}, + {" - tabs shrink to a large width", kMinimumTabWidthSettingLarge, + base::size(kMinimumTabWidthSettingLarge), nullptr}, + {" - tabs do not shrink", kMinimumTabWidthSettingFull, + base::size(kMinimumTabWidthSettingFull), nullptr}}; + const FeatureEntry::FeatureParam kPromoBrowserCommandUnknownCommandParam[] = { {features::kPromoBrowserCommandIdParam, "0"}}; const FeatureEntry::FeatureParam @@ -2941,9 +2960,6 @@ {"stylus-battery-status", flag_descriptions::kStylusBatteryStatusName, flag_descriptions::kStylusBatteryStatusDescription, kOsCrOS, FEATURE_VALUE_TYPE(ash::features::kStylusBatteryStatus)}, - {"system-tray-mic-gain", flag_descriptions::kSystemTrayMicGainName, - flag_descriptions::kSystemTrayMicGainDescription, kOsCrOS, - FEATURE_VALUE_TYPE(ash::features::kSystemTrayMicGainSetting)}, {"deprecate-low-usage-codecs", flag_descriptions::kDeprecateLowUsageCodecsName, flag_descriptions::kDeprecateLowUsageCodecsDescription, kOsCrOS, @@ -3214,6 +3230,10 @@ flag_descriptions::kExtensionContentVerificationName, flag_descriptions::kExtensionContentVerificationDescription, kOsDesktop, MULTI_VALUE_TYPE(kExtensionContentVerificationChoices)}, + {"preemtive-link-to-text-generation", + flag_descriptions::kPreemtiveLinkToTextGenerationName, + flag_descriptions::kPreemtiveLinkToTextGenerationDescription, kOsAll, + FEATURE_VALUE_TYPE(features::kPreemtiveLinkToTextGeneration)}, #if BUILDFLAG(IS_CHROMEOS_ASH) {"keyboard-based-display-arrangement-in-settings", flag_descriptions::kKeyboardBasedDisplayArrangementInSettingsName, @@ -3909,6 +3929,9 @@ {"arc-documents-provider", flag_descriptions::kArcDocumentsProviderName, flag_descriptions::kArcDocumentsProviderDescription, kOsCrOS, FEATURE_VALUE_TYPE(arc::kEnableDocumentsProviderInFilesAppFeature)}, + {"arc-enable-usap", flag_descriptions::kArcEnableUsapName, + flag_descriptions::kArcEnableUsapDesc, kOsCrOS, + FEATURE_VALUE_TYPE(arc::kEnableUsap)}, {"arc-file-picker-experiment", flag_descriptions::kArcFilePickerExperimentName, flag_descriptions::kArcFilePickerExperimentDescription, kOsCrOS, @@ -4520,7 +4543,9 @@ {flag_descriptions::kScrollableTabStripFlagId, flag_descriptions::kScrollableTabStripName, flag_descriptions::kScrollableTabStripDescription, kOsDesktop, - FEATURE_VALUE_TYPE(features::kScrollableTabStrip)}, + FEATURE_WITH_PARAMS_VALUE_TYPE(features::kScrollableTabStrip, + kTabScrollingVariations, + "TabScrolling")}, {"scrollable-tabstrip-buttons", flag_descriptions::kScrollableTabStripButtonsName, @@ -5495,6 +5520,10 @@ flag_descriptions::kEnablePalmOnToolTypePalmName, kOsCrOS, FEATURE_VALUE_TYPE(ui::kEnablePalmOnToolTypePalm)}, + {"enable-pci-guard-ui", flag_descriptions::kEnablePciguardUiName, + flag_descriptions::kEnablePciguardUiDescription, kOsCrOS, + FEATURE_VALUE_TYPE(chromeos::features::kEnablePciguardUi)}, + {"enable-heuristic-stylus-palm-rejection", flag_descriptions::kEnableHeuristicStylusPalmRejectionName, flag_descriptions::kEnableHeuristicStylusPalmRejectionDescription, kOsCrOS, @@ -5675,13 +5704,6 @@ flag_descriptions::kAutofillPruneSuggestionsDescription, kOsAll, FEATURE_VALUE_TYPE(autofill::features::kAutofillPruneSuggestions)}, -#if BUILDFLAG(IS_CHROMEOS_ASH) - {"enable-advanced-ppd-attributes", - flag_descriptions::kEnableAdvancedPpdAttributesName, - flag_descriptions::kEnableAdvancedPpdAttributesDescription, kOsCrOS, - FEATURE_VALUE_TYPE(printing::features::kAdvancedPpdAttributes)}, -#endif // BUILDFLAG(IS_CHROMEOS_ASH) - {"allow-sync-xhr-in-page-dismissal", flag_descriptions::kAllowSyncXHRInPageDismissalName, flag_descriptions::kAllowSyncXHRInPageDismissalDescription,
diff --git a/chrome/browser/android/compositor/tab_content_manager.cc b/chrome/browser/android/compositor/tab_content_manager.cc index de7b2c2..89eedee0 100644 --- a/chrome/browser/android/compositor/tab_content_manager.cc +++ b/chrome/browser/android/compositor/tab_content_manager.cc
@@ -43,6 +43,8 @@ namespace { +const double kDefaultThumbnailAspectRatio = 0.85; + using TabReadbackCallback = base::OnceCallback<void(float, const SkBitmap&)>; } // namespace @@ -72,7 +74,7 @@ if (crop_to_match_aspect_ratio) { double aspect_ratio = base::GetFieldTrialParamByFeatureAsDouble( chrome::android::kTabGridLayoutAndroid, "thumbnail_aspect_ratio", - 1.0); + kDefaultThumbnailAspectRatio); aspect_ratio = ThumbnailCache::clampAspectRatio(aspect_ratio, 0.5, 2.0); int height = std::min(view_size_in_pixels.height(), (int)(view_size_in_pixels.width() / aspect_ratio)); @@ -130,7 +132,8 @@ jboolean save_jpeg_thumbnails) : weak_java_tab_content_manager_(env, obj) { double jpeg_aspect_ratio = base::GetFieldTrialParamByFeatureAsDouble( - chrome::android::kTabGridLayoutAndroid, "thumbnail_aspect_ratio", 1.0); + chrome::android::kTabGridLayoutAndroid, "thumbnail_aspect_ratio", + kDefaultThumbnailAspectRatio); thumbnail_cache_ = std::make_unique<ThumbnailCache>( static_cast<size_t>(default_cache_size), static_cast<size_t>(approximation_cache_size), @@ -393,7 +396,8 @@ // landscape mode. int scale = need_downsampling ? 2 : 1; double aspect_ratio = base::GetFieldTrialParamByFeatureAsDouble( - chrome::android::kTabGridLayoutAndroid, "thumbnail_aspect_ratio", 1.0); + chrome::android::kTabGridLayoutAndroid, "thumbnail_aspect_ratio", + kDefaultThumbnailAspectRatio); aspect_ratio = ThumbnailCache::clampAspectRatio(aspect_ratio, 0.5, 2.0); int width = std::min(bitmap.width() / scale,
diff --git a/chrome/browser/android/contextualsearch/contextual_search_delegate.cc b/chrome/browser/android/contextualsearch/contextual_search_delegate.cc index a18cad2..6f6435c1 100644 --- a/chrome/browser/android/contextualsearch/contextual_search_delegate.cc +++ b/chrome/browser/android/contextualsearch/contextual_search_delegate.cc
@@ -255,12 +255,14 @@ std::string search_url_full; std::string search_url_preload; int coca_card_tag = 0; + std::vector<std::string> related_searches; DecodeSearchTermFromJsonResponse( json_string, &search_term, &display_text, &alternate_term, &mid, &prevent_preload, &mention_start, &mention_end, &context_language, &thumbnail_url, &caption, &quick_action_uri, &quick_action_category, - &logged_event_id, &search_url_full, &search_url_preload, &coca_card_tag); + &logged_event_id, &search_url_full, &search_url_preload, &coca_card_tag, + &related_searches); if (mention_start != 0 || mention_end != 0) { // Sanity check that our selection is non-zero and it is less than // 100 characters as that would make contextual search bar hide. @@ -283,7 +285,7 @@ prevent_preload == kDoPreventPreloadValue, start_adjust, end_adjust, context_language, thumbnail_url, caption, quick_action_uri, quick_action_category, logged_event_id, search_url_full, - search_url_preload, coca_card_tag)); + search_url_preload, coca_card_tag, related_searches)); } std::string ContextualSearchDelegate::BuildRequestUrl( @@ -445,7 +447,8 @@ int64_t* logged_event_id, std::string* search_url_full, std::string* search_url_preload, - int* coca_card_tag) { + int* coca_card_tag, + std::vector<std::string>* related_searches) { bool contains_xssi_escape = base::StartsWith(response, kXssiEscape, base::CompareCase::SENSITIVE); const std::string& proper_json = @@ -563,6 +566,18 @@ search_query_list->GetString(0, display_text); search_query_list->GetString(0, search_term); } + + // For Related Searches extract the array. + base::ListValue* searches_list = nullptr; + dict->GetList(kRelatedSearchesQueryList, &searches_list); + if (base::FeatureList::IsEnabled(chrome::android::kRelatedSearches) && + searches_list && searches_list->GetSize() >= 1) { + for (size_t i = 0; i < searches_list->GetSize(); ++i) { + std::string search; + searches_list->GetString(i, &search); + related_searches->push_back(search); + } + } } // Extract the Start/End of the mentions in the surrounding text
diff --git a/chrome/browser/android/contextualsearch/contextual_search_delegate.h b/chrome/browser/android/contextualsearch/contextual_search_delegate.h index 5b21dca4..23c6dae 100644 --- a/chrome/browser/android/contextualsearch/contextual_search_delegate.h +++ b/chrome/browser/android/contextualsearch/contextual_search_delegate.h
@@ -154,7 +154,8 @@ int64_t* logged_event_id, std::string* search_url_full, std::string* search_url_preload, - int* coca_card_tag); + int* coca_card_tag, + std::vector<std::string>* related_searches); // Extracts the start and end location from a mentions list, and sets the // integers referenced by |startResult| and |endResult|.
diff --git a/chrome/browser/android/contextualsearch/contextual_search_delegate_unittest.cc b/chrome/browser/android/contextualsearch/contextual_search_delegate_unittest.cc index 5e170367..b176e7d 100644 --- a/chrome/browser/android/contextualsearch/contextual_search_delegate_unittest.cc +++ b/chrome/browser/android/contextualsearch/contextual_search_delegate_unittest.cc
@@ -233,6 +233,7 @@ std::string search_url_full() { return search_url_full_; } std::string search_url_preload() { return search_url_preload_; } int coca_card_tag() { return coca_card_tag_; } + std::vector<std::string> related_searches() { return related_searches_; } // The delegate under test. std::unique_ptr<ContextualSearchDelegate> delegate_; @@ -260,6 +261,7 @@ search_url_full_ = resolved_search_term.search_url_full; search_url_preload_ = resolved_search_term.search_url_preload; coca_card_tag_ = resolved_search_term.coca_card_tag; + related_searches_ = resolved_search_term.related_searches; } void recordSampleSelectionAvailable(const std::string& encoding, @@ -288,6 +290,7 @@ std::string search_url_full_; std::string search_url_preload_; int coca_card_tag_; + std::vector<std::string> related_searches_; base::test::SingleThreadTaskEnvironment task_environment_{ base::test::SingleThreadTaskEnvironment::MainThreadType::IO}; @@ -574,12 +577,14 @@ std::string search_url_full; std::string search_url_preload; int coca_card_tag; + std::vector<std::string> related_searches; delegate_->DecodeSearchTermFromJsonResponse( json_with_escape, &search_term, &display_text, &alternate_term, &mid, &prevent_preload, &mention_start, &mention_end, &context_language, &thumbnail_url, &caption, &quick_action_uri, &quick_action_category, - &logged_event_id, &search_url_full, &search_url_preload, &coca_card_tag); + &logged_event_id, &search_url_full, &search_url_preload, &coca_card_tag, + &related_searches); EXPECT_EQ("obama", search_term); EXPECT_EQ("Barack Obama", display_text); @@ -597,6 +602,7 @@ EXPECT_EQ("https://www.google.com/search?q=define+obscure&ctxs=2&pf=c&sns=1", search_url_preload); EXPECT_EQ(12, coca_card_tag); + EXPECT_EQ(0u, related_searches.size()); } TEST_F(ContextualSearchDelegateTest, ResponseWithLanguage) {
diff --git a/chrome/browser/android/contextualsearch/contextual_search_manager.cc b/chrome/browser/android/contextualsearch/contextual_search_manager.cc index 7d1f4429..345d3d5 100644 --- a/chrome/browser/android/contextualsearch/contextual_search_manager.cc +++ b/chrome/browser/android/contextualsearch/contextual_search_manager.cc
@@ -7,6 +7,7 @@ #include <memory> #include <set> +#include "base/android/jni_array.h" #include "base/android/jni_string.h" #include "base/bind.h" #include "base/callback.h" @@ -126,6 +127,9 @@ base::android::ScopedJavaLocalRef<jstring> j_search_url_preload = base::android::ConvertUTF8ToJavaString( env, resolved_search_term.search_url_preload); + base::android::ScopedJavaLocalRef<jobjectArray> j_searches = + base::android::ToJavaArrayOfStrings( + env, resolved_search_term.related_searches); Java_ContextualSearchManager_onSearchTermResolutionResponse( env, java_manager_, resolved_search_term.is_invalid, resolved_search_term.response_code, j_search_term, j_display_text, @@ -135,7 +139,7 @@ j_thumbnail_url, j_caption, j_quick_action_uri, resolved_search_term.quick_action_category, resolved_search_term.logged_event_id, j_search_url_full, - j_search_url_preload, resolved_search_term.coca_card_tag); + j_search_url_preload, resolved_search_term.coca_card_tag, j_searches); } void ContextualSearchManager::OnTextSurroundingSelectionAvailable(
diff --git a/chrome/browser/android/contextualsearch/resolved_search_term.cc b/chrome/browser/android/contextualsearch/resolved_search_term.cc index 1150c62c..0f392e5 100644 --- a/chrome/browser/android/contextualsearch/resolved_search_term.cc +++ b/chrome/browser/android/contextualsearch/resolved_search_term.cc
@@ -24,7 +24,8 @@ logged_event_id(0), search_url_full(""), search_url_preload(""), - coca_card_tag(0) {} + coca_card_tag(0), + related_searches({}) {} ResolvedSearchTerm::ResolvedSearchTerm( bool is_invalid, @@ -44,7 +45,8 @@ int64_t logged_event_id, const std::string& search_url_full, const std::string& search_url_preload, - int coca_card_tag) + int coca_card_tag, + const std::vector<std::string>& related_searches) : is_invalid(is_invalid), response_code(response_code), search_term(search_term), @@ -62,6 +64,7 @@ logged_event_id(logged_event_id), search_url_full(search_url_full), search_url_preload(search_url_preload), - coca_card_tag(coca_card_tag) {} + coca_card_tag(coca_card_tag), + related_searches(related_searches) {} ResolvedSearchTerm::~ResolvedSearchTerm() {}
diff --git a/chrome/browser/android/contextualsearch/resolved_search_term.h b/chrome/browser/android/contextualsearch/resolved_search_term.h index 194f77b..6043ce6 100644 --- a/chrome/browser/android/contextualsearch/resolved_search_term.h +++ b/chrome/browser/android/contextualsearch/resolved_search_term.h
@@ -5,7 +5,23 @@ #ifndef CHROME_BROWSER_ANDROID_CONTEXTUALSEARCH_RESOLVED_SEARCH_TERM_H_ #define CHROME_BROWSER_ANDROID_CONTEXTUALSEARCH_RESOLVED_SEARCH_TERM_H_ -#include <string> +#include <string.h> + +#include <algorithm> +#include <cmath> +#include <new> +#include <ostream> +#include <utility> + +#include "base/bit_cast.h" +#include "base/containers/checked_iterators.h" +#include "base/json/json_writer.h" +#include "base/logging.h" +#include "base/memory/ptr_util.h" +#include "base/stl_util.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "base/trace_event/memory_usage_estimator.h" #include "base/macros.h" @@ -47,9 +63,12 @@ int64_t logged_event_id, const std::string& search_url_full, const std::string& search_url_preload, - int coca_card_tag); + int coca_card_tag, + const std::vector<std::string>& related_searches); ~ResolvedSearchTerm(); + // TODO(donnd): switch to member-initialization style instead of initializers. + // TODO(donnd): change these members names to include an ending underscore. const bool is_invalid; const int response_code; // Use strings, rather than just references, to keep this complete. @@ -69,6 +88,7 @@ const std::string search_url_full; const std::string search_url_preload; const int coca_card_tag; + std::vector<std::string> related_searches; DISALLOW_COPY_AND_ASSIGN(ResolvedSearchTerm); };
diff --git a/chrome/browser/android/contextualsearch/simple_search_term_resolver.cc b/chrome/browser/android/contextualsearch/simple_search_term_resolver.cc index 72cff73..b4f0114 100644 --- a/chrome/browser/android/contextualsearch/simple_search_term_resolver.cc +++ b/chrome/browser/android/contextualsearch/simple_search_term_resolver.cc
@@ -7,6 +7,7 @@ #include <memory> #include <set> +#include "base/android/jni_array.h" #include "base/android/jni_string.h" #include "base/bind.h" #include "base/callback.h" @@ -105,6 +106,9 @@ base::android::ScopedJavaLocalRef<jstring> j_search_url_preload = base::android::ConvertUTF8ToJavaString( env, resolved_search_term.search_url_preload); + base::android::ScopedJavaLocalRef<jobjectArray> j_searches = + base::android::ToJavaArrayOfByteArray( + env, resolved_search_term.related_searches); Java_SimpleSearchTermResolver_onSearchTermResolutionResponse( env, java_instance_, resolved_search_term.is_invalid, resolved_search_term.response_code, j_search_term, j_display_text, @@ -114,7 +118,7 @@ j_thumbnail_url, j_caption, j_quick_action_uri, resolved_search_term.quick_action_category, resolved_search_term.logged_event_id, j_search_url_full, - j_search_url_preload, resolved_search_term.coca_card_tag); + j_search_url_preload, resolved_search_term.coca_card_tag, j_searches); } void SimpleSearchTermResolver::OnTextSurroundingSelectionAvailable(
diff --git a/chrome/browser/android/feed/v2/feed_stream_surface.cc b/chrome/browser/android/feed/v2/feed_stream_surface.cc index f18c0da9..88eda1f2 100644 --- a/chrome/browser/android/feed/v2/feed_stream_surface.cc +++ b/chrome/browser/android/feed/v2/feed_stream_surface.cc
@@ -46,7 +46,8 @@ } FeedStreamSurface::FeedStreamSurface(const JavaRef<jobject>& j_this) - : feed_stream_api_(nullptr) { + : FeedStreamApi::SurfaceInterface(kInterestStream), + feed_stream_api_(nullptr) { java_ref_.Reset(j_this); FeedService* service = FeedServiceFactory::GetForBrowserContext( @@ -95,9 +96,8 @@ if (!feed_stream_api_) return; feed_stream_api_->LoadMore( - GetSurfaceId(), - base::BindOnce(&base::android::RunBooleanCallbackAndroid, - ScopedJavaGlobalRef<jobject>(callback_obj))); + *this, base::BindOnce(&base::android::RunBooleanCallbackAndroid, + ScopedJavaGlobalRef<jobject>(callback_obj))); } void FeedStreamSurface::ProcessThereAndBackAgain( @@ -130,7 +130,8 @@ return 0; std::string data_string; base::android::JavaByteArrayToString(env, data, &data_string); - return feed_stream_api_->CreateEphemeralChangeFromPackedData(data_string) + return feed_stream_api_ + ->CreateEphemeralChangeFromPackedData(GetStreamType(), data_string) .GetUnsafeValue(); } @@ -139,7 +140,8 @@ int change_id) { if (!feed_stream_api_) return; - feed_stream_api_->CommitEphemeralChange(EphemeralChangeId(change_id)); + feed_stream_api_->CommitEphemeralChange(GetStreamType(), + EphemeralChangeId(change_id)); } void FeedStreamSurface::DiscardEphemeralChange(JNIEnv* env, @@ -147,7 +149,8 @@ int change_id) { if (!feed_stream_api_) return; - feed_stream_api_->RejectEphemeralChange(EphemeralChangeId(change_id)); + feed_stream_api_->RejectEphemeralChange(GetStreamType(), + EphemeralChangeId(change_id)); } void FeedStreamSurface::SurfaceOpened(JNIEnv* env, @@ -186,7 +189,7 @@ if (!feed_stream_api_) return; feed_stream_api_->ReportOpenAction( - base::android::ConvertJavaStringToUTF8(env, slice_id)); + GetStreamType(), base::android::ConvertJavaStringToUTF8(env, slice_id)); } void FeedStreamSurface::ReportOpenInNewTabAction( @@ -196,7 +199,7 @@ if (!feed_stream_api_) return; feed_stream_api_->ReportOpenInNewTabAction( - base::android::ConvertJavaStringToUTF8(env, slice_id)); + GetStreamType(), base::android::ConvertJavaStringToUTF8(env, slice_id)); } void FeedStreamSurface::ReportSliceViewed( @@ -206,7 +209,8 @@ if (!feed_stream_api_) return; feed_stream_api_->ReportSliceViewed( - GetSurfaceId(), base::android::ConvertJavaStringToUTF8(env, slice_id)); + GetSurfaceId(), GetStreamType(), + base::android::ConvertJavaStringToUTF8(env, slice_id)); } void FeedStreamSurface::ReportFeedViewed(
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm index 6f0c60b..12935a6 100644 --- a/chrome/browser/app_controller_mac.mm +++ b/chrome/browser/app_controller_mac.mm
@@ -28,6 +28,7 @@ #include "base/task/post_task.h" #include "base/task/thread_pool.h" #include "base/threading/scoped_blocking_call.h" +#include "base/threading/thread_restrictions.h" #include "build/branding_buildflags.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/apps/app_shim/app_shim_manager_mac.h" @@ -221,6 +222,31 @@ } // namespace +// Returns the last profile. This is extracted as a standalone function in order +// to be friend with base::ScopedAllowBlocking. +Profile* GetLastProfileMac() { + ProfileManager* profile_manager = g_browser_process->profile_manager(); + if (!profile_manager) + return nullptr; + + base::FilePath profile_path = + GetStartupProfilePath(profile_manager->user_data_dir(), + /*current_directory=*/base::FilePath(), + *base::CommandLine::ForCurrentProcess(), + /*ignore_profile_picker=*/true); + + // ProfileManager::GetProfile() is blocking if the profile was not loaded yet. + // TODO(https://1176734): Change this code to return nullptr when the profile + // is not loaded, and update all callers to handle this case. + base::ScopedAllowBlocking allow_blocking; + + // lastProfile is used to open URLs passed in application:openFiles: and + // should not default to Guest, even if the profile picker is shown. + // TODO(https://crbug.com/1155158): Remove the ignore_profile_picker parameter + // once the picker supports opening URLs. + return profile_manager->GetProfile(profile_path); +} + @interface AppController () <HandoffActiveURLObserverBridgeDelegate> - (void)initMenuState; - (void)initProfileMenu; @@ -1414,16 +1440,7 @@ if (![self isProfileReady]) return nullptr; - // On first launch, use the logic that ChromeBrowserMain uses to determine - // the initial profile. - ProfileManager* profile_manager = g_browser_process->profile_manager(); - if (!profile_manager) - return nullptr; - - return profile_manager->GetProfile( - GetStartupProfilePath(profile_manager->user_data_dir(), - /*current_directory=*/base::FilePath(), - *base::CommandLine::ForCurrentProcess())); + return GetLastProfileMac(); } - (Profile*)safeLastProfileForNewWindows {
diff --git a/chrome/browser/apps/app_service/app_service_proxy.cc b/chrome/browser/apps/app_service/app_service_proxy.cc index 36e7d75..192f84ab 100644 --- a/chrome/browser/apps/app_service/app_service_proxy.cc +++ b/chrome/browser/apps/app_service/app_service_proxy.cc
@@ -17,6 +17,7 @@ #include "chrome/browser/apps/app_service/app_icon_source.h" #include "chrome/browser/apps/app_service/app_service_metrics.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" +#include "chrome/browser/apps/app_service/launch_utils.h" #include "chrome/browser/chromeos/guest_os/guest_os_registry_service_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/chrome_features.h" @@ -254,10 +255,10 @@ void AppServiceProxy::Launch(const std::string& app_id, int32_t event_flags, apps::mojom::LaunchSource launch_source, - int64_t display_id) { + apps::mojom::WindowInfoPtr window_info) { if (app_service_.is_connected()) { app_registry_cache_.ForOneApp(app_id, [this, event_flags, launch_source, - display_id]( + &window_info]( const apps::AppUpdate& update) { #if BUILDFLAG(IS_CHROMEOS_ASH) if (MaybeShowLaunchPreventionDialog(update)) { @@ -266,8 +267,9 @@ #endif RecordAppLaunch(update.AppId(), launch_source); + app_service_->Launch(update.AppType(), update.AppId(), event_flags, - launch_source, display_id); + launch_source, std::move(window_info)); }); } } @@ -308,7 +310,7 @@ LaunchAppWithIntent( app_id, event_flags, apps_util::CreateShareIntentFromFiles(file_urls, mime_types), - launch_source, display::kDefaultDisplayId); + launch_source, MakeWindowInfo(display::kDefaultDisplayId)); } void AppServiceProxy::LaunchAppWithIntent( @@ -316,10 +318,10 @@ int32_t event_flags, apps::mojom::IntentPtr intent, apps::mojom::LaunchSource launch_source, - int64_t display_id) { + apps::mojom::WindowInfoPtr window_info) { if (app_service_.is_connected()) { app_registry_cache_.ForOneApp(app_id, [this, event_flags, &intent, - launch_source, display_id]( + launch_source, &window_info]( const apps::AppUpdate& update) { #if BUILDFLAG(IS_CHROMEOS_ASH) if (MaybeShowLaunchPreventionDialog(update)) { @@ -327,9 +329,10 @@ } #endif RecordAppLaunch(update.AppId(), launch_source); + app_service_->LaunchAppWithIntent(update.AppType(), update.AppId(), event_flags, std::move(intent), - launch_source, display_id); + launch_source, std::move(window_info)); }); } } @@ -338,9 +341,9 @@ int32_t event_flags, GURL url, apps::mojom::LaunchSource launch_source, - int64_t display_id) { + apps::mojom::WindowInfoPtr window_info) { LaunchAppWithIntent(app_id, event_flags, apps_util::CreateIntentFromUrl(url), - launch_source, display_id); + launch_source, std::move(window_info)); } void AppServiceProxy::SetPermission(const std::string& app_id,
diff --git a/chrome/browser/apps/app_service/app_service_proxy.h b/chrome/browser/apps/app_service/app_service_proxy.h index 77f41a8..3e3f6ece 100644 --- a/chrome/browser/apps/app_service/app_service_proxy.h +++ b/chrome/browser/apps/app_service/app_service_proxy.h
@@ -116,14 +116,12 @@ // Launches the app for the given |app_id|. |event_flags| provides additional // context about the action which launches the app (e.g. a middle click // indicating opening a background tab). |launch_source| is the possible app - // launch sources, e.g. from Shelf, from the search box, etc. |display_id| is - // the id of the display from which the app is launched. - // display::kInvalidDisplayId means that the display does not exist or is not - // set. + // launch sources, e.g. from Shelf, from the search box, etc. |window_info| is + // the window information to launch an app, e.g. display_id, window bounds. void Launch(const std::string& app_id, int32_t event_flags, apps::mojom::LaunchSource launch_source, - int64_t display_id); + apps::mojom::WindowInfoPtr window_info = nullptr); // Launches the app for the given |app_id| with files from |file_paths|. // |event_flags| provides additional context about the action which launches @@ -151,24 +149,24 @@ // Launches an app for the given |app_id|, passing |intent| to the app. // |event_flags| provides additional context about the action which launch the // app (e.g. a middle click indicating opening a background tab). - // |launch_source| is the possible app launch sources. |display_id| is the id - // of the display from which the app is launched. + // |launch_source| is the possible app launch sources. |window_info| is the + // window information to launch an app, e.g. display_id, window bounds. void LaunchAppWithIntent(const std::string& app_id, int32_t event_flags, apps::mojom::IntentPtr intent, apps::mojom::LaunchSource launch_source, - int64_t display_id); + apps::mojom::WindowInfoPtr window_info = nullptr); // Launches an app for the given |app_id|, passing |url| to the app. // |event_flags| provides additional context about the action which launch the // app (e.g. a middle click indicating opening a background tab). - // |launch_source| is the possible app launch sources. |display_id| is the id - // of the display from which the app is launched. + // |launch_source| is the possible app launch sources. |window_info| is the + // window information to launch an app, e.g. display_id, window bounds. void LaunchAppWithUrl(const std::string& app_id, int32_t event_flags, GURL url, apps::mojom::LaunchSource launch_source, - int64_t display_id); + apps::mojom::WindowInfoPtr window_info = nullptr); // Sets |permission| for the app identified by |app_id|. void SetPermission(const std::string& app_id,
diff --git a/chrome/browser/apps/app_service/arc_apps.cc b/chrome/browser/apps/app_service/arc_apps.cc index aec0e3b..aba8ae9 100644 --- a/chrome/browser/apps/app_service/arc_apps.cc +++ b/chrome/browser/apps/app_service/arc_apps.cc
@@ -558,12 +558,14 @@ void ArcApps::Launch(const std::string& app_id, int32_t event_flags, apps::mojom::LaunchSource launch_source, - int64_t display_id) { + apps::mojom::WindowInfoPtr window_info) { auto user_interaction_type = GetUserInterationType(launch_source); if (!user_interaction_type.has_value()) { return; } + int64_t display_id = + window_info ? window_info->display_id : display::kInvalidDisplayId; arc::LaunchApp(profile_, app_id, event_flags, user_interaction_type.value(), display_id); @@ -576,7 +578,7 @@ int32_t event_flags, apps::mojom::IntentPtr intent, apps::mojom::LaunchSource launch_source, - int64_t display_id) { + apps::mojom::WindowInfoPtr window_info) { auto user_interaction_type = GetUserInterationType(launch_source); if (!user_interaction_type.has_value()) { return; @@ -604,6 +606,9 @@ activity->activity_name = intent->activity_name.value(); } + int64_t display_id = + window_info ? window_info->display_id : display::kInvalidDisplayId; + if (intent->mime_type.has_value() && intent->file_urls.has_value()) { const auto file_urls = intent->file_urls.value(); arc::ConvertToContentUrlsAndShare(
diff --git a/chrome/browser/apps/app_service/arc_apps.h b/chrome/browser/apps/app_service/arc_apps.h index 6257d27..23545016 100644 --- a/chrome/browser/apps/app_service/arc_apps.h +++ b/chrome/browser/apps/app_service/arc_apps.h
@@ -89,12 +89,12 @@ void Launch(const std::string& app_id, int32_t event_flags, apps::mojom::LaunchSource launch_source, - int64_t display_id) override; + apps::mojom::WindowInfoPtr window_info) override; void LaunchAppWithIntent(const std::string& app_id, int32_t event_flags, apps::mojom::IntentPtr intent, apps::mojom::LaunchSource launch_source, - int64_t display_id) override; + apps::mojom::WindowInfoPtr window_info) override; void SetPermission(const std::string& app_id, apps::mojom::PermissionPtr permission) override; void Uninstall(const std::string& app_id,
diff --git a/chrome/browser/apps/app_service/borealis_apps.cc b/chrome/browser/apps/app_service/borealis_apps.cc index 49a5cc0..c8abd1b 100644 --- a/chrome/browser/apps/app_service/borealis_apps.cc +++ b/chrome/browser/apps/app_service/borealis_apps.cc
@@ -170,7 +170,7 @@ void BorealisApps::Launch(const std::string& app_id, int32_t event_flags, apps::mojom::LaunchSource launch_source, - int64_t display_id) { + apps::mojom::WindowInfoPtr window_info) { borealis::BorealisService::GetForProfile(profile_)->AppLauncher().Launch( app_id, base::DoNothing()); }
diff --git a/chrome/browser/apps/app_service/borealis_apps.h b/chrome/browser/apps/app_service/borealis_apps.h index 788a4e9cb..8e401b2 100644 --- a/chrome/browser/apps/app_service/borealis_apps.h +++ b/chrome/browser/apps/app_service/borealis_apps.h
@@ -60,7 +60,7 @@ void Launch(const std::string& app_id, int32_t event_flags, apps::mojom::LaunchSource launch_source, - int64_t display_id) override; + apps::mojom::WindowInfoPtr window_info) override; void Uninstall(const std::string& app_id, apps::mojom::UninstallSource uninstall_source, bool clear_site_data,
diff --git a/chrome/browser/apps/app_service/built_in_chromeos_apps.cc b/chrome/browser/apps/app_service/built_in_chromeos_apps.cc index c6dd79d6..2b6f4fa 100644 --- a/chrome/browser/apps/app_service/built_in_chromeos_apps.cc +++ b/chrome/browser/apps/app_service/built_in_chromeos_apps.cc
@@ -122,7 +122,7 @@ void BuiltInChromeOsApps::Launch(const std::string& app_id, int32_t event_flags, apps::mojom::LaunchSource launch_source, - int64_t display_id) { + apps::mojom::WindowInfoPtr window_info) { if (app_id == ash::kInternalAppIdKeyboardShortcutViewer) { ash::ToggleKeyboardShortcutViewer(); }
diff --git a/chrome/browser/apps/app_service/built_in_chromeos_apps.h b/chrome/browser/apps/app_service/built_in_chromeos_apps.h index 4b04f021..6cee114 100644 --- a/chrome/browser/apps/app_service/built_in_chromeos_apps.h +++ b/chrome/browser/apps/app_service/built_in_chromeos_apps.h
@@ -41,7 +41,7 @@ void Launch(const std::string& app_id, int32_t event_flags, apps::mojom::LaunchSource launch_source, - int64_t display_id) override; + apps::mojom::WindowInfoPtr window_info) override; void GetMenuModel(const std::string& app_id, apps::mojom::MenuType menu_type, int64_t display_id,
diff --git a/chrome/browser/apps/app_service/crostini_apps.cc b/chrome/browser/apps/app_service/crostini_apps.cc index 661e353c..be16ba5 100644 --- a/chrome/browser/apps/app_service/crostini_apps.cc +++ b/chrome/browser/apps/app_service/crostini_apps.cc
@@ -141,8 +141,10 @@ void CrostiniApps::Launch(const std::string& app_id, int32_t event_flags, apps::mojom::LaunchSource launch_source, - int64_t display_id) { - crostini::LaunchCrostiniApp(profile_, app_id, display_id); + apps::mojom::WindowInfoPtr window_info) { + crostini::LaunchCrostiniApp( + profile_, app_id, + window_info ? window_info->display_id : display::kInvalidDisplayId); } void CrostiniApps::Uninstall(const std::string& app_id,
diff --git a/chrome/browser/apps/app_service/crostini_apps.h b/chrome/browser/apps/app_service/crostini_apps.h index 0b00d0e..935b593 100644 --- a/chrome/browser/apps/app_service/crostini_apps.h +++ b/chrome/browser/apps/app_service/crostini_apps.h
@@ -58,7 +58,7 @@ void Launch(const std::string& app_id, int32_t event_flags, apps::mojom::LaunchSource launch_source, - int64_t display_id) override; + apps::mojom::WindowInfoPtr window_info) override; void Uninstall(const std::string& app_id, apps::mojom::UninstallSource uninstall_source, bool clear_site_data,
diff --git a/chrome/browser/apps/app_service/extension_apps_base.cc b/chrome/browser/apps/app_service/extension_apps_base.cc index 244afd23..e8a74d1 100644 --- a/chrome/browser/apps/app_service/extension_apps_base.cc +++ b/chrome/browser/apps/app_service/extension_apps_base.cc
@@ -295,7 +295,7 @@ int32_t event_flags, apps::mojom::IntentPtr intent, apps::mojom::LaunchSource launch_source, - int64_t display_id) { + apps::mojom::WindowInfoPtr window_info) { const auto* extension = MaybeGetExtension(app_id); if (!extension || !extensions::util::IsAppLaunchable(app_id, profile_)) { return nullptr; @@ -305,12 +305,14 @@ RunExtensionEnableFlow( app_id, base::BindOnce(&ExtensionAppsBase::LaunchAppWithIntent, weak_factory_.GetWeakPtr(), app_id, event_flags, - std::move(intent), launch_source, display_id)); + std::move(intent), launch_source, + std::move(window_info))); return nullptr; } auto params = apps::CreateAppLaunchParamsForIntent( - app_id, event_flags, GetAppLaunchSource(launch_source), display_id, + app_id, event_flags, GetAppLaunchSource(launch_source), + window_info ? window_info->display_id : display::kInvalidDisplayId, extensions::GetLaunchContainer(extensions::ExtensionPrefs::Get(profile_), extension), std::move(intent)); @@ -393,13 +395,17 @@ void ExtensionAppsBase::Launch(const std::string& app_id, int32_t event_flags, apps::mojom::LaunchSource launch_source, - int64_t display_id) { + apps::mojom::WindowInfoPtr window_info) { const auto* extension = MaybeGetExtension(app_id); - if (!extension || !extensions::util::IsAppLaunchable(app_id, profile_) || - RunExtensionEnableFlow( - app_id, - base::BindOnce(&ExtensionAppsBase::Launch, weak_factory_.GetWeakPtr(), - app_id, event_flags, launch_source, display_id))) { + if (!extension || !extensions::util::IsAppLaunchable(app_id, profile_)) { + return; + } + + if (!extensions::util::IsAppLaunchableWithoutEnabling(app_id, profile_)) { + RunExtensionEnableFlow( + app_id, base::BindOnce(&ExtensionAppsBase::Launch, + weak_factory_.GetWeakPtr(), app_id, event_flags, + launch_source, std::move(window_info))); return; } @@ -435,7 +441,7 @@ // The app will be created for the currently active profile. AppLaunchParams params = CreateAppLaunchParamsWithEventFlags( profile_, extension, event_flags, GetAppLaunchSource(launch_source), - display_id); + window_info ? window_info->display_id : display::kInvalidDisplayId); ash::ShelfLaunchSource source = ConvertLaunchSource(launch_source); if ((source == ash::LAUNCH_FROM_APP_LIST || source == ash::LAUNCH_FROM_APP_LIST_SEARCH) && @@ -472,9 +478,9 @@ int32_t event_flags, apps::mojom::IntentPtr intent, apps::mojom::LaunchSource launch_source, - int64_t display_id) { + apps::mojom::WindowInfoPtr window_info) { LaunchAppWithIntentImpl(app_id, event_flags, std::move(intent), launch_source, - display_id); + std::move(window_info)); } void ExtensionAppsBase::Uninstall(const std::string& app_id,
diff --git a/chrome/browser/apps/app_service/extension_apps_base.h b/chrome/browser/apps/app_service/extension_apps_base.h index 5636c82..1d686e0e 100644 --- a/chrome/browser/apps/app_service/extension_apps_base.h +++ b/chrome/browser/apps/app_service/extension_apps_base.h
@@ -82,7 +82,7 @@ int32_t event_flags, apps::mojom::IntentPtr intent, apps::mojom::LaunchSource launch_source, - int64_t display_id); + apps::mojom::WindowInfoPtr window_info); virtual content::WebContents* LaunchImpl(AppLaunchParams&& params); @@ -123,7 +123,7 @@ void Launch(const std::string& app_id, int32_t event_flags, apps::mojom::LaunchSource launch_source, - int64_t display_id) override; + apps::mojom::WindowInfoPtr window_info) override; void LaunchAppWithFiles(const std::string& app_id, apps::mojom::LaunchContainer container, int32_t event_flags, @@ -133,7 +133,7 @@ int32_t event_flags, apps::mojom::IntentPtr intent, apps::mojom::LaunchSource launch_source, - int64_t display_id) override; + apps::mojom::WindowInfoPtr window_info) override; void Uninstall(const std::string& app_id, apps::mojom::UninstallSource uninstall_source, bool clear_site_data,
diff --git a/chrome/browser/apps/app_service/extension_apps_chromeos.cc b/chrome/browser/apps/app_service/extension_apps_chromeos.cc index 93772dc..786f139 100644 --- a/chrome/browser/apps/app_service/extension_apps_chromeos.cc +++ b/chrome/browser/apps/app_service/extension_apps_chromeos.cc
@@ -190,9 +190,9 @@ int32_t event_flags, apps::mojom::IntentPtr intent, apps::mojom::LaunchSource launch_source, - int64_t display_id) { + apps::mojom::WindowInfoPtr window_info) { auto* tab = LaunchAppWithIntentImpl(app_id, event_flags, std::move(intent), - launch_source, display_id); + launch_source, std::move(window_info)); if (launch_source == apps::mojom::LaunchSource::kFromArc && tab) { // Add a flag to remember this tab originated in the ARC context.
diff --git a/chrome/browser/apps/app_service/extension_apps_chromeos.h b/chrome/browser/apps/app_service/extension_apps_chromeos.h index ad315bd..c8e63e9 100644 --- a/chrome/browser/apps/app_service/extension_apps_chromeos.h +++ b/chrome/browser/apps/app_service/extension_apps_chromeos.h
@@ -80,7 +80,7 @@ int32_t event_flags, apps::mojom::IntentPtr intent, apps::mojom::LaunchSource launch_source, - int64_t display_id) override; + apps::mojom::WindowInfoPtr window_info) override; void PauseApp(const std::string& app_id) override; void UnpauseApps(const std::string& app_id) override; void GetMenuModel(const std::string& app_id,
diff --git a/chrome/browser/apps/app_service/lacros_apps.cc b/chrome/browser/apps/app_service/lacros_apps.cc index 5105559c..7769cc8 100644 --- a/chrome/browser/apps/app_service/lacros_apps.cc +++ b/chrome/browser/apps/app_service/lacros_apps.cc
@@ -110,7 +110,7 @@ void LacrosApps::Launch(const std::string& app_id, int32_t event_flags, apps::mojom::LaunchSource launch_source, - int64_t display_id) { + apps::mojom::WindowInfoPtr window_info) { DCHECK_EQ(extension_misc::kLacrosAppId, app_id); crosapi::BrowserManager::Get()->NewWindow(); }
diff --git a/chrome/browser/apps/app_service/lacros_apps.h b/chrome/browser/apps/app_service/lacros_apps.h index 7cd4e96d..65f7a56 100644 --- a/chrome/browser/apps/app_service/lacros_apps.h +++ b/chrome/browser/apps/app_service/lacros_apps.h
@@ -50,7 +50,7 @@ void Launch(const std::string& app_id, int32_t event_flags, apps::mojom::LaunchSource launch_source, - int64_t display_id) override; + apps::mojom::WindowInfoPtr window_info) override; void GetMenuModel(const std::string& app_id, apps::mojom::MenuType menu_type, int64_t display_id,
diff --git a/chrome/browser/apps/app_service/launch_utils.cc b/chrome/browser/apps/app_service/launch_utils.cc index c9209a2a..67fd88d 100644 --- a/chrome/browser/apps/app_service/launch_utils.cc +++ b/chrome/browser/apps/app_service/launch_utils.cc
@@ -240,4 +240,10 @@ return browser->session_id().id(); } +apps::mojom::WindowInfoPtr MakeWindowInfo(int64_t display_id) { + apps::mojom::WindowInfoPtr window_info = apps::mojom::WindowInfo::New(); + window_info->display_id = display_id; + return window_info; +} + } // namespace apps
diff --git a/chrome/browser/apps/app_service/launch_utils.h b/chrome/browser/apps/app_service/launch_utils.h index 9aaa0c7..ecbd03f 100644 --- a/chrome/browser/apps/app_service/launch_utils.h +++ b/chrome/browser/apps/app_service/launch_utils.h
@@ -76,6 +76,10 @@ int GetSessionIdForRestoreFromWebContents( const content::WebContents* web_contents); +// Helper to create apps::mojom::WindowInfoPtr using |display_id|, which is the +// id of the display from which the app is launched. +apps::mojom::WindowInfoPtr MakeWindowInfo(int64_t display_id); + } // namespace apps #endif // CHROME_BROWSER_APPS_APP_SERVICE_LAUNCH_UTILS_H_
diff --git a/chrome/browser/apps/app_service/notifications_browsertest.cc b/chrome/browser/apps/app_service/notifications_browsertest.cc index df64d8b..7983c86 100644 --- a/chrome/browser/apps/app_service/notifications_browsertest.cc +++ b/chrome/browser/apps/app_service/notifications_browsertest.cc
@@ -46,7 +46,6 @@ #include "extensions/test/extension_test_message_listener.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/receiver.h" -#include "ui/display/display.h" #include "ui/message_center/message_center.h" #include "ui/message_center/public/cpp/notification.h" #include "ui/message_center/public/cpp/notifier_id.h" @@ -143,7 +142,7 @@ ExtensionTestMessageListener launched_listener("launched", true); apps::AppServiceProxyFactory::GetForProfile(profile())->Launch( extension->id(), ui::EF_SHIFT_DOWN, - apps::mojom::LaunchSource::kFromTest, display::kInvalidDisplayId); + apps::mojom::LaunchSource::kFromTest); EXPECT_TRUE(launched_listener.WaitUntilSatisfied()); launched_listener.Reply(create_window_options);
diff --git a/chrome/browser/apps/app_service/plugin_vm_apps.cc b/chrome/browser/apps/app_service/plugin_vm_apps.cc index 55d4356..f88eb34 100644 --- a/chrome/browser/apps/app_service/plugin_vm_apps.cc +++ b/chrome/browser/apps/app_service/plugin_vm_apps.cc
@@ -190,7 +190,7 @@ void PluginVmApps::Launch(const std::string& app_id, int32_t event_flags, apps::mojom::LaunchSource launch_source, - int64_t display_id) { + apps::mojom::WindowInfoPtr window_info) { DCHECK_EQ(plugin_vm::kPluginVmShelfAppId, app_id); if (plugin_vm::PluginVmFeatures::Get()->IsEnabled(profile_)) { plugin_vm::PluginVmManagerFactory::GetForProfile(profile_)->LaunchPluginVm(
diff --git a/chrome/browser/apps/app_service/plugin_vm_apps.h b/chrome/browser/apps/app_service/plugin_vm_apps.h index 87008695..0423614d 100644 --- a/chrome/browser/apps/app_service/plugin_vm_apps.h +++ b/chrome/browser/apps/app_service/plugin_vm_apps.h
@@ -51,7 +51,7 @@ void Launch(const std::string& app_id, int32_t event_flags, apps::mojom::LaunchSource launch_source, - int64_t display_id) override; + apps::mojom::WindowInfoPtr window_info) override; void SetPermission(const std::string& app_id, apps::mojom::PermissionPtr permission) override; void Uninstall(const std::string& app_id,
diff --git a/chrome/browser/apps/app_service/remote_apps.cc b/chrome/browser/apps/app_service/remote_apps.cc index e85a1b7..da96e46 100644 --- a/chrome/browser/apps/app_service/remote_apps.cc +++ b/chrome/browser/apps/app_service/remote_apps.cc
@@ -111,7 +111,7 @@ void RemoteApps::Launch(const std::string& app_id, int32_t event_flags, mojom::LaunchSource launch_source, - int64_t display_id) { + apps::mojom::WindowInfoPtr window_info) { delegate_->LaunchApp(app_id); }
diff --git a/chrome/browser/apps/app_service/remote_apps.h b/chrome/browser/apps/app_service/remote_apps.h index 4e9af10d..32f40dc4 100644 --- a/chrome/browser/apps/app_service/remote_apps.h +++ b/chrome/browser/apps/app_service/remote_apps.h
@@ -74,7 +74,7 @@ void Launch(const std::string& app_id, int32_t event_flags, apps::mojom::LaunchSource launch_source, - int64_t display_id) override; + apps::mojom::WindowInfoPtr window_info) override; void GetMenuModel(const std::string& app_id, apps::mojom::MenuType menu_type, int64_t display_id,
diff --git a/chrome/browser/apps/app_service/web_apps_base.cc b/chrome/browser/apps/app_service/web_apps_base.cc index 785bb11c..4ff1b001 100644 --- a/chrome/browser/apps/app_service/web_apps_base.cc +++ b/chrome/browser/apps/app_service/web_apps_base.cc
@@ -261,7 +261,7 @@ void WebAppsBase::Launch(const std::string& app_id, int32_t event_flags, apps::mojom::LaunchSource launch_source, - int64_t display_id) { + apps::mojom::WindowInfoPtr window_info) { if (!profile_) { return; } @@ -310,7 +310,7 @@ AppLaunchParams params = apps::CreateAppIdLaunchParamsWithEventFlags( web_app->app_id(), event_flags, GetAppLaunchSource(launch_source), - display_id, + window_info ? window_info->display_id : display::kInvalidDisplayId, /*fallback_container=*/ web_app::ConvertDisplayModeToAppLaunchContainer(display_mode)); @@ -338,9 +338,10 @@ int32_t event_flags, apps::mojom::IntentPtr intent, apps::mojom::LaunchSource launch_source, - int64_t display_id) { - LaunchAppWithIntentImpl(app_id, event_flags, std::move(intent), launch_source, - display_id); + apps::mojom::WindowInfoPtr window_info) { + LaunchAppWithIntentImpl( + app_id, event_flags, std::move(intent), launch_source, + window_info ? window_info->display_id : display::kInvalidDisplayId); } void WebAppsBase::SetPermission(const std::string& app_id,
diff --git a/chrome/browser/apps/app_service/web_apps_base.h b/chrome/browser/apps/app_service/web_apps_base.h index 2e9325bb..f1437c9 100644 --- a/chrome/browser/apps/app_service/web_apps_base.h +++ b/chrome/browser/apps/app_service/web_apps_base.h
@@ -108,7 +108,7 @@ void Launch(const std::string& app_id, int32_t event_flags, apps::mojom::LaunchSource launch_source, - int64_t display_id) override; + apps::mojom::WindowInfoPtr window_info) override; void LaunchAppWithFiles(const std::string& app_id, apps::mojom::LaunchContainer container, int32_t event_flags, @@ -118,7 +118,7 @@ int32_t event_flags, apps::mojom::IntentPtr intent, apps::mojom::LaunchSource launch_source, - int64_t display_id) override; + apps::mojom::WindowInfoPtr window_info) override; void SetPermission(const std::string& app_id, apps::mojom::PermissionPtr permission) override; void OpenNativeSettings(const std::string& app_id) override;
diff --git a/chrome/browser/apps/app_service/web_apps_base_browsertest.cc b/chrome/browser/apps/app_service/web_apps_base_browsertest.cc index cc25c1f..b08b7ae 100644 --- a/chrome/browser/apps/app_service/web_apps_base_browsertest.cc +++ b/chrome/browser/apps/app_service/web_apps_base_browsertest.cc
@@ -320,7 +320,8 @@ /*prefer_container=*/true); apps::AppServiceProxyFactory::GetForProfile(profile)->LaunchAppWithIntent( app_id, event_flags, std::move(intent), - apps::mojom::LaunchSource::kFromSharesheet, display::kDefaultDisplayId); + apps::mojom::LaunchSource::kFromSharesheet, + apps::MakeWindowInfo(display::kDefaultDisplayId)); run_loop.Run(); } @@ -356,7 +357,8 @@ /*prefer_container=*/true); apps::AppServiceProxyFactory::GetForProfile(profile)->LaunchAppWithIntent( app_id, event_flags, std::move(intent), - apps::mojom::LaunchSource::kFromSharesheet, display::kDefaultDisplayId); + apps::mojom::LaunchSource::kFromSharesheet, + apps::MakeWindowInfo(display::kDefaultDisplayId)); run_loop.Run(); } @@ -401,7 +403,7 @@ WindowOpenDisposition::NEW_WINDOW, /*prefer_container=*/true); proxy->Launch(app_id, event_flags, apps::mojom::LaunchSource::kUnknown, - display::kDefaultDisplayId); + apps::MakeWindowInfo(display::kDefaultDisplayId)); proxy->FlushMojoCallsForTesting(); proxy->AppRegistryCache().ForOneApp(
diff --git a/chrome/browser/apps/app_service/web_apps_chromeos.cc b/chrome/browser/apps/app_service/web_apps_chromeos.cc index a78c63c0..c37740a 100644 --- a/chrome/browser/apps/app_service/web_apps_chromeos.cc +++ b/chrome/browser/apps/app_service/web_apps_chromeos.cc
@@ -152,9 +152,10 @@ int32_t event_flags, apps::mojom::IntentPtr intent, apps::mojom::LaunchSource launch_source, - int64_t display_id) { + apps::mojom::WindowInfoPtr window_info) { auto* tab = WebAppsChromeOs::LaunchAppWithIntentImpl( - app_id, event_flags, std::move(intent), launch_source, display_id); + app_id, event_flags, std::move(intent), launch_source, + window_info ? window_info->display_id : display::kInvalidDisplayId); if (launch_source != apps::mojom::LaunchSource::kFromArc || !tab) { return;
diff --git a/chrome/browser/apps/app_service/web_apps_chromeos.h b/chrome/browser/apps/app_service/web_apps_chromeos.h index 1ca66a9f..8644a9d 100644 --- a/chrome/browser/apps/app_service/web_apps_chromeos.h +++ b/chrome/browser/apps/app_service/web_apps_chromeos.h
@@ -78,7 +78,7 @@ int32_t event_flags, apps::mojom::IntentPtr intent, apps::mojom::LaunchSource launch_source, - int64_t display_id) override; + apps::mojom::WindowInfoPtr window_info) override; void Uninstall(const std::string& app_id, apps::mojom::UninstallSource uninstall_source, bool clear_site_data,
diff --git a/chrome/browser/apps/platform_apps/app_browsertest.cc b/chrome/browser/apps/platform_apps/app_browsertest.cc index 8e66cf8..b8180b13 100644 --- a/chrome/browser/apps/platform_apps/app_browsertest.cc +++ b/chrome/browser/apps/platform_apps/app_browsertest.cc
@@ -69,7 +69,6 @@ #include "net/test/embedded_test_server/embedded_test_server.h" #include "printing/buildflags/buildflags.h" #include "ui/base/window_open_disposition.h" -#include "ui/display/types/display_constants.h" #include "url/gurl.h" #if BUILDFLAG(IS_CHROMEOS_ASH) @@ -525,7 +524,8 @@ // Tests that extensions can't use platform-app-only APIs. IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, PlatformAppsOnly) { - ASSERT_TRUE(RunExtensionTestIgnoreManifestWarnings("platform_apps/apps_only")) + ASSERT_TRUE(RunExtensionTest({.name = "platform_apps/apps_only"}, + {.ignore_manifest_warnings = true})) << message_; } @@ -1294,8 +1294,7 @@ apps::mojom::LaunchContainer::kLaunchContainerWindow, WindowOpenDisposition::NEW_FOREGROUND_TAB, true /* prefer_container */), - apps::mojom::LaunchSource::kFromTest, - display::kInvalidDisplayId); + apps::mojom::LaunchSource::kFromTest); while (!base::Contains(opener_app_ids_, file_manager->id())) { content::RunAllPendingInMessageLoop();
diff --git a/chrome/browser/ash/accessibility/spoken_feedback_browsertest.cc b/chrome/browser/ash/accessibility/spoken_feedback_browsertest.cc index 177ef05..6ed7c28b3 100644 --- a/chrome/browser/ash/accessibility/spoken_feedback_browsertest.cc +++ b/chrome/browser/ash/accessibility/spoken_feedback_browsertest.cc
@@ -1170,6 +1170,41 @@ sm_.Replay(); } +IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, ClipboardCopySpeech) { + EnableChromeVox(); + sm_.Call([this]() { + ui_test_utils::NavigateToURL(browser(), + GURL("data:text/html,<input autofocus " + "type='text' value='Foo'></input>")); + }); + + // The input is autofocused. + sm_.ExpectSpeech("Edit text"); + + // Select and copy the first character. + sm_.Call([this]() { + SendKeyPressWithShift(ui::VKEY_RIGHT); + SendKeyPressWithControl(ui::VKEY_C); + }); + sm_.ExpectSpeech("copy F."); + + // Select and copy the first two characters. + sm_.Call([this]() { + SendKeyPressWithShift(ui::VKEY_RIGHT); + SendKeyPressWithControl(ui::VKEY_C); + }); + sm_.ExpectSpeech("copy Fo."); + + // Select and copy all characters. + sm_.Call([this]() { + SendKeyPressWithShift(ui::VKEY_RIGHT); + SendKeyPressWithControl(ui::VKEY_C); + }); + sm_.ExpectSpeech("copy Foo."); + + sm_.Replay(); +} + // // Spoken feedback tests of the out-of-box experience. //
diff --git a/chrome/browser/ash/app_mode/kiosk_app_update_service.cc b/chrome/browser/ash/app_mode/kiosk_app_update_service.cc index 16f4b4c..c84f0d12 100644 --- a/chrome/browser/ash/app_mode/kiosk_app_update_service.cc +++ b/chrome/browser/ash/app_mode/kiosk_app_update_service.cc
@@ -7,9 +7,9 @@ #include "base/logging.h" #include "chrome/browser/app_mode/app_mode_utils.h" #include "chrome/browser/ash/app_mode/kiosk_app_manager.h" +#include "chrome/browser/ash/system/automatic_reboot_manager.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process_platform_part_chromeos.h" -#include "chrome/browser/chromeos/system/automatic_reboot_manager.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/lifetime/application_lifetime.h" #include "chrome/browser/profiles/profile.h"
diff --git a/chrome/browser/ash/app_mode/kiosk_app_update_service.h b/chrome/browser/ash/app_mode/kiosk_app_update_service.h index 5c27470..44ba27c 100644 --- a/chrome/browser/ash/app_mode/kiosk_app_update_service.h +++ b/chrome/browser/ash/app_mode/kiosk_app_update_service.h
@@ -14,8 +14,8 @@ #include "chrome/browser/ash/app_mode/kiosk_app_manager_observer.h" // TODO(https://crbug.com/1164001): forward declare when moved to // chrome/browser/ash/. -#include "chrome/browser/chromeos/system/automatic_reboot_manager.h" -#include "chrome/browser/chromeos/system/automatic_reboot_manager_observer.h" +#include "chrome/browser/ash/system/automatic_reboot_manager.h" +#include "chrome/browser/ash/system/automatic_reboot_manager_observer.h" #include "components/keyed_service/content/browser_context_keyed_service_factory.h" #include "components/keyed_service/core/keyed_service.h" #include "extensions/browser/update_observer.h"
diff --git a/chrome/browser/ash/app_mode/kiosk_app_update_service_browsertest.cc b/chrome/browser/ash/app_mode/kiosk_app_update_service_browsertest.cc index 13ae0f7..8668a21 100644 --- a/chrome/browser/ash/app_mode/kiosk_app_update_service_browsertest.cc +++ b/chrome/browser/ash/app_mode/kiosk_app_update_service_browsertest.cc
@@ -27,10 +27,10 @@ #include "base/threading/thread_restrictions.h" #include "base/time/time.h" #include "chrome/browser/apps/platform_apps/app_browsertest_util.h" +#include "chrome/browser/ash/system/automatic_reboot_manager.h" +#include "chrome/browser/ash/system/automatic_reboot_manager_observer.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process_platform_part.h" -#include "chrome/browser/chromeos/system/automatic_reboot_manager.h" -#include "chrome/browser/chromeos/system/automatic_reboot_manager_observer.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/pref_names.h"
diff --git a/chrome/browser/chromeos/system/OWNERS b/chrome/browser/ash/system/OWNERS similarity index 100% rename from chrome/browser/chromeos/system/OWNERS rename to chrome/browser/ash/system/OWNERS
diff --git a/chrome/browser/chromeos/system/automatic_reboot_manager.cc b/chrome/browser/ash/system/automatic_reboot_manager.cc similarity index 99% rename from chrome/browser/chromeos/system/automatic_reboot_manager.cc rename to chrome/browser/ash/system/automatic_reboot_manager.cc index 4af3026..88d7fdd 100644 --- a/chrome/browser/chromeos/system/automatic_reboot_manager.cc +++ b/chrome/browser/ash/system/automatic_reboot_manager.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/chromeos/system/automatic_reboot_manager.h" +#include "chrome/browser/ash/system/automatic_reboot_manager.h" #include <fcntl.h> #include <stddef.h>
diff --git a/chrome/browser/chromeos/system/automatic_reboot_manager.h b/chrome/browser/ash/system/automatic_reboot_manager.h similarity index 96% rename from chrome/browser/chromeos/system/automatic_reboot_manager.h rename to chrome/browser/ash/system/automatic_reboot_manager.h index 34448e6..ec79068 100644 --- a/chrome/browser/chromeos/system/automatic_reboot_manager.h +++ b/chrome/browser/ash/system/automatic_reboot_manager.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_CHROMEOS_SYSTEM_AUTOMATIC_REBOOT_MANAGER_H_ -#define CHROME_BROWSER_CHROMEOS_SYSTEM_AUTOMATIC_REBOOT_MANAGER_H_ +#ifndef CHROME_BROWSER_ASH_SYSTEM_AUTOMATIC_REBOOT_MANAGER_H_ +#define CHROME_BROWSER_ASH_SYSTEM_AUTOMATIC_REBOOT_MANAGER_H_ #include <memory> @@ -15,7 +15,7 @@ #include "base/synchronization/waitable_event.h" #include "base/time/time.h" #include "base/timer/timer.h" -#include "chrome/browser/chromeos/system/automatic_reboot_manager_observer.h" +#include "chrome/browser/ash/system/automatic_reboot_manager_observer.h" #include "chromeos/dbus/power/power_manager_client.h" #include "chromeos/dbus/update_engine_client.h" #include "components/prefs/pref_change_registrar.h" @@ -197,4 +197,4 @@ } } // namespace ash -#endif // CHROME_BROWSER_CHROMEOS_SYSTEM_AUTOMATIC_REBOOT_MANAGER_H_ +#endif // CHROME_BROWSER_ASH_SYSTEM_AUTOMATIC_REBOOT_MANAGER_H_
diff --git a/chrome/browser/chromeos/system/automatic_reboot_manager_observer.h b/chrome/browser/ash/system/automatic_reboot_manager_observer.h similarity index 79% rename from chrome/browser/chromeos/system/automatic_reboot_manager_observer.h rename to chrome/browser/ash/system/automatic_reboot_manager_observer.h index 6ad9774a..7da17ba 100644 --- a/chrome/browser/chromeos/system/automatic_reboot_manager_observer.h +++ b/chrome/browser/ash/system/automatic_reboot_manager_observer.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_CHROMEOS_SYSTEM_AUTOMATIC_REBOOT_MANAGER_OBSERVER_H_ -#define CHROME_BROWSER_CHROMEOS_SYSTEM_AUTOMATIC_REBOOT_MANAGER_OBSERVER_H_ +#ifndef CHROME_BROWSER_ASH_SYSTEM_AUTOMATIC_REBOOT_MANAGER_OBSERVER_H_ +#define CHROME_BROWSER_ASH_SYSTEM_AUTOMATIC_REBOOT_MANAGER_OBSERVER_H_ namespace chromeos { namespace system { @@ -36,4 +36,4 @@ } } // namespace ash -#endif // CHROME_BROWSER_CHROMEOS_SYSTEM_AUTOMATIC_REBOOT_MANAGER_OBSERVER_H_ +#endif // CHROME_BROWSER_ASH_SYSTEM_AUTOMATIC_REBOOT_MANAGER_OBSERVER_H_
diff --git a/chrome/browser/chromeos/system/automatic_reboot_manager_unittest.cc b/chrome/browser/ash/system/automatic_reboot_manager_unittest.cc similarity index 99% rename from chrome/browser/chromeos/system/automatic_reboot_manager_unittest.cc rename to chrome/browser/ash/system/automatic_reboot_manager_unittest.cc index b6a03fc..3e8209f 100644 --- a/chrome/browser/chromeos/system/automatic_reboot_manager_unittest.cc +++ b/chrome/browser/ash/system/automatic_reboot_manager_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/chromeos/system/automatic_reboot_manager.h" +#include "chrome/browser/ash/system/automatic_reboot_manager.h" #include <string> @@ -23,9 +23,9 @@ #include "base/time/tick_clock.h" #include "base/values.h" #include "chrome/browser/ash/profiles/profile_helper.h" +#include "chrome/browser/ash/system/automatic_reboot_manager_observer.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/chromeos/login/users/mock_user_manager.h" -#include "chrome/browser/chromeos/system/automatic_reboot_manager_observer.h" #include "chrome/common/pref_names.h" #include "chrome/test/base/testing_browser_process.h" #include "chromeos/dbus/dbus_thread_manager.h"
diff --git a/chrome/browser/chromeos/system/breakpad_consent_watcher.cc b/chrome/browser/ash/system/breakpad_consent_watcher.cc similarity index 96% rename from chrome/browser/chromeos/system/breakpad_consent_watcher.cc rename to chrome/browser/ash/system/breakpad_consent_watcher.cc index bdf3338..e7eee765 100644 --- a/chrome/browser/chromeos/system/breakpad_consent_watcher.cc +++ b/chrome/browser/ash/system/breakpad_consent_watcher.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/chromeos/system/breakpad_consent_watcher.h" +#include "chrome/browser/ash/system/breakpad_consent_watcher.h" #include <string>
diff --git a/chrome/browser/chromeos/system/breakpad_consent_watcher.h b/chrome/browser/ash/system/breakpad_consent_watcher.h similarity index 90% rename from chrome/browser/chromeos/system/breakpad_consent_watcher.h rename to chrome/browser/ash/system/breakpad_consent_watcher.h index 52dfa80..25d47824 100644 --- a/chrome/browser/chromeos/system/breakpad_consent_watcher.h +++ b/chrome/browser/ash/system/breakpad_consent_watcher.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_CHROMEOS_SYSTEM_BREAKPAD_CONSENT_WATCHER_H_ -#define CHROME_BROWSER_CHROMEOS_SYSTEM_BREAKPAD_CONSENT_WATCHER_H_ +#ifndef CHROME_BROWSER_ASH_SYSTEM_BREAKPAD_CONSENT_WATCHER_H_ +#define CHROME_BROWSER_ASH_SYSTEM_BREAKPAD_CONSENT_WATCHER_H_ #include <memory> @@ -52,4 +52,4 @@ } // namespace system } // namespace chromeos -#endif // CHROME_BROWSER_CHROMEOS_SYSTEM_BREAKPAD_CONSENT_WATCHER_H_ +#endif // CHROME_BROWSER_ASH_SYSTEM_BREAKPAD_CONSENT_WATCHER_H_
diff --git a/chrome/browser/chromeos/system/device_disabling_browsertest.cc b/chrome/browser/ash/system/device_disabling_browsertest.cc similarity index 99% rename from chrome/browser/chromeos/system/device_disabling_browsertest.cc rename to chrome/browser/ash/system/device_disabling_browsertest.cc index a12ef8f..4d3e2e52 100644 --- a/chrome/browser/chromeos/system/device_disabling_browsertest.cc +++ b/chrome/browser/ash/system/device_disabling_browsertest.cc
@@ -13,6 +13,7 @@ #include "base/memory/ref_counted.h" #include "base/run_loop.h" #include "chrome/browser/ash/profiles/profile_helper.h" +#include "chrome/browser/ash/system/device_disabling_manager.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process_platform_part.h" #include "chrome/browser/chromeos/login/login_wizard.h" @@ -25,7 +26,6 @@ #include "chrome/browser/chromeos/login/ui/webui_login_view.h" #include "chrome/browser/chromeos/login/wizard_controller.h" #include "chrome/browser/chromeos/settings/cros_settings.h" -#include "chrome/browser/chromeos/system/device_disabling_manager.h" #include "chrome/browser/ui/webui/chromeos/login/device_disabled_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/network_state_informer.h"
diff --git a/chrome/browser/chromeos/system/device_disabling_manager.cc b/chrome/browser/ash/system/device_disabling_manager.cc similarity index 98% rename from chrome/browser/chromeos/system/device_disabling_manager.cc rename to chrome/browser/ash/system/device_disabling_manager.cc index 89c47e11..5ba4a96 100644 --- a/chrome/browser/chromeos/system/device_disabling_manager.cc +++ b/chrome/browser/ash/system/device_disabling_manager.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/chromeos/system/device_disabling_manager.h" +#include "chrome/browser/ash/system/device_disabling_manager.h" #include "ash/constants/ash_switches.h" #include "base/bind.h"
diff --git a/chrome/browser/chromeos/system/device_disabling_manager.h b/chrome/browser/ash/system/device_disabling_manager.h similarity index 96% rename from chrome/browser/chromeos/system/device_disabling_manager.h rename to chrome/browser/ash/system/device_disabling_manager.h index cc293495..35652c0 100644 --- a/chrome/browser/chromeos/system/device_disabling_manager.h +++ b/chrome/browser/ash/system/device_disabling_manager.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_CHROMEOS_SYSTEM_DEVICE_DISABLING_MANAGER_H_ -#define CHROME_BROWSER_CHROMEOS_SYSTEM_DEVICE_DISABLING_MANAGER_H_ +#ifndef CHROME_BROWSER_ASH_SYSTEM_DEVICE_DISABLING_MANAGER_H_ +#define CHROME_BROWSER_ASH_SYSTEM_DEVICE_DISABLING_MANAGER_H_ #include <memory> #include <string> @@ -154,4 +154,4 @@ } // namespace system } // namespace chromeos -#endif // CHROME_BROWSER_CHROMEOS_SYSTEM_DEVICE_DISABLING_MANAGER_H_ +#endif // CHROME_BROWSER_ASH_SYSTEM_DEVICE_DISABLING_MANAGER_H_
diff --git a/chrome/browser/chromeos/system/device_disabling_manager_default_delegate.cc b/chrome/browser/ash/system/device_disabling_manager_default_delegate.cc similarity index 91% rename from chrome/browser/chromeos/system/device_disabling_manager_default_delegate.cc rename to chrome/browser/ash/system/device_disabling_manager_default_delegate.cc index fd2454d..98e5eb0 100644 --- a/chrome/browser/chromeos/system/device_disabling_manager_default_delegate.cc +++ b/chrome/browser/ash/system/device_disabling_manager_default_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 "chrome/browser/chromeos/system/device_disabling_manager_default_delegate.h" +#include "chrome/browser/ash/system/device_disabling_manager_default_delegate.h" #include "chrome/browser/chromeos/login/ui/login_display_host.h" #include "chrome/browser/chromeos/login/wizard_controller.h"
diff --git a/chrome/browser/chromeos/system/device_disabling_manager_default_delegate.h b/chrome/browser/ash/system/device_disabling_manager_default_delegate.h similarity index 66% rename from chrome/browser/chromeos/system/device_disabling_manager_default_delegate.h rename to chrome/browser/ash/system/device_disabling_manager_default_delegate.h index 2316e70..2a782c8 100644 --- a/chrome/browser/chromeos/system/device_disabling_manager_default_delegate.h +++ b/chrome/browser/ash/system/device_disabling_manager_default_delegate.h
@@ -2,11 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_CHROMEOS_SYSTEM_DEVICE_DISABLING_MANAGER_DEFAULT_DELEGATE_H_ -#define CHROME_BROWSER_CHROMEOS_SYSTEM_DEVICE_DISABLING_MANAGER_DEFAULT_DELEGATE_H_ +#ifndef CHROME_BROWSER_ASH_SYSTEM_DEVICE_DISABLING_MANAGER_DEFAULT_DELEGATE_H_ +#define CHROME_BROWSER_ASH_SYSTEM_DEVICE_DISABLING_MANAGER_DEFAULT_DELEGATE_H_ #include "base/macros.h" -#include "chrome/browser/chromeos/system/device_disabling_manager.h" +#include "chrome/browser/ash/system/device_disabling_manager.h" namespace chromeos { namespace system { @@ -27,4 +27,4 @@ } // namespace system } // namespace chromeos -#endif // CHROME_BROWSER_CHROMEOS_SYSTEM_DEVICE_DISABLING_MANAGER_DEFAULT_DELEGATE_H_ +#endif // CHROME_BROWSER_ASH_SYSTEM_DEVICE_DISABLING_MANAGER_DEFAULT_DELEGATE_H_
diff --git a/chrome/browser/chromeos/system/device_disabling_manager_unittest.cc b/chrome/browser/ash/system/device_disabling_manager_unittest.cc similarity index 99% rename from chrome/browser/chromeos/system/device_disabling_manager_unittest.cc rename to chrome/browser/ash/system/device_disabling_manager_unittest.cc index b01086b..428a446 100644 --- a/chrome/browser/chromeos/system/device_disabling_manager_unittest.cc +++ b/chrome/browser/ash/system/device_disabling_manager_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/chromeos/system/device_disabling_manager.h" +#include "chrome/browser/ash/system/device_disabling_manager.h" #include "ash/constants/ash_switches.h" #include "base/bind.h"
diff --git a/chrome/browser/chromeos/system/fake_input_device_settings.cc b/chrome/browser/ash/system/fake_input_device_settings.cc similarity index 98% rename from chrome/browser/chromeos/system/fake_input_device_settings.cc rename to chrome/browser/ash/system/fake_input_device_settings.cc index 7842d3e..95616ae4 100644 --- a/chrome/browser/chromeos/system/fake_input_device_settings.cc +++ b/chrome/browser/ash/system/fake_input_device_settings.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/chromeos/system/fake_input_device_settings.h" +#include "chrome/browser/ash/system/fake_input_device_settings.h" #include <utility>
diff --git a/chrome/browser/chromeos/system/fake_input_device_settings.h b/chrome/browser/ash/system/fake_input_device_settings.h similarity index 91% rename from chrome/browser/chromeos/system/fake_input_device_settings.h rename to chrome/browser/ash/system/fake_input_device_settings.h index 56c9106a..f51fb36b 100644 --- a/chrome/browser/chromeos/system/fake_input_device_settings.h +++ b/chrome/browser/ash/system/fake_input_device_settings.h
@@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_CHROMEOS_SYSTEM_FAKE_INPUT_DEVICE_SETTINGS_H_ -#define CHROME_BROWSER_CHROMEOS_SYSTEM_FAKE_INPUT_DEVICE_SETTINGS_H_ +#ifndef CHROME_BROWSER_ASH_SYSTEM_FAKE_INPUT_DEVICE_SETTINGS_H_ +#define CHROME_BROWSER_ASH_SYSTEM_FAKE_INPUT_DEVICE_SETTINGS_H_ #include "base/compiler_specific.h" #include "base/macros.h" -#include "chrome/browser/chromeos/system/input_device_settings.h" +#include "chrome/browser/ash/system/input_device_settings.h" namespace chromeos { namespace system { @@ -72,4 +72,4 @@ } // namespace system } // namespace chromeos -#endif // CHROME_BROWSER_CHROMEOS_SYSTEM_FAKE_INPUT_DEVICE_SETTINGS_H_ +#endif // CHROME_BROWSER_ASH_SYSTEM_FAKE_INPUT_DEVICE_SETTINGS_H_
diff --git a/chrome/browser/chromeos/system/input_device_settings.cc b/chrome/browser/ash/system/input_device_settings.cc similarity index 99% rename from chrome/browser/chromeos/system/input_device_settings.cc rename to chrome/browser/ash/system/input_device_settings.cc index b695ebff..4fb62c1b 100644 --- a/chrome/browser/chromeos/system/input_device_settings.cc +++ b/chrome/browser/ash/system/input_device_settings.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/chromeos/system/input_device_settings.h" +#include "chrome/browser/ash/system/input_device_settings.h" #include "chrome/browser/chromeos/policy/enrollment_requisition_manager.h" #include "chromeos/system/statistics_provider.h"
diff --git a/chrome/browser/chromeos/system/input_device_settings.h b/chrome/browser/ash/system/input_device_settings.h similarity index 97% rename from chrome/browser/chromeos/system/input_device_settings.h rename to chrome/browser/ash/system/input_device_settings.h index f222d4d..2d110b44 100644 --- a/chrome/browser/chromeos/system/input_device_settings.h +++ b/chrome/browser/ash/system/input_device_settings.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_CHROMEOS_SYSTEM_INPUT_DEVICE_SETTINGS_H_ -#define CHROME_BROWSER_CHROMEOS_SYSTEM_INPUT_DEVICE_SETTINGS_H_ +#ifndef CHROME_BROWSER_ASH_SYSTEM_INPUT_DEVICE_SETTINGS_H_ +#define CHROME_BROWSER_ASH_SYSTEM_INPUT_DEVICE_SETTINGS_H_ #include "base/callback_forward.h" #include "base/optional.h" @@ -310,4 +310,4 @@ } // namespace system } // namespace chromeos -#endif // CHROME_BROWSER_CHROMEOS_SYSTEM_INPUT_DEVICE_SETTINGS_H_ +#endif // CHROME_BROWSER_ASH_SYSTEM_INPUT_DEVICE_SETTINGS_H_
diff --git a/chrome/browser/chromeos/system/input_device_settings_impl_ozone.cc b/chrome/browser/ash/system/input_device_settings_impl_ozone.cc similarity index 98% rename from chrome/browser/chromeos/system/input_device_settings_impl_ozone.cc rename to chrome/browser/ash/system/input_device_settings_impl_ozone.cc index dd79f35..3507ba54 100644 --- a/chrome/browser/chromeos/system/input_device_settings_impl_ozone.cc +++ b/chrome/browser/ash/system/input_device_settings_impl_ozone.cc
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/chromeos/system/input_device_settings.h" +#include "chrome/browser/ash/system/input_device_settings.h" #include "base/bind.h" #include "base/macros.h" +#include "chrome/browser/ash/system/fake_input_device_settings.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process_platform_part_chromeos.h" -#include "chrome/browser/chromeos/system/fake_input_device_settings.h" #include "chromeos/system/devicemode.h" #include "content/public/browser/browser_thread.h" #include "ui/ozone/public/input_controller.h"
diff --git a/chrome/browser/chromeos/system/pointer_device_observer.cc b/chrome/browser/ash/system/pointer_device_observer.cc similarity index 94% rename from chrome/browser/chromeos/system/pointer_device_observer.cc rename to chrome/browser/ash/system/pointer_device_observer.cc index 709b4914..4bbcfc6 100644 --- a/chrome/browser/chromeos/system/pointer_device_observer.cc +++ b/chrome/browser/ash/system/pointer_device_observer.cc
@@ -2,11 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/chromeos/system/pointer_device_observer.h" +#include "chrome/browser/ash/system/pointer_device_observer.h" #include "base/bind.h" #include "base/callback_helpers.h" -#include "chrome/browser/chromeos/system/input_device_settings.h" +#include "chrome/browser/ash/system/input_device_settings.h" #include "content/public/browser/browser_thread.h" #include "ui/events/devices/device_data_manager.h"
diff --git a/chrome/browser/chromeos/system/pointer_device_observer.h b/chrome/browser/ash/system/pointer_device_observer.h similarity index 88% rename from chrome/browser/chromeos/system/pointer_device_observer.h rename to chrome/browser/ash/system/pointer_device_observer.h index 58dca6bc..eb2d7410 100644 --- a/chrome/browser/chromeos/system/pointer_device_observer.h +++ b/chrome/browser/ash/system/pointer_device_observer.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_CHROMEOS_SYSTEM_POINTER_DEVICE_OBSERVER_H_ -#define CHROME_BROWSER_CHROMEOS_SYSTEM_POINTER_DEVICE_OBSERVER_H_ +#ifndef CHROME_BROWSER_ASH_SYSTEM_POINTER_DEVICE_OBSERVER_H_ +#define CHROME_BROWSER_ASH_SYSTEM_POINTER_DEVICE_OBSERVER_H_ #include "base/macros.h" #include "base/memory/weak_ptr.h" @@ -61,4 +61,4 @@ } // namespace system } // namespace chromeos -#endif // CHROME_BROWSER_CHROMEOS_SYSTEM_POINTER_DEVICE_OBSERVER_H_ +#endif // CHROME_BROWSER_ASH_SYSTEM_POINTER_DEVICE_OBSERVER_H_
diff --git a/chrome/browser/chromeos/system/procfs_util.cc b/chrome/browser/ash/system/procfs_util.cc similarity index 98% rename from chrome/browser/chromeos/system/procfs_util.cc rename to chrome/browser/ash/system/procfs_util.cc index a56ba423..b58514ae 100644 --- a/chrome/browser/chromeos/system/procfs_util.cc +++ b/chrome/browser/ash/system/procfs_util.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/chromeos/system/procfs_util.h" +#include "chrome/browser/ash/system/procfs_util.h" #include "base/files/file_util.h" #include "base/strings/string_number_conversions.h"
diff --git a/chrome/browser/chromeos/system/procfs_util.h b/chrome/browser/ash/system/procfs_util.h similarity index 91% rename from chrome/browser/chromeos/system/procfs_util.h rename to chrome/browser/ash/system/procfs_util.h index b8b77d96..b73c1e6 100644 --- a/chrome/browser/chromeos/system/procfs_util.h +++ b/chrome/browser/ash/system/procfs_util.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_CHROMEOS_SYSTEM_PROCFS_UTIL_H_ -#define CHROME_BROWSER_CHROMEOS_SYSTEM_PROCFS_UTIL_H_ +#ifndef CHROME_BROWSER_ASH_SYSTEM_PROCFS_UTIL_H_ +#define CHROME_BROWSER_ASH_SYSTEM_PROCFS_UTIL_H_ #include "base/files/file_path.h" #include "base/values.h" @@ -61,4 +61,4 @@ } // namespace system } // namespace chromeos -#endif // CHROME_BROWSER_CHROMEOS_SYSTEM_PROCFS_UTIL_H_ +#endif // CHROME_BROWSER_ASH_SYSTEM_PROCFS_UTIL_H_
diff --git a/chrome/browser/chromeos/system/procfs_util_unittest.cc b/chrome/browser/ash/system/procfs_util_unittest.cc similarity index 98% rename from chrome/browser/chromeos/system/procfs_util_unittest.cc rename to chrome/browser/ash/system/procfs_util_unittest.cc index 4a27a133..3cf41b1 100644 --- a/chrome/browser/chromeos/system/procfs_util_unittest.cc +++ b/chrome/browser/ash/system/procfs_util_unittest.cc
@@ -7,7 +7,7 @@ #include "base/strings/string_number_conversions.h" #include "testing/gtest/include/gtest/gtest.h" -#include "chrome/browser/chromeos/system/procfs_util.h" +#include "chrome/browser/ash/system/procfs_util.h" namespace chromeos { namespace system {
diff --git a/chrome/browser/chromeos/system/system_clock.cc b/chrome/browser/ash/system/system_clock.cc similarity index 98% rename from chrome/browser/chromeos/system/system_clock.cc rename to chrome/browser/ash/system/system_clock.cc index 5913cb0..6586657b 100644 --- a/chrome/browser/chromeos/system/system_clock.cc +++ b/chrome/browser/ash/system/system_clock.cc
@@ -2,18 +2,18 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/chromeos/system/system_clock.h" +#include "chrome/browser/ash/system/system_clock.h" #include <memory> #include "base/bind.h" #include "base/logging.h" #include "chrome/browser/ash/profiles/profile_helper.h" +#include "chrome/browser/ash/system/system_clock_observer.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos.h" #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos_factory.h" #include "chrome/browser/chromeos/settings/cros_settings.h" -#include "chrome/browser/chromeos/system/system_clock_observer.h" #include "chrome/common/pref_names.h" #include "chromeos/login/login_state/login_state.h" #include "chromeos/settings/cros_settings_names.h"
diff --git a/chrome/browser/chromeos/system/system_clock.h b/chrome/browser/ash/system/system_clock.h similarity index 94% rename from chrome/browser/chromeos/system/system_clock.h rename to chrome/browser/ash/system/system_clock.h index c1e54d0..e065eed 100644 --- a/chrome/browser/chromeos/system/system_clock.h +++ b/chrome/browser/ash/system/system_clock.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_CHROMEOS_SYSTEM_SYSTEM_CLOCK_H_ -#define CHROME_BROWSER_CHROMEOS_SYSTEM_SYSTEM_CLOCK_H_ +#ifndef CHROME_BROWSER_ASH_SYSTEM_SYSTEM_CLOCK_H_ +#define CHROME_BROWSER_ASH_SYSTEM_SYSTEM_CLOCK_H_ #include <memory> @@ -101,4 +101,4 @@ } // namespace system } // namespace chromeos -#endif // CHROME_BROWSER_CHROMEOS_SYSTEM_SYSTEM_CLOCK_H_ +#endif // CHROME_BROWSER_ASH_SYSTEM_SYSTEM_CLOCK_H_
diff --git a/chrome/browser/chromeos/system/system_clock_observer.cc b/chrome/browser/ash/system/system_clock_observer.cc similarity index 82% rename from chrome/browser/chromeos/system/system_clock_observer.cc rename to chrome/browser/ash/system/system_clock_observer.cc index 52a8dc1..53eedf83 100644 --- a/chrome/browser/chromeos/system/system_clock_observer.cc +++ b/chrome/browser/ash/system/system_clock_observer.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/chromeos/system/system_clock_observer.h" +#include "chrome/browser/ash/system/system_clock_observer.h" namespace chromeos { namespace system {
diff --git a/chrome/browser/chromeos/system/system_clock_observer.h b/chrome/browser/ash/system/system_clock_observer.h similarity index 71% rename from chrome/browser/chromeos/system/system_clock_observer.h rename to chrome/browser/ash/system/system_clock_observer.h index 08f4494f..1d9b984 100644 --- a/chrome/browser/chromeos/system/system_clock_observer.h +++ b/chrome/browser/ash/system/system_clock_observer.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_CHROMEOS_SYSTEM_SYSTEM_CLOCK_OBSERVER_H_ -#define CHROME_BROWSER_CHROMEOS_SYSTEM_SYSTEM_CLOCK_OBSERVER_H_ +#ifndef CHROME_BROWSER_ASH_SYSTEM_SYSTEM_CLOCK_OBSERVER_H_ +#define CHROME_BROWSER_ASH_SYSTEM_SYSTEM_CLOCK_OBSERVER_H_ #include "base/macros.h" @@ -22,4 +22,4 @@ } // namespace system } // namespace chromeos -#endif // CHROME_BROWSER_CHROMEOS_SYSTEM_SYSTEM_CLOCK_OBSERVER_H_ +#endif // CHROME_BROWSER_ASH_SYSTEM_SYSTEM_CLOCK_OBSERVER_H_
diff --git a/chrome/browser/chromeos/system/timezone_resolver_manager.cc b/chrome/browser/ash/system/timezone_resolver_manager.cc similarity index 98% rename from chrome/browser/chromeos/system/timezone_resolver_manager.cc rename to chrome/browser/ash/system/timezone_resolver_manager.cc index 196b811..d568f89f 100644 --- a/chrome/browser/chromeos/system/timezone_resolver_manager.cc +++ b/chrome/browser/ash/system/timezone_resolver_manager.cc
@@ -2,18 +2,18 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/chromeos/system/timezone_resolver_manager.h" +#include "chrome/browser/ash/system/timezone_resolver_manager.h" #include "ash/constants/ash_switches.h" #include "base/bind.h" #include "base/check.h" #include "base/command_line.h" #include "base/notreached.h" +#include "chrome/browser/ash/system/input_device_settings.h" +#include "chrome/browser/ash/system/timezone_util.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process_platform_part.h" #include "chrome/browser/chromeos/preferences.h" -#include "chrome/browser/chromeos/system/input_device_settings.h" -#include "chrome/browser/chromeos/system/timezone_util.h" #include "chrome/common/pref_names.h" #include "components/policy/proto/chrome_device_policy.pb.h" #include "components/prefs/pref_service.h"
diff --git a/chrome/browser/chromeos/system/timezone_resolver_manager.h b/chrome/browser/ash/system/timezone_resolver_manager.h similarity index 94% rename from chrome/browser/chromeos/system/timezone_resolver_manager.h rename to chrome/browser/ash/system/timezone_resolver_manager.h index 02be20d..193c8c5 100644 --- a/chrome/browser/chromeos/system/timezone_resolver_manager.h +++ b/chrome/browser/ash/system/timezone_resolver_manager.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_CHROMEOS_SYSTEM_TIMEZONE_RESOLVER_MANAGER_H_ -#define CHROME_BROWSER_CHROMEOS_SYSTEM_TIMEZONE_RESOLVER_MANAGER_H_ +#ifndef CHROME_BROWSER_ASH_SYSTEM_TIMEZONE_RESOLVER_MANAGER_H_ +#define CHROME_BROWSER_ASH_SYSTEM_TIMEZONE_RESOLVER_MANAGER_H_ #include "base/macros.h" #include "base/memory/weak_ptr.h" @@ -112,4 +112,4 @@ } // namespace system } // namespace chromeos -#endif // CHROME_BROWSER_CHROMEOS_SYSTEM_TIMEZONE_RESOLVER_MANAGER_H_ +#endif // CHROME_BROWSER_ASH_SYSTEM_TIMEZONE_RESOLVER_MANAGER_H_
diff --git a/chrome/browser/chromeos/system/timezone_util.cc b/chrome/browser/ash/system/timezone_util.cc similarity index 98% rename from chrome/browser/chromeos/system/timezone_util.cc rename to chrome/browser/ash/system/timezone_util.cc index 6c50bb4..3987ee3a 100644 --- a/chrome/browser/chromeos/system/timezone_util.cc +++ b/chrome/browser/ash/system/timezone_util.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/chromeos/system/timezone_util.h" +#include "chrome/browser/ash/system/timezone_util.h" #include <stddef.h> @@ -21,11 +21,11 @@ #include "base/synchronization/lock.h" #include "base/values.h" #include "chrome/browser/ash/profiles/profile_helper.h" +#include "chrome/browser/ash/system/timezone_resolver_manager.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process_platform_part.h" #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" #include "chrome/browser/chromeos/settings/cros_settings.h" -#include "chrome/browser/chromeos/system/timezone_resolver_manager.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/common/pref_names.h" #include "chrome/grit/generated_resources.h"
diff --git a/chrome/browser/chromeos/system/timezone_util.h b/chrome/browser/ash/system/timezone_util.h similarity index 93% rename from chrome/browser/chromeos/system/timezone_util.h rename to chrome/browser/ash/system/timezone_util.h index 81a4ee4..98ec1580 100644 --- a/chrome/browser/chromeos/system/timezone_util.h +++ b/chrome/browser/ash/system/timezone_util.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_CHROMEOS_SYSTEM_TIMEZONE_UTIL_H_ -#define CHROME_BROWSER_CHROMEOS_SYSTEM_TIMEZONE_UTIL_H_ +#ifndef CHROME_BROWSER_ASH_SYSTEM_TIMEZONE_UTIL_H_ +#define CHROME_BROWSER_ASH_SYSTEM_TIMEZONE_UTIL_H_ #include <memory> @@ -74,4 +74,4 @@ } // namespace system } // namespace chromeos -#endif // CHROME_BROWSER_CHROMEOS_SYSTEM_TIMEZONE_UTIL_H_ +#endif // CHROME_BROWSER_ASH_SYSTEM_TIMEZONE_UTIL_H_
diff --git a/chrome/browser/chromeos/system/tray_accessibility_browsertest.cc b/chrome/browser/ash/system/tray_accessibility_browsertest.cc similarity index 100% rename from chrome/browser/chromeos/system/tray_accessibility_browsertest.cc rename to chrome/browser/ash/system/tray_accessibility_browsertest.cc
diff --git a/chrome/browser/chromeos/system/user_removal_manager.cc b/chrome/browser/ash/system/user_removal_manager.cc similarity index 97% rename from chrome/browser/chromeos/system/user_removal_manager.cc rename to chrome/browser/ash/system/user_removal_manager.cc index 47fdcb4..d67d02c 100644 --- a/chrome/browser/chromeos/system/user_removal_manager.cc +++ b/chrome/browser/ash/system/user_removal_manager.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/chromeos/system/user_removal_manager.h" +#include "chrome/browser/ash/system/user_removal_manager.h" #include <utility>
diff --git a/chrome/browser/chromeos/system/user_removal_manager.h b/chrome/browser/ash/system/user_removal_manager.h similarity index 88% rename from chrome/browser/chromeos/system/user_removal_manager.h rename to chrome/browser/ash/system/user_removal_manager.h index 5ea2a4dc..3ad83a7 100644 --- a/chrome/browser/chromeos/system/user_removal_manager.h +++ b/chrome/browser/ash/system/user_removal_manager.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_CHROMEOS_SYSTEM_USER_REMOVAL_MANAGER_H_ -#define CHROME_BROWSER_CHROMEOS_SYSTEM_USER_REMOVAL_MANAGER_H_ +#ifndef CHROME_BROWSER_ASH_SYSTEM_USER_REMOVAL_MANAGER_H_ +#define CHROME_BROWSER_ASH_SYSTEM_USER_REMOVAL_MANAGER_H_ #include "base/callback_forward.h" @@ -40,4 +40,4 @@ } // namespace user_removal_manager } // namespace chromeos -#endif // CHROME_BROWSER_CHROMEOS_SYSTEM_USER_REMOVAL_MANAGER_H_ +#endif // CHROME_BROWSER_ASH_SYSTEM_USER_REMOVAL_MANAGER_H_
diff --git a/chrome/browser/chromeos/system/user_removal_manager_unittest.cc b/chrome/browser/ash/system/user_removal_manager_unittest.cc similarity index 97% rename from chrome/browser/chromeos/system/user_removal_manager_unittest.cc rename to chrome/browser/ash/system/user_removal_manager_unittest.cc index 12ae8ea..4d923a4e 100644 --- a/chrome/browser/chromeos/system/user_removal_manager_unittest.cc +++ b/chrome/browser/ash/system/user_removal_manager_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/chromeos/system/user_removal_manager.h" +#include "chrome/browser/ash/system/user_removal_manager.h" #include <memory>
diff --git a/chrome/browser/badging/OWNERS b/chrome/browser/badging/OWNERS index 514fa2a..dfa01f6 100644 --- a/chrome/browser/badging/OWNERS +++ b/chrome/browser/badging/OWNERS
@@ -1,2 +1,4 @@ -cmumford@google.com +cmp@chromium.org +dmurph@chromiumr.org +msw@chromium.org mgiuca@chromium.org
diff --git a/chrome/browser/browser_process_platform_part_chromeos.cc b/chrome/browser/browser_process_platform_part_chromeos.cc index f198517..39fa5ef0 100644 --- a/chrome/browser/browser_process_platform_part_chromeos.cc +++ b/chrome/browser/browser_process_platform_part_chromeos.cc
@@ -13,6 +13,12 @@ #include "base/time/default_tick_clock.h" #include "base/time/tick_clock.h" #include "chrome/browser/ash/profiles/profile_helper.h" +#include "chrome/browser/ash/system/automatic_reboot_manager.h" +#include "chrome/browser/ash/system/device_disabling_manager.h" +#include "chrome/browser/ash/system/device_disabling_manager_default_delegate.h" +#include "chrome/browser/ash/system/system_clock.h" +#include "chrome/browser/ash/system/timezone_resolver_manager.h" +#include "chrome/browser/ash/system/timezone_util.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/login/saml/in_session_password_change_manager.h" #include "chrome/browser/chromeos/login/session/chrome_session_manager.h" @@ -22,12 +28,6 @@ #include "chrome/browser/chromeos/policy/system_proxy_manager.h" #include "chrome/browser/chromeos/scheduler_configuration_manager.h" #include "chrome/browser/chromeos/settings/cros_settings.h" -#include "chrome/browser/chromeos/system/automatic_reboot_manager.h" -#include "chrome/browser/chromeos/system/device_disabling_manager.h" -#include "chrome/browser/chromeos/system/device_disabling_manager_default_delegate.h" -#include "chrome/browser/chromeos/system/system_clock.h" -#include "chrome/browser/chromeos/system/timezone_resolver_manager.h" -#include "chrome/browser/chromeos/system/timezone_util.h" #include "chrome/browser/component_updater/metadata_table_chromeos.h" #include "chrome/common/chrome_switches.h" #include "chromeos/dbus/dbus_thread_manager.h"
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd index 1c1e25c..f8ea6dd8 100644 --- a/chrome/browser/browser_resources.grd +++ b/chrome/browser/browser_resources.grd
@@ -531,6 +531,10 @@ <include name="IDR_MACHINE_LEARNING_INTERNALS_TIME_MOJO_JS" file="${root_gen_dir}\mojo/public/mojom/base/time.mojom-lite.js" use_base_dir="false" type="BINDATA" /> <include name="IDR_MACHINE_LEARNING_INTERNALS_UTILS_JS" file="resources\chromeos\machine_learning\machine_learning_internals_utils.js" type="BINDATA" /> </if> + <if expr="not is_android"> + <!-- Chrome Cart --> + <part file="cart/resources/cart_resources.grdp" /> + </if> </includes> </release> </grit>
diff --git a/chrome/browser/capability_delegation_browsertest.cc b/chrome/browser/capability_delegation_browsertest.cc index c02dea0..7c584bf 100644 --- a/chrome/browser/capability_delegation_browsertest.cc +++ b/chrome/browser/capability_delegation_browsertest.cc
@@ -60,19 +60,25 @@ EXPECT_EQ(cross_site_url, frame_host->GetLastCommittedURL()); EXPECT_TRUE(frame_host->IsCrossProcessSubframe()); - // TODO(mustaq): We need to duplicate the following checks to include the - // cases without any user activation. Calling |EvalJs| with the option - // EXECUTE_SCRIPT_NO_USER_GESTURE is not enough because the - // |NavigateIframeToURL| call above activates the top frame, perhaps to allow - // the navigation to complete. + // Without either user activation or payment request token, PaymentRequest + // dialog is not allowed. + EXPECT_EQ("NotAllowedError", + content::EvalJs(active_web_contents, "sendRequestToSubframe(false)", + content::EXECUTE_SCRIPT_NO_USER_GESTURE)); - // Without payment request token, PaymentRequest dialog is not allowed. + // Without user activation but with the delegation option, PaymentRequest + // dialog is not allowed. + EXPECT_EQ("NotAllowedError", + content::EvalJs(active_web_contents, "sendRequestToSubframe(true)", + content::EXECUTE_SCRIPT_NO_USER_GESTURE)); + + // With user activation but without the delegation option, PaymentRequest + // dialog is not allowed. EXPECT_EQ("NotAllowedError", content::EvalJs(active_web_contents, "sendRequestToSubframe(false)")); - // With payment request token (plus user activation from |NavigateIframeToURL| - // above), PaymentRequest dialog is shown and then successfully aborted by the - // script. + // With both user activation and the delegation option, PaymentRequest dialog + // is shown and then successfully aborted by the script. EXPECT_EQ("AbortError", content::EvalJs(active_web_contents, "sendRequestToSubframe(true)")); }
diff --git a/chrome/browser/cart/cart_service.cc b/chrome/browser/cart/cart_service.cc index c5e135d..06d4da27 100644 --- a/chrome/browser/cart/cart_service.cc +++ b/chrome/browser/cart/cart_service.cc
@@ -3,12 +3,15 @@ // found in the LICENSE file. #include "chrome/browser/cart/cart_service.h" +#include "base/json/json_reader.h" #include "chrome/browser/cart/cart_db_content.pb.h" #include "chrome/browser/history/history_service_factory.h" #include "chrome/common/pref_names.h" +#include "chrome/grit/browser_resources.h" #include "components/prefs/pref_service.h" #include "components/search/ntp_features.h" #include "net/base/registry_controlled_domains/registry_controlled_domain.h" +#include "ui/base/resource/resource_bundle.h" namespace { constexpr char kFakeDataPrefix[] = "Fake:"; @@ -31,6 +34,14 @@ CartDB::KeyAndValue pair2) { return pair1.second.timestamp() > pair2.second.timestamp(); } + +base::Optional<base::Value> JSONToDictionary(int resource_id) { + base::StringPiece json_resource( + ui::ResourceBundle::GetSharedInstance().GetRawDataResource(resource_id)); + base::Optional<base::Value> value = base::JSONReader::Read(json_resource); + DCHECK(value && value.has_value() && value->is_dict()); + return value; +} } // namespace CartService::CartService(Profile* profile) @@ -38,7 +49,10 @@ cart_db_(std::make_unique<CartDB>(profile_)), history_service_(HistoryServiceFactory::GetForProfile( profile_, - ServiceAccessType::EXPLICIT_ACCESS)) { + ServiceAccessType::EXPLICIT_ACCESS)), + domain_name_mapping_(JSONToDictionary(IDR_CART_DOMAIN_NAME_MAPPING_JSON)), + domain_cart_url_mapping_( + JSONToDictionary(IDR_CART_DOMAIN_CART_URL_MAPPING_JSON)) { if (history_service_) { history_service_observation_.Observe(history_service_); }
diff --git a/chrome/browser/cart/cart_service.h b/chrome/browser/cart/cart_service.h index 51b76b52..88e546aa 100644 --- a/chrome/browser/cart/cart_service.h +++ b/chrome/browser/cart/cart_service.h
@@ -7,6 +7,7 @@ #include "base/callback_helpers.h" #include "base/memory/weak_ptr.h" #include "base/scoped_observation.h" +#include "base/values.h" #include "chrome/browser/cart/cart_db.h" #include "chrome/browser/cart/cart_service_factory.h" #include "chrome/browser/profiles/profile.h" @@ -78,6 +79,7 @@ private: friend class CartServiceFactory; + friend class CartServiceTest; // Use |CartServiceFactory::GetForProfile(...)| to get an instance of this // service. @@ -120,6 +122,8 @@ history::HistoryService* history_service_; base::ScopedObservation<history::HistoryService, HistoryServiceObserver> history_service_observation_{this}; + base::Optional<base::Value> domain_name_mapping_; + base::Optional<base::Value> domain_cart_url_mapping_; base::WeakPtrFactory<CartService> weak_ptr_factory_{this}; };
diff --git a/chrome/browser/cart/cart_service_unittest.cc b/chrome/browser/cart/cart_service_unittest.cc index 0dd8db1c..a169e78 100644 --- a/chrome/browser/cart/cart_service_unittest.cc +++ b/chrome/browser/cart/cart_service_unittest.cc
@@ -132,6 +132,21 @@ std::move(closure).Run(); } + std::string getDomainName(base::StringPiece domain) { + std::string* res = service_->domain_name_mapping_->FindStringKey(domain); + if (!res) + return ""; + return *res; + } + + std::string getDomainCartURL(base::StringPiece domain) { + std::string* res = + service_->domain_cart_url_mapping_->FindStringKey(domain); + if (!res) + return ""; + return *res; + } + void TearDown() override {} protected: @@ -651,3 +666,22 @@ run_loop[2].QuitClosure(), result3)); run_loop[2].Run(); } + +// Tests domain to merchant name mapping. +TEST_F(CartServiceTest, TestDomainToNameMapping) { + EXPECT_EQ("Amazon", getDomainName("amazon.com")); + + EXPECT_EQ("eBay", getDomainName("ebay.com")); + + EXPECT_EQ("", getDomainName("example.com")); +} + +// Tests domain to cart URL mapping. +TEST_F(CartServiceTest, TestDomainToCartURLMapping) { + EXPECT_EQ("https://www.amazon.com/gp/cart/view.html?ref_=nav_cart", + getDomainCartURL("amazon.com")); + + EXPECT_EQ("https://cart.ebay.com", getDomainCartURL("ebay.com")); + + EXPECT_EQ("", getDomainCartURL("example.com")); +}
diff --git a/chrome/browser/cart/resources/cart_domain_cart_url_mapping.json b/chrome/browser/cart/resources/cart_domain_cart_url_mapping.json new file mode 100644 index 0000000..c5109d5 --- /dev/null +++ b/chrome/browser/cart/resources/cart_domain_cart_url_mapping.json
@@ -0,0 +1,5 @@ +{ +"amazon.com": "https://www.amazon.com/gp/cart/view.html?ref_=nav_cart", +"ebay.com": "https://cart.ebay.com", +"walmart.com": "https://www.walmart.com/cart" +} \ No newline at end of file
diff --git a/chrome/browser/cart/resources/cart_domain_name_mapping.json b/chrome/browser/cart/resources/cart_domain_name_mapping.json new file mode 100644 index 0000000..5599c17 --- /dev/null +++ b/chrome/browser/cart/resources/cart_domain_name_mapping.json
@@ -0,0 +1,5 @@ +{ +"amazon.com": "Amazon", +"ebay.com": "eBay", +"walmart.com": "Walmart" +}
diff --git a/chrome/browser/cart/resources/cart_resources.grdp b/chrome/browser/cart/resources/cart_resources.grdp new file mode 100644 index 0000000..91ae25f3 --- /dev/null +++ b/chrome/browser/cart/resources/cart_resources.grdp
@@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> +<grit-part> + <include name="IDR_CART_DOMAIN_NAME_MAPPING_JSON" + file="cart/resources/cart_domain_name_mapping.json" type="BINDATA" /> + <include name="IDR_CART_DOMAIN_CART_URL_MAPPING_JSON" + file="cart/resources/cart_domain_cart_url_mapping.json" type="BINDATA" /> +</grit-part> \ No newline at end of file
diff --git a/chrome/browser/chrome_browser_interface_binders.cc b/chrome/browser/chrome_browser_interface_binders.cc index 277a7349..9ff63d2 100644 --- a/chrome/browser/chrome_browser_interface_binders.cc +++ b/chrome/browser/chrome_browser_interface_binders.cc
@@ -111,7 +111,11 @@ #include "chrome/browser/speech/speech_recognition_client_browser_interface.h" #include "chrome/browser/speech/speech_recognition_client_browser_interface_factory.h" #include "chrome/browser/speech/speech_recognition_service.h" +#if BUILDFLAG(IS_CHROMEOS_ASH) +#include "chrome/browser/speech/cros_speech_recognition_service_factory.h" +#else #include "chrome/browser/speech/speech_recognition_service_factory.h" +#endif #include "chrome/browser/ui/webui/downloads/downloads.mojom.h" #include "chrome/browser/ui/webui/downloads/downloads_ui.h" #include "chrome/browser/ui/webui/realbox/realbox.mojom.h" @@ -423,8 +427,13 @@ Profile* profile = Profile::FromBrowserContext( frame_host->GetProcess()->GetBrowserContext()); if (base::FeatureList::IsEnabled(media::kLiveCaption)) { +#if BUILDFLAG(IS_CHROMEOS_ASH) + CrosSpeechRecognitionServiceFactory::GetForProfile(profile)->Create( + std::move(receiver)); +#else SpeechRecognitionServiceFactory::GetForProfile(profile)->Create( std::move(receiver)); +#endif } } @@ -770,11 +779,11 @@ RegisterWebUIControllerInterfaceBinder< chromeos::diagnostics::mojom::SystemDataProvider, - chromeos::DiagnosticsUI>(map); + chromeos::DiagnosticsDialogUI>(map); RegisterWebUIControllerInterfaceBinder< chromeos::diagnostics::mojom::SystemRoutineController, - chromeos::DiagnosticsUI>(map); + chromeos::DiagnosticsDialogUI>(map); RegisterWebUIControllerInterfaceBinder<chromeos::scanning::mojom::ScanService, chromeos::ScanningUI>(map);
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc index 93de272..ea65786 100644 --- a/chrome/browser/chrome_browser_main.cc +++ b/chrome/browser/chrome_browser_main.cc
@@ -446,7 +446,8 @@ base::FilePath user_data_dir = g_browser_process->profile_manager()->user_data_dir(); base::FilePath startup_profile_dir = - GetStartupProfilePath(user_data_dir, current_directory, command_line); + GetStartupProfilePath(user_data_dir, current_directory, command_line, + /*ignore_profile_picker=*/false); StartupBrowserCreator::ProcessCommandLineAlreadyRunning( command_line, current_directory, startup_profile_dir);
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 6783ddf3..16196723 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -413,6 +413,7 @@ #include "ash/public/cpp/tablet_mode.h" #include "chrome/app/chrome_crash_reporter_client.h" #include "chrome/browser/ash/profiles/profile_helper.h" +#include "chrome/browser/ash/system/input_device_settings.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process_platform_part.h" #include "chrome/browser/chromeos/arc/fileapi/arc_content_file_system_backend_delegate.h" @@ -434,7 +435,6 @@ #include "chrome/browser/chromeos/policy/system_features_disable_list_policy_handler.h" #include "chrome/browser/chromeos/policy/system_proxy_manager.h" #include "chrome/browser/chromeos/smb_client/fileapi/smbfs_file_system_backend_delegate.h" -#include "chrome/browser/chromeos/system/input_device_settings.h" #include "chrome/browser/speech/tts_chromeos.h" #include "chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.h" #include "chrome/browser/ui/browser_dialogs.h"
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index 2801656b..17a6363 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -547,6 +547,34 @@ "../ash/profiles/profile_helper.cc", "../ash/profiles/profile_helper.h", "../ash/reset/metrics.h", + "../ash/system/automatic_reboot_manager.cc", + "../ash/system/automatic_reboot_manager.h", + "../ash/system/automatic_reboot_manager_observer.h", + "../ash/system/breakpad_consent_watcher.cc", + "../ash/system/breakpad_consent_watcher.h", + "../ash/system/device_disabling_manager.cc", + "../ash/system/device_disabling_manager.h", + "../ash/system/device_disabling_manager_default_delegate.cc", + "../ash/system/device_disabling_manager_default_delegate.h", + "../ash/system/fake_input_device_settings.cc", + "../ash/system/fake_input_device_settings.h", + "../ash/system/input_device_settings.cc", + "../ash/system/input_device_settings.h", + "../ash/system/input_device_settings_impl_ozone.cc", + "../ash/system/pointer_device_observer.cc", + "../ash/system/pointer_device_observer.h", + "../ash/system/procfs_util.cc", + "../ash/system/procfs_util.h", + "../ash/system/system_clock.cc", + "../ash/system/system_clock.h", + "../ash/system/system_clock_observer.cc", + "../ash/system/system_clock_observer.h", + "../ash/system/timezone_resolver_manager.cc", + "../ash/system/timezone_resolver_manager.h", + "../ash/system/timezone_util.cc", + "../ash/system/timezone_util.h", + "../ash/system/user_removal_manager.cc", + "../ash/system/user_removal_manager.h", "android_sms/android_sms_app_manager.cc", "android_sms/android_sms_app_manager.h", "android_sms/android_sms_app_manager_impl.cc", @@ -2832,34 +2860,6 @@ "sync/split_settings_sync_field_trial.h", "sync/turn_sync_on_helper.cc", "sync/turn_sync_on_helper.h", - "system/automatic_reboot_manager.cc", - "system/automatic_reboot_manager.h", - "system/automatic_reboot_manager_observer.h", - "system/breakpad_consent_watcher.cc", - "system/breakpad_consent_watcher.h", - "system/device_disabling_manager.cc", - "system/device_disabling_manager.h", - "system/device_disabling_manager_default_delegate.cc", - "system/device_disabling_manager_default_delegate.h", - "system/fake_input_device_settings.cc", - "system/fake_input_device_settings.h", - "system/input_device_settings.cc", - "system/input_device_settings.h", - "system/input_device_settings_impl_ozone.cc", - "system/pointer_device_observer.cc", - "system/pointer_device_observer.h", - "system/procfs_util.cc", - "system/procfs_util.h", - "system/system_clock.cc", - "system/system_clock.h", - "system/system_clock_observer.cc", - "system/system_clock_observer.h", - "system/timezone_resolver_manager.cc", - "system/timezone_resolver_manager.h", - "system/timezone_util.cc", - "system/timezone_util.h", - "system/user_removal_manager.cc", - "system/user_removal_manager.h", "system_logs/command_line_log_source.cc", "system_logs/command_line_log_source.h", "system_logs/crosapi_system_log_source.cc", @@ -3437,6 +3437,10 @@ "../ash/app_mode/web_app/web_kiosk_app_launcher_unittest.cc", "../ash/assistant/assistant_util_unittest.cc", "../ash/mobile/mobile_activator_unittest.cc", + "../ash/system/automatic_reboot_manager_unittest.cc", + "../ash/system/device_disabling_manager_unittest.cc", + "../ash/system/procfs_util_unittest.cc", + "../ash/system/user_removal_manager_unittest.cc", "../download/notification/download_item_notification_unittest.cc", "../extensions/api/enterprise_platform_keys/enterprise_platform_keys_api_unittest.cc", "../extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc", @@ -3549,6 +3553,7 @@ "bluetooth/debug_logs_manager_unittest.cc", "borealis/borealis_app_launcher_unittest.cc", "borealis/borealis_context_manager_unittest.cc", + "borealis/borealis_context_unittest.cc", "borealis/borealis_features_unittest.cc", "borealis/borealis_installer_unittest.cc", "borealis/borealis_launch_watcher_unittest.cc", @@ -4052,10 +4057,6 @@ "startup_settings_cache_unittest.cc", "sync/os_sync_util_unittest.cc", "sync/turn_sync_on_helper_unittest.cc", - "system/automatic_reboot_manager_unittest.cc", - "system/device_disabling_manager_unittest.cc", - "system/procfs_util_unittest.cc", - "system/user_removal_manager_unittest.cc", "system_logs/crosapi_system_log_source_unittest.cc", "system_logs/shill_log_source_unittest.cc", "system_logs/single_debug_daemon_log_source_unittest.cc",
diff --git a/chrome/browser/chromeos/android_sms/android_sms_app_manager_impl.cc b/chrome/browser/chromeos/android_sms/android_sms_app_manager_impl.cc index af63d8b..75b91f5b 100644 --- a/chrome/browser/chromeos/android_sms/android_sms_app_manager_impl.cc +++ b/chrome/browser/chromeos/android_sms/android_sms_app_manager_impl.cc
@@ -20,7 +20,6 @@ #include "chromeos/components/multidevice/logging/logging.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" -#include "ui/display/types/display_constants.h" namespace chromeos { @@ -54,8 +53,7 @@ apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerWindow, WindowOpenDisposition::NEW_WINDOW, false /* preferred_containner */), - apps::mojom::LaunchSource::kFromChromeInternal, - display::kInvalidDisplayId); + apps::mojom::LaunchSource::kFromChromeInternal); } bool AndroidSmsAppManagerImpl::PwaDelegate::TransferItemAttributes(
diff --git a/chrome/browser/chromeos/apps/intent_helper/chromeos_intent_picker_helpers.cc b/chrome/browser/chromeos/apps/intent_helper/chromeos_intent_picker_helpers.cc index 6de9731f..5d756b9 100644 --- a/chrome/browser/chromeos/apps/intent_helper/chromeos_intent_picker_helpers.cc +++ b/chrome/browser/chromeos/apps/intent_helper/chromeos_intent_picker_helpers.cc
@@ -186,7 +186,7 @@ GetEventFlags(mojom::LaunchContainer::kLaunchContainerWindow, WindowOpenDisposition::NEW_WINDOW, /*prefer_container=*/true), - url, launch_source, display::kDefaultDisplayId); + url, launch_source, apps::MakeWindowInfo(display::kDefaultDisplayId)); CloseOrGoBack(web_contents); } }
diff --git a/chrome/browser/chromeos/apps/intent_helper/common_apps_navigation_throttle.cc b/chrome/browser/chromeos/apps/intent_helper/common_apps_navigation_throttle.cc index bd6d596..60cb505 100644 --- a/chrome/browser/chromeos/apps/intent_helper/common_apps_navigation_throttle.cc +++ b/chrome/browser/chromeos/apps/intent_helper/common_apps_navigation_throttle.cc
@@ -86,7 +86,8 @@ GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerWindow, WindowOpenDisposition::NEW_WINDOW, /*prefer_container=*/true), - url, launch_source, display::kDefaultDisplayId); + url, launch_source, + apps::MakeWindowInfo(display::kDefaultDisplayId)); CloseOrGoBack(web_contents); IntentHandlingMetrics::RecordIntentPickerUserInteractionMetrics( /*selected_app_package=*/preferred_app_id.value(),
diff --git a/chrome/browser/chromeos/arc/intent_helper/arc_settings_service.cc b/chrome/browser/chromeos/arc/intent_helper/arc_settings_service.cc index 93deaa9..e56729e3 100644 --- a/chrome/browser/chromeos/arc/intent_helper/arc_settings_service.cc +++ b/chrome/browser/chromeos/arc/intent_helper/arc_settings_service.cc
@@ -16,12 +16,12 @@ #include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "base/values.h" +#include "chrome/browser/ash/system/timezone_resolver_manager.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/arc/arc_util.h" #include "chrome/browser/chromeos/arc/policy/arc_policy_util.h" #include "chrome/browser/chromeos/arc/session/arc_session_manager.h" #include "chrome/browser/chromeos/settings/stats_reporting_controller.h" -#include "chrome/browser/chromeos/system/timezone_resolver_manager.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profiles_state.h" #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
diff --git a/chrome/browser/chromeos/borealis/borealis_context.cc b/chrome/browser/chromeos/borealis/borealis_context.cc index aee2e1d2..dfe0be6e 100644 --- a/chrome/browser/chromeos/borealis/borealis_context.cc +++ b/chrome/browser/chromeos/borealis/borealis_context.cc
@@ -6,9 +6,11 @@ #include "base/memory/ptr_util.h" #include "base/scoped_observation.h" +#include "chrome/browser/chromeos/borealis/borealis_metrics.h" #include "chrome/browser/chromeos/borealis/borealis_service.h" #include "chrome/browser/chromeos/borealis/borealis_shutdown_monitor.h" #include "chrome/browser/chromeos/borealis/borealis_window_manager.h" +#include "chrome/browser/chromeos/guest_os/guest_os_stability_monitor.h" namespace borealis { @@ -46,9 +48,16 @@ BorealisContext::~BorealisContext() = default; +void BorealisContext::NotifyUnexpectedVmShutdown() { + guest_os_stability_monitor_->LogUnexpectedVmShutdown(); +} + BorealisContext::BorealisContext(Profile* profile) : profile_(profile), - lifetime_observer_(std::make_unique<BorealisLifetimeObserver>(profile)) {} + lifetime_observer_(std::make_unique<BorealisLifetimeObserver>(profile)), + guest_os_stability_monitor_( + std::make_unique<guest_os::GuestOsStabilityMonitor>( + kBorealisStabilityHistogram)) {} std::unique_ptr<BorealisContext> BorealisContext::CreateBorealisContextForTesting(Profile* profile) {
diff --git a/chrome/browser/chromeos/borealis/borealis_context.h b/chrome/browser/chromeos/borealis/borealis_context.h index 712d0f2..cf0492d 100644 --- a/chrome/browser/chromeos/borealis/borealis_context.h +++ b/chrome/browser/chromeos/borealis/borealis_context.h
@@ -12,6 +12,9 @@ class Profile; +namespace guest_os { +class GuestOsStabilityMonitor; +} namespace borealis { class BorealisLifetimeObserver; @@ -41,6 +44,10 @@ const base::FilePath& disk_path() const { return disk_path_; } void set_disk_path(base::FilePath path) { disk_path_ = std::move(path); } + // Called to signal that this Borealis VM is being unexpectedly shut down. + // Not to be called during intentional shutdowns. + void NotifyUnexpectedVmShutdown(); + private: friend class BorealisContextManagerImpl; @@ -53,6 +60,9 @@ // This instance listens for the session to finish and issues an automatic // shutdown when it does. std::unique_ptr<BorealisLifetimeObserver> lifetime_observer_; + + std::unique_ptr<guest_os::GuestOsStabilityMonitor> + guest_os_stability_monitor_; }; } // namespace borealis
diff --git a/chrome/browser/chromeos/borealis/borealis_context_manager_impl.cc b/chrome/browser/chromeos/borealis/borealis_context_manager_impl.cc index af624fd..d9182570 100644 --- a/chrome/browser/chromeos/borealis/borealis_context_manager_impl.cc +++ b/chrome/browser/chromeos/borealis/borealis_context_manager_impl.cc
@@ -81,9 +81,24 @@ } BorealisContextManagerImpl::BorealisContextManagerImpl(Profile* profile) - : profile_(profile), weak_factory_(this) {} + : profile_(profile), weak_factory_(this) { + // DBusThreadManager may not be initialized in tests. + if (chromeos::DBusThreadManager::IsInitialized()) { + chromeos::DBusThreadManager::Get()->GetConciergeClient()->AddVmObserver( + this); + } +} -BorealisContextManagerImpl::~BorealisContextManagerImpl() = default; +BorealisContextManagerImpl::~BorealisContextManagerImpl() { + // Even if initialized, DBusThreadManager may be destroyed prior to + // BorealisService/BorealisContextManagerImpl in tests. Therefore we must not + // keep a pointer to the observed ConciergeClient, either directly or via + // ScopedObservation or similar. + if (chromeos::DBusThreadManager::IsInitialized()) { + chromeos::DBusThreadManager::Get()->GetConciergeClient()->RemoveVmObserver( + this); + } +} void BorealisContextManagerImpl::StartBorealis(ResultCallback callback) { if (context_) { @@ -199,4 +214,23 @@ } } +// TODO(b/179620544): Move handling of unexpected shutdowns to +// BorealisLaunchWatcher. +void BorealisContextManagerImpl::OnVmStarted( + const vm_tools::concierge::VmStartedSignal& signal) {} + +void BorealisContextManagerImpl::OnVmStopped( + const vm_tools::concierge::VmStoppedSignal& signal) { + if (context_ && context_->vm_name() == signal.name() && + signal.owner_id() == + chromeos::ProfileHelper::GetUserIdHashFromProfile(profile_)) { + // If |context_| exists, it's a "running" Borealis instance which we didn't + // request to shut down. + context_->NotifyUnexpectedVmShutdown(); + + // Update our state to reflect the unexpected VM exit. + context_.reset(); + } +} + } // namespace borealis
diff --git a/chrome/browser/chromeos/borealis/borealis_context_manager_impl.h b/chrome/browser/chromeos/borealis/borealis_context_manager_impl.h index b4a3d6e..b2b7a7e 100644 --- a/chrome/browser/chromeos/borealis/borealis_context_manager_impl.h +++ b/chrome/browser/chromeos/borealis/borealis_context_manager_impl.h
@@ -14,6 +14,7 @@ #include "chrome/browser/chromeos/borealis/infra/described.h" #include "chrome/browser/chromeos/borealis/infra/transition.h" #include "chrome/browser/profiles/profile.h" +#include "chromeos/dbus/concierge_client.h" namespace borealis { @@ -21,7 +22,9 @@ // The Borealis Context Manager is a keyed service responsible for managing // the Borealis VM startup flow and guaranteeing its state to other processes. -class BorealisContextManagerImpl : public BorealisContextManager { +class BorealisContextManagerImpl + : public BorealisContextManager, + public chromeos::ConciergeClient::VmObserver { public: explicit BorealisContextManagerImpl(Profile* profile); BorealisContextManagerImpl(const BorealisContextManagerImpl&) = delete; @@ -83,7 +86,12 @@ BorealisContextManager::ContextOrFailure GetResult( const Startup::Result& completion_result); + // chromeos::ConciergeClient::VmObserver: + void OnVmStarted(const vm_tools::concierge::VmStartedSignal& signal) override; + void OnVmStopped(const vm_tools::concierge::VmStoppedSignal& signal) override; + Profile* const profile_; + std::unique_ptr<Startup> in_progress_startup_; std::unique_ptr<BorealisContext> context_; base::queue<ResultCallback> callback_queue_;
diff --git a/chrome/browser/chromeos/borealis/borealis_context_manager_unittest.cc b/chrome/browser/chromeos/borealis/borealis_context_manager_unittest.cc index 3c307f51..2dc62ac4 100644 --- a/chrome/browser/chromeos/borealis/borealis_context_manager_unittest.cc +++ b/chrome/browser/chromeos/borealis/borealis_context_manager_unittest.cc
@@ -11,9 +11,11 @@ #include "base/containers/queue.h" #include "base/test/bind.h" #include "base/test/metrics/histogram_tester.h" +#include "chrome/browser/ash/profiles/profile_helper.h" #include "chrome/browser/chromeos/borealis/borealis_context_manager.h" #include "chrome/browser/chromeos/borealis/borealis_metrics.h" #include "chrome/browser/chromeos/borealis/borealis_task.h" +#include "chrome/browser/chromeos/guest_os/guest_os_stability_monitor.h" #include "chrome/browser/chromeos/login/users/mock_user_manager.h" #include "chrome/test/base/testing_profile.h" #include "chromeos/dbus/dbus_thread_manager.h" @@ -108,6 +110,17 @@ histogram_tester_.reset(); } + void SendVmStoppedSignal() { + auto* concierge_client = static_cast<chromeos::FakeConciergeClient*>( + chromeos::DBusThreadManager::Get()->GetConciergeClient()); + + vm_tools::concierge::VmStoppedSignal signal; + signal.set_name("test_vm_name"); + signal.set_owner_id( + ash::ProfileHelper::GetUserIdHashFromProfile(profile_.get())); + concierge_client->NotifyVmStopped(signal); + } + content::BrowserTaskEnvironment task_environment_; std::unique_ptr<TestingProfile> profile_; std::unique_ptr<base::HistogramTester> histogram_tester_; @@ -336,5 +349,59 @@ task_environment_.RunUntilIdle(); } +TEST_F(BorealisContextManagerTest, ShouldNotLogVmStoppedWhenNotRunning) { + SendVmStoppedSignal(); + histogram_tester_->ExpectUniqueSample(kBorealisStabilityHistogram, + guest_os::FailureClasses::VmStopped, 0); +} + +TEST_F(BorealisContextManagerTest, ShouldNotLogVmStoppedDuringStartup) { + testing::StrictMock<ResultCallbackHandler> callback_expectation; + + BorealisContextManagerImplForTesting context_manager( + profile_.get(), /*tasks=*/1, /*success=*/true); + context_manager.StartBorealis(callback_expectation.GetCallback()); + + SendVmStoppedSignal(); + + histogram_tester_->ExpectUniqueSample(kBorealisStabilityHistogram, + guest_os::FailureClasses::VmStopped, 0); +} + +TEST_F(BorealisContextManagerTest, ShouldNotLogVmStoppedWhenExpected) { + testing::StrictMock<ResultCallbackHandler> callback_expectation; + // No need to verify the shutdown callback for this test case. + ShutdownCallbackHandler shutdown_callback; + + BorealisContextManagerImplForTesting context_manager( + profile_.get(), /*tasks=*/1, /*success=*/true); + EXPECT_CALL(callback_expectation, Callback(IsSuccessResult())); + context_manager.StartBorealis(callback_expectation.GetCallback()); + task_environment_.RunUntilIdle(); + + context_manager.ShutDownBorealis(shutdown_callback.GetCallback()); + SendVmStoppedSignal(); + + histogram_tester_->ExpectUniqueSample(kBorealisStabilityHistogram, + guest_os::FailureClasses::VmStopped, 0); + + // Wait for shutdown to complete before destructing |shutdown_callback|. + task_environment_.RunUntilIdle(); +} + +TEST_F(BorealisContextManagerTest, LogVmStoppedWhenUnexpected) { + testing::StrictMock<ResultCallbackHandler> callback_expectation; + + BorealisContextManagerImplForTesting context_manager( + profile_.get(), /*tasks=*/1, /*success=*/true); + EXPECT_CALL(callback_expectation, Callback(IsSuccessResult())); + context_manager.StartBorealis(callback_expectation.GetCallback()); + task_environment_.RunUntilIdle(); + + SendVmStoppedSignal(); + histogram_tester_->ExpectUniqueSample(kBorealisStabilityHistogram, + guest_os::FailureClasses::VmStopped, 1); +} + } // namespace } // namespace borealis
diff --git a/chrome/browser/chromeos/borealis/borealis_context_unittest.cc b/chrome/browser/chromeos/borealis/borealis_context_unittest.cc new file mode 100644 index 0000000..dd879e837 --- /dev/null +++ b/chrome/browser/chromeos/borealis/borealis_context_unittest.cc
@@ -0,0 +1,142 @@ +// 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 "chrome/browser/chromeos/guest_os/guest_os_stability_monitor.h" + +#include <memory> + +#include "base/barrier_closure.h" +#include "base/run_loop.h" +#include "base/test/metrics/histogram_tester.h" +#include "chrome/browser/chromeos/borealis/borealis_context.h" +#include "chrome/browser/chromeos/borealis/borealis_metrics.h" +#include "chrome/browser/chromeos/borealis/borealis_service_fake.h" +#include "chrome/browser/chromeos/borealis/borealis_shutdown_monitor.h" +#include "chrome/browser/chromeos/borealis/borealis_window_manager.h" +#include "chrome/test/base/testing_profile.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/fake_chunneld_client.h" +#include "chromeos/dbus/fake_cicerone_client.h" +#include "chromeos/dbus/fake_concierge_client.h" +#include "chromeos/dbus/fake_seneschal_client.h" +#include "content/public/test/browser_task_environment.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace borealis { + +class BorealisContextTest : public testing::Test { + public: + BorealisContextTest() { + chromeos::DBusThreadManager::Initialize(); + + profile_ = std::make_unique<TestingProfile>(); + borealis_shutdown_monitor_ = + std::make_unique<BorealisShutdownMonitor>(profile_.get()); + borealis_window_manager = + std::make_unique<BorealisWindowManager>(profile_.get()); + + service_fake_ = BorealisServiceFake::UseFakeForTesting(profile_.get()); + service_fake_->SetShutdownMonitorForTesting( + borealis_shutdown_monitor_.get()); + service_fake_->SetWindowManagerForTesting(borealis_window_manager.get()); + + borealis_context_ = + BorealisContext::CreateBorealisContextForTesting(profile_.get()); + + // When GuestOsStabilityMonitor is initialized, it waits for the DBus + // services to become available before monitoring them. In tests this + // happens instantly, but the notification still comes via a callback on the + // task queue, so run all queued tasks here. + FlushTaskQueue(); + + histogram_tester_.ExpectTotalCount(kBorealisStabilityHistogram, 0); + } + + ~BorealisContextTest() override { + borealis_context_.reset(); // must destroy before DBusThreadManager + chromeos::DBusThreadManager::Shutdown(); + } + + // Run all tasks queued prior to this method being called, but not any tasks + // that are scheduled as a result of those tasks running. This is done by + // placing a quit closure at the current end of the queue and running until we + // hit it. + void FlushTaskQueue() { + base::RunLoop run_loop; + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, + run_loop.QuitClosure()); + run_loop.Run(); + } + + protected: + content::BrowserTaskEnvironment task_env_; + std::unique_ptr<borealis::BorealisContext> borealis_context_; + std::unique_ptr<TestingProfile> profile_; + BorealisServiceFake* service_fake_; + std::unique_ptr<BorealisShutdownMonitor> borealis_shutdown_monitor_; + std::unique_ptr<BorealisWindowManager> borealis_window_manager; + base::HistogramTester histogram_tester_; +}; + +TEST_F(BorealisContextTest, ConciergeFailure) { + auto* concierge_client = static_cast<chromeos::FakeConciergeClient*>( + chromeos::DBusThreadManager::Get()->GetConciergeClient()); + + concierge_client->NotifyConciergeStopped(); + histogram_tester_.ExpectUniqueSample( + kBorealisStabilityHistogram, guest_os::FailureClasses::ConciergeStopped, + 1); + + concierge_client->NotifyConciergeStarted(); + histogram_tester_.ExpectUniqueSample( + kBorealisStabilityHistogram, guest_os::FailureClasses::ConciergeStopped, + 1); +} + +TEST_F(BorealisContextTest, CiceroneFailure) { + auto* cicerone_client = static_cast<chromeos::FakeCiceroneClient*>( + chromeos::DBusThreadManager::Get()->GetCiceroneClient()); + + cicerone_client->NotifyCiceroneStopped(); + histogram_tester_.ExpectUniqueSample( + kBorealisStabilityHistogram, guest_os::FailureClasses::CiceroneStopped, + 1); + + cicerone_client->NotifyCiceroneStarted(); + histogram_tester_.ExpectUniqueSample( + kBorealisStabilityHistogram, guest_os::FailureClasses::CiceroneStopped, + 1); +} + +TEST_F(BorealisContextTest, SeneschalFailure) { + auto* seneschal_client = static_cast<chromeos::FakeSeneschalClient*>( + chromeos::DBusThreadManager::Get()->GetSeneschalClient()); + + seneschal_client->NotifySeneschalStopped(); + histogram_tester_.ExpectUniqueSample( + kBorealisStabilityHistogram, guest_os::FailureClasses::SeneschalStopped, + 1); + + seneschal_client->NotifySeneschalStarted(); + histogram_tester_.ExpectUniqueSample( + kBorealisStabilityHistogram, guest_os::FailureClasses::SeneschalStopped, + 1); +} + +TEST_F(BorealisContextTest, ChunneldFailure) { + auto* chunneld_client = static_cast<chromeos::FakeChunneldClient*>( + chromeos::DBusThreadManager::Get()->GetChunneldClient()); + + chunneld_client->NotifyChunneldStopped(); + histogram_tester_.ExpectUniqueSample( + kBorealisStabilityHistogram, guest_os::FailureClasses::ChunneldStopped, + 1); + + chunneld_client->NotifyChunneldStarted(); + histogram_tester_.ExpectUniqueSample( + kBorealisStabilityHistogram, guest_os::FailureClasses::ChunneldStopped, + 1); +} + +} // namespace borealis
diff --git a/chrome/browser/chromeos/borealis/borealis_metrics.cc b/chrome/browser/chromeos/borealis/borealis_metrics.cc index d50b2b1..2a0730b 100644 --- a/chrome/browser/chromeos/borealis/borealis_metrics.cc +++ b/chrome/browser/chromeos/borealis/borealis_metrics.cc
@@ -13,6 +13,7 @@ const char kBorealisInstallResultHistogram[] = "Borealis.Install.Result"; const char kBorealisInstallOverallTimeHistogram[] = "Borealis.Install.OverallTime"; +const char kBorealisStabilityHistogram[] = "Borealis.Stability"; const char kBorealisStartupNumAttemptsHistogram[] = "Borealis.Startup.NumAttempts"; const char kBorealisStartupResultHistogram[] = "Borealis.Startup.Result";
diff --git a/chrome/browser/chromeos/borealis/borealis_metrics.h b/chrome/browser/chromeos/borealis/borealis_metrics.h index dc99f70..9ccfa21 100644 --- a/chrome/browser/chromeos/borealis/borealis_metrics.h +++ b/chrome/browser/chromeos/borealis/borealis_metrics.h
@@ -12,6 +12,7 @@ extern const char kBorealisInstallNumAttemptsHistogram[]; extern const char kBorealisInstallResultHistogram[]; extern const char kBorealisInstallOverallTimeHistogram[]; +extern const char kBorealisStabilityHistogram[]; extern const char kBorealisStartupNumAttemptsHistogram[]; extern const char kBorealisStartupResultHistogram[]; extern const char kBorealisStartupOverallTimeHistogram[];
diff --git a/chrome/browser/chromeos/borealis/borealis_service_fake.cc b/chrome/browser/chromeos/borealis/borealis_service_fake.cc index 8b3d4f0..e7f31b68 100644 --- a/chrome/browser/chromeos/borealis/borealis_service_fake.cc +++ b/chrome/browser/chromeos/borealis/borealis_service_fake.cc
@@ -23,37 +23,37 @@ BorealisServiceFake::~BorealisServiceFake() = default; BorealisAppLauncher& BorealisServiceFake::AppLauncher() { - DCHECK(app_launcher_); + CHECK(app_launcher_); return *app_launcher_; } BorealisAppUninstaller& BorealisServiceFake::AppUninstaller() { - DCHECK(app_uninstaller_); + CHECK(app_uninstaller_); return *app_uninstaller_; } BorealisContextManager& BorealisServiceFake::ContextManager() { - DCHECK(context_manager_); + CHECK(context_manager_); return *context_manager_; } BorealisFeatures& BorealisServiceFake::Features() { - DCHECK(features_); + CHECK(features_); return *features_; } BorealisInstaller& BorealisServiceFake::Installer() { - DCHECK(installer_); + CHECK(installer_); return *installer_; } BorealisShutdownMonitor& BorealisServiceFake::ShutdownMonitor() { - DCHECK(shutdown_monitor_); + CHECK(shutdown_monitor_); return *shutdown_monitor_; } BorealisWindowManager& BorealisServiceFake::WindowManager() { - DCHECK(window_manager_); + CHECK(window_manager_); return *window_manager_; }
diff --git a/chrome/browser/chromeos/borealis/borealis_task_unittest.cc b/chrome/browser/chromeos/borealis/borealis_task_unittest.cc index da532571..ff71164 100644 --- a/chrome/browser/chromeos/borealis/borealis_task_unittest.cc +++ b/chrome/browser/chromeos/borealis/borealis_task_unittest.cc
@@ -62,6 +62,7 @@ void TearDown() override { profile_.reset(); + context_.reset(); // must destroy before DBus shutdown chromeos::DlcserviceClient::Shutdown(); chromeos::DBusThreadManager::Shutdown();
diff --git a/chrome/browser/chromeos/child_accounts/time_limits/app_service_wrapper.cc b/chrome/browser/chromeos/child_accounts/time_limits/app_service_wrapper.cc index 7a542ec9..fe193c26 100644 --- a/chrome/browser/chromeos/child_accounts/time_limits/app_service_wrapper.cc +++ b/chrome/browser/chromeos/child_accounts/time_limits/app_service_wrapper.cc
@@ -13,6 +13,7 @@ #include "base/optional.h" #include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" +#include "chrome/browser/apps/app_service/launch_utils.h" #include "chrome/browser/chromeos/child_accounts/time_limits/app_time_limit_utils.h" #include "chrome/browser/chromeos/child_accounts/time_limits/app_types.h" #include "chrome/browser/profiles/profile.h" @@ -97,7 +98,7 @@ void AppServiceWrapper::LaunchApp(const std::string& app_service_id) { GetAppProxy()->Launch(app_service_id, ui::EventFlags::EF_NONE, apps::mojom::LaunchSource::kFromParentalControls, - display::kDefaultDisplayId); + apps::MakeWindowInfo(display::kDefaultDisplayId)); } std::vector<AppId> AppServiceWrapper::GetInstalledApps() const {
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc index 0168a047..3c12f50e 100644 --- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc +++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -42,6 +42,9 @@ #include "chrome/browser/ash/app_mode/kiosk_mode_idle_app_name_notification.h" #include "chrome/browser/ash/app_mode/web_app/web_kiosk_app_manager.h" #include "chrome/browser/ash/profiles/profile_helper.h" +#include "chrome/browser/ash/system/breakpad_consent_watcher.h" +#include "chrome/browser/ash/system/input_device_settings.h" +#include "chrome/browser/ash/system/user_removal_manager.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process_platform_part_chromeos.h" #include "chrome/browser/chrome_notification_types.h" @@ -119,9 +122,6 @@ #include "chrome/browser/chromeos/settings/device_settings_service.h" #include "chrome/browser/chromeos/settings/shutdown_policy_forwarder.h" #include "chrome/browser/chromeos/startup_settings_cache.h" -#include "chrome/browser/chromeos/system/breakpad_consent_watcher.h" -#include "chrome/browser/chromeos/system/input_device_settings.h" -#include "chrome/browser/chromeos/system/user_removal_manager.h" #include "chrome/browser/chromeos/system_token_cert_db_initializer.h" #include "chrome/browser/chromeos/ui/gnubby_notification.h" #include "chrome/browser/chromeos/ui/low_disk_notification.h"
diff --git a/chrome/browser/chromeos/crostini/crosvm_metrics.h b/chrome/browser/chromeos/crostini/crosvm_metrics.h index b6d98d8..d428398 100644 --- a/chrome/browser/chromeos/crostini/crosvm_metrics.h +++ b/chrome/browser/chromeos/crostini/crosvm_metrics.h
@@ -14,7 +14,7 @@ #include "base/optional.h" #include "base/sequenced_task_runner.h" #include "base/timer/timer.h" -#include "chrome/browser/chromeos/system/procfs_util.h" +#include "chrome/browser/ash/system/procfs_util.h" namespace crostini {
diff --git a/chrome/browser/chromeos/crostini/crosvm_process_list.h b/chrome/browser/chromeos/crostini/crosvm_process_list.h index 708629f9..1040ecdc 100644 --- a/chrome/browser/chromeos/crostini/crosvm_process_list.h +++ b/chrome/browser/chromeos/crostini/crosvm_process_list.h
@@ -9,7 +9,7 @@ #include <unordered_map> #include "base/files/file_path.h" -#include "chrome/browser/chromeos/system/procfs_util.h" +#include "chrome/browser/ash/system/procfs_util.h" namespace crostini {
diff --git a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc index 558a1b4d..0d5461b 100644 --- a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc +++ b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
@@ -59,6 +59,7 @@ #include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/ash/assistant/assistant_util.h" +#include "chrome/browser/ash/system/input_device_settings.h" #include "chrome/browser/banners/app_banner_manager_desktop.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process_platform_part.h" @@ -84,7 +85,6 @@ #include "chrome/browser/chromeos/printing/cups_printers_manager_factory.h" #include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/browser/chromeos/settings/stats_reporting_controller.h" -#include "chrome/browser/chromeos/system/input_device_settings.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/lifetime/application_lifetime.h" #include "chrome/browser/policy/chrome_policy_conversions_client.h"
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_browser_handler_api.cc b/chrome/browser/chromeos/extensions/file_manager/file_browser_handler_api.cc index 6ff5287c..054dc8ab 100644 --- a/chrome/browser/chromeos/extensions/file_manager/file_browser_handler_api.cc +++ b/chrome/browser/chromeos/extensions/file_manager/file_browser_handler_api.cc
@@ -336,7 +336,7 @@ // Grant access to this particular file to target extension. This will // ensure that the target extension can access only this FS entry and // prevent from traversing FS hierarchy upward. - external_backend->GrantFileAccessToExtension(extension_id(), + external_backend->GrantFileAccessToExtension(extension_id_or_file_app_id(), file_definition.virtual_path); // Grant access to the selected file to target extensions render view process. @@ -344,7 +344,8 @@ render_frame_host()->GetProcess()->GetID(), full_path); file_manager::util::ConvertFileDefinitionToEntryDefinition( - chrome_details.GetProfile(), extension_id(), file_definition, + chrome_details.GetProfile(), extension_id_or_file_app_id(), + file_definition, base::BindOnce( &FileBrowserHandlerInternalSelectFileFunction::RespondEntryDefinition, this));
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc b/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc index 2b18be2f7..6b46b1a 100644 --- a/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc +++ b/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc
@@ -446,8 +446,8 @@ } IN_PROC_BROWSER_TEST_F(FileManagerPrivateApiTest, Permissions) { - EXPECT_TRUE( - RunExtensionTestIgnoreManifestWarnings("file_browser/permissions")); + EXPECT_TRUE(RunExtensionTest({.name = "file_browser/permissions"}, + {.ignore_manifest_warnings = true})); const extensions::Extension* extension = GetSingleLoadedExtension(); ASSERT_TRUE(extension); ASSERT_EQ(1u, extension->install_warnings().size());
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_base.h b/chrome/browser/chromeos/extensions/file_manager/private_api_base.h index 28423ff3..be25965a 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_base.h +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_base.h
@@ -8,6 +8,7 @@ #define CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_MANAGER_PRIVATE_API_BASE_H_ #include "base/time/time.h" +#include "chrome/browser/chromeos/extensions/file_manager/files_extension_function.h" #include "extensions/browser/extension_function.h" namespace extensions { @@ -20,7 +21,7 @@ // set_log_on_completion(true) to enable it, if they want. However, even if // the logging is turned off, a warning is emitted when a function call is // very slow. See the implementation of OnResponded() for details. -class LoggedExtensionFunction : public ExtensionFunction { +class LoggedExtensionFunction : public FilesExtensionFunction { public: LoggedExtensionFunction();
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc index 3363f02b..40f945d42 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc
@@ -397,7 +397,8 @@ if (profile->IsOffTheRecord()) continue; storage::FileSystemContext* const context = - util::GetStoragePartitionForExtensionId(extension_id(), profile) + util::GetStoragePartitionForExtensionId(extension_id_or_file_app_id(), + profile) ->GetFileSystemContext(); for (const auto& url : params->entry_urls) { const storage::FileSystemURL file_system_url = @@ -408,7 +409,7 @@ file_system_url.mount_type() != storage::kFileSystemTypeExternal) { continue; } - backend->GrantFileAccessToExtension(extension_id(), + backend->GrantFileAccessToExtension(extension_id_or_file_app_id(), file_system_url.virtual_path()); content::ChildProcessSecurityPolicy::GetInstance() ->GrantCreateReadWriteFile(render_frame_host()->GetProcess()->GetID(), @@ -525,7 +526,7 @@ &PostNotificationCallbackTaskToUIThread, base::BindRepeating( &file_manager::EventRouter::OnWatcherManagerNotification, - event_router, file_system_url, extension_id()))); + event_router, file_system_url, extension_id_or_file_app_id()))); } void FileManagerPrivateInternalAddFileWatchFunction:: @@ -537,7 +538,8 @@ // Obsolete. Fallback code if storage::WatcherManager is not implemented. event_router->AddFileWatch( - file_system_url.path(), file_system_url.virtual_path(), extension_id(), + file_system_url.path(), file_system_url.virtual_path(), + extension_id_or_file_app_id(), base::BindOnce(&FileWatchFunctionBase::RespondWith, this)); } @@ -566,7 +568,8 @@ DCHECK(event_router); // Obsolete. Fallback code if storage::WatcherManager is not implemented. - event_router->RemoveFileWatch(file_system_url.path(), extension_id()); + event_router->RemoveFileWatch(file_system_url.path(), + extension_id_or_file_app_id()); RespondWith(true); } @@ -1062,8 +1065,8 @@ FileDefinition file_definition; const bool result = file_manager::util::ConvertAbsoluteFilePathToRelativeFileSystemPath( - chrome_details.GetProfile(), extension_id(), file_system_url.path(), - &file_definition.virtual_path); + chrome_details.GetProfile(), extension_id_or_file_app_id(), + file_system_url.path(), &file_definition.virtual_path); if (!result) continue; // The API only supports isolated files. It still works for directories, @@ -1073,7 +1076,7 @@ } file_manager::util::ConvertFileDefinitionListToEntryDefinitionList( - chrome_details.GetProfile(), extension_id(), + chrome_details.GetProfile(), extension_id_or_file_app_id(), file_definition_list, // Safe, since copied internally. base::BindOnce( &FileManagerPrivateInternalResolveIsolatedEntriesFunction:: @@ -1302,7 +1305,8 @@ GURL url; base::FilePath my_files_virtual_path; if (!file_manager::util::ConvertAbsoluteFilePathToFileSystemUrl( - chrome_details_.GetProfile(), my_files_path, extension_id(), &url) || + chrome_details_.GetProfile(), my_files_path, + extension_id_or_file_app_id(), &url) || !storage::ExternalMountPoints::GetSystemInstance()->GetVirtualPath( my_files_path, &my_files_virtual_path)) { Respond(Error("My files is not mounted"));
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.h b/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.h index 0def3ace0..506e5a2 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.h +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.h
@@ -19,6 +19,7 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "chrome/browser/chromeos/extensions/file_manager/file_stream_string_converter.h" +#include "chrome/browser/chromeos/extensions/file_manager/files_extension_function.h" #include "chrome/browser/chromeos/extensions/file_manager/private_api_base.h" #include "chrome/browser/extensions/chrome_extension_function_details.h" #include "components/drive/file_errors.h" @@ -72,7 +73,7 @@ // Grants R/W permissions to profile-specific directories (Drive, Downloads) // from other profiles. -class FileManagerPrivateGrantAccessFunction : public ExtensionFunction { +class FileManagerPrivateGrantAccessFunction : public FilesExtensionFunction { public: FileManagerPrivateGrantAccessFunction();
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc index 727c235..c0bc776 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
@@ -801,11 +801,11 @@ continue; } auto entry = std::make_unique<base::DictionaryValue>(); - entry->SetString( - "fileSystemRoot", - storage::GetExternalFileSystemRootURIString( - extensions::Extension::GetBaseURLFromExtensionId(extension_id()), - mount_name)); + entry->SetString("fileSystemRoot", + storage::GetExternalFileSystemRootURIString( + extensions::Extension::GetBaseURLFromExtensionId( + extension_id_or_file_app_id()), + mount_name)); entry->SetString("fileSystemName", file_system_name); entry->SetString("fileFullPath", full_path); // All shared paths should be directories. Even if this is not true, @@ -1043,7 +1043,8 @@ model->GetRecentFiles( file_system_context.get(), - Extension::GetBaseURLFromExtensionId(extension_id()), file_type, + Extension::GetBaseURLFromExtensionId(extension_id_or_file_app_id()), + file_type, base::BindOnce( &FileManagerPrivateInternalGetRecentFilesFunction::OnGetRecentFiles, this, params->restriction)); @@ -1067,14 +1068,14 @@ // Recent file system only lists regular files, not directories. file_definition.is_directory = false; if (file_manager::util::ConvertAbsoluteFilePathToRelativeFileSystemPath( - chrome_details_.GetProfile(), extension_id(), file.url().path(), - &file_definition.virtual_path)) { + chrome_details_.GetProfile(), extension_id_or_file_app_id(), + file.url().path(), &file_definition.virtual_path)) { file_definition_list.emplace_back(std::move(file_definition)); } } file_manager::util::ConvertFileDefinitionListToEntryDefinitionList( - chrome_details_.GetProfile(), extension_id(), + chrome_details_.GetProfile(), extension_id_or_file_app_id(), file_definition_list, // Safe, since copied internally. base::BindOnce(&FileManagerPrivateInternalGetRecentFilesFunction:: OnConvertFileDefinitionListToEntryDefinitionList,
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h index 164d9672..6ac97559 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h
@@ -13,6 +13,7 @@ #include <vector> #include "base/files/file.h" +#include "chrome/browser/chromeos/extensions/file_manager/files_extension_function.h" #include "chrome/browser/chromeos/extensions/file_manager/private_api_base.h" #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h" #include "chrome/browser/extensions/chrome_extension_function_details.h" @@ -355,7 +356,7 @@ // Implements the chrome.fileManagerPrivate.getCrostiniSharedPaths // method. Returns list of file entries. class FileManagerPrivateInternalGetCrostiniSharedPathsFunction - : public ExtensionFunction { + : public FilesExtensionFunction { public: DECLARE_EXTENSION_FUNCTION( "fileManagerPrivateInternal.getCrostiniSharedPaths",
diff --git a/chrome/browser/chromeos/extensions/info_private_api.cc b/chrome/browser/chromeos/extensions/info_private_api.cc index 53ba8f8..177906a 100644 --- a/chrome/browser/chromeos/extensions/info_private_api.cc +++ b/chrome/browser/chromeos/extensions/info_private_api.cc
@@ -19,13 +19,13 @@ #include "base/values.h" #include "chrome/browser/app_mode/app_mode_utils.h" #include "chrome/browser/ash/profiles/profile_helper.h" +#include "chrome/browser/ash/system/timezone_util.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process_platform_part.h" #include "chrome/browser/chromeos/arc/arc_util.h" #include "chrome/browser/chromeos/login/startup_utils.h" #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" #include "chrome/browser/chromeos/settings/cros_settings.h" -#include "chrome/browser/chromeos/system/timezone_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/pref_names.h" #include "chromeos/network/device_state.h"
diff --git a/chrome/browser/chromeos/first_run/first_run.cc b/chrome/browser/chromeos/first_run/first_run.cc index 0d42b070..7a8fa2df 100644 --- a/chrome/browser/chromeos/first_run/first_run.cc +++ b/chrome/browser/chromeos/first_run/first_run.cc
@@ -40,7 +40,6 @@ #include "content/public/common/content_switches.h" #include "extensions/browser/extension_registry.h" #include "extensions/common/constants.h" -#include "ui/display/types/display_constants.h" #include "ui/events/event_constants.h" #include "ui/gfx/geometry/rect.h" @@ -54,8 +53,7 @@ apps::AppServiceProxyFactory::GetForProfile(profile); proxy->Launch(app_id, ui::EventFlags::EF_NONE, - apps::mojom::LaunchSource::kFromChromeInternal, - display::kInvalidDisplayId); + apps::mojom::LaunchSource::kFromChromeInternal); profile->GetPrefs()->SetBoolean(prefs::kFirstRunTutorialShown, true); }
diff --git a/chrome/browser/chromeos/login/existing_user_controller.cc b/chrome/browser/chromeos/login/existing_user_controller.cc index 2a381cd..8588dc8 100644 --- a/chrome/browser/chromeos/login/existing_user_controller.cc +++ b/chrome/browser/chromeos/login/existing_user_controller.cc
@@ -33,6 +33,7 @@ #include "chrome/browser/ash/app_mode/kiosk_app_launch_error.h" #include "chrome/browser/ash/app_mode/kiosk_app_types.h" #include "chrome/browser/ash/profiles/profile_helper.h" +#include "chrome/browser/ash/system/device_disabling_manager.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process_platform_part.h" #include "chrome/browser/chrome_notification_types.h" @@ -62,7 +63,6 @@ #include "chrome/browser/chromeos/policy/minimum_version_policy_handler.h" #include "chrome/browser/chromeos/policy/powerwash_requirements_checker.h" #include "chrome/browser/chromeos/settings/cros_settings.h" -#include "chrome/browser/chromeos/system/device_disabling_manager.h" #include "chrome/browser/net/system_network_context_manager.h" #include "chrome/browser/notifications/system_notification_helper.h" #include "chrome/browser/policy/profile_policy_connector.h"
diff --git a/chrome/browser/chromeos/login/lock/views_screen_locker.cc b/chrome/browser/chromeos/login/lock/views_screen_locker.cc index 794726e..b10e2079 100644 --- a/chrome/browser/chromeos/login/lock/views_screen_locker.cc +++ b/chrome/browser/chromeos/login/lock/views_screen_locker.cc
@@ -19,6 +19,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" +#include "chrome/browser/ash/system/system_clock.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process_platform_part.h" #include "chrome/browser/chromeos/authpolicy/authpolicy_helper.h" @@ -30,7 +31,6 @@ #include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_factory.h" #include "chrome/browser/chromeos/login/screens/chrome_user_selection_screen.h" #include "chrome/browser/chromeos/login/user_board_view_mojo.h" -#include "chrome/browser/chromeos/system/system_clock.h" #include "chrome/browser/ui/ash/session_controller_client_impl.h" #include "chrome/browser/ui/ash/wallpaper_controller_client.h" #include "chrome/common/pref_names.h"
diff --git a/chrome/browser/chromeos/login/screens/device_disabled_screen.h b/chrome/browser/chromeos/login/screens/device_disabled_screen.h index 5326861..4067f84a 100644 --- a/chrome/browser/chromeos/login/screens/device_disabled_screen.h +++ b/chrome/browser/chromeos/login/screens/device_disabled_screen.h
@@ -6,8 +6,8 @@ #define CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_DEVICE_DISABLED_SCREEN_H_ #include "base/macros.h" +#include "chrome/browser/ash/system/device_disabling_manager.h" #include "chrome/browser/chromeos/login/screens/base_screen.h" -#include "chrome/browser/chromeos/system/device_disabling_manager.h" namespace chromeos {
diff --git a/chrome/browser/chromeos/login/screens/user_selection_screen.cc b/chrome/browser/chromeos/login/screens/user_selection_screen.cc index 3dcf4f8..37385a3 100644 --- a/chrome/browser/chromeos/login/screens/user_selection_screen.cc +++ b/chrome/browser/chromeos/login/screens/user_selection_screen.cc
@@ -23,6 +23,7 @@ #include "base/time/time.h" #include "base/values.h" #include "chrome/browser/ash/profiles/profile_helper.h" +#include "chrome/browser/ash/system/system_clock.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process_platform_part.h" #include "chrome/browser/chromeos/login/demo_mode/demo_session.h" @@ -39,7 +40,6 @@ #include "chrome/browser/chromeos/login/users/default_user_image/default_user_images.h" #include "chrome/browser/chromeos/login/users/multi_profile_user_controller.h" #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" -#include "chrome/browser/chromeos/system/system_clock.h" #include "chrome/browser/ui/ash/login_screen_client.h" #include "chrome/browser/ui/webui/chromeos/login/l10n_util.h" #include "chrome/common/pref_names.h"
diff --git a/chrome/browser/chromeos/login/screens/user_selection_screen.h b/chrome/browser/chromeos/login/screens/user_selection_screen.h index b04151f..7b945e6 100644 --- a/chrome/browser/chromeos/login/screens/user_selection_screen.h +++ b/chrome/browser/chromeos/login/screens/user_selection_screen.h
@@ -16,12 +16,12 @@ #include "base/time/time.h" #include "base/timer/timer.h" #include "base/values.h" +#include "chrome/browser/ash/system/system_clock.h" #include "chrome/browser/chromeos/login/saml/password_sync_token_checkers_collection.h" #include "chrome/browser/chromeos/login/screens/base_screen.h" #include "chrome/browser/chromeos/login/signin/token_handle_util.h" #include "chrome/browser/chromeos/login/ui/login_display.h" #include "chrome/browser/chromeos/settings/cros_settings.h" -#include "chrome/browser/chromeos/system/system_clock.h" #include "chromeos/components/proximity_auth/screenlock_bridge.h" #include "chromeos/dbus/cryptohome/rpc.pb.h" #include "components/account_id/account_id.h"
diff --git a/chrome/browser/chromeos/login/screens/welcome_screen.cc b/chrome/browser/chromeos/login/screens/welcome_screen.cc index d0013d7..d53094c 100644 --- a/chrome/browser/chromeos/login/screens/welcome_screen.cc +++ b/chrome/browser/chromeos/login/screens/welcome_screen.cc
@@ -17,6 +17,8 @@ #include "base/time/default_tick_clock.h" #include "chrome/browser/ash/accessibility/accessibility_manager.h" #include "chrome/browser/ash/accessibility/magnification_manager.h" +#include "chrome/browser/ash/system/timezone_resolver_manager.h" +#include "chrome/browser/ash/system/timezone_util.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/base/locale_util.h" #include "chrome/browser/chromeos/customization/customization_document.h" @@ -26,8 +28,6 @@ #include "chrome/browser/chromeos/login/ui/input_events_blocker.h" #include "chrome/browser/chromeos/login/wizard_controller.h" #include "chrome/browser/chromeos/policy/enrollment_requisition_manager.h" -#include "chrome/browser/chromeos/system/timezone_resolver_manager.h" -#include "chrome/browser/chromeos/system/timezone_util.h" #include "chrome/browser/lifetime/application_lifetime.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/webui/chromeos/login/l10n_util.h"
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_common.cc b/chrome/browser/chromeos/login/ui/login_display_host_common.cc index 4ba7c97e..f690f3a 100644 --- a/chrome/browser/chromeos/login/ui/login_display_host_common.cc +++ b/chrome/browser/chromeos/login/ui/login_display_host_common.cc
@@ -7,8 +7,10 @@ #include "ash/constants/ash_features.h" #include "base/bind.h" #include "base/callback_helpers.h" +#include "base/feature_list.h" #include "chrome/browser/ash/app_mode/kiosk_app_types.h" #include "chrome/browser/ash/profiles/profile_helper.h" +#include "chrome/browser/ash/system/device_disabling_manager.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process_platform_part.h" #include "chrome/browser/chrome_notification_types.h" @@ -25,9 +27,9 @@ #include "chrome/browser/chromeos/login/ui/webui_accelerator_mapping.h" #include "chrome/browser/chromeos/login/wizard_controller.h" #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" -#include "chrome/browser/chromeos/system/device_disabling_manager.h" #include "chrome/browser/ui/ash/wallpaper_controller_client.h" #include "chrome/browser/ui/browser_list.h" +#include "chrome/browser/ui/webui/chromeos/diagnostics_dialog.h" #include "chrome/browser/ui/webui/chromeos/internet_detail_dialog.h" #include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/locale_switch_screen_handler.h" @@ -340,6 +342,18 @@ weak_factory_.GetWeakPtr())); return true; } + + if (action == ash::LoginAcceleratorAction::kLaunchDiagnostics && + base::FeatureList::IsEnabled(chromeos::features::kDiagnosticsApp)) { + // Don't handle this action if device is disabled. + if (system::DeviceDisablingManager:: + IsDeviceDisabledDuringNormalOperation()) { + return false; + } + chromeos::DiagnosticsDialog::ShowDialog(); + return true; + } + if (WizardController::default_controller() && WizardController::default_controller()->is_initialized()) { if (WizardController::default_controller()->HandleAccelerator(action))
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_webui.cc b/chrome/browser/chromeos/login/ui/login_display_host_webui.cc index d03731f..44b43c5 100644 --- a/chrome/browser/chromeos/login/ui/login_display_host_webui.cc +++ b/chrome/browser/chromeos/login/ui/login_display_host_webui.cc
@@ -33,6 +33,10 @@ #include "chrome/browser/ash/app_mode/arc/arc_kiosk_app_manager.h" #include "chrome/browser/ash/app_mode/kiosk_app_types.h" #include "chrome/browser/ash/app_mode/web_app/web_kiosk_app_manager.h" +#include "chrome/browser/ash/system/device_disabling_manager.h" +#include "chrome/browser/ash/system/input_device_settings.h" +#include "chrome/browser/ash/system/timezone_resolver_manager.h" +#include "chrome/browser/ash/system/timezone_util.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process_platform_part.h" #include "chrome/browser/chrome_notification_types.h" @@ -55,10 +59,6 @@ #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" #include "chrome/browser/chromeos/policy/enrollment_config.h" #include "chrome/browser/chromeos/settings/cros_settings.h" -#include "chrome/browser/chromeos/system/device_disabling_manager.h" -#include "chrome/browser/chromeos/system/input_device_settings.h" -#include "chrome/browser/chromeos/system/timezone_resolver_manager.h" -#include "chrome/browser/chromeos/system/timezone_util.h" #include "chrome/browser/lifetime/browser_shutdown.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/ash/ash_util.h"
diff --git a/chrome/browser/chromeos/login/ui/login_screen_extension_ui/web_dialog_view.cc b/chrome/browser/chromeos/login/ui/login_screen_extension_ui/web_dialog_view.cc index 763d4c3..eb595262 100644 --- a/chrome/browser/chromeos/login/ui/login_screen_extension_ui/web_dialog_view.cc +++ b/chrome/browser/chromeos/login/ui/login_screen_extension_ui/web_dialog_view.cc
@@ -8,6 +8,7 @@ #include "chrome/browser/chromeos/login/ui/login_screen_extension_ui/dialog_delegate.h" #include "chrome/browser/ui/ash/login_screen_client.h" #include "content/public/browser/browser_context.h" +#include "ui/views/metadata/metadata_impl_macros.h" namespace chromeos { @@ -43,6 +44,9 @@ web_contents()->Focus(); } +BEGIN_METADATA(WebDialogView, views::WebDialogView) +END_METADATA + } // namespace login_screen_extension_ui } // namespace chromeos
diff --git a/chrome/browser/chromeos/login/ui/login_screen_extension_ui/web_dialog_view.h b/chrome/browser/chromeos/login/ui/login_screen_extension_ui/web_dialog_view.h index 2dc690da..ad44f17 100644 --- a/chrome/browser/chromeos/login/ui/login_screen_extension_ui/web_dialog_view.h +++ b/chrome/browser/chromeos/login/ui/login_screen_extension_ui/web_dialog_view.h
@@ -11,6 +11,7 @@ #include "ash/public/cpp/system_tray_focus_observer.h" #include "base/macros.h" #include "ui/views/controls/webview/web_dialog_view.h" +#include "ui/views/metadata/metadata_header_macros.h" #include "ui/web_dialogs/web_dialog_web_contents_delegate.h" namespace content { @@ -29,11 +30,14 @@ class WebDialogView : public views::WebDialogView, public ash::SystemTrayFocusObserver { public: + METADATA_HEADER(WebDialogView); explicit WebDialogView( content::BrowserContext* context, DialogDelegate* delegate, std::unique_ptr<ui::WebDialogWebContentsDelegate::WebContentsHandler> handler); + WebDialogView(const WebDialogView&) = delete; + WebDialogView& operator=(const WebDialogView&) = delete; ~WebDialogView() override; // views::WebDialogView @@ -44,8 +48,6 @@ private: DialogDelegate* delegate_ = nullptr; - - DISALLOW_COPY_AND_ASSIGN(WebDialogView); }; } // namespace login_screen_extension_ui
diff --git a/chrome/browser/chromeos/login/ui/webui_accelerator_mapping.cc b/chrome/browser/chromeos/login/ui/webui_accelerator_mapping.cc index 216dd1d..382d71a7 100644 --- a/chrome/browser/chromeos/login/ui/webui_accelerator_mapping.cc +++ b/chrome/browser/chromeos/login/ui/webui_accelerator_mapping.cc
@@ -26,6 +26,7 @@ const char kAccelNameAppLaunchNetworkConfig[] = "app_launch_network_config"; const char kAccelNameDemoMode[] = "demo_mode"; const char kAccelSendFeedback[] = "send_feedback"; +const char kAccelNameLaunchDiagnostics[] = "launch_diagnostics"; } // namespace @@ -55,6 +56,8 @@ return kAccelNameDeviceRequisitionRemora; case ash::LoginAcceleratorAction::kStartDemoMode: return kAccelNameDemoMode; + case ash::LoginAcceleratorAction::kLaunchDiagnostics: + return kAccelNameLaunchDiagnostics; } }
diff --git a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc index 3f1b0d9d..29a5a33 100644 --- a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc +++ b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
@@ -35,6 +35,8 @@ #include "base/values.h" #include "chrome/browser/ash/app_mode/kiosk_app_manager.h" #include "chrome/browser/ash/profiles/profile_helper.h" +#include "chrome/browser/ash/system/timezone_resolver_manager.h" +#include "chrome/browser/ash/system/timezone_util.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process_platform_part.h" #include "chrome/browser/chrome_notification_types.h" @@ -64,8 +66,6 @@ #include "chrome/browser/chromeos/policy/user_network_configuration_updater.h" #include "chrome/browser/chromeos/session_length_limiter.h" #include "chrome/browser/chromeos/settings/cros_settings.h" -#include "chrome/browser/chromeos/system/timezone_resolver_manager.h" -#include "chrome/browser/chromeos/system/timezone_util.h" #include "chrome/browser/extensions/extension_tab_util.h" #include "chrome/browser/extensions/permissions_updater.h" #include "chrome/browser/profiles/profile.h"
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc index 9a13bc5..932ce46 100644 --- a/chrome/browser/chromeos/login/wizard_controller.cc +++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -36,6 +36,9 @@ #include "chrome/browser/ash/app_mode/kiosk_app_manager.h" #include "chrome/browser/ash/app_mode/kiosk_app_types.h" #include "chrome/browser/ash/app_mode/web_app/web_kiosk_app_manager.h" +#include "chrome/browser/ash/system/device_disabling_manager.h" +#include "chrome/browser/ash/system/timezone_resolver_manager.h" +#include "chrome/browser/ash/system/timezone_util.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process_platform_part.h" #include "chrome/browser/chrome_notification_types.h" @@ -105,9 +108,6 @@ #include "chrome/browser/chromeos/policy/enrollment_requisition_manager.h" #include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/browser/chromeos/settings/stats_reporting_controller.h" -#include "chrome/browser/chromeos/system/device_disabling_manager.h" -#include "chrome/browser/chromeos/system/timezone_resolver_manager.h" -#include "chrome/browser/chromeos/system/timezone_util.h" #include "chrome/browser/lifetime/application_lifetime.h" #include "chrome/browser/metrics/metrics_reporting_state.h" #include "chrome/browser/policy/profile_policy_connector.h"
diff --git a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc index f91af7c..94e102e 100644 --- a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc +++ b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
@@ -23,6 +23,7 @@ #include "base/task/post_task.h" #include "base/task/thread_pool.h" #include "base/threading/thread_task_runner_handle.h" +#include "chrome/browser/ash/system/timezone_util.h" #include "chrome/browser/chromeos/attestation/attestation_ca_client.h" #include "chrome/browser/chromeos/policy/active_directory_policy_manager.h" #include "chrome/browser/chromeos/policy/adb_sideloading_allowance_mode_policy_handler.h" @@ -55,7 +56,6 @@ #include "chrome/browser/chromeos/printing/bulk_printers_calculator_factory.h" #include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/browser/chromeos/settings/device_settings_service.h" -#include "chrome/browser/chromeos/system/timezone_util.h" #include "chrome/browser/chromeos/ui/adb_sideloading_policy_change_notification.h" #include "chrome/browser/policy/device_management_service_configuration.h" #include "chrome/common/chrome_features.h"
diff --git a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc index c18d0b9..2fe0d799c 100644 --- a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc +++ b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
@@ -45,6 +45,7 @@ #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/apps/app_service/launch_utils.h" #include "chrome/browser/ash/profiles/profile_helper.h" +#include "chrome/browser/ash/system/timezone_util.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process_platform_part.h" #include "chrome/browser/chrome_notification_types.h" @@ -78,7 +79,6 @@ #include "chrome/browser/chromeos/policy/device_network_configuration_updater.h" #include "chrome/browser/chromeos/policy/device_policy_builder.h" #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h" -#include "chrome/browser/chromeos/system/timezone_util.h" #include "chrome/browser/extensions/crx_installer.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/updater/chromeos_extension_cache_delegate.h" @@ -1583,7 +1583,8 @@ WindowOpenDisposition::NEW_WINDOW, false /* preferred_containner */), apps::mojom::LaunchSource::kFromChromeInternal, - display::Screen::GetScreen()->GetPrimaryDisplay().id()); + apps::MakeWindowInfo( + display::Screen::GetScreen()->GetPrimaryDisplay().id())); proxy->FlushMojoCallsForTesting(); run_loop_->Run(); EXPECT_EQ(1U, app_window_registry->app_windows().size());
diff --git a/chrome/browser/chromeos/policy/device_system_use_24hour_clock_browsertest.cc b/chrome/browser/chromeos/policy/device_system_use_24hour_clock_browsertest.cc index 8c2322e..ad92f86 100644 --- a/chrome/browser/chromeos/policy/device_system_use_24hour_clock_browsertest.cc +++ b/chrome/browser/chromeos/policy/device_system_use_24hour_clock_browsertest.cc
@@ -10,12 +10,12 @@ #include "base/macros.h" #include "base/run_loop.h" #include "base/threading/thread_task_runner_handle.h" +#include "chrome/browser/ash/system/system_clock.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process_platform_part.h" #include "chrome/browser/chromeos/login/ui/login_display_host.h" #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h" #include "chrome/browser/chromeos/settings/cros_settings.h" -#include "chrome/browser/chromeos/system/system_clock.h" #include "chrome/browser/lifetime/application_lifetime.h" #include "components/policy/proto/chrome_device_policy.pb.h" #include "content/public/test/browser_test.h"
diff --git a/chrome/browser/chromeos/policy/remote_commands/device_command_wipe_users_job.cc b/chrome/browser/chromeos/policy/remote_commands/device_command_wipe_users_job.cc index f00c11f..135c061 100644 --- a/chrome/browser/chromeos/policy/remote_commands/device_command_wipe_users_job.cc +++ b/chrome/browser/chromeos/policy/remote_commands/device_command_wipe_users_job.cc
@@ -6,7 +6,7 @@ #include "base/bind.h" #include "base/time/time.h" -#include "chrome/browser/chromeos/system/user_removal_manager.h" +#include "chrome/browser/ash/system/user_removal_manager.h" #include "components/policy/core/common/remote_commands/remote_commands_service.h" #include "components/policy/proto/device_management_backend.pb.h"
diff --git a/chrome/browser/chromeos/policy/remote_commands/device_command_wipe_users_job_unittest.cc b/chrome/browser/chromeos/policy/remote_commands/device_command_wipe_users_job_unittest.cc index b69f8cb..ec47c0f 100644 --- a/chrome/browser/chromeos/policy/remote_commands/device_command_wipe_users_job_unittest.cc +++ b/chrome/browser/chromeos/policy/remote_commands/device_command_wipe_users_job_unittest.cc
@@ -17,9 +17,9 @@ #include "base/task_runner.h" #include "base/threading/sequenced_task_runner_handle.h" #include "base/time/time.h" +#include "chrome/browser/ash/system/user_removal_manager.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/policy/remote_commands/device_commands_factory_chromeos.h" -#include "chrome/browser/chromeos/system/user_removal_manager.h" #include "chrome/common/pref_names.h" #include "chrome/test/base/scoped_testing_local_state.h" #include "chrome/test/base/testing_browser_process.h"
diff --git a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.cc b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.cc index b86fc5ab..de3d673 100644 --- a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.cc +++ b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.cc
@@ -326,10 +326,6 @@ } } -bool UserCloudPolicyManagerChromeOS::IsClientRegistered() const { - return client() && client()->is_registered(); -} - void UserCloudPolicyManagerChromeOS::EnableWildcardLoginCheck( const std::string& username) { DCHECK(access_token_.empty());
diff --git a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.h b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.h index b67ed99..f537039 100644 --- a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.h +++ b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.h
@@ -141,9 +141,6 @@ // uploading status report) for child user. bool RequiresOAuthTokenForChildUser() const; - // Returns true if the underlying CloudPolicyClient is already registered. - bool IsClientRegistered() const; - // Indicates a wildcard login check should be performed once an access token // is available. void EnableWildcardLoginCheck(const std::string& username);
diff --git a/chrome/browser/chromeos/power/process_data_collector.cc b/chrome/browser/chromeos/power/process_data_collector.cc index d52c590..4f336e9 100644 --- a/chrome/browser/chromeos/power/process_data_collector.cc +++ b/chrome/browser/chromeos/power/process_data_collector.cc
@@ -36,7 +36,7 @@ #include "base/threading/scoped_blocking_call.h" #include "base/time/time.h" #include "base/values.h" -#include "chrome/browser/chromeos/system/procfs_util.h" +#include "chrome/browser/ash/system/procfs_util.h" #include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/power/power_manager_client.h" #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/chromeos/preferences.cc b/chrome/browser/chromeos/preferences.cc index 11ff8dfa..5449f16 100644 --- a/chrome/browser/chromeos/preferences.cc +++ b/chrome/browser/chromeos/preferences.cc
@@ -26,6 +26,9 @@ #include "base/strings/utf_string_conversions.h" #include "chrome/browser/ash/accessibility/magnification_manager.h" #include "chrome/browser/ash/profiles/profile_helper.h" +#include "chrome/browser/ash/system/input_device_settings.h" +#include "chrome/browser/ash/system/timezone_resolver_manager.h" +#include "chrome/browser/ash/system/timezone_util.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process_platform_part.h" #include "chrome/browser/chrome_notification_types.h" @@ -40,9 +43,6 @@ #include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/browser/chromeos/sync/split_settings_sync_field_trial.h" #include "chrome/browser/chromeos/sync/turn_sync_on_helper.h" -#include "chrome/browser/chromeos/system/input_device_settings.h" -#include "chrome/browser/chromeos/system/timezone_resolver_manager.h" -#include "chrome/browser/chromeos/system/timezone_util.h" #include "chrome/browser/download/download_prefs.h" #include "chrome/browser/prefs/pref_service_syncable_util.h" #include "chrome/browser/ui/ash/system_tray_client.h"
diff --git a/chrome/browser/chromeos/preferences_chromeos_browsertest.cc b/chrome/browser/chromeos/preferences_chromeos_browsertest.cc index bdfeb30..35e3fa53 100644 --- a/chrome/browser/chromeos/preferences_chromeos_browsertest.cc +++ b/chrome/browser/chromeos/preferences_chromeos_browsertest.cc
@@ -11,6 +11,7 @@ #include "base/stl_util.h" #include "base/test/scoped_feature_list.h" #include "chrome/browser/ash/profiles/profile_helper.h" +#include "chrome/browser/ash/system/fake_input_device_settings.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/input_method/input_method_manager_impl.h" #include "chrome/browser/chromeos/login/login_manager_test.h" @@ -19,7 +20,6 @@ #include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/browser/chromeos/settings/scoped_testing_cros_settings.h" #include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h" -#include "chrome/browser/chromeos/system/fake_input_device_settings.h" #include "chrome/common/pref_names.h" #include "components/feedback/tracing_manager.h" #include "components/prefs/pref_service.h"
diff --git a/chrome/browser/chromeos/web_applications/help_app_integration_browsertest.cc b/chrome/browser/chromeos/web_applications/help_app_integration_browsertest.cc index 706f0dd..170962e 100644 --- a/chrome/browser/chromeos/web_applications/help_app_integration_browsertest.cc +++ b/chrome/browser/chromeos/web_applications/help_app_integration_browsertest.cc
@@ -15,6 +15,7 @@ #include "chrome/browser/apps/app_service/app_launch_params.h" #include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" +#include "chrome/browser/apps/app_service/launch_utils.h" #include "chrome/browser/chromeos/release_notes/release_notes_notification.h" #include "chrome/browser/chromeos/release_notes/release_notes_storage.h" #include "chrome/browser/chromeos/web_applications/system_web_app_integration_test.h" @@ -127,7 +128,7 @@ proxy->Launch( *GetManager().GetAppIdForSystemApp(web_app::SystemAppType::HELP), ui::EventFlags::EF_NONE, apps::mojom::LaunchSource::kFromKeyboard, - display::kDefaultDisplayId); + apps::MakeWindowInfo(display::kDefaultDisplayId)); navigation_observer.Wait(); // The HELP app is 18, see DefaultAppName in
diff --git a/chrome/browser/dev_ui/android/dev_ui_loader_throttle.cc b/chrome/browser/dev_ui/android/dev_ui_loader_throttle.cc index a020fb5..114ee21 100644 --- a/chrome/browser/dev_ui/android/dev_ui_loader_throttle.cc +++ b/chrome/browser/dev_ui/android/dev_ui_loader_throttle.cc
@@ -36,6 +36,7 @@ host == chrome::kChromeUIDeviceLogHost || host == chrome::kChromeUIDomainReliabilityInternalsHost || host == chrome::kChromeUIDownloadInternalsHost || + host == chrome::kChromeUIFamilyLinkUserInternalsHost || host == chrome::kChromeUIGCMInternalsHost || host == chrome::kChromeUIInternalsHost || host == chrome::kChromeUIInterstitialHost || @@ -56,7 +57,6 @@ host == chrome::kChromeUISiteEngagementHost || host == chrome::kChromeUISnippetsInternalsHost || host == chrome::kChromeUISuggestionsHost || - host == chrome::kChromeUISupervisedUserInternalsHost || host == chrome::kChromeUISyncInternalsHost || host == chrome::kChromeUITranslateInternalsHost || host == chrome::kChromeUIUsbInternalsHost ||
diff --git a/chrome/browser/dev_ui_browser_resources.grd b/chrome/browser/dev_ui_browser_resources.grd index e602404..c92f620 100644 --- a/chrome/browser/dev_ui_browser_resources.grd +++ b/chrome/browser/dev_ui_browser_resources.grd
@@ -82,9 +82,9 @@ </if> <if expr="enable_supervised_users"> - <include name="IDR_SUPERVISED_USER_INTERNALS_HTML" file="resources\supervised_user_internals\supervised_user_internals.html" allowexternalscript="true" type="BINDATA" /> - <include name="IDR_SUPERVISED_USER_INTERNALS_CSS" file="resources\supervised_user_internals\supervised_user_internals.css" type="BINDATA" /> - <include name="IDR_SUPERVISED_USER_INTERNALS_JS" file="resources\supervised_user_internals\supervised_user_internals.js" type="BINDATA" /> + <include name="IDR_FAMILY_LINK_USER_INTERNALS_HTML" file="resources\family_link_user_internals\family_link_user_internals.html" allowexternalscript="true" type="BINDATA" /> + <include name="IDR_FAMILY_LINK_USER_INTERNALS_CSS" file="resources\family_link_user_internals\family_link_user_internals.css" type="BINDATA" /> + <include name="IDR_FAMILY_LINK_USER_INTERNALS_JS" file="resources\family_link_user_internals\family_link_user_internals.js" type="BINDATA" /> </if> <include name="IDR_TRANSLATE_INTERNALS_HTML" file="../../components/translate/translate_internals/translate_internals.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" /> <include name="IDR_TRANSLATE_INTERNALS_JS" file="../../components/translate/translate_internals/translate_internals.js" type="BINDATA" />
diff --git a/chrome/browser/enterprise/connectors/analysis/content_analysis_dialog_browsertest.cc b/chrome/browser/enterprise/connectors/analysis/content_analysis_dialog_browsertest.cc index 9d344fa..8123f45 100644 --- a/chrome/browser/enterprise/connectors/analysis/content_analysis_dialog_browsertest.cc +++ b/chrome/browser/enterprise/connectors/analysis/content_analysis_dialog_browsertest.cc
@@ -56,6 +56,22 @@ "block_until_verdict": 1 })"; +constexpr char kBlockingScansForDlpAndMalwareWithCustomMessage[] = R"( +{ + "service_provider": "google", + "enable": [ + { + "url_list": ["*"], + "tags": ["dlp", "malware"] + } + ], + "block_until_verdict": 1, + "custom_messages": [{ + "message": "Custom message", + "learn_more_url": "http://www.example.com/" + }] +})"; + base::string16 text() { return base::UTF8ToUTF16(std::string(100, 'a')); } @@ -364,13 +380,8 @@ // The dialog shows the failure or success message for the appropriate // access point and scan type. base::string16 final_message = dialog->GetMessageForTesting()->GetText(); - int files_count = file_scan() ? 1 : 0; - base::string16 expected_message = - success() - ? l10n_util::GetPluralStringFUTF16( - IDS_DEEP_SCANNING_DIALOG_SUCCESS_MESSAGE, files_count) - : l10n_util::GetPluralStringFUTF16( - IDS_DEEP_SCANNING_DIALOG_UPLOAD_FAILURE_MESSAGE, files_count); + base::string16 expected_message = GetExpectedMessage(); + ASSERT_EQ(final_message, expected_message); // The top image is the failure/success one corresponding to the access @@ -404,6 +415,16 @@ ASSERT_FALSE(dialog->GetSideIconSpinnerForTesting()); } + virtual base::string16 GetExpectedMessage() { + int files_count = file_scan() ? 1 : 0; + return success() + ? l10n_util::GetPluralStringFUTF16( + IDS_DEEP_SCANNING_DIALOG_SUCCESS_MESSAGE, files_count) + : l10n_util::GetPluralStringFUTF16( + IDS_DEEP_SCANNING_DIALOG_UPLOAD_FAILURE_MESSAGE, + files_count); + } + void DestructorCalled(ContentAnalysisDialog* dialog) override { // End the test once the dialog gets destroyed. CallQuitClosure(); @@ -418,6 +439,23 @@ } }; +// Tests the behavior of the dialog in the same way as +// ContentAnalysisDialogAppearanceBrowserTest but with a custom message set by +// the admin. +class ContentAnalysisDialogCustomMessageAppearanceBrowserTest + : public ContentAnalysisDialogAppearanceBrowserTest { + private: + base::string16 GetExpectedMessage() override { + int files_count = file_scan() ? 1 : 0; + return success() + ? l10n_util::GetPluralStringFUTF16( + IDS_DEEP_SCANNING_DIALOG_SUCCESS_MESSAGE, files_count) + : l10n_util::GetStringFUTF16( + IDS_DEEP_SCANNING_DIALOG_CUSTOM_MESSAGE, + base::ASCIIToUTF16("Custom message")); + } +}; + constexpr char kTestUrl[] = "https://google.com"; } // namespace @@ -644,4 +682,63 @@ safe_browsing::DeepScanAccessPoint::DRAG_AND_DROP, safe_browsing::DeepScanAccessPoint::PASTE))); +IN_PROC_BROWSER_TEST_P(ContentAnalysisDialogCustomMessageAppearanceBrowserTest, + Test) { + base::ScopedAllowBlockingForTesting allow_blocking; + + // Setup policies to enable deep scanning, its UI and the responses to be + // simulated. + safe_browsing::SetAnalysisConnector( + browser()->profile()->GetPrefs(), FILE_ATTACHED, + kBlockingScansForDlpAndMalwareWithCustomMessage); + + SetStatusCallbackResponse( + safe_browsing::SimpleContentAnalysisResponseForTesting(success(), + success())); + + // Set up delegate test values. + FakeContentAnalysisDelegate::SetResponseDelay(kSmallDelay); + SetUpDelegate(); + + bool called = false; + base::RunLoop run_loop; + SetQuitClosure(run_loop.QuitClosure()); + + ContentAnalysisDelegate::Data data; + + // Use a file path or text to validate the appearance of the dialog for both + // types of scans. + if (file_scan()) + CreateFilesForTest({"foo.doc"}, {"content"}, &data); + else + data.text.emplace_back(text()); + ASSERT_TRUE(ContentAnalysisDelegate::IsEnabled( + browser()->profile(), GURL(kTestUrl), &data, + enterprise_connectors::AnalysisConnector::FILE_ATTACHED)); + + ContentAnalysisDelegate::CreateForWebContents( + browser()->tab_strip_model()->GetActiveWebContents(), std::move(data), + base::BindLambdaForTesting( + [this, &called](const ContentAnalysisDelegate::Data& data, + const ContentAnalysisDelegate::Result& result) { + for (bool result : result.paths_results) + ASSERT_EQ(result, success()); + called = true; + }), + access_point()); + run_loop.Run(); + EXPECT_TRUE(called); +} + +INSTANTIATE_TEST_SUITE_P( + , + ContentAnalysisDialogCustomMessageAppearanceBrowserTest, + testing::Combine( + /*file_scan=*/testing::Bool(), + /*success=*/testing::Bool(), + /*access_point=*/ + testing::Values(safe_browsing::DeepScanAccessPoint::UPLOAD, + safe_browsing::DeepScanAccessPoint::DRAG_AND_DROP, + safe_browsing::DeepScanAccessPoint::PASTE))); + } // namespace enterprise_connectors
diff --git a/chrome/browser/enterprise/connectors/connectors_service.cc b/chrome/browser/enterprise/connectors/connectors_service.cc index f324ceb..30d33e4 100644 --- a/chrome/browser/enterprise/connectors/connectors_service.cc +++ b/chrome/browser/enterprise/connectors/connectors_service.cc
@@ -303,20 +303,11 @@ if (!policy::BrowserDMTokenStorage::Get()->RetrieveDMToken().is_valid()) return true; - policy::UserCloudPolicyManager* profile_policy_manager = - Profile::FromBrowserContext(context_)->GetUserCloudPolicyManager(); - policy::MachineLevelUserCloudPolicyManager* browser_policy_manager = - g_browser_process->browser_policy_connector() - ->machine_level_user_cloud_policy_manager(); - - if (!profile_policy_manager || !browser_policy_manager || - !profile_policy_manager->IsClientRegistered() || - !browser_policy_manager->IsClientRegistered()) { - return false; - } - - auto* profile_policy = profile_policy_manager->core()->store()->policy(); - auto* browser_policy = browser_policy_manager->core()->store()->policy(); + const enterprise_management::PolicyData* profile_policy = + chrome::enterprise_util::GetProfilePolicyData( + Profile::FromBrowserContext(context_)); + const enterprise_management::PolicyData* browser_policy = + chrome::enterprise_util::GetBrowserPolicyData(); if (!profile_policy || !browser_policy) return false;
diff --git a/chrome/browser/enterprise/util/affiliation.cc b/chrome/browser/enterprise/util/affiliation.cc index 506d164a..87aec75 100644 --- a/chrome/browser/enterprise/util/affiliation.cc +++ b/chrome/browser/enterprise/util/affiliation.cc
@@ -3,11 +3,53 @@ // found in the LICENSE file. #include "chrome/browser/enterprise/util/affiliation.h" + #include <set> +#include "chrome/browser/browser_process.h" +#include "chrome/browser/policy/chrome_browser_policy_connector.h" +#include "chrome/browser/profiles/profile.h" +#include "components/policy/core/common/cloud/machine_level_user_cloud_policy_manager.h" +#include "components/policy/core/common/cloud/user_cloud_policy_manager.h" + namespace chrome { namespace enterprise_util { +#if !BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OS_ANDROID) + +namespace { + +const enterprise_management::PolicyData* GetPolicyData( + policy::CloudPolicyManager* policy_manager) { + if (!policy_manager || !policy_manager->IsClientRegistered() || + !policy_manager->core() || !policy_manager->core()->store()) { + return nullptr; + } + + return policy_manager->core()->store()->policy(); +} + +} // namespace + +const enterprise_management::PolicyData* GetProfilePolicyData( + Profile* profile) { + DCHECK(profile); + return GetPolicyData(profile->GetUserCloudPolicyManager()); +} + +const enterprise_management::PolicyData* GetBrowserPolicyData() { + if (!g_browser_process->browser_policy_connector()) + return nullptr; + + policy::MachineLevelUserCloudPolicyManager* policy_manager = + g_browser_process->browser_policy_connector() + ->machine_level_user_cloud_policy_manager(); + + return GetPolicyData(policy_manager); +} + +#endif // !BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OS_ANDROID) + bool IsProfileAffiliated( const enterprise_management::PolicyData& profile_policy, const enterprise_management::PolicyData& browser_policy) {
diff --git a/chrome/browser/enterprise/util/affiliation.h b/chrome/browser/enterprise/util/affiliation.h index 55de0787..fb3e866 100644 --- a/chrome/browser/enterprise/util/affiliation.h +++ b/chrome/browser/enterprise/util/affiliation.h
@@ -5,11 +5,27 @@ #ifndef CHROME_BROWSER_ENTERPRISE_UTIL_AFFILIATION_H_ #define CHROME_BROWSER_ENTERPRISE_UTIL_AFFILIATION_H_ +#include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "device_management_backend.pb.h" +class Profile; + namespace chrome { namespace enterprise_util { +#if !BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OS_ANDROID) + +// Returns the PolicyData corresponding to |profile|, or nullptr if it can't be +// obtained. +const enterprise_management::PolicyData* GetProfilePolicyData(Profile* profile); + +// Returns the PolicyData corresponding to the browser, or nullptr if it can't +// be obtained. +const enterprise_management::PolicyData* GetBrowserPolicyData(); + +#endif // !BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OS_ANDROID) + // Returns true if the profile and browser are managed by the same customer // (affiliated). This is determined by comparing affiliation IDs obtained in the // policy fetching response. If either policies has no affiliation IDs, this
diff --git a/chrome/browser/error_reporting/BUILD.gn b/chrome/browser/error_reporting/BUILD.gn index 2faabc2..f9ba071 100644 --- a/chrome/browser/error_reporting/BUILD.gn +++ b/chrome/browser/error_reporting/BUILD.gn
@@ -1,10 +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. +import("//build/config/chromeos/ui_mode.gni") # TODO(crbug.com/1129544) This is currently disabled due to Windows DLL # thunking issues. Fix & re-enable. -assert(is_linux || is_chromeos) +assert(is_linux || is_chromeos_ash || is_chromeos_lacros) + +source_set("constants") { + sources = [ + "constants.cc", + "constants.h", + ] + deps = [ "//build:chromeos_buildflags" ] +} static_library("error_reporting") { sources = [ @@ -25,6 +34,12 @@ "//services/network:network_service", "//services/network/public/cpp", ] + if (is_chromeos_ash || is_chromeos_lacros) { + sources += [ "chrome_js_error_report_processor_chromeos.cc" ] + deps += [ ":constants" ] + } else { + sources += [ "chrome_js_error_report_processor_nonchromeos.cc" ] + } } source_set("test_support") { @@ -42,6 +57,9 @@ "//components/crash/content/browser/error_reporting", "//components/crash/content/browser/error_reporting:mock_crash_endpoint", ] + if (is_chromeos_ash || is_chromeos_lacros) { + data_deps = [ ":mock_chromeos_crash_reporter" ] + } } source_set("unit_test") { @@ -61,3 +79,17 @@ "//testing/gtest", ] } + +if (is_chromeos_ash || is_chromeos_lacros) { + executable("mock_chromeos_crash_reporter") { + testonly = true + sources = [ "mock_chromeos_crash_reporter.cc" ] + + deps = [ + ":constants", + "//base", + "//net", + "//third_party/crashpad/crashpad/third_party/cpp-httplib", + ] + } +}
diff --git a/chrome/browser/error_reporting/chrome_js_error_report_processor.cc b/chrome/browser/error_reporting/chrome_js_error_report_processor.cc index 9ec9a63..ac1414f 100644 --- a/chrome/browser/error_reporting/chrome_js_error_report_processor.cc +++ b/chrome/browser/error_reporting/chrome_js_error_report_processor.cc
@@ -6,43 +6,32 @@ #include <tuple> #include <utility> -#include <vector> #include "base/callback.h" #include "base/callback_helpers.h" -#include "base/files/file.h" -#include "base/files/file_path.h" #include "base/logging.h" #include "base/memory/scoped_refptr.h" -#include "base/path_service.h" #include "base/strings/strcat.h" #include "base/strings/string_number_conversions.h" -#include "base/strings/stringprintf.h" #include "base/system/sys_info.h" #include "base/task/task_traits.h" #include "base/task/thread_pool.h" #include "base/time/default_clock.h" #include "build/build_config.h" -#include "chrome/common/chrome_paths.h" #include "components/crash/content/browser/error_reporting/javascript_error_report.h" #include "components/crash/core/app/client_upload_info.h" #include "components/crash/core/app/crashpad.h" #include "components/feedback/redaction_tool.h" #include "components/startup_metric_utils/browser/startup_metric_utils.h" -#include "components/upload_list/crash_upload_list.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/storage_partition.h" #include "net/base/escape.h" #include "services/network/public/cpp/shared_url_loader_factory.h" -#include "services/network/public/cpp/simple_url_loader.h" namespace { -constexpr char kCrashEndpointUrl[] = "https://clients2.google.com/cr/report"; -constexpr char kCrashEndpointStagingUrl[] = - "https://clients2.google.com/cr/staging_report"; constexpr char kNoBrowserNoWindow[] = "NO_BROWSER"; constexpr char kRegularTabbedWindow[] = "REGULAR_TABBED"; constexpr char kWebAppWindow[] = "WEB_APP"; @@ -74,18 +63,6 @@ .Redact(message); } -using ParameterMap = std::map<std::string, std::string>; - -std::string BuildPostRequestQueryString(const ParameterMap& params) { - std::vector<std::string> query_parts; - for (const auto& kv : params) { - query_parts.push_back(base::StrCat( - {kv.first, "=", - net::EscapeQueryParamValue(kv.second, /*use_plus=*/false)})); - } - return base::JoinString(query_parts, "&"); -} - std::string MapWindowTypeToString(WindowType window_type) { switch (window_type) { case WindowType::kRegularTabbed: @@ -105,69 +82,19 @@ : clock_(base::DefaultClock::GetInstance()) {} ChromeJsErrorReportProcessor::~ChromeJsErrorReportProcessor() = default; -#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS) -void ChromeJsErrorReportProcessor::UpdateReportDatabase( - std::string remote_report_id, - base::Time report_time) { - // Uploads.log format is "seconds_since_epoch,crash_id\n" - base::FilePath crash_dir_path; - if (!base::PathService::Get(chrome::DIR_CRASH_DUMPS, &crash_dir_path)) { - VLOG(1) << "Nowhere to write uploads.log"; - return; - } - base::FilePath upload_log_path = - crash_dir_path.AppendASCII(CrashUploadList::kReporterLogFilename); - base::File upload_log(upload_log_path, - base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_APPEND); - if (!upload_log.IsValid()) { - VLOG(1) << "Could not open upload.log: " - << base::File::ErrorToString(upload_log.error_details()); - return; - } - std::string line = base::StrCat({base::NumberToString(report_time.ToTimeT()), - ",", remote_report_id, "\n"}); - // WriteAtCurrentPos because O_APPEND. - if (upload_log.WriteAtCurrentPos(line.c_str(), line.length()) != - static_cast<int>(line.length())) { - VLOG(1) << "Could not write to upload.log"; - return; - } -} -#endif // !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS) - -void ChromeJsErrorReportProcessor::OnRequestComplete( - std::unique_ptr<network::SimpleURLLoader> url_loader, - base::ScopedClosureRunner callback_runner, - base::Time report_time, - std::unique_ptr<std::string> response_body) { - if (response_body) { - VLOG(1) << "Uploaded crash report. ID: " << *response_body; - // On Chrome OS, we use a different format than other platforms. Since we - // will soon not call this function at all on Chrome OS (crbug.com/986166), - // don't bother writing code to write to that format. -#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS) - base::ThreadPool::PostTaskAndReply( - FROM_HERE, {base::MayBlock()}, - base::BindOnce(&ChromeJsErrorReportProcessor::UpdateReportDatabase, - this, *response_body, report_time), - callback_runner.Release()); -#endif // !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS) - } else { - LOG(ERROR) << "Failed to upload crash report"; - } - // callback_runner may implicitly run the callback when we reach this line if - // we didn't add a task to update the report database. -} - // Returns the redacted, fixed-up error report if the user consented to have it // sent. Returns base::nullopt if the user did not consent or we otherwise // should not send the report. All the MayBlock work should be done in here. base::Optional<JavaScriptErrorReport> ChromeJsErrorReportProcessor::CheckConsentAndRedact( JavaScriptErrorReport error_report) { + // Consent is handled at the OS level by crash_reporter so we don't need to + // check it here for Chrome OS. +#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS) if (!crash_reporter::GetClientCollectStatsConsent()) { return base::nullopt; } +#endif // Remove error message from stack trace before redaction, since redaction // might change the error message enough that we don't find it. @@ -186,7 +113,6 @@ std::string product_name; std::string version; std::string channel; - std::string os_version; }; ChromeJsErrorReportProcessor::PlatformInfo @@ -199,79 +125,9 @@ crash_reporter::GetClientProductNameAndVersion(&info.product_name, &info.version, &info.channel); #endif - int32_t os_major_version = 0; - int32_t os_minor_version = 0; - int32_t os_bugfix_version = 0; - GetOsVersion(os_major_version, os_minor_version, os_bugfix_version); - info.os_version = base::StringPrintf("%d.%d.%d", os_major_version, - os_minor_version, os_bugfix_version); return info; } -void ChromeJsErrorReportProcessor::SendReport( - const GURL& url, - const std::string& body, - base::ScopedClosureRunner callback_runner, - base::Time report_time, - network::SharedURLLoaderFactory* loader_factory) { - auto resource_request = std::make_unique<network::ResourceRequest>(); - resource_request->method = "POST"; - resource_request->url = url; - - const auto traffic_annotation = - net::DefineNetworkTrafficAnnotation("javascript_report_error", R"( - semantics { - sender: "JavaScript error reporter" - description: - "Chrome can send JavaScript errors that occur within built-in " - "component extensions and chrome:// webpages. If enabled, the error " - "message, along with information about Chrome and the operating " - "system, is sent to Google for debugging." - trigger: - "A JavaScript error occurs in a Chrome component extension (an " - "extension bundled with the Chrome browser, not downloaded " - "separately) or in certain chrome:// webpages." - data: - "The JavaScript error message, the version and channel of Chrome, " - "the URL of the extension or webpage, the line and column number of " - "the JavaScript code where the error occurred, and a stack trace of " - "the error." - destination: GOOGLE_OWNED_SERVICE - } - policy { - cookies_allowed: NO - setting: - "You can enable or disable this feature via 'Automatically send " - "usage statistics and crash reports to Google' in Chromium's " - "settings under Advanced, Privacy. (This is in System Settings on " - "Chromebooks.) This feature is enabled by default." - chrome_policy { - MetricsReportingEnabled { - policy_options {mode: MANDATORY} - MetricsReportingEnabled: false - } - } - })"); - - VLOG(1) << "Sending crash report: " << resource_request->url; - - auto url_loader = network::SimpleURLLoader::Create( - std::move(resource_request), traffic_annotation); - - if (!body.empty()) { - url_loader->AttachStringForUpload(body, "text/plain"); - } - - constexpr int kCrashEndpointResponseMaxSizeInBytes = 1024; - network::SimpleURLLoader* loader = url_loader.get(); - loader->DownloadToString( - loader_factory, - base::BindOnce(&ChromeJsErrorReportProcessor::OnRequestComplete, this, - std::move(url_loader), std::move(callback_runner), - report_time), - kCrashEndpointResponseMaxSizeInBytes); -} - // Finishes sending process once the MayBlock processing is done. On UI thread. void ChromeJsErrorReportProcessor::OnConsentCheckCompleted( base::ScopedClosureRunner callback_runner, @@ -285,13 +141,7 @@ return; } - std::string crash_endpoint_string = error_report->send_to_production_servers - ? GetCrashEndpoint() - : GetCrashEndpointStaging(); - - // TODO(https://crbug.com/986166): Use crash_reporter for Chrome OS. const auto platform = GetPlatformInfo(); - const GURL source(error_report->url); const auto product = error_report->product.empty() ? platform.product_name : error_report->product; @@ -311,8 +161,8 @@ params["os"] = "ChromeOS"; #else params["os"] = base::SysInfo::OperatingSystemName(); + params["os_version"] = GetOsVersion(); #endif - params["os_version"] = platform.os_version; constexpr char kSourceSystemParamName[] = "source_system"; switch (error_report->source_system) { case JavaScriptErrorReport::SourceSystem::kUnknown: @@ -345,15 +195,10 @@ } if (error_report->app_locale) params["app_locale"] = std::move(*error_report->app_locale); - const GURL url(base::StrCat( - {crash_endpoint_string, "?", BuildPostRequestQueryString(params)})); - std::string body; - if (error_report->stack_trace) { - body = std::move(*error_report->stack_trace); - } - SendReport(url, body, std::move(callback_runner), report_time, - loader_factory.get()); + SendReport(std::move(params), std::move(error_report->stack_trace), + error_report->send_to_production_servers, + std::move(callback_runner), report_time, loader_factory); } void ChromeJsErrorReportProcessor::CheckAndUpdateRecentErrorReports( @@ -458,11 +303,14 @@ base::ScopedClosureRunner callback_runner(std::move(completion_callback)); + scoped_refptr<network::SharedURLLoaderFactory> loader_factory; +#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS) // loader_factory must be created on UI thread. Get it now while we still // know the browser_context pointer is valid. - scoped_refptr<network::SharedURLLoaderFactory> loader_factory = + loader_factory = content::BrowserContext::GetDefaultStoragePartition(browser_context) ->GetURLLoaderFactoryForBrowserProcess(); +#endif // Get browser uptime before swapping threads to reduce lag time between the // error report occurring and sending it off. @@ -481,18 +329,3 @@ std::move(loader_factory), browser_process_uptime, clock_->Now())); } - -std::string ChromeJsErrorReportProcessor::GetCrashEndpoint() { - return kCrashEndpointUrl; -} - -std::string ChromeJsErrorReportProcessor::GetCrashEndpointStaging() { - return kCrashEndpointStagingUrl; -} - -void ChromeJsErrorReportProcessor::GetOsVersion(int32_t& os_major_version, - int32_t& os_minor_version, - int32_t& os_bugfix_version) { - base::SysInfo::OperatingSystemVersionNumbers( - &os_major_version, &os_minor_version, &os_bugfix_version); -}
diff --git a/chrome/browser/error_reporting/chrome_js_error_report_processor.h b/chrome/browser/error_reporting/chrome_js_error_report_processor.h index 1ac534e..c702ad4a 100644 --- a/chrome/browser/error_reporting/chrome_js_error_report_processor.h +++ b/chrome/browser/error_reporting/chrome_js_error_report_processor.h
@@ -9,10 +9,12 @@ #include <memory> #include <string> +#include <vector> #include "base/callback_forward.h" #include "base/callback_helpers.h" #include "base/containers/flat_map.h" +#include "base/optional.h" #include "base/time/clock.h" #include "base/time/time.h" #include "build/chromeos_buildflags.h" @@ -49,11 +51,30 @@ return recent_error_reports_; } +#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) + // Force the error report processor to use the less-commonly-used temp file + // solution for communicating with crash_reporter. This is normally only used + // on old kernels without memfd_create, so we don't get good unit test + // coverage unless we force it. + void set_force_non_memfd_for_test() { force_non_memfd_for_test_ = true; } +#endif + protected: // Non-tests should call ChromeJsErrorReportProcessor::Create() instead. ChromeJsErrorReportProcessor(); ~ChromeJsErrorReportProcessor() override; +#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) + // Returns the first element(s) of the crash_reporter argv. By default, this + // is just the command name (so {"/sbin/crash_reporter"}). Virtual so that + // tests can override and can provide additional arguments to the test binary + // if needed. + virtual std::vector<std::string> GetCrashReporterArgvStart(); +#else + // Determines the version of the OS we are on. Virtual so that tests can + // override. On Chrome OS, this information is added by the crash_reporter. + virtual std::string GetOsVersion(); + // Testing hook -- returns the URL we will send the error reports to. By // default, returns the real endpoint. virtual std::string GetCrashEndpoint(); @@ -63,13 +84,6 @@ // default, returns the real staging endpoint. virtual std::string GetCrashEndpointStaging(); - // Determines the version of the OS we are on. Virtual so that tests can - // override. - virtual void GetOsVersion(int32_t& os_major_version, - int32_t& os_minor_version, - int32_t& os_bugfix_version); - -#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS) // Update the uploads.log file with a record of this error report. This // ensures that the error appears on chrome://crashes and is listed in the // feedback reports. @@ -79,11 +93,7 @@ private: struct PlatformInfo; - - void OnRequestComplete(std::unique_ptr<network::SimpleURLLoader> url_loader, - base::ScopedClosureRunner callback_runner, - base::Time report_time, - std::unique_ptr<std::string> response_body); + using ParameterMap = std::map<std::string, std::string>; base::Optional<JavaScriptErrorReport> CheckConsentAndRedact( JavaScriptErrorReport error_report); @@ -114,6 +124,41 @@ const JavaScriptErrorReport& error_report, bool* should_send); + void SendReport( + ParameterMap params, + base::Optional<std::string> stack_trace, + bool send_to_production_servers, + base::ScopedClosureRunner callback_runner, + base::Time report_time, + scoped_refptr<network::SharedURLLoaderFactory> loader_factory); + +#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) + // Write the parameters (and the stack_trace, if present) into a string + // suitable for passing the crash_reporter. Returns the string. + // + // Format is the same key:length:value format used by Crashpad and Breakpad + // when talking to crash_reporter. Example: + // value1:5:abcdevalue2:10:hellothere + static std::string ParamsToCrashReporterString( + const ParameterMap& params, + const base::Optional<std::string>& stack_trace); + + void SendReportViaCrashReporter(ParameterMap params, + base::Optional<std::string> stack_trace); + + bool force_non_memfd_for_test_ = false; +#else + // Turn the parameter key/value pairs into a list of parameters suitable for + // being the query part of a URL. Does URL escaping and such. + static std::string BuildPostRequestQueryString(const ParameterMap& params); + + void OnRequestComplete(std::unique_ptr<network::SimpleURLLoader> url_loader, + base::ScopedClosureRunner callback_runner, + base::Time report_time, + std::unique_ptr<std::string> response_body); + +#endif + // For JavaScript error reports, a mapping of message+product+line+column to // the last time we sent an error message for that // message+product+line+column.
diff --git a/chrome/browser/error_reporting/chrome_js_error_report_processor_chromeos.cc b/chrome/browser/error_reporting/chrome_js_error_report_processor_chromeos.cc new file mode 100644 index 0000000..f28b23f --- /dev/null +++ b/chrome/browser/error_reporting/chrome_js_error_report_processor_chromeos.cc
@@ -0,0 +1,187 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/error_reporting/chrome_js_error_report_processor.h" + +#include <errno.h> + +#include <algorithm> + +#include "base/callback_helpers.h" +#include "base/files/file.h" +#include "base/files/file_util.h" +#include "base/files/scoped_file.h" +#include "base/logging.h" +#include "base/posix/eintr_wrapper.h" +#include "base/process/launch.h" +#include "base/process/process.h" +#include "base/strings/strcat.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" +#include "base/task/task_traits.h" +#include "base/task/thread_pool.h" +#include "base/threading/thread_restrictions.h" +#include "chrome/browser/error_reporting/constants.h" + +// Per the memfd_create man page, we need _GNU_SOURCE +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include <sys/mman.h> + +namespace { + +// The format used to communicate with crash_reporter keys treats ':' as special +// (introducing the length of the value). Remove any :'s from the key names in +// place. +void ReplaceColonsWithUnderscores(std::string& key) { + std::replace(key.begin(), key.end(), ':', '_'); +} + +// Gets a File pointing to some temporary location. In some cases, we have to +// do extra cleanup; pass an *unbound* ScopedClosureRunner in |cleanup| so that +// this function can add the necessary cleanup function. +// If |force_non_memfd_for_test| is true, we act as if the memfd call failed and +// go to the temp file case. Since most machines have memfd_create implemented, +// this is the only way to get some unit-test coverage on the non-memfd_create +// path. +base::File GetMemfdOrTempFile(base::ScopedClosureRunner& cleanup, + bool force_non_memfd_for_test) { + DCHECK(!cleanup) << "cleanup must be unbound"; + if (!force_non_memfd_for_test) { + int memfd = HANDLE_EINTR(memfd_create("javascript_error", 0)); + if (memfd != -1) { + return base::File(memfd); + } + + if (errno != ENOSYS) { + PLOG(ERROR) + << "Could not create memfd file for JavaScript error reporting"; + return base::File(base::File::FILE_ERROR_FAILED); + } + } + + // Note that some VMs and boards with old kernels don't have memfd_create + // implemented yet. Work around by creating a temp file. + base::FilePath output_path; + base::ScopedFILE output_file = CreateAndOpenTemporaryStream(&output_path); + if (!output_file) { + PLOG(ERROR) + << "memfd_create not implemented and cannot create temporary stream"; + return base::File(base::File::FILE_ERROR_FAILED); + } + + DLOG(WARNING) << "JavaScript error reporting: Falling back to temp file " + << output_path.value(); + + // Need to actually delete the temp file once we're done. + cleanup.ReplaceClosure( + base::BindOnce(base::GetDeleteFileCallback(), std::move(output_path))); + return base::FILEToFile(output_file.release()); +} + +} // namespace + +std::vector<std::string> +ChromeJsErrorReportProcessor::GetCrashReporterArgvStart() { + return {"/sbin/crash_reporter"}; +} + +std::string ChromeJsErrorReportProcessor::ParamsToCrashReporterString( + const ParameterMap& params, + const base::Optional<std::string>& stack_trace) { + std::string result; + for (const auto& param : params) { + std::string key = param.first; + const std::string& value = param.second; + ReplaceColonsWithUnderscores(key); + std::string value_length_string = base::NumberToString(value.length()); + base::StrAppend(&result, {key, ":", value_length_string, ":", value}); + } + if (stack_trace) { + const std::string& payload = stack_trace.value(); + + std::string value_length_string = base::NumberToString(payload.length()); + base::StrAppend( + &result, {kJavaScriptStackKey, ":", value_length_string, ":", payload}); + } + + return result; +} + +void ChromeJsErrorReportProcessor::SendReportViaCrashReporter( + ParameterMap params, + base::Optional<std::string> stack_trace) { + base::ScopedClosureRunner cleanup; + base::File output(GetMemfdOrTempFile(cleanup, force_non_memfd_for_test_)); + if (!output.IsValid()) { + return; // Already logged error message in GetMemfdOrTempFile. + } + + std::string string_to_write = + ParamsToCrashReporterString(params, stack_trace); + if (output.WriteAtCurrentPos(string_to_write.data(), + string_to_write.length()) != + static_cast<int>(string_to_write.length())) { + PLOG(ERROR) << "Failed to write to crash_reporter pipe"; + return; + } + + base::LaunchOptions crash_reporter_options; + crash_reporter_options.fds_to_remap.emplace_back(output.GetPlatformFile(), + output.GetPlatformFile()); + + std::vector<std::string> argv(GetCrashReporterArgvStart()); + argv.insert(argv.end(), + {base::StrCat({"--chrome_memfd=", + base::NumberToString(output.GetPlatformFile())}), + base::StrCat({"--pid=", base::NumberToString(getpid())}), + base::StrCat({"--uid=", base::NumberToString(geteuid())}), + "--error_key=jserror"}); + + base::Process process = base::LaunchProcess(argv, crash_reporter_options); + if (!process.IsValid()) { + PLOG(ERROR) << "Failed to launch " << base::JoinString(argv, " "); + return; + } + + { + base::ScopedAllowBaseSyncPrimitives allow_wait_for_exit; + // Wait for crash_reporter to finish. We need to wait for it to finish + // before we delete the temporary files that may have been created in + // GetMemfdOrTempFile(). + int return_code = 0; + constexpr base::TimeDelta kMaximumWait = base::TimeDelta::FromMinutes(1); + if (process.WaitForExitWithTimeout(kMaximumWait, &return_code)) { + if (return_code != 0) { + LOG(WARNING) << "crash_reporter subprocess failed with return value " + << return_code + << (return_code == -1 ? " or maybe crashed" : ""); + } + } else { + // Kill the stuck process to avoid zombies. + LOG(WARNING) << "crash_reporter failed to complete within " + << kMaximumWait; + process.Terminate(0, false /*wait*/); + } + } +} + +void ChromeJsErrorReportProcessor::SendReport( + ParameterMap params, + base::Optional<std::string> stack_trace, + bool send_to_production_servers, + base::ScopedClosureRunner callback_runner, + base::Time report_time, + scoped_refptr<network::SharedURLLoaderFactory> loader_factory) { + // On Chrome OS, send the report through the OS crash reporting system to + // get more metadata and to keep all the consent logic in one place. We need + // to do file I/O, so over to a blockable thread for the send and then back to + // the UI thread for the finished callback. + base::ThreadPool::PostTaskAndReply( + FROM_HERE, {base::MayBlock()}, + base::BindOnce(&ChromeJsErrorReportProcessor::SendReportViaCrashReporter, + this, std::move(params), std::move(stack_trace)), + callback_runner.Release()); +}
diff --git a/chrome/browser/error_reporting/chrome_js_error_report_processor_nonchromeos.cc b/chrome/browser/error_reporting/chrome_js_error_report_processor_nonchromeos.cc new file mode 100644 index 0000000..7bfa4012 --- /dev/null +++ b/chrome/browser/error_reporting/chrome_js_error_report_processor_nonchromeos.cc
@@ -0,0 +1,181 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/error_reporting/chrome_js_error_report_processor.h" + +#include <utility> + +#include "base/callback_helpers.h" +#include "base/files/file.h" +#include "base/files/file_path.h" +#include "base/path_service.h" +#include "base/strings/strcat.h" +#include "base/strings/string_number_conversions.h" +#include "base/system/sys_info.h" +#include "base/task/task_traits.h" +#include "base/task/thread_pool.h" +#include "chrome/common/chrome_paths.h" +#include "components/upload_list/crash_upload_list.h" +#include "net/base/escape.h" +#include "services/network/public/cpp/resource_request.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" +#include "services/network/public/cpp/simple_url_loader.h" +#include "url/gurl.h" + +namespace { + +constexpr char kCrashEndpointUrl[] = "https://clients2.google.com/cr/report"; +constexpr char kCrashEndpointStagingUrl[] = + "https://clients2.google.com/cr/staging_report"; + +} // namespace + +void ChromeJsErrorReportProcessor::OnRequestComplete( + std::unique_ptr<network::SimpleURLLoader> url_loader, + base::ScopedClosureRunner callback_runner, + base::Time report_time, + std::unique_ptr<std::string> response_body) { + if (response_body) { + DVLOG(1) << "Uploaded crash report. ID: " << *response_body; + base::ThreadPool::PostTaskAndReply( + FROM_HERE, {base::MayBlock()}, + base::BindOnce(&ChromeJsErrorReportProcessor::UpdateReportDatabase, + this, std::move(*response_body), report_time), + callback_runner.Release()); + } else { + DLOG(ERROR) << "Failed to upload crash report"; + } + // callback_runner may implicitly run the callback when we reach this line if + // we didn't add a task to update the report database. +} + +std::string ChromeJsErrorReportProcessor::BuildPostRequestQueryString( + const ParameterMap& params) { + std::vector<std::string> query_parts; + for (const auto& kv : params) { + query_parts.push_back(base::StrCat( + {kv.first, "=", + net::EscapeQueryParamValue(kv.second, /*use_plus=*/false)})); + } + return base::JoinString(query_parts, "&"); +} + +void ChromeJsErrorReportProcessor::UpdateReportDatabase( + std::string remote_report_id, + base::Time report_time) { + // Uploads.log format is "seconds_since_epoch,crash_id\n" + base::FilePath crash_dir_path; + if (!base::PathService::Get(chrome::DIR_CRASH_DUMPS, &crash_dir_path)) { + DVLOG(1) << "Nowhere to write uploads.log"; + return; + } + base::FilePath upload_log_path = + crash_dir_path.AppendASCII(CrashUploadList::kReporterLogFilename); + base::File upload_log(upload_log_path, + base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_APPEND); + if (!upload_log.IsValid()) { + DVLOG(1) << "Could not open upload.log: " + << base::File::ErrorToString(upload_log.error_details()); + return; + } + std::string line = base::StrCat({base::NumberToString(report_time.ToTimeT()), + ",", remote_report_id, "\n"}); + // WriteAtCurrentPos because O_APPEND. + if (upload_log.WriteAtCurrentPos(line.c_str(), line.length()) != + static_cast<int>(line.length())) { + DVLOG(1) << "Could not write to upload.log"; + return; + } +} + +std::string ChromeJsErrorReportProcessor::GetCrashEndpoint() { + return kCrashEndpointUrl; +} + +std::string ChromeJsErrorReportProcessor::GetCrashEndpointStaging() { + return kCrashEndpointStagingUrl; +} + +// On non-Chrome OS platforms, send the report directly. +void ChromeJsErrorReportProcessor::SendReport( + ParameterMap params, + base::Optional<std::string> stack_trace, + bool send_to_production_servers, + base::ScopedClosureRunner callback_runner, + base::Time report_time, + scoped_refptr<network::SharedURLLoaderFactory> loader_factory) { + std::string crash_endpoint_string = send_to_production_servers + ? GetCrashEndpoint() + : GetCrashEndpointStaging(); + + const GURL url(base::StrCat( + {crash_endpoint_string, "?", BuildPostRequestQueryString(params)})); + auto resource_request = std::make_unique<network::ResourceRequest>(); + resource_request->method = "POST"; + resource_request->url = url; + + const auto traffic_annotation = + net::DefineNetworkTrafficAnnotation("javascript_report_error", R"( + semantics { + sender: "JavaScript error reporter" + description: + "Chrome can send JavaScript errors that occur within built-in " + "component extensions and chrome:// webpages. If enabled, the error " + "message, along with information about Chrome and the operating " + "system, is sent to Google for debugging." + trigger: + "A JavaScript error occurs in a Chrome component extension (an " + "extension bundled with the Chrome browser, not downloaded " + "separately) or in certain chrome:// webpages." + data: + "The JavaScript error message, the version and channel of Chrome, " + "the URL of the extension or webpage, the line and column number of " + "the JavaScript code where the error occurred, and a stack trace of " + "the error." + destination: GOOGLE_OWNED_SERVICE + } + policy { + cookies_allowed: NO + setting: + "You can enable or disable this feature via 'Automatically send " + "usage statistics and crash reports to Google' in Chromium's " + "settings under Advanced, Privacy. (This is in System Settings on " + "Chromebooks.) This feature is enabled by default." + chrome_policy { + MetricsReportingEnabled { + policy_options {mode: MANDATORY} + MetricsReportingEnabled: false + } + } + })"); + + DVLOG(1) << "Sending crash report: " << resource_request->url; + + auto url_loader = network::SimpleURLLoader::Create( + std::move(resource_request), traffic_annotation); + + if (stack_trace) { + url_loader->AttachStringForUpload(*stack_trace, "text/plain"); + } + + constexpr int kCrashEndpointResponseMaxSizeInBytes = 1024; + network::SimpleURLLoader* loader = url_loader.get(); + loader->DownloadToString( + loader_factory.get(), + base::BindOnce(&ChromeJsErrorReportProcessor::OnRequestComplete, this, + std::move(url_loader), std::move(callback_runner), + report_time), + kCrashEndpointResponseMaxSizeInBytes); +} + +std::string ChromeJsErrorReportProcessor::GetOsVersion() { + int32_t os_major_version = 0; + int32_t os_minor_version = 0; + int32_t os_bugfix_version = 0; + base::SysInfo::OperatingSystemVersionNumbers( + &os_major_version, &os_minor_version, &os_bugfix_version); + return base::StrCat({base::NumberToString(os_major_version), ".", + base::NumberToString(os_minor_version), ".", + base::NumberToString(os_bugfix_version)}); +}
diff --git a/chrome/browser/error_reporting/chrome_js_error_report_processor_unittest.cc b/chrome/browser/error_reporting/chrome_js_error_report_processor_unittest.cc index d05996b..245b942d 100644 --- a/chrome/browser/error_reporting/chrome_js_error_report_processor_unittest.cc +++ b/chrome/browser/error_reporting/chrome_js_error_report_processor_unittest.cc
@@ -9,6 +9,7 @@ #include "base/callback.h" #include "base/callback_helpers.h" +#include "base/run_loop.h" #include "base/strings/strcat.h" #include "base/strings/utf_string_conversions.h" #include "base/test/simple_test_clock.h" @@ -70,6 +71,10 @@ run_loop.Run(); } + // Helper for TEST_F(ChromeJsErrorReportProcessorTest, AllFields) and + // TEST_F(ChromeJsErrorReportProcessorTest, WorksWithoutMemfdCreate). + void TestAllFields(); + protected: base::SimpleTestClock test_clock_; content::BrowserTaskEnvironment task_environment_; @@ -122,10 +127,13 @@ EXPECT_THAT(actual_report->query, HasSubstr("full_url=https%3A%2F%2Fwww.chromium.org%2FHome")); EXPECT_THAT(actual_report->query, HasSubstr("url=%2FHome")); - // This is from MockChromeJsErrorReportProcessor::GetOsVersion() - EXPECT_THAT(actual_report->query, HasSubstr("os_version=7.20.1")); EXPECT_THAT(actual_report->query, HasSubstr("browser=Chrome")); EXPECT_THAT(actual_report->query, Not(HasSubstr("source_system="))); + +#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS) + // This is from MockChromeJsErrorReportProcessor::GetOsVersion() + EXPECT_THAT(actual_report->query, HasSubstr("os_version=7.20.1")); +#endif // These are from MockCrashEndpoint::Client::GetProductNameAndVersion, which // is only defined for non-MAC POSIX systems. TODO(https://crbug.com/1121816): // Get this info for non-POSIX platforms. @@ -138,7 +146,7 @@ EXPECT_EQ(actual_report->content, ""); } -TEST_F(ChromeJsErrorReportProcessorTest, AllFields) { +void ChromeJsErrorReportProcessorTest::TestAllFields() { auto report = MakeErrorReport("Hello World"); report.url = "https://www.chromium.org/Home"; report.product = "Unit test"; @@ -168,8 +176,6 @@ EXPECT_THAT(actual_report->query, HasSubstr("full_url=https%3A%2F%2Fwww.chromium.org%2FHome")); EXPECT_THAT(actual_report->query, HasSubstr("url=%2FHome")); - // This is from MockChromeJsErrorReportProcessor::GetOsVersion() - EXPECT_THAT(actual_report->query, HasSubstr("os_version=7.20.1")); EXPECT_THAT(actual_report->query, HasSubstr("browser=Chrome")); // product is double-escaped. The first time, it transforms to Unit%20test, // then the % is turned into %25. @@ -178,6 +184,11 @@ EXPECT_THAT(actual_report->query, HasSubstr("line=83")); EXPECT_THAT(actual_report->query, HasSubstr("column=14")); EXPECT_THAT(actual_report->query, HasSubstr("source_system=webui_observer")); + +#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS) + // This is from MockChromeJsErrorReportProcessor::GetOsVersion() + EXPECT_THAT(actual_report->query, HasSubstr("os_version=7.20.1")); +#endif // These are from MockCrashEndpoint::Client::GetProductNameAndVersion, which // is only defined for non-MAC POSIX systems. TODO(https://crbug.com/1121816): // Get this info for non-POSIX platforms. @@ -188,6 +199,13 @@ EXPECT_EQ(actual_report->content, "bad_func(1, 2)\nonclick()\n"); } +TEST_F(ChromeJsErrorReportProcessorTest, AllFields) { + TestAllFields(); +} + +#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS) +// On Chrome OS, consent checks are handled in the crash_reporter, not in the +// browser. TEST_F(ChromeJsErrorReportProcessorTest, NoConsent) { endpoint_->set_consented(false); auto report = MakeErrorReport("Hello World"); @@ -198,6 +216,7 @@ EXPECT_FALSE(endpoint_->last_report()); } +#endif // !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS) TEST_F(ChromeJsErrorReportProcessorTest, StackTraceWithErrorMessage) { auto report = MakeErrorReport("Hello World"); @@ -511,3 +530,10 @@ << UploadInfoVectorToString(uploads); } #endif // !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS) + +#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) +TEST_F(ChromeJsErrorReportProcessorTest, WorksWithoutMemfdCreate) { + processor_->set_force_non_memfd_for_test(); + TestAllFields(); +} +#endif // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
diff --git a/chrome/browser/error_reporting/constants.cc b/chrome/browser/error_reporting/constants.cc new file mode 100644 index 0000000..774c90b --- /dev/null +++ b/chrome/browser/error_reporting/constants.cc
@@ -0,0 +1,9 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/error_reporting/constants.h" + +#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) +const char kJavaScriptStackKey[] = "upload_file_js_stack\"; filename=\"stack\""; +#endif
diff --git a/chrome/browser/error_reporting/constants.h b/chrome/browser/error_reporting/constants.h new file mode 100644 index 0000000..2d96c57 --- /dev/null +++ b/chrome/browser/error_reporting/constants.h
@@ -0,0 +1,19 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_ERROR_REPORTING_CONSTANTS_H_ +#define CHROME_BROWSER_ERROR_REPORTING_CONSTANTS_H_ + +#include "build/chromeos_buildflags.h" + +#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) +// The key we pass to crash_reporter to indicate this key/value pair is the +// JavaScript stack payload. +// The format of the key needs to match Chrome OS's +// ChromeCollector::ParseCrashLog and kDefaultJavaScriptStackName. The +// 'filename' within the key doesn't actually matter but must be present. +extern const char kJavaScriptStackKey[]; +#endif // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) + +#endif // CHROME_BROWSER_ERROR_REPORTING_CONSTANTS_H_
diff --git a/chrome/browser/error_reporting/mock_chrome_js_error_report_processor.cc b/chrome/browser/error_reporting/mock_chrome_js_error_report_processor.cc index 5437218c..a6a40e45 100644 --- a/chrome/browser/error_reporting/mock_chrome_js_error_report_processor.cc +++ b/chrome/browser/error_reporting/mock_chrome_js_error_report_processor.cc
@@ -4,8 +4,13 @@ #include "chrome/browser/error_reporting/mock_chrome_js_error_report_processor.h" +#include "base/base_paths.h" #include "base/check.h" +#include "base/files/file_path.h" #include "base/logging.h" +#include "base/path_service.h" +#include "base/run_loop.h" +#include "base/strings/strcat.h" #include "components/crash/content/browser/error_reporting/javascript_error_report.h" #include "components/crash/content/browser/error_reporting/mock_crash_endpoint.h" @@ -44,6 +49,24 @@ crash_endpoint_staging_ = crash_endpoint; } +#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) +std::vector<std::string> +MockChromeJsErrorReportProcessor::GetCrashReporterArgvStart() { + // Redirect uploads to our a simple upload shim which will then send them to + // the MockCrashEndpoint. This simulates the Chrome OS crash_reporter and + // crash_sender in a way that allows most tests to run without changes. + base::FilePath mock_crash_reporter_path; + CHECK(base::PathService::Get(base::DIR_EXE, &mock_crash_reporter_path)); + mock_crash_reporter_path = + mock_crash_reporter_path.Append("mock_chromeos_crash_reporter"); + return {mock_crash_reporter_path.value(), + base::StrCat({"--upload_to=", crash_endpoint_})}; +} +#else +std::string MockChromeJsErrorReportProcessor::GetOsVersion() { + return "7.20.1"; +} + std::string MockChromeJsErrorReportProcessor::GetCrashEndpoint() { return crash_endpoint_; } @@ -52,16 +75,6 @@ return crash_endpoint_staging_; } -void MockChromeJsErrorReportProcessor::GetOsVersion( - int32_t& os_major_version, - int32_t& os_minor_version, - int32_t& os_bugfix_version) { - os_major_version = 7; - os_minor_version = 20; - os_bugfix_version = 1; -} - -#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS) void MockChromeJsErrorReportProcessor::UpdateReportDatabase( std::string remote_report_id, base::Time report_time) {
diff --git a/chrome/browser/error_reporting/mock_chrome_js_error_report_processor.h b/chrome/browser/error_reporting/mock_chrome_js_error_report_processor.h index 015ca699..2b8dcec 100644 --- a/chrome/browser/error_reporting/mock_chrome_js_error_report_processor.h +++ b/chrome/browser/error_reporting/mock_chrome_js_error_report_processor.h
@@ -9,8 +9,10 @@ #include <memory> #include <string> +#include <vector> #include "base/memory/scoped_refptr.h" +#include "base/synchronization/lock.h" #include "base/test/scoped_path_override.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/error_reporting/chrome_js_error_report_processor.h" @@ -53,15 +55,13 @@ #endif protected: +#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) + std::vector<std::string> GetCrashReporterArgvStart() override; +#else + // Always returns "7.20.1" (arbitrary). + std::string GetOsVersion() override; std::string GetCrashEndpoint() override; std::string GetCrashEndpointStaging() override; - - // Always returns 7.20.1 (arbitrary). - void GetOsVersion(int32_t& os_major_version, - int32_t& os_minor_version, - int32_t& os_bugfix_version) override; - -#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS) void UpdateReportDatabase(std::string remote_report_id, base::Time report_time) override; #endif
diff --git a/chrome/browser/error_reporting/mock_chromeos_crash_reporter.cc b/chrome/browser/error_reporting/mock_chromeos_crash_reporter.cc new file mode 100644 index 0000000..551e714 --- /dev/null +++ b/chrome/browser/error_reporting/mock_chromeos_crash_reporter.cc
@@ -0,0 +1,177 @@ +// Copyright 2021 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. + +// A simple binary that replicates the crash_reporter / crash_sender +// functionality of Chrome OS for testing purposes. In particular, it has a +// stripped-down version of the parsing logic in +// src/platform2/crash-reporter/chrome_collector.cc, coupled with a simple +// upload function similar to src/platform2/crash-reporter/crash_sender_util.cc +// (but without the compression). This is used in tests to substitute for the +// actual OS crash reporting system. + +#include <stdio.h> +#include <stdlib.h> + +#include <map> +#include <memory> +#include <string> + +#include "base/at_exit.h" +#include "base/bind.h" +#include "base/callback.h" +#include "base/command_line.h" +#include "base/files/file_util.h" +#include "base/files/scoped_file.h" +#include "base/logging.h" +#include "base/run_loop.h" +#include "base/strings/strcat.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" +#include "base/task/single_thread_task_executor.h" +#include "base/threading/thread_restrictions.h" +#include "chrome/browser/error_reporting/constants.h" +#include "net/base/escape.h" +#include "net/http/http_status_code.h" +#include "third_party/crashpad/crashpad/third_party/cpp-httplib/cpp-httplib/httplib.h" +#include "url/gurl.h" + +namespace { + +// Parses the key:length:value triplets similar to +// ChromeCollector::ParseCrashLog. Input is the file descriptor |fd|, +// return is a list of key/value pairs in |values| and a payload in |payload|. +// +// Closes |fd| when done. +bool ParseTriplets(int fd, + std::map<std::string, std::string>& values, + std::string& payload) { + base::ScopedFILE stream(fdopen(fd, "rb")); + if (!stream.get()) { + PLOG(ERROR) << "fdopen failed!"; + return false; + } + std::string data; + if (!base::ReadStreamToString(stream.get(), &data)) { + LOG(WARNING) << "Read failed!"; + } + + std::string::size_type pos = 0; + while (pos < data.size()) { + std::string::size_type end_of_key = data.find(':', pos); + if (end_of_key == std::string::npos) { + LOG(ERROR) << "Incomplete value found, starting at position " << pos; + return false; + } + + std::string key = data.substr(pos, end_of_key - pos); + std::string::size_type end_of_length = data.find(':', end_of_key + 1); + if (end_of_length == std::string::npos) { + LOG(ERROR) << "Incomplete length found, starting at position " + << (end_of_key + 1); + return false; + } + + std::string length_string = + data.substr(end_of_key + 1, end_of_length - (end_of_key + 1)); + size_t length; + if (!base::StringToSizeT(length_string, &length)) { + LOG(ERROR) << "Bad length string '" << length_string << "'"; + return false; + } + + std::string value = data.substr(end_of_length + 1, length); + pos = end_of_length + length + 1; + + if (key == kJavaScriptStackKey) { + payload = std::move(value); + } else { + values.emplace(std::move(key), std::move(value)); + } + } + return true; +} + +// Upload the error report to the provided URL. +bool UploadViaHttp(const std::string& base_url, + const std::map<std::string, std::string>& values, + const std::string& payload) { + std::vector<std::string> query_parts; + for (const auto& kv : values) { + query_parts.emplace_back(base::StrCat( + {net::EscapeQueryParamValue(kv.first, /*use_plus=*/false), "=", + net::EscapeQueryParamValue(kv.second, /*use_plus=*/false)})); + } + std::string upload_str = + base::StrCat({base_url, "?", base::JoinString(query_parts, "&")}); + + GURL upload_url(upload_str); + if (!upload_url.is_valid()) { + LOG(ERROR) << "Invalid upload_to URL: '" << upload_str << "'"; + return false; + } + + // Upload using httplib. The normal Chromium way (SimpleURLLoader) needs a lot + // of browser stuff to be set up before it can be used, so we use the + // standalone httplib in this test binary. + std::string host = upload_url.host(); + httplib::Client cli(host.c_str(), upload_url.EffectiveIntPort()); + if (!cli.is_valid()) { + LOG(ERROR) << "httplib::Client setup error"; + return false; + } + + std::string path = upload_url.PathForRequest(); + auto response = cli.Post(path.c_str(), payload, "text/plain"); + if (!response) { + LOG(ERROR) << "No response to Post"; + return false; + } + + if (response->status != net::HTTP_OK) { + LOG(ERROR) << "http response " << response->status; + return false; + } + return true; +} + +} // namespace + +int main(int argc, char** argv) { + base::AtExitManager exit_manager; + base::CommandLine::Init(argc, argv); + base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); + + constexpr char kFdSwitch[] = "chrome_memfd"; + if (!cmd_line->HasSwitch(kFdSwitch)) { + LOG(ERROR) << "No --chrome_memfd"; + return EXIT_FAILURE; + } + auto fd_string = cmd_line->GetSwitchValueASCII(kFdSwitch); + int fd; + if (!base::StringToInt(fd_string, &fd)) { + LOG(ERROR) << "Can't parse --chrome_memfd '" << fd_string << "' as int"; + return EXIT_FAILURE; + } + + // Note: This must be a map (not an unordered_map or such) because some unit + // tests rely on the order of the parameters in the URL string. Until that's + // fixed, keep the values sorted by key in the URL. + std::map<std::string, std::string> values; + std::string payload; + if (!ParseTriplets(fd, values, payload)) { + return EXIT_FAILURE; + } + + constexpr char kUploadSwitch[] = "upload_to"; + if (!cmd_line->HasSwitch(kUploadSwitch)) { + LOG(ERROR) << "No --upload_to"; + return EXIT_FAILURE; + } + std::string base_url = cmd_line->GetSwitchValueASCII(kUploadSwitch); + if (!UploadViaHttp(base_url, values, payload)) { + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +}
diff --git a/chrome/browser/extensions/activity_log/activity_log_unittest.cc b/chrome/browser/extensions/activity_log/activity_log_unittest.cc index fbec527..2b2336a 100644 --- a/chrome/browser/extensions/activity_log/activity_log_unittest.cc +++ b/chrome/browser/extensions/activity_log/activity_log_unittest.cc
@@ -88,6 +88,9 @@ void SetWebViewPartitionID(const std::string& partition_id) override {} void SetScriptingAllowlist( const std::vector<std::string>& extension_ids) override {} + void UpdateDefaultPolicyHostRestrictions( + const URLPatternSet& default_policy_blocked_hosts, + const URLPatternSet& default_policy_allowed_hosts) override {} mojo::AssociatedReceiverSet<mojom::Renderer> receivers_; };
diff --git a/chrome/browser/extensions/api/bookmarks/bookmark_apitest.cc b/chrome/browser/extensions/api/bookmarks/bookmark_apitest.cc index 09c46fdc..b503e71 100644 --- a/chrome/browser/extensions/api/bookmarks/bookmark_apitest.cc +++ b/chrome/browser/extensions/api/bookmarks/bookmark_apitest.cc
@@ -59,13 +59,10 @@ profile->GetPrefs()->Set(bookmarks::prefs::kManagedBookmarks, list); ASSERT_EQ(2u, managed->managed_node()->children().size()); - if (GetParam() == ContextType::kEventPage) { - ASSERT_TRUE(RunExtensionTest("bookmarks")) << message_; - } else { - ASSERT_TRUE(RunExtensionTestWithFlags( - "bookmarks", kFlagRunAsServiceWorkerBasedExtension, kFlagNone)) - << message_; - } + ASSERT_TRUE(RunExtensionTest( + {.name = "bookmarks"}, + {.load_as_service_worker = GetParam() == ContextType::kServiceWorker})) + << message_; } } // namespace extensions
diff --git a/chrome/browser/extensions/api/context_menus/context_menu_apitest.cc b/chrome/browser/extensions/api/context_menus/context_menu_apitest.cc index 43682fb..2d8f632 100644 --- a/chrome/browser/extensions/api/context_menus/context_menu_apitest.cc +++ b/chrome/browser/extensions/api/context_menus/context_menu_apitest.cc
@@ -32,9 +32,8 @@ }; IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ServiceWorkerContextMenus) { - ASSERT_TRUE(RunExtensionTestWithFlags("context_menus/event_page", - kFlagRunAsServiceWorkerBasedExtension, - kFlagNone)) + ASSERT_TRUE(RunExtensionTest({.name = "context_menus/event_page"}, + {.load_as_service_worker = true})) << message_; }
diff --git a/chrome/browser/extensions/api/crash_report_private/crash_report_private_apitest.cc b/chrome/browser/extensions/api/crash_report_private/crash_report_private_apitest.cc index 4484e8c..a3443a2 100644 --- a/chrome/browser/extensions/api/crash_report_private/crash_report_private_apitest.cc +++ b/chrome/browser/extensions/api/crash_report_private/crash_report_private_apitest.cc
@@ -119,7 +119,7 @@ "\\d+&browser_" "version=1.2.3.4&channel=Stable&" "error_message=hi&full_url=http%3A%2F%2Fwww.test.com%2F&" - "os=ChromeOS&os_version=7.20.1" + "os=ChromeOS" "&prod=Chrome_ChromeOS&renderer_process_uptime_ms=\\d+&" "source_system=crash_report_api&src=" "http%3A%2F%2Fwww.test." @@ -152,7 +152,7 @@ "\\d+&browser_" "version=1.2.3.4&channel=Stable&column=456&" "error_message=hi&full_url=http%3A%2F%2Fwww.test.com%2Ffoo" - "&line=123&os=ChromeOS&os_version=7.20.1" + "&line=123&os=ChromeOS" "&prod=Chrome%2520\\(Chrome%2520OS\\)&renderer_process_" "uptime_ms=\\d+&" "source_system=crash_report_api&" @@ -184,7 +184,7 @@ "\\d+&browser_version=1.2." "3.4&channel=Stable&column=456&" "error_message=hi&full_url=http%3A%2F%2Fwww.test.com%2Ffoo&" - "line=123&os=ChromeOS&os_version=7.20.1" + "line=123&os=ChromeOS" "&prod=TestApp&renderer_process_uptime_ms=\\d+&" "source_system=crash_report_api&src=http%3A%" "2F%2Fwww.test.com%2Ffoo&type=" @@ -218,8 +218,7 @@ "3.4&channel=Stable&column=456&" "error_message=%5BMAC%20OUI%3D06%3A00%3A00%20IFACE%3D1%5D&" "full_url=http%3A%2F%2Fwww.test.com%2Ffoo&line=123&os=ChromeOS&" - "os_version=7.20.1" - "&prod=TestApp&renderer_process_uptime_ms=\\d+&" + "prod=TestApp&renderer_process_uptime_ms=\\d+&" "source_system=crash_report_api&src=http%3A%2F%2Fwww." "test.com%2Ffoo&type=" "JavascriptError&url=%2Ffoo&ver=1.0.0.0")); @@ -259,27 +258,6 @@ ASSERT_FALSE(report); } -// Ensures that reportError checks user consent for data collection on the -// correct thread and correctly handles the case where consent is not given. -IN_PROC_BROWSER_TEST_F(CrashReportPrivateApiTest, NoConsent) { - constexpr char kTestScript[] = R"( - chrome.crashReportPrivate.reportError({ - message: "hi", - url: "http://www.test.com", - }, - () => { - window.domAutomationController.send(chrome.runtime.lastError ? - chrome.runtime.lastError.message : "") - }); - )"; - - crash_endpoint_->set_consented(false); - EXPECT_EQ("", ExecuteScriptInBackgroundPage(extension_->id(), kTestScript)); - // The server should not receive any reports. - const base::Optional<MockCrashEndpoint::Report>& report = last_report(); - EXPECT_FALSE(report); -} - // Test REGULAR_TABBED is detected when |CrashReportPrivate| is called from a // tab's |web_contents|. IN_PROC_BROWSER_TEST_F(CrashReportPrivateApiTest, CalledFromWebContentsInTab) { @@ -310,7 +288,7 @@ "\\d+&browser_" "version=1.2.3.4&channel=Stable&" "error_message=hi&full_url=http%3A%2F%2Fwww.test.com%2F&" - "os=ChromeOS&os_version=7.20.1" + "os=ChromeOS" "&prod=Chrome_ChromeOS&renderer_process_uptime_ms=\\d+&" "source_system=crash_report_api&src=" "http%3A%2F%2Fwww.test." @@ -361,7 +339,7 @@ "\\d+&browser_" "version=1.2.3.4&channel=Stable&" "error_message=hi&full_url=http%3A%2F%2Fwww.test.com%2F&" - "os=ChromeOS&os_version=7.20.1" + "os=ChromeOS" "&prod=Chrome_ChromeOS&renderer_process_uptime_ms=\\d+&" "source_system=crash_report_api&src=" "http%3A%2F%2Fwww.test." @@ -396,7 +374,7 @@ "\\d+&browser_" "version=1.2.3.4&channel=Stable&" "error_message=hi&full_url=http%3A%2F%2Fwww.test.com%2F&" - "os=ChromeOS&os_version=7.20.1" + "os=ChromeOS" "&prod=Chrome_ChromeOS&renderer_process_uptime_ms=\\d+&" "source_system=crash_report_api&src=" "http%3A%2F%2Fwww.test."
diff --git a/chrome/browser/extensions/api/declarative_content/content_action.cc b/chrome/browser/extensions/api/declarative_content/content_action.cc index a6c583b1..443ddce5 100644 --- a/chrome/browser/extensions/api/declarative_content/content_action.cc +++ b/chrome/browser/extensions/api/declarative_content/content_action.cc
@@ -20,10 +20,10 @@ #include "content/public/browser/invalidate_type.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" -#include "extensions/browser/declarative_user_script_manager.h" #include "extensions/browser/extension_action.h" #include "extensions/browser/extension_action_manager.h" #include "extensions/browser/extension_system.h" +#include "extensions/browser/user_script_manager.h" #include "extensions/common/api/declarative/declarative_constants.h" #include "extensions/common/extension.h" #include "extensions/common/extension_messages.h" @@ -321,7 +321,8 @@ HostID host_id(HostID::EXTENSIONS, extension->id()); InitScript(host_id, extension, script_data); - script_set_ = DeclarativeUserScriptManager::Get(browser_context) + script_set_ = ExtensionSystem::Get(browser_context) + ->user_script_manager() ->GetDeclarativeUserScriptSetByID(host_id); AddScript(); }
diff --git a/chrome/browser/extensions/api/declarative_content/content_action_unittest.cc b/chrome/browser/extensions/api/declarative_content/content_action_unittest.cc index a45f0f1a..22ea2b4 100644 --- a/chrome/browser/extensions/api/declarative_content/content_action_unittest.cc +++ b/chrome/browser/extensions/api/declarative_content/content_action_unittest.cc
@@ -20,6 +20,7 @@ #include "extensions/browser/extension_action.h" #include "extensions/browser/extension_action_manager.h" #include "extensions/browser/extension_system.h" +#include "extensions/browser/user_script_manager.h" #include "extensions/common/api/declarative/declarative_constants.h" #include "extensions/common/extension.h" #include "extensions/common/extension_builder.h" @@ -57,8 +58,10 @@ // issue is fixed. virtual void Init() { InitializeEmptyExtensionService(); - static_cast<TestExtensionSystem*>(ExtensionSystem::Get(profile()))-> - SetReady(); + auto* extension_system = + static_cast<TestExtensionSystem*>(ExtensionSystem::Get(profile())); + extension_system->CreateUserScriptManager(); + extension_system->SetReady(); base::RunLoop().RunUntilIdle(); }
diff --git a/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_apitest.cc b/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_apitest.cc index 2b8067b8..4bec694 100644 --- a/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_apitest.cc +++ b/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_apitest.cc
@@ -50,11 +50,9 @@ } bool RunTest(const std::string& extension_path) { - if (GetParam() != ContextType::kServiceWorker) { - return RunExtensionTest(extension_path); - } - return RunExtensionTestWithFlags( - extension_path, kFlagRunAsServiceWorkerBasedExtension, kFlagNone); + return RunExtensionTest( + {.name = extension_path.c_str()}, + {.load_as_service_worker = GetParam() == ContextType::kServiceWorker}); } private:
diff --git a/chrome/browser/extensions/api/enterprise_reporting_private/context_info_fetcher.cc b/chrome/browser/extensions/api/enterprise_reporting_private/context_info_fetcher.cc index 2b75de2..1c12f6f 100644 --- a/chrome/browser/extensions/api/enterprise_reporting_private/context_info_fetcher.cc +++ b/chrome/browser/extensions/api/enterprise_reporting_private/context_info_fetcher.cc
@@ -6,12 +6,20 @@ #include <memory> +#include "base/callback_forward.h" +#include "base/threading/thread_task_runner_handle.h" +#include "chrome/browser/enterprise/util/affiliation.h" +#include "chrome/browser/profiles/profile.h" +#include "device_management_backend.pb.h" + namespace extensions { namespace enterprise_reporting { ContextInfoFetcher::ContextInfoFetcher( + content::BrowserContext* browser_context, enterprise_connectors::ConnectorsService* connectors_service) - : connectors_service_(connectors_service) { + : browser_context_(browser_context), + connectors_service_(connectors_service) { DCHECK(connectors_service_); } @@ -19,13 +27,15 @@ // static std::unique_ptr<ContextInfoFetcher> ContextInfoFetcher::CreateInstance( + content::BrowserContext* browser_context, enterprise_connectors::ConnectorsService* connectors_service) { // TODO(domfc): Add platform overrides of the class once they are needed for // an attribute. - return std::make_unique<ContextInfoFetcher>(connectors_service); + return std::make_unique<ContextInfoFetcher>(browser_context, + connectors_service); } -api::enterprise_reporting_private::ContextInfo ContextInfoFetcher::Fetch() { +void ContextInfoFetcher::Fetch(ContextInfoCallback callback) { api::enterprise_reporting_private::ContextInfo info; info.browser_affiliation_ids = GetBrowserAffiliationIDs(); @@ -40,17 +50,37 @@ info.on_security_event_providers = GetOnSecurityEventProviders(); info.browser_version = GetBrowserVersion(); - return info; + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), std::move(info))); } std::vector<std::string> ContextInfoFetcher::GetBrowserAffiliationIDs() { - // TODO(crbug.com/1169200): Add code to get the affiliation IDs. - return {}; + const enterprise_management::PolicyData* browser_policy_data = + chrome::enterprise_util::GetBrowserPolicyData(); + + if (!browser_policy_data || + browser_policy_data->device_affiliation_ids().empty()) { + return {}; + } + + const auto& affiliation_ids = browser_policy_data->device_affiliation_ids(); + return std::vector<std::string>(affiliation_ids.begin(), + affiliation_ids.end()); } std::vector<std::string> ContextInfoFetcher::GetProfileAffiliationIDs() { - // TODO(crbug.com/1169212): Add code to get the affiliation IDs. - return {}; + const enterprise_management::PolicyData* profile_policy_data = + chrome::enterprise_util::GetProfilePolicyData( + Profile::FromBrowserContext(browser_context_)); + + if (!profile_policy_data || + profile_policy_data->user_affiliation_ids().empty()) { + return {}; + } + + const auto& affiliation_ids = profile_policy_data->user_affiliation_ids(); + return std::vector<std::string>(affiliation_ids.begin(), + affiliation_ids.end()); } std::vector<std::string> ContextInfoFetcher::GetAnalysisConnectorProviders(
diff --git a/chrome/browser/extensions/api/enterprise_reporting_private/context_info_fetcher.h b/chrome/browser/extensions/api/enterprise_reporting_private/context_info_fetcher.h index 6ac67d64..d68a8f8 100644 --- a/chrome/browser/extensions/api/enterprise_reporting_private/context_info_fetcher.h +++ b/chrome/browser/extensions/api/enterprise_reporting_private/context_info_fetcher.h
@@ -5,9 +5,14 @@ #ifndef CHROME_BROWSER_EXTENSIONS_API_ENTERPRISE_REPORTING_PRIVATE_CONTEXT_INFO_FETCHER_H_ #define CHROME_BROWSER_EXTENSIONS_API_ENTERPRISE_REPORTING_PRIVATE_CONTEXT_INFO_FETCHER_H_ +#include "base/callback_forward.h" #include "chrome/browser/enterprise/connectors/connectors_service.h" #include "chrome/common/extensions/api/enterprise_reporting_private.h" +namespace content { +class BrowserContext; +} // namespace content + namespace extensions { namespace enterprise_reporting { @@ -16,7 +21,10 @@ // has its own subclass implementation. class ContextInfoFetcher { public: - explicit ContextInfoFetcher( + using ContextInfoCallback = + base::OnceCallback<void(api::enterprise_reporting_private::ContextInfo)>; + ContextInfoFetcher( + content::BrowserContext* browser_context, enterprise_connectors::ConnectorsService* connectors_service); virtual ~ContextInfoFetcher(); @@ -25,10 +33,14 @@ // Returns a platform specific instance of ContextInfoFetcher. static std::unique_ptr<ContextInfoFetcher> CreateInstance( + content::BrowserContext* browser_context, enterprise_connectors::ConnectorsService* connectors_service); - // Fetches the device information for the current platform. - api::enterprise_reporting_private::ContextInfo Fetch(); + // Fetches the context information for the current platform. Eventually calls + // |callback_|. This function takes a callback to return a ContextInfo instead + // of returning synchronously because some attributes need to be fetched + // asynchronously. + void Fetch(ContextInfoCallback callback); private: // The following private methods each populate an attribute of ContextInfo. If @@ -49,6 +61,8 @@ std::string GetBrowserVersion(); + content::BrowserContext* browser_context_; + // |connectors_service| is used to obtain the value of each Connector policy. enterprise_connectors::ConnectorsService* connectors_service_; };
diff --git a/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_api.cc b/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_api.cc index 361587e..3ee39eb 100644 --- a/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_api.cc +++ b/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_api.cc
@@ -282,25 +282,13 @@ enterprise_connectors::ConnectorsServiceFactory::GetInstance() ->GetForBrowserContext(browser_context()); DCHECK(connectors_service); -#if defined(OS_WIN) - base::PostTaskAndReplyWithResult( - base::ThreadPool::CreateCOMSTATaskRunner({}).get(), FROM_HERE, - base::BindOnce(&enterprise_reporting::ContextInfoFetcher::Fetch, - enterprise_reporting::ContextInfoFetcher::CreateInstance( - connectors_service)), - base::BindOnce(&EnterpriseReportingPrivateGetContextInfoFunction:: - OnContextInfoRetrieved, - this)); -#else - base::PostTaskAndReplyWithResult( - base::ThreadPool::CreateTaskRunner({}).get(), FROM_HERE, - base::BindOnce(&enterprise_reporting::ContextInfoFetcher::Fetch, - enterprise_reporting::ContextInfoFetcher::CreateInstance( - connectors_service)), - base::BindOnce(&EnterpriseReportingPrivateGetContextInfoFunction:: - OnContextInfoRetrieved, - this)); -#endif // defined(OS_WIN) + + context_info_fetcher_ = + enterprise_reporting::ContextInfoFetcher::CreateInstance( + browser_context(), connectors_service); + context_info_fetcher_->Fetch(base::BindOnce( + &EnterpriseReportingPrivateGetContextInfoFunction::OnContextInfoRetrieved, + this)); return RespondLater(); }
diff --git a/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_api.h b/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_api.h index 1486fba..85845486 100644 --- a/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_api.h +++ b/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_api.h
@@ -10,6 +10,7 @@ #include "chrome/browser/enterprise/signals/device_info_fetcher.h" #include "chrome/browser/extensions/api/enterprise_reporting_private/chrome_desktop_report_request_helper.h" +#include "chrome/browser/extensions/api/enterprise_reporting_private/context_info_fetcher.h" #include "chrome/common/extensions/api/enterprise_reporting_private.h" #include "extensions/browser/extension_function.h" @@ -157,6 +158,9 @@ // Callback once the context data is retrieved. void OnContextInfoRetrieved( api::enterprise_reporting_private::ContextInfo context_info); + + std::unique_ptr<enterprise_reporting::ContextInfoFetcher> + context_info_fetcher_; }; } // namespace extensions
diff --git a/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_browsertest.cc b/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_browsertest.cc new file mode 100644 index 0000000..27a9b7d --- /dev/null +++ b/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_browsertest.cc
@@ -0,0 +1,144 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#include "chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_api.h" + +#include "chrome/browser/browser_process.h" +#include "chrome/browser/extensions/extension_function_test_utils.h" +#include "chrome/browser/policy/chrome_browser_policy_connector.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_test_utils.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/common/extensions/api/enterprise_reporting_private.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "components/enterprise/browser/controller/fake_browser_dm_token_storage.h" +#include "components/enterprise/browser/enterprise_switches.h" +#include "components/policy/core/common/cloud/machine_level_user_cloud_policy_manager.h" +#include "components/policy/core/common/cloud/user_cloud_policy_manager.h" +#include "content/public/test/browser_test.h" + +namespace enterprise_reporting_private = + ::extensions::api::enterprise_reporting_private; + +namespace extensions { + +namespace { + +constexpr char kBrowserID1[] = "browser_id_1"; +constexpr char kBrowserID2[] = "browser_id_2"; +constexpr char kProfileID1[] = "profile_id_1"; +constexpr char kProfileID2[] = "profile_id_2"; + +} // namespace + +// This browser test class is used to avoid mocking too much browser/profile +// management objects in order to keep the test simple and useful. Please add +// new tests for the getContextInfo API in enterprise_reporting_private_unittest +// and only add tests in this file if they have similar constraints. +class EnterpriseReportingPrivateGetContextInfoBrowserTest + : public InProcessBrowserTest, + public testing::WithParamInterface<testing::tuple<bool, bool>> { + public: + EnterpriseReportingPrivateGetContextInfoBrowserTest() { + if (browser_managed()) { + browser_dm_token_storage_ = + std::make_unique<policy::FakeBrowserDMTokenStorage>(); + browser_dm_token_storage_->SetEnrollmentToken("enrollment_token"); + browser_dm_token_storage_->SetClientId("id"); + browser_dm_token_storage_->SetDMToken("dm_token"); + policy::BrowserDMTokenStorage::SetForTesting( + browser_dm_token_storage_.get()); + } + } + + bool browser_managed() const { return testing::get<0>(GetParam()); } + + bool profile_managed() const { return testing::get<1>(GetParam()); } + + void SetUpOnMainThread() override { + InProcessBrowserTest::SetUpOnMainThread(); + + if (browser_managed()) { + auto* browser_policy_manager = + g_browser_process->browser_policy_connector() + ->machine_level_user_cloud_policy_manager(); + auto browser_policy_data = + std::make_unique<enterprise_management::PolicyData>(); + browser_policy_data->add_device_affiliation_ids(kBrowserID1); + browser_policy_data->add_device_affiliation_ids(kBrowserID2); + browser_policy_manager->core()->store()->set_policy_data_for_testing( + std::move(browser_policy_data)); + } + + if (profile_managed()) { + safe_browsing::SetProfileDMToken(browser()->profile(), "dm_token"); + auto* profile_policy_manager = + browser()->profile()->GetUserCloudPolicyManager(); + auto profile_policy_data = + std::make_unique<enterprise_management::PolicyData>(); + profile_policy_data->add_user_affiliation_ids(kProfileID1); + profile_policy_data->add_user_affiliation_ids(kProfileID2); + profile_policy_manager->core()->store()->set_policy_data_for_testing( + std::move(profile_policy_data)); + } + } + +#if !BUILDFLAG(GOOGLE_CHROME_BRANDING) && !BUILDFLAG(IS_CHROMEOS_ASH) + void SetUpDefaultCommandLine(base::CommandLine* command_line) override { + InProcessBrowserTest::SetUpDefaultCommandLine(command_line); + command_line->AppendSwitch(::switches::kEnableChromeBrowserCloudManagement); + } +#endif + + private: + std::unique_ptr<policy::FakeBrowserDMTokenStorage> browser_dm_token_storage_; +}; + +INSTANTIATE_TEST_SUITE_P(, + EnterpriseReportingPrivateGetContextInfoBrowserTest, + testing::Combine(testing::Bool(), testing::Bool())); + +IN_PROC_BROWSER_TEST_P(EnterpriseReportingPrivateGetContextInfoBrowserTest, + AffiliationIDs) { + auto function = + base::MakeRefCounted<EnterpriseReportingPrivateGetContextInfoFunction>(); + auto context_info_value = std::unique_ptr<base::Value>( + extension_function_test_utils::RunFunctionAndReturnSingleResult( + function.get(), + /*args*/ "[]", browser())); + ASSERT_TRUE(context_info_value.get()); + + enterprise_reporting_private::ContextInfo info; + ASSERT_TRUE(enterprise_reporting_private::ContextInfo::Populate( + *context_info_value, &info)); + + if (profile_managed()) { + EXPECT_EQ(2u, info.profile_affiliation_ids.size()); + EXPECT_EQ(kProfileID1, info.profile_affiliation_ids[0]); + EXPECT_EQ(kProfileID2, info.profile_affiliation_ids[1]); + } else { + EXPECT_TRUE(info.profile_affiliation_ids.empty()); + } + + if (browser_managed()) { + EXPECT_EQ(2u, info.browser_affiliation_ids.size()); + EXPECT_EQ(kBrowserID1, info.browser_affiliation_ids[0]); + EXPECT_EQ(kBrowserID2, info.browser_affiliation_ids[1]); + } else { + EXPECT_TRUE(info.browser_affiliation_ids.empty()); + } + + EXPECT_TRUE(info.on_file_attached_providers.empty()); + EXPECT_TRUE(info.on_file_downloaded_providers.empty()); + EXPECT_TRUE(info.on_bulk_data_entry_providers.empty()); + EXPECT_EQ(enterprise_reporting_private::REALTIME_URL_CHECK_MODE_DISABLED, + info.realtime_url_check_mode); + EXPECT_TRUE(info.on_security_event_providers.empty()); + + // TODO(crbug.com/1169222): Change this assertion once this attribute is + // implemented, as it should be returned even when no special context applies + // to the browser. + EXPECT_EQ("", info.browser_version); +} + +} // namespace extensions
diff --git a/chrome/browser/extensions/api/gcm/gcm_apitest.cc b/chrome/browser/extensions/api/gcm/gcm_apitest.cc index 4aed8ec..8985adc 100644 --- a/chrome/browser/extensions/api/gcm/gcm_apitest.cc +++ b/chrome/browser/extensions/api/gcm/gcm_apitest.cc
@@ -266,7 +266,8 @@ ResultCatcher incognito_catcher; incognito_catcher.RestrictToBrowserContext(profile()->GetPrimaryOTRProfile()); - ASSERT_TRUE(RunExtensionTestIncognito("gcm/functions/incognito")); + ASSERT_TRUE(RunExtensionTest({.name = "gcm/functions/incognito"}, + {.allow_in_incognito = true})); EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); EXPECT_TRUE(incognito_catcher.GetNextResult()) << incognito_catcher.message();
diff --git a/chrome/browser/extensions/api/instance_id/instance_id_apitest.cc b/chrome/browser/extensions/api/instance_id/instance_id_apitest.cc index 0b9d2807..39a7ebf 100644 --- a/chrome/browser/extensions/api/instance_id/instance_id_apitest.cc +++ b/chrome/browser/extensions/api/instance_id/instance_id_apitest.cc
@@ -66,7 +66,8 @@ ResultCatcher incognito_catcher; incognito_catcher.RestrictToBrowserContext(profile()->GetPrimaryOTRProfile()); - ASSERT_TRUE(RunExtensionTestIncognito("instance_id/incognito")); + ASSERT_TRUE(RunExtensionTest({.name = "instance_id/incognito"}, + {.allow_in_incognito = true})); EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); EXPECT_TRUE(incognito_catcher.GetNextResult()) << incognito_catcher.message();
diff --git a/chrome/browser/extensions/api/messaging/native_messaging_apitest.cc b/chrome/browser/extensions/api/messaging/native_messaging_apitest.cc index 6244a7cc..c3fdd23 100644 --- a/chrome/browser/extensions/api/messaging/native_messaging_apitest.cc +++ b/chrome/browser/extensions/api/messaging/native_messaging_apitest.cc
@@ -53,11 +53,9 @@ public testing::WithParamInterface<ContextType> { protected: bool RunLazyTest(const std::string& extension_name) { - if (GetParam() == ContextType::kEventPage) { - return RunExtensionTest(extension_name); - } - return RunExtensionTestWithFlags( - extension_name, kFlagRunAsServiceWorkerBasedExtension, kFlagNone); + return RunExtensionTest( + {.name = extension_name.c_str()}, + {.load_as_service_worker = GetParam() == ContextType::kServiceWorker}); } };
diff --git a/chrome/browser/extensions/api/module/module_apitest.cc b/chrome/browser/extensions/api/module/module_apitest.cc index 6d1831d..7b3af50 100644 --- a/chrome/browser/extensions/api/module/module_apitest.cc +++ b/chrome/browser/extensions/api/module/module_apitest.cc
@@ -8,13 +8,15 @@ using ExtensionModuleApiTest = extensions::ExtensionApiTest; IN_PROC_BROWSER_TEST_F(ExtensionModuleApiTest, CognitoFile) { - ASSERT_TRUE(RunExtensionTestWithFileAccess("extension_module/cognito_file")) + ASSERT_TRUE(RunExtensionTest({.name = "extension_module/cognito_file"}, + {.allow_file_access = true})) << message_; } IN_PROC_BROWSER_TEST_F(ExtensionModuleApiTest, IncognitoFile) { - ASSERT_TRUE(RunExtensionTestIncognitoWithFileAccess( - "extension_module/incognito_file")) + ASSERT_TRUE( + RunExtensionTest({.name = "extension_module/incognito_file"}, + {.allow_in_incognito = true, .allow_file_access = true})) << message_; } @@ -23,6 +25,7 @@ } IN_PROC_BROWSER_TEST_F(ExtensionModuleApiTest, IncognitoNoFile) { - ASSERT_TRUE(RunExtensionTestIncognito("extension_module/incognito_nofile")) + ASSERT_TRUE(RunExtensionTest({.name = "extension_module/incognito_nofile"}, + {.allow_in_incognito = true})) << message_; }
diff --git a/chrome/browser/extensions/api/omnibox/omnibox_api_interactive_test.cc b/chrome/browser/extensions/api/omnibox/omnibox_api_interactive_test.cc index 270e7a77..050730d 100644 --- a/chrome/browser/extensions/api/omnibox/omnibox_api_interactive_test.cc +++ b/chrome/browser/extensions/api/omnibox/omnibox_api_interactive_test.cc
@@ -261,7 +261,9 @@ ResultCatcher catcher_incognito; catcher_incognito.RestrictToBrowserContext(profile->GetPrimaryOTRProfile()); - ASSERT_TRUE(RunExtensionTestIncognito("omnibox")) << message_; + ASSERT_TRUE( + RunExtensionTest({.name = "omnibox"}, {.allow_in_incognito = true})) + << message_; // Open an incognito window and wait for the incognito extension process to // respond.
diff --git a/chrome/browser/extensions/api/permissions/permissions_apitest.cc b/chrome/browser/extensions/api/permissions/permissions_apitest.cc index c8194d2..d08dadf 100644 --- a/chrome/browser/extensions/api/permissions/permissions_apitest.cc +++ b/chrome/browser/extensions/api/permissions/permissions_apitest.cc
@@ -206,7 +206,8 @@ EXPECT_TRUE(RunExtensionTest("permissions/file_access_no")) << message_; EXPECT_FALSE(prefs->AllowFileAccess(last_loaded_extension_id())); - EXPECT_TRUE(RunExtensionTestWithFileAccess("permissions/file_access_yes")) + EXPECT_TRUE(RunExtensionTest({.name = "permissions/file_access_yes"}, + {.allow_file_access = true})) << message_; EXPECT_TRUE(prefs->AllowFileAccess(last_loaded_extension_id())); }
diff --git a/chrome/browser/extensions/api/preference/preference_apitest.cc b/chrome/browser/extensions/api/preference/preference_apitest.cc index 009b85e..66a90dc 100644 --- a/chrome/browser/extensions/api/preference/preference_apitest.cc +++ b/chrome/browser/extensions/api/preference/preference_apitest.cc
@@ -193,9 +193,9 @@ PrefService* prefs = profile_->GetPrefs(); SetCookieControlsMode(prefs, CookieControlsMode::kOff); - EXPECT_TRUE( - RunExtensionTestIncognito("preference/persistent_incognito")) << - message_; + EXPECT_TRUE(RunExtensionTest({.name = "preference/persistent_incognito"}, + {.allow_in_incognito = true})) + << message_; // Setting an incognito preference should not create an incognito profile. EXPECT_FALSE(profile_->HasPrimaryOTRProfile()); @@ -221,9 +221,9 @@ PrefService* prefs = profile_->GetPrefs(); SetCookieControlsMode(prefs, CookieControlsMode::kOff); - EXPECT_TRUE( - RunExtensionTestIncognito("preference/session_only_incognito")) << - message_; + EXPECT_TRUE(RunExtensionTest({.name = "preference/session_only_incognito"}, + {.allow_in_incognito = true})) + << message_; EXPECT_TRUE(profile_->HasPrimaryOTRProfile()); @@ -253,8 +253,9 @@ } IN_PROC_BROWSER_TEST_F(ExtensionPreferenceApiTest, OnChange) { - EXPECT_TRUE(RunExtensionTestIncognito("preference/onchange")) << - message_; + EXPECT_TRUE(RunExtensionTest({.name = "preference/onchange"}, + {.allow_in_incognito = true})) + << message_; } IN_PROC_BROWSER_TEST_F(ExtensionPreferenceApiTest, OnChangeSplit) {
diff --git a/chrome/browser/extensions/api/proxy/proxy_apitest.cc b/chrome/browser/extensions/api/proxy/proxy_apitest.cc index d34b516..c227b40 100644 --- a/chrome/browser/extensions/api/proxy/proxy_apitest.cc +++ b/chrome/browser/extensions/api/proxy/proxy_apitest.cc
@@ -101,7 +101,9 @@ // Tests direct connection settings. IN_PROC_BROWSER_TEST_F(ProxySettingsApiTest, ProxyDirectSettings) { - ASSERT_TRUE(RunExtensionTestIncognito("proxy/direct")) << message_; + ASSERT_TRUE( + RunExtensionTest({.name = "proxy/direct"}, {.allow_in_incognito = true})) + << message_; const Extension* extension = GetSingleLoadedExtension(); ASSERT_TRUE(extension); @@ -119,7 +121,9 @@ // Tests that proxy settings are changed appropriately when the extension is // disabled or enabled. IN_PROC_BROWSER_TEST_F(ProxySettingsApiTest, SettingsChangeOnDisableEnable) { - ASSERT_TRUE(RunExtensionTestIncognito("proxy/direct")) << message_; + ASSERT_TRUE( + RunExtensionTest({.name = "proxy/direct"}, {.allow_in_incognito = true})) + << message_; const Extension* extension = GetSingleLoadedExtension(); ASSERT_TRUE(extension); @@ -138,7 +142,9 @@ // Tests that proxy settings corresponding to an extension are removed when // the extension is uninstalled. IN_PROC_BROWSER_TEST_F(ProxySettingsApiTest, SettingsRemovedOnUninstall) { - ASSERT_TRUE(RunExtensionTestIncognito("proxy/direct")) << message_; + ASSERT_TRUE( + RunExtensionTest({.name = "proxy/direct"}, {.allow_in_incognito = true})) + << message_; const Extension* extension = GetSingleLoadedExtension(); ASSERT_TRUE(extension); @@ -155,7 +161,9 @@ // crbug.com/709264. IN_PROC_BROWSER_TEST_F(ProxySettingsApiTest, PRE_SettingsRemovedOnPolicyBlocklist) { - ASSERT_TRUE(RunExtensionTestIncognito("proxy/direct")) << message_; + ASSERT_TRUE( + RunExtensionTest({.name = "proxy/direct"}, {.allow_in_incognito = true})) + << message_; const Extension* extension = GetSingleLoadedExtension(); ASSERT_TRUE(extension); @@ -194,7 +202,9 @@ // Tests auto-detect settings. IN_PROC_BROWSER_TEST_F(ProxySettingsApiTest, ProxyAutoSettings) { - ASSERT_TRUE(RunExtensionTestIncognito("proxy/auto")) << message_; + ASSERT_TRUE( + RunExtensionTest({.name = "proxy/auto"}, {.allow_in_incognito = true})) + << message_; const Extension* extension = GetSingleLoadedExtension(); ASSERT_TRUE(extension); @@ -285,7 +295,9 @@ // Tests setting separate proxies for each scheme. IN_PROC_BROWSER_TEST_F(ProxySettingsApiTest, ProxyFixedIndividual) { - ASSERT_TRUE(RunExtensionTestIncognito("proxy/individual")) << message_; + ASSERT_TRUE(RunExtensionTest({.name = "proxy/individual"}, + {.allow_in_incognito = true})) + << message_; const Extension* extension = GetSingleLoadedExtension(); ASSERT_TRUE(extension); @@ -314,8 +326,9 @@ // Tests setting values only for incognito mode IN_PROC_BROWSER_TEST_F(ProxySettingsApiTest, ProxyFixedIndividualIncognitoOnly) { - ASSERT_TRUE(RunExtensionTestIncognito("proxy/individual_incognito_only")) << - message_; + ASSERT_TRUE(RunExtensionTest({.name = "proxy/individual_incognito_only"}, + {.allow_in_incognito = true})) + << message_; const Extension* extension = GetSingleLoadedExtension(); ASSERT_TRUE(extension); @@ -337,8 +350,9 @@ // Tests setting values also for incognito mode IN_PROC_BROWSER_TEST_F(ProxySettingsApiTest, ProxyFixedIndividualIncognitoAlso) { - ASSERT_TRUE(RunExtensionTestIncognito("proxy/individual_incognito_also")) << - message_; + ASSERT_TRUE(RunExtensionTest({.name = "proxy/individual_incognito_also"}, + {.allow_in_incognito = true})) + << message_; const Extension* extension = GetSingleLoadedExtension(); ASSERT_TRUE(extension); @@ -376,7 +390,9 @@ IN_PROC_BROWSER_TEST_F(ProxySettingsApiTest, ProxyBypass) { - ASSERT_TRUE(RunExtensionTestIncognito("proxy/bypass")) << message_; + ASSERT_TRUE( + RunExtensionTest({.name = "proxy/bypass"}, {.allow_in_incognito = true})) + << message_; const Extension* extension = GetSingleLoadedExtension(); ASSERT_TRUE(extension);
diff --git a/chrome/browser/extensions/api/scripting/scripting_api.cc b/chrome/browser/extensions/api/scripting/scripting_api.cc index 335d17a..5ad3ca90 100644 --- a/chrome/browser/extensions/api/scripting/scripting_api.cc +++ b/chrome/browser/extensions/api/scripting/scripting_api.cc
@@ -26,6 +26,53 @@ namespace { constexpr char kCouldNotLoadFileError[] = "Could not load file: '*'."; +constexpr char kExactlyOneOfCssAndFilesError[] = + "Exactly one of 'css' and 'files' must be specified."; + +// Note: CSS always injects as soon as possible, so we default to +// document_start. Because of tab loading, there's no guarantee this will +// *actually* inject before page load, but it will at least inject "soon". +constexpr UserScript::RunLocation kCSSRunLocation = UserScript::DOCUMENT_START; + +// Converts the given `style_origin` to a CSSOrigin. +CSSOrigin ConvertStyleOriginToCSSOrigin( + api::scripting::StyleOrigin style_origin) { + CSSOrigin css_origin = CSSOrigin::kAuthor; + switch (style_origin) { + case api::scripting::STYLE_ORIGIN_NONE: + case api::scripting::STYLE_ORIGIN_AUTHOR: + css_origin = CSSOrigin::kAuthor; + break; + case api::scripting::STYLE_ORIGIN_USER: + css_origin = CSSOrigin::kUser; + break; + } + + return css_origin; +} + +// Checks `files` and populates `resource_out` with the appropriate extension +// resource. Returns true on success; on failure, populates `error_out`. +bool GetFileResource(const std::vector<std::string>& files, + const Extension& extension, + ExtensionResource* resource_out, + std::string* error_out) { + if (files.size() != 1) { + constexpr char kExactlyOneFileError[] = + "Exactly one file must be specified."; + *error_out = kExactlyOneFileError; + return false; + } + ExtensionResource resource = extension.GetResource(files[0]); + if (resource.extension_root().empty() || resource.relative_path().empty()) { + *error_out = + ErrorUtils::FormatErrorMessage(kCouldNotLoadFileError, files[0]); + return false; + } + + *resource_out = std::move(resource); + return true; +} // Returns true if the `permissions` allow for injection into the given `frame`. // If false, populates `error`. @@ -160,17 +207,9 @@ bool requires_localization, LoadAndLocalizeResourceCallback callback, std::string* error) { - if (files.size() != 1) { - constexpr char kExactlyOneFileError[] = - "Exactly one file must be specified."; - *error = kExactlyOneFileError; + ExtensionResource resource; + if (!GetFileResource(files, extension, &resource, error)) return false; - } - ExtensionResource resource = extension.GetResource(files[0]); - if (resource.extension_root().empty() || resource.relative_path().empty()) { - *error = ErrorUtils::FormatErrorMessage(kCouldNotLoadFileError, files[0]); - return false; - } LoadAndLocalizeResource(extension, resource, requires_localization, std::move(callback)); @@ -259,7 +298,7 @@ ScriptExecutor::MATCH_ABOUT_BLANK, UserScript::DOCUMENT_IDLE, ScriptExecutor::DEFAULT_PROCESS, /* webview_src */ GURL(), std::move(script_url), user_gesture(), - CSS_ORIGIN_AUTHOR, ScriptExecutor::JSON_SERIALIZED_RESULT, + CSSOrigin::kAuthor, ScriptExecutor::JSON_SERIALIZED_RESULT, base::BindOnce(&ScriptingExecuteScriptFunction::OnScriptExecuted, this)); return true; @@ -311,8 +350,7 @@ if ((injection_.files && injection_.css) || (!injection_.files && !injection_.css)) { - return RespondNow( - Error("Exactly one of 'css' and 'files' must be specified")); + return RespondNow(Error(kExactlyOneOfCssAndFilesError)); } if (injection_.files) { @@ -369,27 +407,13 @@ } DCHECK(script_executor); - CSSOrigin origin = CSS_ORIGIN_AUTHOR; - switch (injection_.origin) { - case api::scripting::STYLE_ORIGIN_NONE: - case api::scripting::STYLE_ORIGIN_AUTHOR: - origin = CSS_ORIGIN_AUTHOR; - break; - case api::scripting::STYLE_ORIGIN_USER: - origin = CSS_ORIGIN_USER; - break; - } - - // Note: CSS always injects as soon as possible, so we default to - // document_start. Because of tab loading, there's no guarantee this will - // *actually* inject before page load, but it will at least inject "soon". - constexpr UserScript::RunLocation kRunLocation = UserScript::DOCUMENT_START; script_executor->ExecuteScript( HostID(HostID::EXTENSIONS, extension()->id()), UserScript::ADD_CSS, std::move(code_to_execute), frame_scope, frame_ids, - ScriptExecutor::MATCH_ABOUT_BLANK, kRunLocation, + ScriptExecutor::MATCH_ABOUT_BLANK, kCSSRunLocation, ScriptExecutor::DEFAULT_PROCESS, - /* webview_src */ GURL(), std::move(script_url), user_gesture(), origin, + /* webview_src */ GURL(), std::move(script_url), user_gesture(), + ConvertStyleOriginToCSSOrigin(injection_.origin), ScriptExecutor::NO_RESULT, base::BindOnce(&ScriptingInsertCSSFunction::OnCSSInserted, this)); @@ -408,4 +432,72 @@ Respond(NoArguments()); } +ScriptingRemoveCSSFunction::ScriptingRemoveCSSFunction() = default; +ScriptingRemoveCSSFunction::~ScriptingRemoveCSSFunction() = default; + +ExtensionFunction::ResponseAction ScriptingRemoveCSSFunction::Run() { + std::unique_ptr<api::scripting::RemoveCSS::Params> params( + api::scripting::RemoveCSS::Params::Create(*args_)); + EXTENSION_FUNCTION_VALIDATE(params); + + api::scripting::CSSInjection& injection = params->injection; + + if ((injection.files && injection.css) || + (!injection.files && !injection.css)) { + return RespondNow(Error(kExactlyOneOfCssAndFilesError)); + } + + GURL script_url; + std::string error; + std::string code; + if (injection.files) { + // Note: Since we're just removing the CSS, we don't actually need to load + // the file here. It's okay for `code` to be empty in this case. + ExtensionResource resource; + if (!GetFileResource(*injection.files, *extension(), &resource, &error)) + return RespondNow(Error(std::move(error))); + + script_url = extension()->GetResourceURL(injection.files->at(0)); + } else { + DCHECK(injection.css); + code = std::move(*injection.css); + } + + ScriptExecutor* script_executor = nullptr; + ScriptExecutor::FrameScope frame_scope = ScriptExecutor::SPECIFIED_FRAMES; + std::vector<int> frame_ids; + if (!CanAccessTarget(*extension()->permissions_data(), injection.target, + browser_context(), include_incognito_information(), + &script_executor, &frame_scope, &frame_ids, &error)) { + return RespondNow(Error(std::move(error))); + } + DCHECK(script_executor); + + DCHECK(code.empty() || !script_url.is_valid()); + + script_executor->ExecuteScript( + HostID(HostID::EXTENSIONS, extension()->id()), UserScript::REMOVE_CSS, + std::move(code), frame_scope, frame_ids, + ScriptExecutor::MATCH_ABOUT_BLANK, kCSSRunLocation, + ScriptExecutor::DEFAULT_PROCESS, + /* webview_src */ GURL(), std::move(script_url), user_gesture(), + ConvertStyleOriginToCSSOrigin(injection.origin), + ScriptExecutor::NO_RESULT, + base::BindOnce(&ScriptingRemoveCSSFunction::OnCSSRemoved, this)); + + return RespondLater(); +} + +void ScriptingRemoveCSSFunction::OnCSSRemoved( + std::vector<ScriptExecutor::FrameResult> results) { + // If only a single frame was included and the injection failed, respond with + // an error. + if (results.size() == 1 && !results[0].error.empty()) { + Respond(Error(std::move(results[0].error))); + return; + } + + Respond(NoArguments()); +} + } // namespace extensions
diff --git a/chrome/browser/extensions/api/scripting/scripting_api.h b/chrome/browser/extensions/api/scripting/scripting_api.h index 947dc261..56669ab1 100644 --- a/chrome/browser/extensions/api/scripting/scripting_api.h +++ b/chrome/browser/extensions/api/scripting/scripting_api.h
@@ -74,6 +74,25 @@ api::scripting::CSSInjection injection_; }; +class ScriptingRemoveCSSFunction : public ExtensionFunction { + public: + DECLARE_EXTENSION_FUNCTION("scripting.removeCSS", SCRIPTING_REMOVECSS) + + ScriptingRemoveCSSFunction(); + ScriptingRemoveCSSFunction(const ScriptingRemoveCSSFunction&) = delete; + ScriptingRemoveCSSFunction& operator=(const ScriptingRemoveCSSFunction&) = + delete; + + // ExtensionFunction: + ResponseAction Run() override; + + private: + ~ScriptingRemoveCSSFunction() override; + + // Called when the CSS removal is complete. + void OnCSSRemoved(std::vector<ScriptExecutor::FrameResult> results); +}; + } // namespace extensions #endif // CHROME_BROWSER_EXTENSIONS_API_SCRIPTING_SCRIPTING_API_H_
diff --git a/chrome/browser/extensions/api/scripting/scripting_apitest.cc b/chrome/browser/extensions/api/scripting/scripting_apitest.cc index b7a2fd5..1cd9cfde 100644 --- a/chrome/browser/extensions/api/scripting/scripting_apitest.cc +++ b/chrome/browser/extensions/api/scripting/scripting_apitest.cc
@@ -66,7 +66,8 @@ OpenURLInNewTab( embedded_test_server()->GetURL("chromium.org", "/title2.html")); - ASSERT_TRUE(RunExtensionTestIgnoreManifestWarnings("scripting/main_frame")) + ASSERT_TRUE(RunExtensionTest({.name = "scripting/main_frame"}, + {.ignore_manifest_warnings = true})) << message_; } @@ -94,4 +95,8 @@ ASSERT_TRUE(RunExtensionTest("scripting/css_injection")) << message_; } +IN_PROC_BROWSER_TEST_F(ScriptingAPITest, CSSRemoval) { + ASSERT_TRUE(RunExtensionTest("scripting/remove_css")) << message_; +} + } // namespace extensions
diff --git a/chrome/browser/extensions/api/search/search_api_apitest.cc b/chrome/browser/extensions/api/search/search_api_apitest.cc index bb2d8a64..388e480 100644 --- a/chrome/browser/extensions/api/search/search_api_apitest.cc +++ b/chrome/browser/extensions/api/search/search_api_apitest.cc
@@ -21,7 +21,9 @@ IN_PROC_BROWSER_TEST_F(SearchApiTest, Incognito) { ResultCatcher catcher; CreateIncognitoBrowser(browser()->profile()); - ASSERT_TRUE(RunExtensionTestIncognito("search/query/incognito")) << message_; + ASSERT_TRUE(RunExtensionTest({.name = "search/query/incognito"}, + {.allow_in_incognito = true})) + << message_; } // Test incognito browser in extension split mode. @@ -30,7 +32,8 @@ catcher.RestrictToBrowserContext( browser()->profile()->GetPrimaryOTRProfile()); CreateIncognitoBrowser(browser()->profile()); - ASSERT_TRUE(RunExtensionTestIncognito("search/query/incognito_split")) + ASSERT_TRUE(RunExtensionTest({.name = "search/query/incognito_split"}, + {.allow_in_incognito = true})) << message_; }
diff --git a/chrome/browser/extensions/api/settings_private/chromeos_resolve_time_zone_by_geolocation_method_short.cc b/chrome/browser/extensions/api/settings_private/chromeos_resolve_time_zone_by_geolocation_method_short.cc index dbaadf5..d3cc53b4 100644 --- a/chrome/browser/extensions/api/settings_private/chromeos_resolve_time_zone_by_geolocation_method_short.cc +++ b/chrome/browser/extensions/api/settings_private/chromeos_resolve_time_zone_by_geolocation_method_short.cc
@@ -4,9 +4,9 @@ #include "chrome/browser/extensions/api/settings_private/chromeos_resolve_time_zone_by_geolocation_method_short.h" +#include "chrome/browser/ash/system/timezone_resolver_manager.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process_platform_part.h" -#include "chrome/browser/chromeos/system/timezone_resolver_manager.h" #include "chrome/browser/extensions/api/settings_private/generated_pref.h" #include "chrome/browser/extensions/api/settings_private/generated_time_zone_pref_base.h" #include "chrome/browser/profiles/profile.h"
diff --git a/chrome/browser/extensions/api/settings_private/chromeos_resolve_time_zone_by_geolocation_on_off.cc b/chrome/browser/extensions/api/settings_private/chromeos_resolve_time_zone_by_geolocation_on_off.cc index 9eaea7c..8f404b82 100644 --- a/chrome/browser/extensions/api/settings_private/chromeos_resolve_time_zone_by_geolocation_on_off.cc +++ b/chrome/browser/extensions/api/settings_private/chromeos_resolve_time_zone_by_geolocation_on_off.cc
@@ -4,9 +4,9 @@ #include "chrome/browser/extensions/api/settings_private/chromeos_resolve_time_zone_by_geolocation_on_off.h" +#include "chrome/browser/ash/system/timezone_resolver_manager.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process_platform_part.h" -#include "chrome/browser/chromeos/system/timezone_resolver_manager.h" #include "chrome/browser/extensions/api/settings_private/generated_pref.h" #include "chrome/browser/extensions/api/settings_private/generated_time_zone_pref_base.h" #include "chrome/browser/profiles/profile.h"
diff --git a/chrome/browser/extensions/api/settings_private/generated_time_zone_pref_base.cc b/chrome/browser/extensions/api/settings_private/generated_time_zone_pref_base.cc index 13c821c8..fbc2a3aa5 100644 --- a/chrome/browser/extensions/api/settings_private/generated_time_zone_pref_base.cc +++ b/chrome/browser/extensions/api/settings_private/generated_time_zone_pref_base.cc
@@ -4,9 +4,9 @@ #include "chrome/browser/extensions/api/settings_private/generated_time_zone_pref_base.h" +#include "chrome/browser/ash/system/timezone_resolver_manager.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process_platform_part.h" -#include "chrome/browser/chromeos/system/timezone_resolver_manager.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/common/extensions/api/settings_private.h" #include "components/user_manager/user_manager.h"
diff --git a/chrome/browser/extensions/api/settings_private/generated_time_zone_pref_base.h b/chrome/browser/extensions/api/settings_private/generated_time_zone_pref_base.h index 99ec2946..3ad6369 100644 --- a/chrome/browser/extensions/api/settings_private/generated_time_zone_pref_base.h +++ b/chrome/browser/extensions/api/settings_private/generated_time_zone_pref_base.h
@@ -8,7 +8,7 @@ #include <string> #include "base/macros.h" -#include "chrome/browser/chromeos/system/timezone_resolver_manager.h" +#include "chrome/browser/ash/system/timezone_resolver_manager.h" #include "chrome/browser/extensions/api/settings_private/generated_pref.h" class Profile;
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc index 50f8070f..ec4c176 100644 --- a/chrome/browser/extensions/api/settings_private/prefs_util.cc +++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -57,6 +57,7 @@ #include "ash/public/cpp/ambient/ambient_prefs.h" #include "ash/public/cpp/ash_pref_names.h" // nogncheck #include "chrome/browser/ash/profiles/profile_helper.h" +#include "chrome/browser/ash/system/timezone_util.h" #include "chrome/browser/chromeos/crostini/crostini_pref_names.h" #include "chrome/browser/chromeos/full_restore/full_restore_prefs.h" #include "chrome/browser/chromeos/guest_os/guest_os_pref_names.h" @@ -66,7 +67,6 @@ #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" #include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/browser/chromeos/settings/supervised_user_cros_settings_provider.h" -#include "chrome/browser/chromeos/system/timezone_util.h" #include "chrome/browser/extensions/api/settings_private/chromeos_resolve_time_zone_by_geolocation_method_short.h" #include "chrome/browser/extensions/api/settings_private/chromeos_resolve_time_zone_by_geolocation_on_off.h" #include "chromeos/services/assistant/public/cpp/assistant_prefs.h"
diff --git a/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc b/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc index f15516d..3166295 100644 --- a/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc +++ b/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc
@@ -219,14 +219,12 @@ } IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, ClientRedirect) { - ASSERT_TRUE(RunExtensionTest("webnavigation/clientRedirect")) - << message_; + ASSERT_TRUE(RunExtensionTest("webnavigation/clientRedirect")) << message_; } IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, ServerRedirect) { ASSERT_TRUE(StartEmbeddedTestServer()); - ASSERT_TRUE(RunExtensionTest("webnavigation/serverRedirect")) - << message_; + ASSERT_TRUE(RunExtensionTest("webnavigation/serverRedirect")) << message_; } IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, FormSubmission) { @@ -253,8 +251,7 @@ content::RenderProcessHost::SetMaxRendererProcessCount(1); // Wait for the extension to set itself up and return control to us. - ASSERT_TRUE( - RunExtensionTest("webnavigation/serverRedirectSingleProcess")) + ASSERT_TRUE(RunExtensionTest("webnavigation/serverRedirectSingleProcess")) << message_; WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents(); @@ -353,8 +350,7 @@ IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, RequestOpenTab) { // Wait for the extension to set itself up and return control to us. - ASSERT_TRUE(RunExtensionTest("webnavigation/requestOpenTab")) - << message_; + ASSERT_TRUE(RunExtensionTest("webnavigation/requestOpenTab")) << message_; WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents(); EXPECT_TRUE(content::WaitForLoadStop(tab)); @@ -424,7 +420,8 @@ ASSERT_TRUE(StartEmbeddedTestServer()); // Wait for the extension to set itself up and return control to us. - ASSERT_TRUE(RunExtensionTestIncognito("webnavigation/targetBlank")) + ASSERT_TRUE(RunExtensionTest({.name = "webnavigation/targetBlank"}, + {.allow_in_incognito = true})) << message_; ResultCatcher catcher;
diff --git a/chrome/browser/extensions/chrome_test_extension_loader.cc b/chrome/browser/extensions/chrome_test_extension_loader.cc index c10382a..6c6882f 100644 --- a/chrome/browser/extensions/chrome_test_extension_loader.cc +++ b/chrome/browser/extensions/chrome_test_extension_loader.cc
@@ -21,11 +21,11 @@ #include "extensions/browser/extension_creator.h" #include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_system.h" -#include "extensions/browser/extension_user_script_manager.h" #include "extensions/browser/extension_util.h" #include "extensions/browser/notification_types.h" #include "extensions/browser/test_extension_registry_observer.h" #include "extensions/browser/user_script_loader.h" +#include "extensions/browser/user_script_manager.h" #include "extensions/common/manifest_handlers/background_info.h" #include "extensions/common/manifest_handlers/content_scripts_handler.h" #include "extensions/common/manifest_handlers/incognito_info.h" @@ -125,12 +125,13 @@ bool ChromeTestExtensionLoader::WaitForExtensionReady( const Extension& extension) { - ExtensionUserScriptManager* user_script_manager = - ExtensionSystem::Get(browser_context_)->extension_user_script_manager(); + UserScriptManager* user_script_manager = + ExtensionSystem::Get(browser_context_)->user_script_manager(); // Note: |user_script_manager| can be null in tests. if (user_script_manager && !ContentScriptsInfo::GetContentScripts(&extension).empty()) { - UserScriptLoader* user_script_loader = user_script_manager->script_loader(); + UserScriptLoader* user_script_loader = + user_script_manager->manifest_script_loader(); HostID host_id(HostID::EXTENSIONS, extension_id_); if (!user_script_loader->HasLoadedScripts(host_id)) { ContentScriptLoadWaiter waiter(user_script_loader);
diff --git a/chrome/browser/extensions/chrome_test_extension_loader_browsertest.cc b/chrome/browser/extensions/chrome_test_extension_loader_browsertest.cc index fc10b37..061f3ffc 100644 --- a/chrome/browser/extensions/chrome_test_extension_loader_browsertest.cc +++ b/chrome/browser/extensions/chrome_test_extension_loader_browsertest.cc
@@ -14,8 +14,8 @@ #include "content/public/test/browser_test.h" #include "content/public/test/browser_test_utils.h" #include "extensions/browser/extension_system.h" -#include "extensions/browser/extension_user_script_manager.h" #include "extensions/browser/user_script_loader.h" +#include "extensions/browser/user_script_manager.h" #include "extensions/common/host_id.h" #include "extensions/test/test_extension_dir.h" #include "net/dns/mock_host_resolver.h" @@ -80,8 +80,8 @@ ExtensionSystem* extension_system = ExtensionSystem::Get(profile()); EXPECT_TRUE( - extension_system->extension_user_script_manager() - ->script_loader() + extension_system->user_script_manager() + ->manifest_script_loader() ->HasLoadedScripts(HostID(HostID::EXTENSIONS, extension->id()))); // Sanity check: Test that the scripts inject.
diff --git a/chrome/browser/extensions/cross_origin_xhr_apitest.cc b/chrome/browser/extensions/cross_origin_xhr_apitest.cc index 0b08e41..8bafd616 100644 --- a/chrome/browser/extensions/cross_origin_xhr_apitest.cc +++ b/chrome/browser/extensions/cross_origin_xhr_apitest.cc
@@ -32,7 +32,8 @@ // "<all_urls>" host permissions. IN_PROC_BROWSER_TEST_F(CrossOriginXHR, FileAccessAllURLs) { ASSERT_TRUE( - RunExtensionTestWithFileAccess("cross_origin_xhr/file_access_all_urls")) + RunExtensionTest({.name = "cross_origin_xhr/file_access_all_urls"}, + {.allow_file_access = true})) << message_; } @@ -47,6 +48,7 @@ // permissions to the file scheme even though it has file access. IN_PROC_BROWSER_TEST_F(CrossOriginXHR, FileAccessNoHosts) { ASSERT_TRUE( - RunExtensionTestWithFileAccess("cross_origin_xhr/file_access_no_hosts")) + RunExtensionTest({.name = "cross_origin_xhr/file_access_no_hosts"}, + {.allow_file_access = true})) << message_; }
diff --git a/chrome/browser/extensions/extension_apitest.cc b/chrome/browser/extensions/extension_apitest.cc index 6ee1054..74ed5274 100644 --- a/chrome/browser/extensions/extension_apitest.cc +++ b/chrome/browser/extensions/extension_apitest.cc
@@ -86,9 +86,88 @@ test_config_.reset(NULL); } +bool ExtensionApiTest::RunExtensionTest(const RunOptions& run_options) { + return RunExtensionTest(run_options, {}); +} + bool ExtensionApiTest::RunExtensionTest(const std::string& extension_name) { - return RunExtensionTestImpl(extension_name, std::string(), nullptr, kFlagNone, - kFlagNone); + return RunExtensionTest({.name = extension_name.c_str()}, {}); +} + +bool ExtensionApiTest::RunExtensionTest(const RunOptions& run_options, + const LoadOptions& load_options) { + // Do some sanity checks for options that are mutually exclusive or + // only valid with other options. + CHECK(run_options.name || run_options.page_url) + << "Must specify either 'name' or 'page_url'"; + CHECK(!(run_options.extension_url && run_options.page_url)) + << "'extension_url' and 'page_url' are mutually exclusive."; + CHECK(!run_options.open_in_incognito || run_options.page_url) + << "'open_in_incognito' is only allowed if specifiying 'page_url'"; + CHECK(!(run_options.launch_as_platform_app && run_options.page_url)) + << "'launch_as_platform_app' and 'page_url' are mutually exclusive."; + + if (run_options.custom_arg) + SetCustomArg(run_options.custom_arg); + + ResultCatcher catcher; + + const Extension* extension = nullptr; + if (run_options.name) { + const base::FilePath& root_path = run_options.use_extensions_root_dir + ? shared_test_data_dir_ + : test_data_dir_; + base::FilePath extension_path = root_path.AppendASCII(run_options.name); + // TODO(https://crbug.com/1171429): Move load_as_component into LoadOptions + // and unify LoadExtension and LoadExtensionAsComponent. + // As it stands today, all LoadOptions will be ignored when loading the + // extension as a component extension. + if (run_options.load_as_component) { + extension = LoadExtensionAsComponent(extension_path); + } else { + extension = LoadExtension(extension_path, load_options); + } + if (!extension) { + message_ = "Failed to load extension."; + return false; + } + } + + // If there is a page_url to load, navigate it. + // TODO(https://crbug.com/1171429): Separate page_url into page_url and + // extension_url. + if (run_options.page_url) { + GURL url(run_options.page_url); + + // Note: We use is_valid() here in the expectation that the provided url + // may lack a scheme & host and thus be a relative url within the loaded + // extension. + if (!url.is_valid()) { + DCHECK(run_options.name) << "Relative page_url given with no name"; + + url = extension->GetResourceURL(run_options.page_url); + } + + if (run_options.open_in_incognito) + OpenURLOffTheRecord(browser()->profile(), url); + else + ui_test_utils::NavigateToURL(browser(), url); + } else if (run_options.launch_as_platform_app) { + apps::AppLaunchParams params( + extension->id(), LaunchContainer::kLaunchContainerNone, + WindowOpenDisposition::NEW_WINDOW, AppLaunchSource::kSourceTest); + params.command_line = *base::CommandLine::ForCurrentProcess(); + apps::AppServiceProxyFactory::GetForProfile(browser()->profile()) + ->BrowserAppLauncher() + ->LaunchAppWithParams(std::move(params)); + } + + if (!catcher.GetNextResult()) { + message_ = catcher.message(); + return false; + } + + return true; } bool ExtensionApiTest::RunExtensionTestWithFlags( @@ -115,24 +194,6 @@ browser_test_flags, api_test_flags); } -bool ExtensionApiTest::RunExtensionTestIncognito( - const std::string& extension_name) { - return RunExtensionTestImpl(extension_name, std::string(), nullptr, - kFlagEnableIncognito, kFlagNone); -} - -bool ExtensionApiTest::RunExtensionTestIgnoreManifestWarnings( - const std::string& extension_name) { - return RunExtensionTestImpl(extension_name, std::string(), nullptr, - kFlagIgnoreManifestWarnings, kFlagNone); -} - -bool ExtensionApiTest::RunExtensionTestAllowOldManifestVersion( - const std::string& extension_name) { - return RunExtensionTestImpl(extension_name, std::string(), nullptr, - kFlagAllowOldManifestVersions, kFlagNone); -} - bool ExtensionApiTest::RunComponentExtensionTest( const std::string& extension_name) { return RunExtensionTestImpl(extension_name, std::string(), nullptr, kFlagNone, @@ -146,19 +207,6 @@ kFlagNone, kFlagLoadAsComponent); } -bool ExtensionApiTest::RunExtensionTestWithFileAccess( - const std::string& extension_name) { - return RunExtensionTestImpl(extension_name, std::string(), nullptr, - kFlagEnableFileAccess, kFlagNone); -} - -bool ExtensionApiTest::RunExtensionTestIncognitoWithFileAccess( - const std::string& extension_name) { - return RunExtensionTestImpl(extension_name, std::string(), nullptr, - kFlagEnableFileAccess | kFlagEnableIncognito, - kFlagNone); -} - bool ExtensionApiTest::RunExtensionSubtest(const std::string& extension_name, const std::string& page_url) { return RunExtensionSubtestWithArgAndFlags(extension_name, page_url, nullptr,
diff --git a/chrome/browser/extensions/extension_apitest.h b/chrome/browser/extensions/extension_apitest.h index e6f1b52..04887fe 100644 --- a/chrome/browser/extensions/extension_apitest.h +++ b/chrome/browser/extensions/extension_apitest.h
@@ -52,6 +52,38 @@ kFlagUseRootExtensionsDir = ExtensionBrowserTest::kFlagNextValue << 3, }; + struct RunOptions { + // Load the specified extension for the test. This is a subdirectory + // in "chrome/test/data/extensions/api_test". + const char* name = nullptr; + + // Start the test by opening the specified page URL. This must be an + // absolute URL. + const char* page_url = nullptr; + + // Start the test by opening the specified extension URL. This is treated + // as a relative path to an extension resource. + const char* extension_url = nullptr; + + // The custom arg to be passed into the test. + const char* custom_arg = nullptr; + + // Launch the test page in an incognito window. + bool open_in_incognito = false; + + // TODO(https://crbug.com/1171429): Move to load options and + // refactor implementation into ExtensionBrowserTest. + // Loads the extension with location COMPONENT. + bool load_as_component = false; + + // Launch the extension as a platform app. + bool launch_as_platform_app = false; + + // Use //extensions/test/data/ as the root path instead of the default + // path of //chrome/test/data/extensions/api_test/. + bool use_extensions_root_dir = false; + }; + ExtensionApiTest(); ~ExtensionApiTest() override; @@ -60,8 +92,13 @@ void SetUpOnMainThread() override; void TearDownOnMainThread() override; - // Loads |extension_name| and waits for pass / fail notification. - // |extension_name| is a directory in "chrome/test/data/extensions/api_test". + bool RunExtensionTest(const RunOptions& run_options, + const LoadOptions& load_options) WARN_UNUSED_RESULT; + + bool RunExtensionTest(const RunOptions& run_options) WARN_UNUSED_RESULT; + + // Loads the extension with |extension_name| and default RunOptions and + // LoadOptions bool RunExtensionTest(const std::string& extension_name) WARN_UNUSED_RESULT; // Same as RunExtensionTest, except run with the specific |flags| (as defined @@ -83,18 +120,6 @@ int browser_test_flags, int api_test_flags) WARN_UNUSED_RESULT; - // Same as RunExtensionTest, but enables the extension for incognito mode. - bool RunExtensionTestIncognito(const std::string& extension_name) - WARN_UNUSED_RESULT; - - // Same as RunExtensionTest, but ignores any warnings in the manifest. - bool RunExtensionTestIgnoreManifestWarnings(const std::string& extension_name) - WARN_UNUSED_RESULT; - - // Same as RunExtensionTest, allow old manifest ersions. - bool RunExtensionTestAllowOldManifestVersion( - const std::string& extension_name) WARN_UNUSED_RESULT; - // Same as RunExtensionTest, but loads extension as component. bool RunComponentExtensionTest(const std::string& extension_name) WARN_UNUSED_RESULT; @@ -104,14 +129,6 @@ const char* custom_arg) WARN_UNUSED_RESULT; - // Same as RunExtensionTest, but enables file access. - bool RunExtensionTestWithFileAccess(const std::string& extension_name) - WARN_UNUSED_RESULT; - - // Same as RunExtensionTestIncognito, but enables file access. - bool RunExtensionTestIncognitoWithFileAccess( - const std::string& extension_name) WARN_UNUSED_RESULT; - // If not empty, Load |extension_name|, load |page_url| and wait for pass / // fail notification from the extension API on the page. Note that if // |page_url| is not a valid url, it will be treated as a resource within
diff --git a/chrome/browser/extensions/extension_incognito_apitest.cc b/chrome/browser/extensions/extension_incognito_apitest.cc index 16d4750c..f2614c9e 100644 --- a/chrome/browser/extensions/extension_incognito_apitest.cc +++ b/chrome/browser/extensions/extension_incognito_apitest.cc
@@ -91,8 +91,9 @@ // accidentally create an incognito profile. IN_PROC_BROWSER_TEST_F(IncognitoApiTest, DontCreateIncognitoProfile) { ASSERT_FALSE(browser()->profile()->HasPrimaryOTRProfile()); - ASSERT_TRUE(RunExtensionTestIncognito( - "incognito/dont_create_profile")) << message_; + ASSERT_TRUE(RunExtensionTest({.name = "incognito/dont_create_profile"}, + {.allow_in_incognito = true})) + << message_; ASSERT_FALSE(browser()->profile()->HasPrimaryOTRProfile()); }
diff --git a/chrome/browser/extensions/extension_keybinding_apitest.cc b/chrome/browser/extensions/extension_keybinding_apitest.cc index 218a39d..0ce3c0c 100644 --- a/chrome/browser/extensions/extension_keybinding_apitest.cc +++ b/chrome/browser/extensions/extension_keybinding_apitest.cc
@@ -532,8 +532,7 @@ ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); - ASSERT_TRUE(RunExtensionTest("keybinding/basics")) - << message_; + ASSERT_TRUE(RunExtensionTest("keybinding/basics")) << message_; CommandService* command_service = CommandService::Get(browser()->profile()); @@ -1029,10 +1028,9 @@ bool is_incognito_enabled = GetParam(); - if (is_incognito_enabled) - ASSERT_TRUE(RunExtensionTestIncognito("keybinding/basics")) << message_; - else - ASSERT_TRUE(RunExtensionTest("keybinding/basics")) << message_; + ASSERT_TRUE(RunExtensionTest({.name = "keybinding/basics"}, + {.allow_in_incognito = is_incognito_enabled})) + << message_; // Open incognito window and navigate to test page. Browser* incognito_browser = OpenURLOffTheRecord(
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc index c2f75b6..4c45066 100644 --- a/chrome/browser/extensions/extension_service_unittest.cc +++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -847,13 +847,16 @@ scripts[0]->js_scripts()[0]->relative_path()); base::FilePath expected_path = base::MakeAbsoluteFilePath(extension->path().AppendASCII("script1.js")); - EXPECT_TRUE(resource00.ComparePathWithDefault(expected_path)); + + EXPECT_EQ(expected_path.NormalizePathSeparators(), + resource00.GetFilePath().NormalizePathSeparators()); ExtensionResource resource01(extension->id(), scripts[0]->js_scripts()[1]->extension_root(), scripts[0]->js_scripts()[1]->relative_path()); expected_path = base::MakeAbsoluteFilePath(extension->path().AppendASCII("script2.js")); - EXPECT_TRUE(resource01.ComparePathWithDefault(expected_path)); + EXPECT_EQ(expected_path.NormalizePathSeparators(), + resource01.GetFilePath().NormalizePathSeparators()); EXPECT_EQ(1u, scripts[1]->url_patterns().patterns().size()); EXPECT_EQ("http://*.news.com/*", scripts[1]->url_patterns().begin()->GetAsString()); @@ -863,7 +866,8 @@ expected_path = extension->path().AppendASCII("js_files").AppendASCII("script3.js"); expected_path = base::MakeAbsoluteFilePath(expected_path); - EXPECT_TRUE(resource10.ComparePathWithDefault(expected_path)); + EXPECT_EQ(expected_path.NormalizePathSeparators(), + resource10.GetFilePath().NormalizePathSeparators()); expected_patterns.ClearPatterns(); AddPattern(&expected_patterns, "http://*.google.com/*");
diff --git a/chrome/browser/extensions/extension_startup_browsertest.cc b/chrome/browser/extensions/extension_startup_browsertest.cc index 0a78f45..fe8e19ec 100644 --- a/chrome/browser/extensions/extension_startup_browsertest.cc +++ b/chrome/browser/extensions/extension_startup_browsertest.cc
@@ -36,8 +36,8 @@ #include "content/public/test/browser_test_utils.h" #include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_system.h" -#include "extensions/browser/extension_user_script_manager.h" #include "extensions/browser/user_script_loader.h" +#include "extensions/browser/user_script_manager.h" #include "extensions/common/extension.h" #include "extensions/common/extension_set.h" #include "extensions/common/feature_switch.h" @@ -151,11 +151,11 @@ ->extension_service(); ASSERT_EQ(expect_extensions_enabled, service->extensions_enabled()); - extensions::ExtensionUserScriptManager* manager = + extensions::UserScriptManager* manager = extensions::ExtensionSystem::Get(browser()->profile()) - ->extension_user_script_manager(); + ->user_script_manager(); - extensions::UserScriptLoader* loader = manager->script_loader(); + extensions::UserScriptLoader* loader = manager->manifest_script_loader(); if (!loader->initial_load_complete()) extensions::ContentScriptLoadWaiter(loader).Wait(); ASSERT_TRUE(loader->initial_load_complete()); @@ -237,11 +237,11 @@ extension_list.push_back(it->get()); } - extensions::ExtensionUserScriptManager* manager = + extensions::UserScriptManager* manager = extensions::ExtensionSystem::Get(browser()->profile()) - ->extension_user_script_manager(); + ->user_script_manager(); - extensions::UserScriptLoader* loader = manager->script_loader(); + extensions::UserScriptLoader* loader = manager->manifest_script_loader(); for (size_t i = 0; i < extension_list.size(); ++i) { extensions::ContentScriptLoadWaiter waiter(loader);
diff --git a/chrome/browser/extensions/extension_system_factory.cc b/chrome/browser/extensions/extension_system_factory.cc index 6306356..ccf132f9 100644 --- a/chrome/browser/extensions/extension_system_factory.cc +++ b/chrome/browser/extensions/extension_system_factory.cc
@@ -12,7 +12,6 @@ #include "chrome/browser/signin/identity_manager_factory.h" #include "chrome/browser/ui/global_error/global_error_service_factory.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" -#include "extensions/browser/declarative_user_script_manager_factory.h" #include "extensions/browser/event_router_factory.h" #include "extensions/browser/extension_prefs_factory.h" #include "extensions/browser/extension_registry_factory.h" @@ -51,7 +50,6 @@ DependsOn(ProcessManagerFactory::GetInstance()); DependsOn(RendererStartupHelperFactory::GetInstance()); DependsOn(BlocklistFactory::GetInstance()); - DependsOn(DeclarativeUserScriptManagerFactory::GetInstance()); DependsOn(EventRouterFactory::GetInstance()); // This depends on ExtensionDownloader, which depends on // IdentityManager for webstore authentication.
diff --git a/chrome/browser/extensions/extension_system_impl.cc b/chrome/browser/extensions/extension_system_impl.cc index 22a91233..dec68dc2 100644 --- a/chrome/browser/extensions/extension_system_impl.cc +++ b/chrome/browser/extensions/extension_system_impl.cc
@@ -50,7 +50,6 @@ #include "extensions/browser/extension_pref_value_map_factory.h" #include "extensions/browser/extension_prefs.h" #include "extensions/browser/extension_registry.h" -#include "extensions/browser/extension_user_script_manager.h" #include "extensions/browser/extension_util.h" #include "extensions/browser/info_map.h" #include "extensions/browser/quota_service.h" @@ -58,6 +57,7 @@ #include "extensions/browser/service_worker_manager.h" #include "extensions/browser/state_store.h" #include "extensions/browser/updater/uninstall_ping_sender.h" +#include "extensions/browser/user_script_manager.h" #include "extensions/browser/value_store/value_store_factory_impl.h" #include "extensions/common/constants.h" #include "extensions/common/features/feature_channel.h" @@ -201,8 +201,7 @@ service_worker_manager_.reset(new ServiceWorkerManager(profile_)); - extension_user_script_manager_ = - std::make_unique<ExtensionUserScriptManager>(profile_); + user_script_manager_ = std::make_unique<UserScriptManager>(profile_); // ExtensionService depends on RuntimeData. runtime_data_.reset(new RuntimeData(ExtensionRegistry::Get(profile_))); @@ -334,9 +333,8 @@ return management_policy_.get(); } -ExtensionUserScriptManager* -ExtensionSystemImpl::Shared::extension_user_script_manager() { - return extension_user_script_manager_.get(); +UserScriptManager* ExtensionSystemImpl::Shared::user_script_manager() { + return user_script_manager_.get(); } InfoMap* ExtensionSystemImpl::Shared::info_map() { @@ -379,7 +377,7 @@ void ExtensionSystemImpl::InitForRegularProfile(bool extensions_enabled) { TRACE_EVENT0("browser,startup", "ExtensionSystemImpl::InitForRegularProfile"); - if (extension_user_script_manager() || extension_service()) + if (user_script_manager() || extension_service()) return; // Already initialized. // The InfoMap needs to be created before the ProcessManager. @@ -403,9 +401,8 @@ return shared_->service_worker_manager(); } -ExtensionUserScriptManager* -ExtensionSystemImpl::extension_user_script_manager() { - return shared_->extension_user_script_manager(); +UserScriptManager* ExtensionSystemImpl::user_script_manager() { + return shared_->user_script_manager(); } StateStore* ExtensionSystemImpl::state_store() {
diff --git a/chrome/browser/extensions/extension_system_impl.h b/chrome/browser/extensions/extension_system_impl.h index c6ba543..e7ad220 100644 --- a/chrome/browser/extensions/extension_system_impl.h +++ b/chrome/browser/extensions/extension_system_impl.h
@@ -55,8 +55,7 @@ RuntimeData* runtime_data() override; // shared ManagementPolicy* management_policy() override; // shared ServiceWorkerManager* service_worker_manager() override; // shared - ExtensionUserScriptManager* extension_user_script_manager() - override; // shared + UserScriptManager* user_script_manager() override; // shared StateStore* state_store() override; // shared StateStore* rules_store() override; // shared scoped_refptr<ValueStoreFactory> store_factory() override; // shared @@ -115,7 +114,7 @@ RuntimeData* runtime_data(); ManagementPolicy* management_policy(); ServiceWorkerManager* service_worker_manager(); - ExtensionUserScriptManager* extension_user_script_manager(); + UserScriptManager* user_script_manager(); InfoMap* info_map(); QuotaService* quota_service(); AppSorting* app_sorting(); @@ -137,7 +136,7 @@ std::unique_ptr<ServiceWorkerManager> service_worker_manager_; // Shared memory region manager for scripts statically declared in extension // manifests. This region is shared between all extensions. - std::unique_ptr<ExtensionUserScriptManager> extension_user_script_manager_; + std::unique_ptr<UserScriptManager> user_script_manager_; std::unique_ptr<RuntimeData> runtime_data_; // ExtensionService depends on StateStore, Blocklist and RuntimeData. std::unique_ptr<ExtensionService> extension_service_;
diff --git a/chrome/browser/extensions/permissions_updater.cc b/chrome/browser/extensions/permissions_updater.cc index a7b95c1..223bfa32 100644 --- a/chrome/browser/extensions/permissions_updater.cc +++ b/chrome/browser/extensions/permissions_updater.cc
@@ -36,10 +36,12 @@ #include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_util.h" #include "extensions/browser/notification_types.h" +#include "extensions/browser/renderer_startup_helper.h" #include "extensions/common/cors_util.h" #include "extensions/common/extension.h" #include "extensions/common/extension_messages.h" #include "extensions/common/manifest_handlers/permissions_parser.h" +#include "extensions/common/mojom/renderer.mojom.h" #include "extensions/common/permissions/permission_set.h" #include "extensions/common/permissions/permissions_data.h" @@ -672,18 +674,22 @@ const URLPatternSet default_runtime_allowed_hosts) { Profile* profile = Profile::FromBrowserContext(browser_context); - ExtensionMsg_UpdateDefaultPolicyHostRestrictions_Params params; - params.default_policy_blocked_hosts = default_runtime_blocked_hosts.Clone(); - params.default_policy_allowed_hosts = default_runtime_allowed_hosts.Clone(); - // Send the new policy to the renderers. for (RenderProcessHost::iterator host_iterator( RenderProcessHost::AllHostsIterator()); !host_iterator.IsAtEnd(); host_iterator.Advance()) { RenderProcessHost* host = host_iterator.GetCurrentValue(); - if (profile->IsSameOrParent( + if (host->IsInitializedAndNotDead() && + profile->IsSameOrParent( Profile::FromBrowserContext(host->GetBrowserContext()))) { - host->Send(new ExtensionMsg_UpdateDefaultPolicyHostRestrictions(params)); + mojom::Renderer* renderer = + RendererStartupHelperFactory::GetForBrowserContext( + host->GetBrowserContext()) + ->GetRenderer(host); + if (renderer) { + renderer->UpdateDefaultPolicyHostRestrictions( + default_runtime_blocked_hosts, default_runtime_allowed_hosts); + } } } }
diff --git a/chrome/browser/extensions/permissions_updater.h b/chrome/browser/extensions/permissions_updater.h index 8be23beb..217ca019 100644 --- a/chrome/browser/extensions/permissions_updater.h +++ b/chrome/browser/extensions/permissions_updater.h
@@ -190,8 +190,7 @@ // Issues the relevant events, messages and notifications when the default // scope management policy have changed. - // Specifically, this sends the ExtensionMsg_UpdateDefaultHostRestrictions - // IPC message. + // Specifically, this sends the UpdateDefaultHostRestrictions Mojo message. static void NotifyDefaultPolicyHostRestrictionsUpdated( content::BrowserContext* browser_context, const URLPatternSet default_runtime_blocked_hosts,
diff --git a/chrome/browser/extensions/script_executor_browsertest.cc b/chrome/browser/extensions/script_executor_browsertest.cc index 31184ebba..c4db58f 100644 --- a/chrome/browser/extensions/script_executor_browsertest.cc +++ b/chrome/browser/extensions/script_executor_browsertest.cc
@@ -129,7 +129,7 @@ {ExtensionApiFrameIdMap::kTopFrameId}, ScriptExecutor::DONT_MATCH_ABOUT_BLANK, UserScript::DOCUMENT_IDLE, ScriptExecutor::DEFAULT_PROCESS, GURL() /* webview_src */, - GURL() /* script_url */, false /* user_gesture */, CSS_ORIGIN_AUTHOR, + GURL() /* script_url */, false /* user_gesture */, CSSOrigin::kAuthor, ScriptExecutor::JSON_SERIALIZED_RESULT, helper.GetCallback()); helper.Wait(); EXPECT_EQ("New Title", base::UTF16ToUTF8(web_contents->GetTitle())); @@ -209,7 +209,7 @@ kCode, ScriptExecutor::SPECIFIED_FRAMES, {frame1_id, frame2_id}, ScriptExecutor::DONT_MATCH_ABOUT_BLANK, UserScript::DOCUMENT_IDLE, ScriptExecutor::DEFAULT_PROCESS, GURL() /* webview_src */, - GURL() /* script_url */, false /* user_gesture */, CSS_ORIGIN_AUTHOR, + GURL() /* script_url */, false /* user_gesture */, CSSOrigin::kAuthor, ScriptExecutor::JSON_SERIALIZED_RESULT, helper.GetCallback()); helper.Wait(); @@ -228,7 +228,7 @@ kCode, ScriptExecutor::INCLUDE_SUB_FRAMES, {frame1_id, frame2_id}, ScriptExecutor::DONT_MATCH_ABOUT_BLANK, UserScript::DOCUMENT_IDLE, ScriptExecutor::DEFAULT_PROCESS, GURL() /* webview_src */, - GURL() /* script_url */, false /* user_gesture */, CSS_ORIGIN_AUTHOR, + GURL() /* script_url */, false /* user_gesture */, CSSOrigin::kAuthor, ScriptExecutor::JSON_SERIALIZED_RESULT, helper.GetCallback()); helper.Wait(); @@ -257,7 +257,7 @@ {frame1_id, frame2_id, kNonExistentFrameId}, ScriptExecutor::DONT_MATCH_ABOUT_BLANK, UserScript::DOCUMENT_IDLE, ScriptExecutor::DEFAULT_PROCESS, GURL() /* webview_src */, - GURL() /* script_url */, false /* user_gesture */, CSS_ORIGIN_AUTHOR, + GURL() /* script_url */, false /* user_gesture */, CSSOrigin::kAuthor, ScriptExecutor::JSON_SERIALIZED_RESULT, helper.GetCallback()); helper.Wait(); @@ -279,7 +279,7 @@ kCode, ScriptExecutor::SPECIFIED_FRAMES, {kNonExistentFrameId}, ScriptExecutor::DONT_MATCH_ABOUT_BLANK, UserScript::DOCUMENT_IDLE, ScriptExecutor::DEFAULT_PROCESS, GURL() /* webview_src */, - GURL() /* script_url */, false /* user_gesture */, CSS_ORIGIN_AUTHOR, + GURL() /* script_url */, false /* user_gesture */, CSSOrigin::kAuthor, ScriptExecutor::JSON_SERIALIZED_RESULT, helper.GetCallback()); helper.Wait();
diff --git a/chrome/browser/extensions/test_extension_system.cc b/chrome/browser/extensions/test_extension_system.cc index 4691b3e..f4275e3 100644 --- a/chrome/browser/extensions/test_extension_system.cc +++ b/chrome/browser/extensions/test_extension_system.cc
@@ -30,6 +30,7 @@ #include "extensions/browser/quota_service.h" #include "extensions/browser/runtime_data.h" #include "extensions/browser/state_store.h" +#include "extensions/browser/user_script_manager.h" #include "extensions/browser/value_store/test_value_store_factory.h" #include "extensions/browser/value_store/testing_value_store.h" #include "services/data_decoder/data_decoder_service.h" @@ -89,6 +90,10 @@ return extension_service_.get(); } +void TestExtensionSystem::CreateUserScriptManager() { + user_script_manager_ = std::make_unique<UserScriptManager>(profile_); +} + ExtensionService* TestExtensionSystem::extension_service() { return extension_service_.get(); } @@ -109,9 +114,8 @@ return nullptr; } -ExtensionUserScriptManager* -TestExtensionSystem::extension_user_script_manager() { - return nullptr; +UserScriptManager* TestExtensionSystem::user_script_manager() { + return user_script_manager_.get(); } StateStore* TestExtensionSystem::state_store() {
diff --git a/chrome/browser/extensions/test_extension_system.h b/chrome/browser/extensions/test_extension_system.h index 9fa72e5..70d51a0 100644 --- a/chrome/browser/extensions/test_extension_system.h +++ b/chrome/browser/extensions/test_extension_system.h
@@ -52,13 +52,16 @@ void CreateSocketManager(); + // Creates a UserScriptManager initialized with the testing profile, + void CreateUserScriptManager(); + void InitForRegularProfile(bool extensions_enabled) override {} void SetExtensionService(ExtensionService* service); ExtensionService* extension_service() override; RuntimeData* runtime_data() override; ManagementPolicy* management_policy() override; ServiceWorkerManager* service_worker_manager() override; - ExtensionUserScriptManager* extension_user_script_manager() override; + UserScriptManager* user_script_manager() override; StateStore* state_store() override; StateStore* rules_store() override; scoped_refptr<ValueStoreFactory> store_factory() override; @@ -107,6 +110,7 @@ scoped_refptr<InfoMap> info_map_; std::unique_ptr<QuotaService> quota_service_; std::unique_ptr<AppSorting> app_sorting_; + std::unique_ptr<UserScriptManager> user_script_manager_; base::OneShotEvent ready_; std::unique_ptr<data_decoder::test::InProcessDataDecoder>
diff --git a/chrome/browser/extensions/user_script_listener.cc b/chrome/browser/extensions/user_script_listener.cc index da9f6f17..565803b 100644 --- a/chrome/browser/extensions/user_script_listener.cc +++ b/chrome/browser/extensions/user_script_listener.cc
@@ -16,7 +16,7 @@ #include "content/public/browser/navigation_throttle.h" #include "content/public/browser/notification_service.h" #include "extensions/browser/extension_system.h" -#include "extensions/browser/extension_user_script_manager.h" +#include "extensions/browser/user_script_manager.h" #include "extensions/common/extension.h" #include "extensions/common/manifest_handlers/content_scripts_handler.h" #include "extensions/common/url_pattern.h" @@ -203,11 +203,12 @@ DCHECK(!extension_registry_observer_.IsObserving(registry)); extension_registry_observer_.Add(registry); - ExtensionUserScriptManager* user_script_manager = - ExtensionSystem::Get(profile)->extension_user_script_manager(); + UserScriptManager* user_script_manager = + ExtensionSystem::Get(profile)->user_script_manager(); // Note: |user_script_manager| can be null in some tests. if (user_script_manager) { - UserScriptLoader* loader = user_script_manager->script_loader(); + UserScriptLoader* loader = + user_script_manager->manifest_script_loader(); DCHECK(!user_script_loader_observer_.IsObserving(loader)); user_script_loader_observer_.Add(loader); }
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index fb7e0fb..d7144e5 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -155,6 +155,11 @@ "expiry_milestone": 76 }, { + "name": "arc-enable-usap", + "owners": [ "camurcu" ], + "expiry_milestone": 92 + }, + { "name": "arc-file-picker-experiment", "owners": [ "niwa" ], "expiry_milestone": 95 @@ -1607,11 +1612,6 @@ "expiry_milestone": 89 }, { - "name": "enable-experimental-accessibility-cursor-colors", - "owners": [ "katie" ], - "expiry_milestone": 87 - }, - { "name": "enable-experimental-accessibility-dictation-extension", "owners": [ "akihiroota" ], "expiry_milestone": 92 @@ -2055,11 +2055,6 @@ "expiry_milestone": -1 }, { - "name": "enable-on-device-assistant", - "owners": [ "croissant-eng" ], - "expiry_milestone": 88 - }, - { "name": "enable-oop-print-drivers", "owners": [ "awscreen", "thestig" ], "expiry_milestone": 92 @@ -2101,6 +2096,11 @@ // it can badly break pages under test. "expiry_milestone": -1 }, + { + "name": "enable-pci-guard-ui", + "owners": [ "jimmyxgong", "cros-peripherals@google.com" ], + "expiry_milestone": 94 + }, { "name": "enable-phone-hub", "owners": [ "better-together-dev@google.com", "tjohnsonkanu", "khorimoto" ], "expiry_milestone": 90 @@ -2797,7 +2797,7 @@ }, { "name": "focus-mode", - "owners": [ "dfried", "pbos", "yiningwang@google.com" ], + "owners": [ "dfried", "pbos" ], "expiry_milestone": 82 }, { @@ -3244,11 +3244,6 @@ "expiry_milestone": 92 }, { - "name": "launcher-settings-search", - "owners": [ "jiameng", "tby" ], - "expiry_milestone": 88 - }, - { "name": "legacy-tls-enforced", "owners": [ "cthomp" ], "expiry_milestone": 92 @@ -4074,6 +4069,11 @@ "expiry_milestone": 100 }, { + "name": "preemtive-link-to-text-generation", + "owners": [ "cheickcisse@google.com" ], + "expiry_milestone": 92 + }, + { "name": "prefer-constant-frame-rate", "owners": [ "chromeos-camera-eng@google.com" ], "expiry_milestone": 96 @@ -4362,7 +4362,7 @@ "bdea", "chrome-safebrowsing-core@google.com" ], - "expiry_milestone": 88 + "expiry_milestone": 91 }, { "name": "safe-browsing-enhanced-protection-android", @@ -4517,7 +4517,7 @@ }, { "name": "select-to-speak-navigation-control", - "owners": [ "joelriley" ], + "owners": [ "joelriley@google.com" ], "expiry_milestone": 89 }, { @@ -4786,11 +4786,6 @@ "expiry_milestone": 95 }, { - "name": "system-tray-mic-gain", - "owners": [ "amehfooz", "tengs" ], - "expiry_milestone": 86 - }, - { "name": "tab-groups", "owners": [ "chrome-desktop-ui-sea@google.com", "connily" ], "expiry_milestone": 88 @@ -4938,13 +4933,13 @@ }, { "name": "turn-off-streaming-media-caching-always", - "owners": [ "shawnpi@microsoft.com", "cassew@google.com" ], - "expiry_milestone": 89 + "owners": [ "wicarr@microsoft.com", "cassew@google.com" ], + "expiry_milestone": 91 }, { "name": "turn-off-streaming-media-caching-on-battery", - "owners": [ "shawnpi@microsoft.com", "cassew@google.com" ], - "expiry_milestone": 89 + "owners": [ "wicarr@microsoft.com", "cassew@google.com" ], + "expiry_milestone": 91 }, { "name": "ui-debug-tools",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 79c6031a..046a069 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -984,6 +984,12 @@ const char kEnableLoginDetectionDescription[] = "Allow user sign-in to be detected based on heuristics."; +const char kEnablePciguardUiName[] = + "Enable Pciguard (Thunderbolt + USB4 tunneling) UI for settings"; +const char kEnablePciguardUiDescription[] = + "Enable toggling Pciguard settings through the Settings App. By default, " + "this flag is disabled."; + const char kEnablePixelCanvasRecordingName[] = "Enable pixel canvas recording"; const char kEnablePixelCanvasRecordingDescription[] = "Pixel canvas recording allows the compositor to raster contents aligned " @@ -2283,11 +2289,6 @@ "Enables viewing the current stylus battery level in the stylus tools " "menu."; -const char kSystemTrayMicGainName[] = "Modify mic gain in the system tray"; -const char kSystemTrayMicGainDescription[] = - "Enables mic gain settings in the system tray audio " - "settings."; - const char kTabEngagementReportingName[] = "Tab Engagement Metrics"; const char kTabEngagementReportingDescription[] = "Tracks tab engagement and lifetime metrics."; @@ -2620,6 +2621,11 @@ "restrictions make it unlikely that a URL can be generated and actually " "work when shared."; +const char kPreemtiveLinkToTextGenerationName[] = + "Preemptive generation of link to text"; +const char kPreemtiveLinkToTextGenerationDescription[] = + "Enables link to text to be generated in advance."; + // Android --------------------------------------------------------------------- #if defined(OS_ANDROID) @@ -3818,6 +3824,12 @@ "Allow Android to use high-memory dalvik profile when applicable for " "high-memory devices."; +const char kArcEnableUsapName[] = + "Enable ARC Unspecialized Application Processes"; +const char kArcEnableUsapDesc[] = + "Enable ARC Unspecialized Application Processes when applicable for " + "high-memory devices."; + const char kArcUsbHostName[] = "Enable ARC USB host integration"; const char kArcUsbHostDescription[] = "Allow Android apps to use USB host feature on ChromeOS devices."; @@ -4053,11 +4065,6 @@ const char kMovablePartialScreenshotDescription[] = "Allow partial screenshot region to be moved/resized via mouse/touch."; -const char kEnableAdvancedPpdAttributesName[] = - "Enable advanced PPD attributes"; -const char kEnableAdvancedPpdAttributesDescription[] = - "Enable advanced settings on CUPS printers"; - const char kEnableAppDataSearchName[] = "Enable app data search in launcher"; const char kEnableAppDataSearchDescription[] = "Allow launcher search to access data available through Firebase App "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index f75a4bb..72f71ee 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -564,6 +564,9 @@ extern const char kEnableNewDownloadBackendName[]; extern const char kEnableNewDownloadBackendDescription[]; +extern const char kEnablePciguardUiName[]; +extern const char kEnablePciguardUiDescription[]; + extern const char kEnablePortalsName[]; extern const char kEnablePortalsDescription[]; @@ -1324,9 +1327,6 @@ extern const char kSyncSandboxName[]; extern const char kSyncSandboxDescription[]; -extern const char kSystemTrayMicGainName[]; -extern const char kSystemTrayMicGainDescription[]; - extern const char kTabEngagementReportingName[]; extern const char kTabEngagementReportingDescription[]; @@ -1522,6 +1522,9 @@ extern const char kSharedHighlightingUseBlocklistName[]; extern const char kSharedHighlightingUseBlocklistDescription[]; +extern const char kPreemtiveLinkToTextGenerationName[]; +extern const char kPreemtiveLinkToTextGenerationDescription[]; + // Android -------------------------------------------------------------------- #if defined(OS_ANDROID) @@ -2206,6 +2209,9 @@ extern const char kArcUseHighMemoryDalvikProfileName[]; extern const char kArcUseHighMemoryDalvikProfileDesc[]; +extern const char kArcEnableUsapName[]; +extern const char kArcEnableUsapDesc[]; + extern const char kArcUsbHostName[]; extern const char kArcUsbHostDescription[];
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc index 473184ed..905332f 100644 --- a/chrome/browser/flags/android/chrome_feature_list.cc +++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -101,6 +101,7 @@ &features::kMetricsSettingsAndroid, &features::kNetworkServiceInProcess, &features::kPredictivePrefetchingAllowedOnAllConnectionTypes, + &features::kPreemtiveLinkToTextGeneration, &features::kPrivacyReorderedAndroid, &features::kPrivacySandboxSettings, &features::kPrioritizeBootstrapTasks, @@ -609,7 +610,7 @@ "TabEngagementReportingAndroid", base::FEATURE_DISABLED_BY_DEFAULT}; const base::Feature kTabGroupsAndroid{"TabGroupsAndroid", - base::FEATURE_DISABLED_BY_DEFAULT}; + base::FEATURE_ENABLED_BY_DEFAULT}; const base::Feature kTabGroupsContinuationAndroid{ "TabGroupsContinuationAndroid", base::FEATURE_DISABLED_BY_DEFAULT}; @@ -618,7 +619,7 @@ "TabGroupsUiImprovementsAndroid", base::FEATURE_ENABLED_BY_DEFAULT}; const base::Feature kTabGridLayoutAndroid{"TabGridLayoutAndroid", - base::FEATURE_DISABLED_BY_DEFAULT}; + base::FEATURE_ENABLED_BY_DEFAULT}; const base::Feature kTabReparenting{"TabReparenting", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java index c0803b76..b880bef 100644 --- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java +++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -382,6 +382,7 @@ public static final String PHOTO_PICKER_VIDEO_SUPPORT = "PhotoPickerVideoSupport"; public static final String PORTALS = "Portals"; public static final String PORTALS_CROSS_ORIGIN = "PortalsCrossOrigin"; + public static final String PREEMTIVE_LINK_TO_TEXT_GENERATION = "PreemtiveLinkToTextGeneration"; public static final String PREDICTIVE_PREFETCHING_ALLOWED_ON_ALL_CONNECTION_TYPES = "PredictivePrefetchingAllowedOnAllConnectionTypes"; public static final String PREFETCH_NOTIFICATION_SCHEDULING_INTEGRATION =
diff --git a/chrome/browser/global_keyboard_shortcuts_mac.mm b/chrome/browser/global_keyboard_shortcuts_mac.mm index df41350..78529f1 100644 --- a/chrome/browser/global_keyboard_shortcuts_mac.mm +++ b/chrome/browser/global_keyboard_shortcuts_mac.mm
@@ -8,6 +8,7 @@ #include <Carbon/Carbon.h> #include "base/check.h" +#include "base/feature_list.h" #include "base/mac/foundation_util.h" #include "base/no_destructor.h" #include "base/stl_util.h" @@ -19,6 +20,7 @@ #include "ui/base/accelerators/accelerator.h" #include "ui/base/accelerators/platform_accelerator_cocoa.h" #import "ui/base/cocoa/nsmenuitem_additions.h" +#include "ui/base/ui_base_features.h" #include "ui/events/event_constants.h" #include "ui/events/keycodes/keyboard_code_conversion_mac.h" @@ -174,6 +176,14 @@ if (base::FeatureList::IsEnabled(features::kTabSearch)) { keys->push_back({true, true, false, false, kVK_ANSI_A, IDC_TAB_SEARCH}); } + if (base::FeatureList::IsEnabled(features::kUIDebugTools)) { + keys->push_back({false, true, true, true, kVK_ANSI_T, + IDC_DEBUG_TOGGLE_TABLET_MODE}); + keys->push_back({false, true, true, true, kVK_ANSI_V, + IDC_DEBUG_PRINT_VIEW_TREE}); + keys->push_back({false, true, true, true, kVK_ANSI_M, + IDC_DEBUG_PRINT_VIEW_TREE_DETAILS}); + } // clang-format on return *keys; }
diff --git a/chrome/browser/media/cast_mirroring_performance_browsertest.cc b/chrome/browser/media/cast_mirroring_performance_browsertest.cc index ab0c19e3c..d440e0a 100644 --- a/chrome/browser/media/cast_mirroring_performance_browsertest.cc +++ b/chrome/browser/media/cast_mirroring_performance_browsertest.cc
@@ -895,6 +895,8 @@ void DidStart() override {} void DidStop() override {} + void LogInfoMessage(const std::string& message) override {} + void LogErrorMessage(const std::string& message) override {} // CastMessageChannel implementation void Send(mirroring::mojom::CastMessagePtr message) override {
diff --git a/chrome/browser/media/cast_mirroring_service_host_browsertest.cc b/chrome/browser/media/cast_mirroring_service_host_browsertest.cc index 81bd592..2b80b06 100644 --- a/chrome/browser/media/cast_mirroring_service_host_browsertest.cc +++ b/chrome/browser/media/cast_mirroring_service_host_browsertest.cc
@@ -214,6 +214,8 @@ MOCK_METHOD1(OnError, void(mojom::SessionError)); MOCK_METHOD0(DidStart, void()); MOCK_METHOD0(DidStop, void()); + MOCK_METHOD1(LogInfoMessage, void(const std::string&)); + MOCK_METHOD1(LogErrorMessage, void(const std::string&)); // mojom::CastMessageChannel mocks. MOCK_METHOD1(Send, void(mojom::CastMessagePtr));
diff --git a/chrome/browser/media/router/providers/cast/mirroring_activity.cc b/chrome/browser/media/router/providers/cast/mirroring_activity.cc index b3d048d..d80de671 100644 --- a/chrome/browser/media/router/providers/cast/mirroring_activity.cc +++ b/chrome/browser/media/router/providers/cast/mirroring_activity.cc
@@ -208,6 +208,13 @@ } void MirroringActivity::OnError(SessionError error) { + logger_->LogError( + media_router::mojom::LogCategory::kMirroring, kLoggerComponent, + base::StringPrintf( + "Mirroring will stop. MirroringService.SessionError: %d", + static_cast<int>(error)), + route_.media_sink_id(), route_.media_source().id(), + route_.presentation_id()); if (will_start_mirroring_timestamp_) { // An error was encountered while attempting to start mirroring. base::UmaHistogramEnumeration(kHistogramStartFailureNative, error); @@ -236,6 +243,18 @@ StopMirroring(); } +void MirroringActivity::LogInfoMessage(const std::string& message) { + logger_->LogInfo(media_router::mojom::LogCategory::kMirroring, + kLoggerComponent, message, route_.media_sink_id(), + route_.media_source().id(), route_.presentation_id()); +} + +void MirroringActivity::LogErrorMessage(const std::string& message) { + logger_->LogError(media_router::mojom::LogCategory::kMirroring, + kLoggerComponent, message, route_.media_sink_id(), + route_.media_source().id(), route_.presentation_id()); +} + void MirroringActivity::Send(mirroring::mojom::CastMessagePtr message) { DCHECK(message); DVLOG(2) << "Relaying message to receiver: " << message->json_format_data;
diff --git a/chrome/browser/media/router/providers/cast/mirroring_activity.h b/chrome/browser/media/router/providers/cast/mirroring_activity.h index ea87119..2ca6b41 100644 --- a/chrome/browser/media/router/providers/cast/mirroring_activity.h +++ b/chrome/browser/media/router/providers/cast/mirroring_activity.h
@@ -57,6 +57,8 @@ void OnError(mirroring::mojom::SessionError error) override; void DidStart() override; void DidStop() override; + void LogInfoMessage(const std::string& message) override; + void LogErrorMessage(const std::string& message) override; // CastMessageChannel implementation void Send(mirroring::mojom::CastMessagePtr message) override;
diff --git a/chrome/browser/metrics/browser_window_histogram_helper.cc b/chrome/browser/metrics/browser_window_histogram_helper.cc deleted file mode 100644 index 268ff6d..0000000 --- a/chrome/browser/metrics/browser_window_histogram_helper.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 "chrome/browser/metrics/browser_window_histogram_helper.h" - -#include "components/startup_metric_utils/browser/startup_metric_utils.h" - -BrowserWindowHistogramHelper::~BrowserWindowHistogramHelper() {} - -// static -std::unique_ptr<BrowserWindowHistogramHelper> -BrowserWindowHistogramHelper::MaybeRecordValueAndCreateInstanceOnBrowserPaint( - ui::Compositor* compositor) { - static bool did_first_paint = false; - if (did_first_paint) - return nullptr; - - did_first_paint = true; - - return std::unique_ptr<BrowserWindowHistogramHelper>( - new BrowserWindowHistogramHelper(compositor)); -} - -BrowserWindowHistogramHelper::BrowserWindowHistogramHelper( - ui::Compositor* compositor) { - startup_metric_utils::RecordBrowserWindowFirstPaint(base::TimeTicks::Now()); - -#if defined(OS_MAC) - if (!compositor) { - // In Cocoa version of Chromium, UI is rendered inside the main process - // using CoreAnimation compositor, and at this point everything is already - // visible to the user. - startup_metric_utils::RecordBrowserWindowFirstPaintCompositingEnded( - base::TimeTicks::Now()); - return; - } -#endif // OS_MAC - - scoped_observer_.Add(compositor); -} - -void BrowserWindowHistogramHelper::OnCompositingEnded( - ui::Compositor* compositor) { - startup_metric_utils::RecordBrowserWindowFirstPaintCompositingEnded( - base::TimeTicks::Now()); - - scoped_observer_.RemoveAll(); -} - -void BrowserWindowHistogramHelper::OnCompositingShuttingDown( - ui::Compositor* compositor) { - scoped_observer_.RemoveAll(); -}
diff --git a/chrome/browser/metrics/browser_window_histogram_helper.h b/chrome/browser/metrics/browser_window_histogram_helper.h deleted file mode 100644 index 648f3823..0000000 --- a/chrome/browser/metrics/browser_window_histogram_helper.h +++ /dev/null
@@ -1,46 +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 CHROME_BROWSER_METRICS_BROWSER_WINDOW_HISTOGRAM_HELPER_H_ -#define CHROME_BROWSER_METRICS_BROWSER_WINDOW_HISTOGRAM_HELPER_H_ - -#include <memory> - -#include "base/macros.h" -#include "base/scoped_observer.h" -#include "base/time/time.h" -#include "ui/compositor/compositor.h" -#include "ui/compositor/compositor_observer.h" - -// Class that encapsulates logic of recording -// Startup.BrowserWindow.FirstPaint* histograms. -// -// There's a dependency on ui/compositor therefore it can't be moved to -// components/startup_metrics_utils. -class BrowserWindowHistogramHelper : public ui::CompositorObserver { - public: - ~BrowserWindowHistogramHelper() override; - - // Call this when the Browser finishes painting its UI, and the user will see - // it after next Compositor frame swap. - // |compositor| is the compositor that composites the just-painted Browser - // widget, or nullptr in Cocoa (we're using CoreAnimation's compositor there). - // Returned object should stay alive until next |OnCompositingStarted| - // callback. - static std::unique_ptr<BrowserWindowHistogramHelper> - MaybeRecordValueAndCreateInstanceOnBrowserPaint(ui::Compositor* compositor); - - private: - explicit BrowserWindowHistogramHelper(ui::Compositor* compositor); - - // ui::CompositorObserver: - void OnCompositingEnded(ui::Compositor* compositor) override; - void OnCompositingShuttingDown(ui::Compositor* compositor) override; - - ScopedObserver<ui::Compositor, ui::CompositorObserver> scoped_observer_{this}; - - DISALLOW_COPY_AND_ASSIGN(BrowserWindowHistogramHelper); -}; - -#endif // CHROME_BROWSER_METRICS_BROWSER_WINDOW_HISTOGRAM_HELPER_H_
diff --git a/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc b/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc index 46769834..d789da77 100644 --- a/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc +++ b/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc
@@ -558,7 +558,6 @@ #endif ); -#if defined(OS_WIN) // Records whether or not PartitionAlloc-Everywhere is enabled, and whether // PCScan is enabled on top of it. This is meant for a 3-way experiment with 2 // binaries: @@ -581,11 +580,8 @@ "Disabled" #endif // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) ); -#endif // defined(OS_WIN) #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) - -#if defined(OS_WIN) // Records whether or not BackupRefPtr and/or PCScan is enabled. This is meant // for a 3-way experiment with 2 binaries: // - binary A: deployed to 66% users, with half of them having PCScan on and @@ -607,16 +603,6 @@ : "Disabled" #endif ); -#else // defined(OS_WIN) - ChromeMetricsServiceAccessor::RegisterSyntheticFieldTrial("BackupRefPtr", -#if BUILDFLAG(USE_BACKUP_REF_PTR) - "Enabled" -#else - "Disabled" -#endif - ); -#endif // defined(OS_WIN) - #endif // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) ChromeMetricsServiceAccessor::RegisterSyntheticFieldTrial(
diff --git a/chrome/browser/metrics/desktop_platform_features_metrics_provider.cc b/chrome/browser/metrics/desktop_platform_features_metrics_provider.cc index 85751fe..b79b6d61a 100644 --- a/chrome/browser/metrics/desktop_platform_features_metrics_provider.cc +++ b/chrome/browser/metrics/desktop_platform_features_metrics_provider.cc
@@ -11,6 +11,8 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/read_later/reading_list_model_factory.h" #include "components/reading_list/core/reading_list_model.h" #include "components/reading_list/features/reading_list_switches.h" @@ -27,6 +29,14 @@ kMaxValue = kDark, }; +bool AnyBrowserWindowHasName() { + for (auto* browser : *BrowserList::GetInstance()) { + if (!browser->user_title().empty()) + return true; + } + return false; +} + } // namespace DesktopPlatformFeaturesMetricsProvider:: @@ -59,4 +69,6 @@ } } } + + UMA_HISTOGRAM_BOOLEAN("Browser.AnyWindowHasName", AnyBrowserWindowHasName()); }
diff --git a/chrome/browser/metrics/startup_metrics_browsertest.cc b/chrome/browser/metrics/startup_metrics_browsertest.cc index 4edaf52..d8767df 100644 --- a/chrome/browser/metrics/startup_metrics_browsertest.cc +++ b/chrome/browser/metrics/startup_metrics_browsertest.cc
@@ -21,7 +21,6 @@ constexpr const char* kStartupMetrics[] = { "Startup.BrowserMessageLoopStartTime", "Startup.BrowserWindow.FirstPaint", - "Startup.BrowserWindow.FirstPaint.CompositingEnded", "Startup.BrowserWindowDisplay", "Startup.FirstWebContents.MainNavigationFinished", "Startup.FirstWebContents.MainNavigationStart",
diff --git a/chrome/browser/metrics/tab_stats/tab_stats_observer.h b/chrome/browser/metrics/tab_stats/tab_stats_observer.h index d246d85..fa25abb 100644 --- a/chrome/browser/metrics/tab_stats/tab_stats_observer.h +++ b/chrome/browser/metrics/tab_stats/tab_stats_observer.h
@@ -29,6 +29,11 @@ virtual void OnTabReplaced(content::WebContents* old_contents, content::WebContents* new_contents) {} + // Called whenever a main frame navigation is committed in any of the observed + // tabs. + virtual void OnMainFrameNavigationCommitted( + content::WebContents* web_contents) {} + // Records that there's been a direct user interaction with a tab, see the // comment for |DidGetUserInteraction| in // content/public/browser/web_contents_observer.h for a list of the possible
diff --git a/chrome/browser/metrics/tab_stats/tab_stats_tracker.cc b/chrome/browser/metrics/tab_stats/tab_stats_tracker.cc index 0d0a00d..df970bc 100644 --- a/chrome/browser/metrics/tab_stats/tab_stats_tracker.cc +++ b/chrome/browser/metrics/tab_stats/tab_stats_tracker.cc
@@ -285,6 +285,12 @@ navigation_time_ = navigation_handle->NavigationStart(); ukm_source_id_ = ukm::ConvertToSourceId( navigation_handle->GetNavigationId(), ukm::SourceIdType::NAVIGATION_ID); + + // Update observers. + for (TabStatsObserver& tab_stats_observer : + tab_stats_tracker_->tab_stats_observers_) { + tab_stats_observer.OnMainFrameNavigationCommitted(web_contents()); + } } void DidGetUserInteraction(const blink::WebInputEvent& event) override {
diff --git a/chrome/browser/metrics/tab_stats/tab_stats_tracker_unittest.cc b/chrome/browser/metrics/tab_stats/tab_stats_tracker_unittest.cc index 6f3be7f..7424f092 100644 --- a/chrome/browser/metrics/tab_stats/tab_stats_tracker_unittest.cc +++ b/chrome/browser/metrics/tab_stats/tab_stats_tracker_unittest.cc
@@ -15,6 +15,7 @@ #include "components/prefs/pref_registry_simple.h" #include "components/prefs/testing_pref_service.h" #include "content/public/browser/web_contents.h" +#include "content/public/test/navigation_simulator.h" #include "content/public/test/web_contents_tester.h" #include "testing/gtest/include/gtest/gtest.h" @@ -31,6 +32,22 @@ return base::StrCat({histogram_name, suffix}); } +class TestTabStatsObserver : public TabStatsObserver { + public: + // Functions used to update the counts. + void OnMainFrameNavigationCommitted( + content::WebContents* web_contents) override { + ++main_frame_committed_navigations_count_; + } + + size_t main_frame_committed_navigations_count() { + return main_frame_committed_navigations_count_; + } + + private: + size_t main_frame_committed_navigations_count_ = 0; +}; + class TestTabStatsTracker : public TabStatsTracker { public: using TabStatsTracker::OnHeartbeatEvent; @@ -191,6 +208,27 @@ } // namespace +TEST_F(TabStatsTrackerTest, MainFrameCommittedNavigationTriggersUpdate) { + constexpr const char kFirstUrl[] = "https://parent.com/"; + + TestTabStatsObserver tab_stats_observer; + tab_stats_tracker_->AddObserverAndSetInitialState(&tab_stats_observer); + // Number of navigations starts of at zero. + ASSERT_EQ(tab_stats_observer.main_frame_committed_navigations_count(), 0u); + + // Insert a new tab. + std::unique_ptr<content::WebContents> web_contents = CreateTestWebContents(); + tab_stats_tracker_->OnInitialOrInsertedTab(web_contents.get()); + + // Commit a main frame navigation on the observed tab. + auto* parent = content::NavigationSimulator::NavigateAndCommitFromBrowser( + web_contents.get(), GURL(kFirstUrl)); + DCHECK(parent); + + // Navigation registered. + ASSERT_EQ(tab_stats_observer.main_frame_committed_navigations_count(), 1u); +} + TEST_F(TabStatsTrackerTest, OnResume) { // Makes sure that there's no sample initially. histogram_tester_.ExpectTotalCount(
diff --git a/chrome/browser/metrics/usage_scenario/tab_usage_scenario_tracker.cc b/chrome/browser/metrics/usage_scenario/tab_usage_scenario_tracker.cc index 3763f969..bee2eb3 100644 --- a/chrome/browser/metrics/usage_scenario/tab_usage_scenario_tracker.cc +++ b/chrome/browser/metrics/usage_scenario/tab_usage_scenario_tracker.cc
@@ -137,4 +137,10 @@ } } +void TabUsageScenarioTracker::OnMainFrameNavigationCommitted( + content::WebContents* web_contents) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + usage_scenario_data_store_->OnTopLevelNavigation(); +} + } // namespace metrics
diff --git a/chrome/browser/metrics/usage_scenario/tab_usage_scenario_tracker.h b/chrome/browser/metrics/usage_scenario/tab_usage_scenario_tracker.h index 1d7e0fe..5bcadbf 100644 --- a/chrome/browser/metrics/usage_scenario/tab_usage_scenario_tracker.h +++ b/chrome/browser/metrics/usage_scenario/tab_usage_scenario_tracker.h
@@ -39,6 +39,8 @@ void OnTabInteraction(content::WebContents* web_contents) override; void OnMediaEffectivelyFullscreenChanged(content::WebContents* web_contents, bool is_fullscreen) override; + void OnMainFrameNavigationCommitted( + content::WebContents* web_contents) override; // display::DisplayObserver: void OnDisplayAdded(const display::Display& new_display) override;
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc index cf9f5f3..f4803b8 100644 --- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc +++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc
@@ -25,6 +25,7 @@ #include "chrome/browser/heavy_ad_intervention/heavy_ad_service_factory.h" #include "chrome/common/chrome_features.h" #include "components/page_load_metrics/browser/metrics_web_contents_observer.h" +#include "components/page_load_metrics/browser/page_load_metrics_memory_tracker.h" #include "components/page_load_metrics/browser/page_load_metrics_util.h" #include "components/page_load_metrics/browser/resource_tracker.h" #include "components/page_load_metrics/common/page_end_reason.h" @@ -70,25 +71,6 @@ const base::Feature kRestrictedNavigationAdTagging{ "RestrictedNavigationAdTagging", base::FEATURE_ENABLED_BY_DEFAULT}; -// Enables or disables per-frame memory monitoring. -const base::Feature kV8PerAdFrameMemoryMonitoring{ - "V8PerAdFrameMemoryMonitoring", base::FEATURE_DISABLED_BY_DEFAULT}; - -// Minimum time between memory measurements. -const base::FeatureParam<int> kMemoryPollInterval = { - &kV8PerAdFrameMemoryMonitoring, "MemoryPollInterval", 40}; - -// Available memory measurement modes. -const base::FeatureParam<MeasurementMode>::Option memory_poll_modes[] = { - {MeasurementMode::kLazy, "lazy"}, - {MeasurementMode::kBounded, "bounded"}, - {MeasurementMode::kEagerForTesting, "eager_for_testing"}}; - -// Memory measurement mode. -const base::FeatureParam<MeasurementMode> kMemoryPollMode = { - &kV8PerAdFrameMemoryMonitoring, "MemoryPollMode", MeasurementMode::kLazy, - &memory_poll_modes}; - } // namespace features namespace { @@ -259,10 +241,7 @@ std::make_unique<HeavyAdThresholdNoiseProvider>( heavy_ad_privacy_mitigations_enabled_ /* use_noise */)) {} -AdsPageLoadMetricsObserver::~AdsPageLoadMetricsObserver() { - if (memory_request_) - memory_request_->RemoveObserver(this); -} +AdsPageLoadMetricsObserver::~AdsPageLoadMetricsObserver() = default; page_load_metrics::PageLoadMetricsObserver::ObservePolicy AdsPageLoadMetricsObserver::OnStart( @@ -429,18 +408,6 @@ previous_data->UpdateForNavigation(ad_host, frame_navigated); return; } - if (base::FeatureList::IsEnabled(features::kV8PerAdFrameMemoryMonitoring) && - !memory_request_) { - // The first ad subframe has been detected, so instantiate the - // memory request and add AdsPLMO as an observer. Without any ads, there - // would be no reason to monitor ad-frame memory usage and - // |memory_request_| wouldn't be needed. - memory_request_ = std::make_unique< - performance_manager::v8_memory::V8DetailedMemoryRequestAnySeq>( - base::TimeDelta::FromSeconds(features::kMemoryPollInterval.Get()), - features::kMemoryPollMode.Get()); - memory_request_->AddObserver(this); - } // Construct a new FrameTreeData to track this ad frame, and update it for // the navigation. @@ -716,37 +683,27 @@ ad_frames_data_.erase(id_and_data); } -void AdsPageLoadMetricsObserver::OnV8MemoryMeasurementAvailable( - performance_manager::RenderProcessHostId render_process_host_id, - const performance_manager::v8_memory::V8DetailedMemoryProcessData& - process_data, - const V8DetailedMemoryObserverAnySeq::FrameDataMap& frame_data) { - num_memory_updates_++; +void AdsPageLoadMetricsObserver::OnV8MemoryChanged( + const std::vector<page_load_metrics::MemoryUpdate>& memory_updates) { + for (const auto& update : memory_updates) { + memory_update_count_++; - // Iterate through frames with available measurements. - for (const auto& map_pair : frame_data) { - content::GlobalFrameRoutingId frame_routing_id = map_pair.first; - content::RenderFrameHost* rfh = - content::RenderFrameHost::FromID(frame_routing_id); + content::RenderFrameHost* render_frame_host = + content::RenderFrameHost::FromID(update.routing_id); - if (!rfh) { - num_missed_memory_measurements_++; + if (!render_frame_host) continue; - } - uint64_t bytes_used = map_pair.second.v8_bytes_used(); - - FrameTreeNodeId frame_node_id = rfh->GetFrameTreeNodeId(); + FrameTreeNodeId frame_node_id = render_frame_host->GetFrameTreeNodeId(); FrameTreeData* ad_frame_data = FindFrameData(frame_node_id); if (ad_frame_data) { - int64_t delta = UpdateMemoryUsageForFrame(frame_node_id, bytes_used); - ad_frame_data->UpdateMemoryUsage(delta); - UpdateAggregateMemoryUsage(delta, ad_frame_data->visibility()); - } else if (!rfh->GetParent()) { - // |rfh| is the main frame. - int64_t delta = UpdateMemoryUsageForFrame(frame_node_id, bytes_used); - aggregate_frame_data_->update_main_frame_memory(delta); + ad_frame_data->UpdateMemoryUsage(update.delta_bytes); + UpdateAggregateMemoryUsage(update.delta_bytes, + ad_frame_data->visibility()); + } else if (!render_frame_host->GetParent()) { + // |render_frame_host| is the main frame. + aggregate_frame_data_->update_main_frame_memory(update.delta_bytes); } } } @@ -803,33 +760,6 @@ return is_new_ad ? resource->received_data_length - resource->delta_bytes : 0; } -int64_t AdsPageLoadMetricsObserver::UpdateMemoryUsageForFrame( - FrameTreeNodeId frame_node_id, - uint64_t current_bytes) { - auto it = v8_current_memory_usage_map_.find(frame_node_id); - - if (it == v8_current_memory_usage_map_.end()) { - v8_current_memory_usage_map_[frame_node_id] = current_bytes; - return current_bytes; - } - - int64_t delta = current_bytes - it->second; - it->second = current_bytes; - return delta; -} - -int64_t AdsPageLoadMetricsObserver::RemoveMemoryUsageForFrame( - FrameTreeNodeId frame_node_id) { - auto it = v8_current_memory_usage_map_.find(frame_node_id); - - if (it == v8_current_memory_usage_map_.end()) - return 0; - - int64_t delta = -it->second; - v8_current_memory_usage_map_.erase(it); - return delta; -} - void AdsPageLoadMetricsObserver::ProcessResourceForPage( int process_id, const page_load_metrics::mojom::ResourceDataUpdatePtr& resource) { @@ -1050,8 +980,7 @@ visibility, visibility_data.bytes); ADS_HISTOGRAM("Bytes.AdFrames.Aggregate.Network", PAGE_BYTES_HISTOGRAM, visibility, visibility_data.network_bytes); - - if (memory_request_) { + if (base::FeatureList::IsEnabled(features::kV8PerFrameMemoryMonitoring)) { ADS_HISTOGRAM("Memory.Aggregate.Max", PAGE_BYTES_HISTOGRAM, visibility, visibility_data.memory.max_bytes_used()); } @@ -1071,14 +1000,11 @@ main_frame_resource_data.ad_network_bytes()); ADS_HISTOGRAM("Bytes.MainFrame.Ads.Total2", PAGE_BYTES_HISTOGRAM, visibility, main_frame_resource_data.ad_bytes()); - if (memory_request_) { + if (base::FeatureList::IsEnabled(features::kV8PerFrameMemoryMonitoring)) { PAGE_BYTES_HISTOGRAM("PageLoad.Clients.Ads.Memory.MainFrame.Max", aggregate_frame_data_->main_frame_max_memory()); UMA_HISTOGRAM_COUNTS_10000("PageLoad.Clients.Ads.Memory.UpdateCount", - num_memory_updates_); - UMA_HISTOGRAM_COUNTS_1000( - "PageLoad.Clients.Ads.Memory.MissedMeasurementCount", - num_missed_memory_measurements_); + memory_update_count_); } } @@ -1166,7 +1092,7 @@ visibility, resource_data.bytes()); ADS_HISTOGRAM("Bytes.AdFrames.PerFrame.Network", PAGE_BYTES_HISTOGRAM, visibility, resource_data.network_bytes()); - if (memory_request_) { + if (base::FeatureList::IsEnabled(features::kV8PerFrameMemoryMonitoring)) { ADS_HISTOGRAM("Memory.PerFrame.Max", PAGE_BYTES_HISTOGRAM, visibility, ad_frame_data.v8_max_memory_bytes_used()); } @@ -1465,10 +1391,6 @@ if (!frame_data) return; - int64_t delta_bytes = RemoveMemoryUsageForFrame(id); - frame_data->UpdateMemoryUsage(delta_bytes); - UpdateAggregateMemoryUsage(delta_bytes, frame_data->visibility()); - if (record_metrics) RecordPerFrameMetrics(*frame_data, GetDelegate().GetPageUkmSourceId());
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.h index 2a10fc1..01970ce 100644 --- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.h +++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.h
@@ -21,22 +21,14 @@ #include "components/blocklist/opt_out_blocklist/opt_out_blocklist_data.h" #include "components/page_load_metrics/browser/page_load_metrics_observer.h" #include "components/page_load_metrics/common/page_load_metrics.mojom-forward.h" -#include "components/performance_manager/public/v8_memory/v8_detailed_memory.h" #include "components/subresource_filter/content/browser/subresource_filter_observer.h" #include "components/subresource_filter/content/browser/subresource_filter_observer_manager.h" #include "components/subresource_filter/core/common/load_policy.h" #include "net/http/http_response_info.h" #include "services/metrics/public/cpp/ukm_source.h" -using MeasurementMode = - performance_manager::v8_memory::V8DetailedMemoryRequest::MeasurementMode; - namespace features { extern const base::Feature kRestrictedNavigationAdTagging; -extern const base::Feature kV8PerAdFrameMemoryMonitoring; -extern const base::FeatureParam<int> kMemoryPollInterval; -extern const base::FeatureParam<MeasurementMode>::Option memory_poll_modes[]; -extern const base::FeatureParam<MeasurementMode> kMemoryPollMode; } class HeavyAdBlocklist; @@ -45,7 +37,6 @@ // relevant per-frame and whole-page byte statistics. class AdsPageLoadMetricsObserver : public page_load_metrics::PageLoadMetricsObserver, - public performance_manager::v8_memory::V8DetailedMemoryObserverAnySeq, public subresource_filter::SubresourceFilterObserver { public: using AggregateFrameData = ad_metrics::AggregateFrameData; @@ -136,12 +127,8 @@ heavy_ad_threshold_noise_provider_ = std::move(noise_provider); } - // performance_manager::v8_memory::V8DetailedMemoryObserverAnySeq - void OnV8MemoryMeasurementAvailable( - performance_manager::RenderProcessHostId render_process_host_id, - const performance_manager::v8_memory::V8DetailedMemoryProcessData& - process_data, - const V8DetailedMemoryObserverAnySeq::FrameDataMap& frame_data) override; + void OnV8MemoryChanged(const std::vector<page_load_metrics::MemoryUpdate>& + memory_updates) override; void UpdateAggregateMemoryUsage(int64_t bytes, ad_metrics::FrameVisibility visibility); @@ -209,14 +196,6 @@ int process_id, const page_load_metrics::mojom::ResourceDataUpdatePtr& resource) const; - // Looks up the |frame_node_id| in the current memory usage map, updates it - // with the current bytes (or removes it), and returns the - // difference between the new value (0 if removed) and the old one, or the - // delta in the amount of memory the frame is using. - int64_t UpdateMemoryUsageForFrame(FrameTreeNodeId frame_node_id, - uint64_t current_bytes); - int64_t RemoveMemoryUsageForFrame(FrameTreeNodeId frame_node_id); - // Updates page level counters for resource loads. void ProcessResourceForPage( int process_id, @@ -340,17 +319,8 @@ // The maximum ad density measurements for the page during its lifecycle. PageAdDensityTracker page_ad_density_tracker_; - // Tracks per ad-frame V8 memory measurements for the page during its - // lifecycle. Lazily initialized when the first ad is detected. - std::unique_ptr<performance_manager::v8_memory::V8DetailedMemoryRequestAnySeq> - memory_request_; - // Tracks number of memory updates received. - int num_memory_updates_ = 0; - - // Tracks number of per-frame memory measurements missed due to receipt - // after the corresponding RenderFrameHost has been destroyed. - int num_missed_memory_measurements_ = 0; + int memory_update_count_ = 0; DISALLOW_COPY_AND_ASSIGN(AdsPageLoadMetricsObserver); };
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc index 805a89b4..3dbd4d84 100644 --- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc +++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc
@@ -23,7 +23,9 @@ #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" #include "components/page_load_metrics/browser/observers/use_counter_page_load_metrics_observer.h" +#include "components/page_load_metrics/browser/page_load_metrics_memory_tracker.h" #include "components/page_load_metrics/browser/page_load_metrics_test_waiter.h" +#include "components/performance_manager/public/v8_memory/v8_detailed_memory.h" #include "components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h" #include "components/subresource_filter/content/browser/ruleset_service.h" #include "components/subresource_filter/core/browser/subresource_filter_features.h" @@ -199,7 +201,7 @@ void SetUp() override { std::vector<base::Feature> enabled = { subresource_filter::kAdTagging, features::kSitePerProcess, - features::kV8PerAdFrameMemoryMonitoring}; + features::kV8PerFrameMemoryMonitoring}; std::vector<base::Feature> disabled = {}; scoped_feature_list_.InitWithFeatures(enabled, disabled); @@ -2249,7 +2251,7 @@ std::vector<base::test::ScopedFeatureList::FeatureAndParams> enabled = { {subresource_filter::kAdTagging, {{}}}, {features::kSitePerProcess, {{}}}, - {features::kV8PerAdFrameMemoryMonitoring, memory_poll_params}}; + {features::kV8PerFrameMemoryMonitoring, memory_poll_params}}; std::vector<base::Feature> disabled = {}; scoped_feature_list_.InitWithFeaturesAndParameters(enabled, disabled); @@ -2282,12 +2284,14 @@ SingleAdFrame_MaxMemoryBytesRecorded) { base::HistogramTester histogram_tester; - // Instantiate a memory request and waiter to wait for a minimum - // number of memory measurements to be received. + // Instantiate a memory request and waiter to wait for expected + // memory measurements to be received. std::unique_ptr<performance_manager::v8_memory::V8DetailedMemoryRequestAnySeq> memory_request = std::make_unique< performance_manager::v8_memory::V8DetailedMemoryRequestAnySeq>( - base::TimeDelta::FromSeconds(1), MeasurementMode::kEagerForTesting); + base::TimeDelta::FromSeconds(1), + performance_manager::v8_memory::V8DetailedMemoryRequest:: + MeasurementMode::kEagerForTesting); auto waiter = std::make_unique<MemoryMeasurementWaiter>(); memory_request->AddObserver(waiter.get());
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc index bd5bc70a..8cda3d2 100644 --- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc +++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc
@@ -31,6 +31,7 @@ #include "components/blocklist/opt_out_blocklist/opt_out_store.h" #include "components/page_load_metrics/browser/metrics_web_contents_observer.h" #include "components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.h" +#include "components/page_load_metrics/browser/page_load_metrics_memory_tracker.h" #include "components/page_load_metrics/browser/page_load_metrics_observer.h" #include "components/page_load_metrics/browser/page_load_tracker.h" #include "components/page_load_metrics/common/page_load_metrics_util.h" @@ -71,15 +72,8 @@ namespace { -using FrameDataMap = - AdsPageLoadMetricsObserver::V8DetailedMemoryObserverAnySeq::FrameDataMap; using FrameTreeNodeId = int; -struct MemoryFrameData { - int frame_id; - uint64_t bytes_used; -}; - struct ExpectedFrameBytes { ExpectedFrameBytes(size_t cached_kb, size_t uncached_kb) : cached_kb(cached_kb), uncached_kb(uncached_kb) {} @@ -137,21 +131,6 @@ AdsPageLoadMetricsObserver::HeavyAdThresholdNoiseProvider:: kMaxNetworkThresholdNoiseBytes; -FrameDataMap MakeFrameDataMap(int process_id, - std::vector<MemoryFrameData> data) { - FrameDataMap data_map; - - for (const auto& entry : data) { - content::GlobalFrameRoutingId global_id(process_id, entry.frame_id); - performance_manager::v8_memory::V8DetailedMemoryExecutionContextData - frame_data; - frame_data.set_v8_bytes_used(entry.bytes_used); - data_map[global_id] = frame_data; - } - - return data_map; -} - // Calls PopulateRequiredTimingFields with |first_eligible_to_paint| and // |first_contentful_paint| fields temporarily nullified. void PopulateRequiredTimingFieldsExceptFEtPAndFCP( @@ -819,20 +798,9 @@ "Activated.PostActivation"); } - void OnV8MemoryMeasurementAvailable( - content::RenderProcessHost* render_process_host, - const std::vector<MemoryFrameData>& memory_data) { - int process_id = render_process_host->GetID(); - performance_manager::RenderProcessHostId pm_process_id = - static_cast<performance_manager::RenderProcessHostId>(process_id); - - FrameDataMap frame_data = MakeFrameDataMap(process_id, memory_data); - performance_manager::v8_memory::V8DetailedMemoryProcessData process_data; - - if (ads_observer_) { - ads_observer_->OnV8MemoryMeasurementAvailable(pm_process_id, process_data, - frame_data); - } + void SimulateV8MemoryChange(content::RenderFrameHost* render_frame_host, + int64_t delta_bytes) { + tester()->SimulateMemoryUpdate(render_frame_host, delta_bytes); } private: @@ -2962,7 +2930,7 @@ public: void SetUp() override { scoped_feature_list_.InitAndEnableFeature( - features::kV8PerAdFrameMemoryMonitoring); + features::kV8PerFrameMemoryMonitoring); AdsPageLoadMetricsObserverTest::SetUp(); } @@ -2973,170 +2941,126 @@ TEST_F(AdsMemoryMeasurementTest, SingleAdFrame_MaxMemoryBytesRecorded) { RenderFrameHost* main_frame = NavigateMainFrame(kNonAdUrl); RenderFrameHost* ad_frame = CreateAndNavigateSubFrame(kAdUrl, main_frame); - content::RenderProcessHost* process = ad_frame->GetProcess(); // Load kilobytes in frame so that aggregates are recorded. ResourceDataUpdate(ad_frame, ResourceCached::kNotCached, 10); - // Set initial memory usage data. - std::vector<MemoryFrameData> memory_data = { - {ad_frame->GetRoutingID(), 10 * 1024 /* bytes_used */}}; - // Notify that memory measurement is available. - OnV8MemoryMeasurementAvailable(process, memory_data); + SimulateV8MemoryChange(ad_frame, 10 * 1024); - // Update memory usage. The max will change, as - // 40 > 10. - memory_data[0].bytes_used = 40 * 1024; - OnV8MemoryMeasurementAvailable(process, memory_data); + // Update memory usage. The max will change, as 30 is positive. + SimulateV8MemoryChange(ad_frame, 30 * 1024); - // Update memory usage. The max will remain the same, as - // 20 < 40. - memory_data[0].bytes_used = 20 * 1024; - OnV8MemoryMeasurementAvailable(process, memory_data); + // Update memory usage. The max will remain the same, as -20 is negative. + SimulateV8MemoryChange(ad_frame, -20 * 1024); // Navigate main frame to record histograms. NavigateMainFrame(kNonAdUrl); - histogram_tester().ExpectUniqueSample(kMemoryPerFrameMaxHistogramId, 40, 1); - histogram_tester().ExpectUniqueSample(kMemoryAggregateMaxHistogramId, 40, 1); + histogram_tester().ExpectUniqueSample(kMemoryPerFrameMaxHistogramId, 10 + 30, + 1); + histogram_tester().ExpectUniqueSample(kMemoryAggregateMaxHistogramId, 10 + 30, + 1); histogram_tester().ExpectUniqueSample(kMemoryUpdateCountHistogramId, 3, 1); } -TEST_F(AdsMemoryMeasurementTest, - MultiAdFramesSingleProcess_MaxMemoryBytesRecorded) { +TEST_F(AdsMemoryMeasurementTest, MultiAdFramesNested_MaxMemoryBytesRecorded) { RenderFrameHost* main_frame = NavigateMainFrame(kNonAdUrl); RenderFrameHost* ad_frame1 = CreateAndNavigateSubFrame(kAdUrl, main_frame); - content::RenderProcessHost* process1 = ad_frame1->GetProcess(); // Create a nested subframe with the same origin as its parent. RenderFrameHost* ad_frame2 = CreateAndNavigateSubFrame(kAdUrl, ad_frame1); - content::RenderProcessHost* process2 = ad_frame2->GetProcess(); - - // Expect a parent and child with the same origin on the same page - // to be hosted by the same process. - EXPECT_EQ(process1->GetID(), process2->GetID()); // Load kilobytes in each frame so that aggregates are recorded. ResourceDataUpdate(ad_frame1, ResourceCached::kNotCached, 10); ResourceDataUpdate(ad_frame2, ResourceCached::kNotCached, 10); - // Set initial memory usage data. - std::vector<MemoryFrameData> memory_data = { - {ad_frame1->GetRoutingID(), 10 * 1024 /* bytes_used */}, - {ad_frame2->GetRoutingID(), 10 * 1024 /* bytes_used */}}; - // Notify that memory measurement is available. - OnV8MemoryMeasurementAvailable(process1, memory_data); + SimulateV8MemoryChange(ad_frame1, 10 * 1024); + SimulateV8MemoryChange(ad_frame2, 10 * 1024); // Update memory usage. The max will change, as these values are both - // greater than the initial values. - memory_data[0].bytes_used = 40 * 1024; - memory_data[1].bytes_used = 20 * 1024; - OnV8MemoryMeasurementAvailable(process1, memory_data); + // positive. + SimulateV8MemoryChange(ad_frame1, 30 * 1024); + SimulateV8MemoryChange(ad_frame2, 10 * 1024); // Update memory usage. The max will remain the same, as these values - // are both less than the previous values. - memory_data[0].bytes_used = 5 * 1024; - memory_data[1].bytes_used = 15 * 1024; - OnV8MemoryMeasurementAvailable(process1, memory_data); + // are both negative. + SimulateV8MemoryChange(ad_frame1, -25 * 1024); + SimulateV8MemoryChange(ad_frame2, -5 * 1024); // Navigate main frame to record histograms. NavigateMainFrame(kNonAdUrl); - histogram_tester().ExpectUniqueSample(kMemoryPerFrameMaxHistogramId, 40 + 20, - 1); - histogram_tester().ExpectUniqueSample(kMemoryAggregateMaxHistogramId, 40 + 20, - 1); - histogram_tester().ExpectUniqueSample(kMemoryUpdateCountHistogramId, 3, 1); + histogram_tester().ExpectUniqueSample(kMemoryPerFrameMaxHistogramId, + 10 + 10 + 30 + 10, 1); + histogram_tester().ExpectUniqueSample(kMemoryAggregateMaxHistogramId, + 10 + 10 + 30 + 10, 1); + histogram_tester().ExpectUniqueSample(kMemoryUpdateCountHistogramId, 6, 1); } TEST_F(AdsMemoryMeasurementTest, - MultiAdFramesMultiProcess_MaxMemoryBytesRecorded) { + MultiAdFramesNonNested_MaxMemoryBytesRecorded) { RenderFrameHost* main_frame = NavigateMainFrame(kNonAdUrl); RenderFrameHost* ad_frame1 = CreateAndNavigateSubFrame(kAdUrl, main_frame); - content::RenderProcessHost* process1 = ad_frame1->GetProcess(); // Create another ad subframe with a different origin. RenderFrameHost* ad_frame2 = CreateAndNavigateSubFrame(kOtherAdUrl, main_frame); - content::RenderProcessHost* process2 = ad_frame2->GetProcess(); - - // Only continue the test if the frames have different processes. - // Older versions of Android do not have site isolation. - if (process1->GetID() == process2->GetID()) - return; // Load kilobytes in each frame so that aggregates are recorded. ResourceDataUpdate(ad_frame1, ResourceCached::kNotCached, 10); ResourceDataUpdate(ad_frame2, ResourceCached::kNotCached, 10); - // Set initial memory usage data. - std::vector<MemoryFrameData> memory_data1 = { - {ad_frame1->GetRoutingID(), 10 * 1024 /* bytes_used */}}; - std::vector<MemoryFrameData> memory_data2 = { - {ad_frame2->GetRoutingID(), 10 * 1024 /* bytes_used */}}; - // Notify that memory measurement is available. - OnV8MemoryMeasurementAvailable(process1, memory_data1); - OnV8MemoryMeasurementAvailable(process2, memory_data2); + SimulateV8MemoryChange(ad_frame1, 10 * 1024); + SimulateV8MemoryChange(ad_frame2, 10 * 1024); // Update memory usage. The second max and aggregate max // will change. - memory_data1[0].bytes_used = 1 * 1024; - memory_data2[0].bytes_used = 100 * 1024; - OnV8MemoryMeasurementAvailable(process1, memory_data1); - OnV8MemoryMeasurementAvailable(process2, memory_data2); + SimulateV8MemoryChange(ad_frame1, -9 * 1024); + SimulateV8MemoryChange(ad_frame2, 100 * 1024); // Update memory usage. The aggregate max will change // again after the first update. - memory_data1[0].bytes_used = 2 * 1024; - memory_data2[0].bytes_used = 20 * 1024; - OnV8MemoryMeasurementAvailable(process1, memory_data1); - OnV8MemoryMeasurementAvailable(process2, memory_data2); + SimulateV8MemoryChange(ad_frame1, 1 * 1024); + SimulateV8MemoryChange(ad_frame2, -90 * 1024); // Update memory usage. The first max will change. - memory_data1[0].bytes_used = 50 * 1024; - memory_data2[0].bytes_used = 5 * 1024; - OnV8MemoryMeasurementAvailable(process1, memory_data1); - OnV8MemoryMeasurementAvailable(process2, memory_data2); + SimulateV8MemoryChange(ad_frame1, 50 * 1024); + SimulateV8MemoryChange(ad_frame2, -5 * 1024); // Navigate main frame to record histograms. NavigateMainFrame(kNonAdUrl); - histogram_tester().ExpectBucketCount(kMemoryPerFrameMaxHistogramId, 50, 1); - histogram_tester().ExpectBucketCount(kMemoryPerFrameMaxHistogramId, 100, 1); - histogram_tester().ExpectUniqueSample(kMemoryAggregateMaxHistogramId, 2 + 100, - 1); + histogram_tester().ExpectBucketCount(kMemoryPerFrameMaxHistogramId, + 10 - 9 + 1 + 50, 1); + histogram_tester().ExpectBucketCount(kMemoryPerFrameMaxHistogramId, 10 + 100, + 1); + histogram_tester().ExpectUniqueSample(kMemoryAggregateMaxHistogramId, + 10 - 9 + 10 + 100 + 1, 1); histogram_tester().ExpectUniqueSample(kMemoryUpdateCountHistogramId, 8, 1); } TEST_F(AdsMemoryMeasurementTest, MainFrame_MaxMemoryBytesRecorded) { RenderFrameHost* main_frame = NavigateMainFrame(kNonAdUrl); RenderFrameHost* ad_frame = CreateAndNavigateSubFrame(kAdUrl, main_frame); - content::RenderProcessHost* process = main_frame->GetProcess(); - // Load kilobytes in each frame. |ad_frame| must be used for the test to - // compile. + // Load kilobytes in each frame. |ad_frame| must exist for ad metrics to be + // tracked. ResourceDataUpdate(main_frame, ResourceCached::kNotCached, 1000); ResourceDataUpdate(ad_frame, ResourceCached::kNotCached, 10); - // Set initial memory usage data. - std::vector<MemoryFrameData> memory_data = { - {main_frame->GetRoutingID(), 1000 * 1024 /* bytes_used */}}; - // Notify that memory measurement is available. - OnV8MemoryMeasurementAvailable(process, memory_data); + SimulateV8MemoryChange(main_frame, 1000 * 1024); - // Update memory usage. The max will also change, as this value is greater - // than the initial value. - memory_data[0].bytes_used = 2000 * 1024; - OnV8MemoryMeasurementAvailable(process, memory_data); + // Update memory usage. The max will also change, as this value is + // positive. + SimulateV8MemoryChange(main_frame, 1000 * 1024); - // Update memory usage. The max will remain the same, as this value is less - // than the previous value. - memory_data[0].bytes_used = 20 * 1024; - OnV8MemoryMeasurementAvailable(process, memory_data); + // Update memory usage. The max will remain the same, as this value is + // negative. + SimulateV8MemoryChange(main_frame, -1980 * 1024); // Navigate to record histograms. NavigateFrame(kNonAdUrl, main_frame); @@ -3145,41 +3069,3 @@ 1); histogram_tester().ExpectUniqueSample(kMemoryUpdateCountHistogramId, 3, 1); } - -TEST_F(AdsMemoryMeasurementTest, AdFrameDeleted_MaxMemoryBytesRecorded) { - RenderFrameHost* main_frame = NavigateMainFrame(kNonAdUrl); - RenderFrameHost* ad_frame1 = CreateAndNavigateSubFrame(kAdUrl, main_frame); - content::RenderProcessHost* process1 = ad_frame1->GetProcess(); - - // Create a nested subframe with the same origin as its parent. - RenderFrameHost* ad_frame2 = CreateAndNavigateSubFrame(kAdUrl, ad_frame1); - - // Load kilobytes in each frame so that aggregates are recorded. - ResourceDataUpdate(ad_frame1, ResourceCached::kNotCached, 100); - ResourceDataUpdate(ad_frame2, ResourceCached::kNotCached, 100); - - // Set initial memory usage data. - std::vector<MemoryFrameData> memory_data1 = { - {ad_frame1->GetRoutingID(), 100 * 1024 /* bytes_used */}, - {ad_frame2->GetRoutingID(), 100 * 1024 /* bytes_used */}}; - - // Notify that memory measurement is available. - OnV8MemoryMeasurementAvailable(process1, memory_data1); - - // Delete |ad_frame2|. The corresponding per-frame memory data will be - // deleted, changing the current usage, but the max will remain the same. - content::RenderFrameHostTester::For(ad_frame2)->Detach(); - - // Update memory usage. The max will change, as this value is - // greater than the sum of the initial values. - std::vector<MemoryFrameData> memory_data2 = { - {ad_frame1->GetRoutingID(), 500 * 1024 /* bytes_used */}}; - OnV8MemoryMeasurementAvailable(process1, memory_data2); - - // Navigate main frame to record histograms. - NavigateMainFrame(kNonAdUrl); - - histogram_tester().ExpectUniqueSample(kMemoryPerFrameMaxHistogramId, 500, 1); - histogram_tester().ExpectUniqueSample(kMemoryAggregateMaxHistogramId, 500, 1); - histogram_tester().ExpectUniqueSample(kMemoryUpdateCountHistogramId, 2, 1); -}
diff --git a/chrome/browser/page_load_metrics/observers/core/ukm_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/core/ukm_page_load_metrics_observer.cc index 4613d0c..0a633c6 100644 --- a/chrome/browser/page_load_metrics/observers/core/ukm_page_load_metrics_observer.cc +++ b/chrome/browser/page_load_metrics/observers/core/ukm_page_load_metrics_observer.cc
@@ -13,6 +13,7 @@ #include "base/metrics/histogram_macros.h" #include "base/timer/elapsed_timer.h" #include "base/trace_event/common/trace_event_common.h" +#include "build/build_config.h" #include "cc/metrics/ukm_smoothness_data.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/content_settings/cookie_settings_factory.h" @@ -53,6 +54,11 @@ #include "chrome/browser/offline_pages/offline_page_tab_helper.h" #endif +#if !defined(OS_ANDROID) +#include "chrome/browser/ui/browser_finder.h" +#include "chrome/browser/ui/tabs/tab_strip_model.h" +#endif // !defined(OS_ANDROID) + namespace { const char kOfflinePreviewsMimeType[] = "multipart/related"; @@ -251,6 +257,19 @@ ->GetSiteInstance() ->GetLastProcessAssignmentOutcome(); + // Android has a different tab model, and will need its own implementation. +#if !defined(OS_ANDROID) + auto* contents = navigation_handle->GetWebContents(); + DCHECK(contents); + if (Browser* browser = chrome::FindBrowserWithWebContents(contents)) { + int tab_index = browser->tab_strip_model()->GetIndexOfWebContents(contents); + if (tab_index != TabStripModel::kNoTab && + browser->tab_strip_model()->GetTabGroupForTab(tab_index).has_value()) { + memories_signals_.is_existing_part_of_tab_group = true; + } + } +#endif // !defined(OS_ANDROID) + return CONTINUE_OBSERVING; } @@ -798,7 +817,7 @@ builder.SetNavigationEntryOffset(navigation_entry_offset_); builder.SetMainDocumentSequenceNumber(main_document_sequence_number_); } - builder.SetOmniboxUrlCopied(omnibox_url_copied_); + builder.Record(ukm::UkmRecorder::Get()); } @@ -1111,6 +1130,11 @@ if (timing) RecordAbortMetrics(*timing, page_end_time, &builder); + // Add Memories signals to UKM. + builder.SetOmniboxUrlCopied(memories_signals_.omnibox_url_copied); + builder.SetIsExistingPartOfTabGroup( + memories_signals_.is_existing_part_of_tab_group); + builder.Record(ukm::UkmRecorder::Get()); } @@ -1223,7 +1247,7 @@ page_load_metrics::PageLoadMetricsEvent event) { if (event == page_load_metrics::PageLoadMetricsEvent:: OMNIBOX_URL_COPIED_TO_CLIPBOARD) { - omnibox_url_copied_ = true; + memories_signals_.omnibox_url_copied = true; } }
diff --git a/chrome/browser/page_load_metrics/observers/core/ukm_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/core/ukm_page_load_metrics_observer.h index 24f797b..c03af51a 100644 --- a/chrome/browser/page_load_metrics/observers/core/ukm_page_load_metrics_observer.h +++ b/chrome/browser/page_load_metrics/observers/core/ukm_page_load_metrics_observer.h
@@ -287,9 +287,17 @@ base::ReadOnlySharedMemoryMapping ukm_smoothness_data_; - // True if the user has cut or copied the omnibox URL to the clipboard for - // this page load. - bool omnibox_url_copied_ = false; + // This data is collected during the page lifetime and is meant to be sent to + // both UKM and History in OnComplete(). The recording is delayed until then + // to ensure that History has a visit entry ready for this navigation. + struct MemoriesSignals { + // True if the user has cut or copied the omnibox URL to the clipboard for + // this page load. + bool omnibox_url_copied = false; + + // True if the page was in a tab group when the navigation was committed. + bool is_existing_part_of_tab_group = false; + } memories_signals_; DISALLOW_COPY_AND_ASSIGN(UkmPageLoadMetricsObserver); };
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc b/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc index bfa4193..49dee5d 100644 --- a/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc +++ b/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
@@ -39,12 +39,14 @@ #include "chrome/browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer.h" #include "chrome/browser/page_load_metrics/observers/third_party_metrics_observer.h" #include "chrome/browser/page_load_metrics/observers/translate_page_load_metrics_observer.h" +#include "chrome/browser/page_load_metrics/page_load_metrics_memory_tracker_factory.h" #include "chrome/browser/prefetch/no_state_prefetch/chrome_no_state_prefetch_contents_delegate.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/search/search.h" #include "components/no_state_prefetch/browser/no_state_prefetch_contents.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_memory_tracker.h" #include "components/page_load_metrics/browser/page_load_tracker.h" #include "content/public/browser/web_contents.h" #include "extensions/buildflags/buildflags.h" @@ -74,6 +76,9 @@ bool IsNewTabPageUrl(const GURL& url) override; bool IsPrerender(content::WebContents* web_contents) override; bool IsExtensionUrl(const GURL& url) override; + page_load_metrics::PageLoadMetricsMemoryTracker* + GetMemoryTrackerForBrowserContext( + content::BrowserContext* browser_context) override; protected: // page_load_metrics::PageLoadMetricsEmbedderBase: @@ -195,6 +200,16 @@ #endif } +page_load_metrics::PageLoadMetricsMemoryTracker* +PageLoadMetricsEmbedder::GetMemoryTrackerForBrowserContext( + content::BrowserContext* browser_context) { + if (!base::FeatureList::IsEnabled(features::kV8PerFrameMemoryMonitoring)) + return nullptr; + + return page_load_metrics::PageLoadMetricsMemoryTrackerFactory:: + GetForBrowserContext(browser_context); +} + } // namespace void InitializePageLoadMetricsForWebContents(
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_memory_tracker_factory.cc b/chrome/browser/page_load_metrics/page_load_metrics_memory_tracker_factory.cc new file mode 100644 index 0000000..821ef183 --- /dev/null +++ b/chrome/browser/page_load_metrics/page_load_metrics_memory_tracker_factory.cc
@@ -0,0 +1,47 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/page_load_metrics/page_load_metrics_memory_tracker_factory.h" + +#include "base/memory/singleton.h" +#include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "components/keyed_service/content/browser_context_keyed_service_factory.h" +#include "components/page_load_metrics/browser/page_load_metrics_memory_tracker.h" + +namespace page_load_metrics { + +PageLoadMetricsMemoryTracker* +PageLoadMetricsMemoryTrackerFactory::GetForBrowserContext( + content::BrowserContext* context) { + return static_cast<page_load_metrics::PageLoadMetricsMemoryTracker*>( + GetInstance()->GetServiceForBrowserContext(context, true)); +} + +PageLoadMetricsMemoryTrackerFactory* +PageLoadMetricsMemoryTrackerFactory::GetInstance() { + return base::Singleton<PageLoadMetricsMemoryTrackerFactory>::get(); +} + +PageLoadMetricsMemoryTrackerFactory::PageLoadMetricsMemoryTrackerFactory() + : BrowserContextKeyedServiceFactory( + "PageLoadMetricsMemoryTracker", + BrowserContextDependencyManager::GetInstance()) {} + +bool PageLoadMetricsMemoryTrackerFactory::ServiceIsCreatedWithBrowserContext() + const { + return base::FeatureList::IsEnabled(features::kV8PerFrameMemoryMonitoring); +} + +KeyedService* PageLoadMetricsMemoryTrackerFactory::BuildServiceInstanceFor( + content::BrowserContext* context) const { + return new page_load_metrics::PageLoadMetricsMemoryTracker(); +} + +content::BrowserContext* +PageLoadMetricsMemoryTrackerFactory::GetBrowserContextToUse( + content::BrowserContext* context) const { + return context; +} + +} // namespace page_load_metrics
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_memory_tracker_factory.h b/chrome/browser/page_load_metrics/page_load_metrics_memory_tracker_factory.h new file mode 100644 index 0000000..6c9f19d4 --- /dev/null +++ b/chrome/browser/page_load_metrics/page_load_metrics_memory_tracker_factory.h
@@ -0,0 +1,37 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_PAGE_LOAD_METRICS_PAGE_LOAD_METRICS_MEMORY_TRACKER_FACTORY_H_ +#define CHROME_BROWSER_PAGE_LOAD_METRICS_PAGE_LOAD_METRICS_MEMORY_TRACKER_FACTORY_H_ + +#include "components/keyed_service/content/browser_context_keyed_service_factory.h" + +namespace page_load_metrics { + +class PageLoadMetricsMemoryTracker; + +class PageLoadMetricsMemoryTrackerFactory + : public BrowserContextKeyedServiceFactory { + public: + static PageLoadMetricsMemoryTracker* GetForBrowserContext( + content::BrowserContext* context); + + static PageLoadMetricsMemoryTrackerFactory* GetInstance(); + + PageLoadMetricsMemoryTrackerFactory(); + + private: + // BrowserContextKeyedServiceFactory: + bool ServiceIsCreatedWithBrowserContext() const override; + + KeyedService* BuildServiceInstanceFor( + content::BrowserContext* context) const override; + + content::BrowserContext* GetBrowserContextToUse( + content::BrowserContext* context) const override; +}; + +} // namespace page_load_metrics + +#endif // CHROME_BROWSER_PAGE_LOAD_METRICS_PAGE_LOAD_METRICS_MEMORY_TRACKER_FACTORY_H_
diff --git a/chrome/browser/paint_preview/android/java/src/org/chromium/chrome/browser/paint_preview/StartupPaintPreview.java b/chrome/browser/paint_preview/android/java/src/org/chromium/chrome/browser/paint_preview/StartupPaintPreview.java index afe8f2d6..3670f19d 100644 --- a/chrome/browser/paint_preview/android/java/src/org/chromium/chrome/browser/paint_preview/StartupPaintPreview.java +++ b/chrome/browser/paint_preview/android/java/src/org/chromium/chrome/browser/paint_preview/StartupPaintPreview.java
@@ -274,9 +274,6 @@ if (!mTabbedPaintPreview.isAttached()) return; - // If the tab is hidden as a result of pausing the activity we shouldn't remove it. - if (hidingType == TabHidingType.ACTIVITY_HIDDEN) return; - remove(StartupPaintPreviewMetrics.ExitCause.TAB_HIDDEN); }
diff --git a/chrome/browser/platform_util.h b/chrome/browser/platform_util.h index a94781c..47c6edd 100644 --- a/chrome/browser/platform_util.h +++ b/chrome/browser/platform_util.h
@@ -102,6 +102,9 @@ // gesture, if enabled in System Preferences. This function returns true if // the feature is supported and enabled, and false otherwise. bool IsSwipeTrackingFromScrollEventsEnabled(); + +// Returns the active window which accepts keyboard inputs. +NSWindow* GetActiveWindow(); #endif // Returns true if the given browser window is in locked fullscreen mode
diff --git a/chrome/browser/platform_util_mac.mm b/chrome/browser/platform_util_mac.mm index b9cc149..2e154a4 100644 --- a/chrome/browser/platform_util_mac.mm +++ b/chrome/browser/platform_util_mac.mm
@@ -138,4 +138,8 @@ && [NSEvent performSelector:selector]; } +NSWindow* GetActiveWindow() { + return [NSApp keyWindow]; +} + } // namespace platform_util
diff --git a/chrome/browser/policy/extension_policy_browsertest.cc b/chrome/browser/policy/extension_policy_browsertest.cc index e7388c83..21b844a 100644 --- a/chrome/browser/policy/extension_policy_browsertest.cc +++ b/chrome/browser/policy/extension_policy_browsertest.cc
@@ -30,6 +30,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/web_applications/components/app_registrar.h" +#include "chrome/browser/web_applications/components/externally_installed_web_app_prefs.h" #include "chrome/browser/web_applications/components/install_manager.h" #include "chrome/browser/web_applications/components/os_integration_manager.h" #include "chrome/browser/web_applications/components/web_app_provider_base.h" @@ -1970,21 +1971,29 @@ // before the browser is started. class WebAppInstallForceListPolicyTest : public ExtensionPolicyTest { public: - WebAppInstallForceListPolicyTest() {} - ~WebAppInstallForceListPolicyTest() override {} + WebAppInstallForceListPolicyTest() + : test_page_("/banners/manifest_test_page.html") {} + ~WebAppInstallForceListPolicyTest() override = default; + WebAppInstallForceListPolicyTest(const WebAppInstallForceListPolicyTest&) = + delete; + WebAppInstallForceListPolicyTest& operator=( + const WebAppInstallForceListPolicyTest&) = delete; void SetUpInProcessBrowserTestFixture() override { ExtensionPolicyTest::SetUpInProcessBrowserTestFixture(); ASSERT_TRUE(embedded_test_server()->Start()); - policy_app_url_ = - embedded_test_server()->GetURL("/banners/manifest_test_page.html"); + policy_app_url_ = embedded_test_server()->GetURL(test_page_); base::Value url(policy_app_url_.spec()); base::Value launch_container("window"); base::Value item(base::Value::Type::DICTIONARY); item.SetKey("url", std::move(url)); item.SetKey("default_launch_container", std::move(launch_container)); + if (fallback_app_name_.has_value()) { + base::Value fallback_app_name(fallback_app_name_.value()); + item.SetKey("fallback_app_name", std::move(fallback_app_name)); + } base::Value list(base::Value::Type::LIST); list.Append(std::move(item)); @@ -1995,10 +2004,9 @@ } protected: + std::string test_page_; GURL policy_app_url_; - - private: - DISALLOW_COPY_AND_ASSIGN(WebAppInstallForceListPolicyTest); + base::Optional<std::string> fallback_app_name_; }; IN_PROC_BROWSER_TEST_F(WebAppInstallForceListPolicyTest, StartUpInstallation) { @@ -2013,6 +2021,141 @@ EXPECT_EQ(policy_app_url_, registrar.GetAppStartUrl(*app_id)); } +class WebAppInstallForceListPolicyWithAppFallbackNameManifestTest + : public WebAppInstallForceListPolicyTest { + public: + WebAppInstallForceListPolicyWithAppFallbackNameManifestTest() { + test_page_ = "/banners/manifest_test_page.html"; + fallback_app_name_ = "fallback app name"; + } + + ~WebAppInstallForceListPolicyWithAppFallbackNameManifestTest() override = + default; + WebAppInstallForceListPolicyWithAppFallbackNameManifestTest( + const WebAppInstallForceListPolicyWithAppFallbackNameManifestTest&) = + delete; + WebAppInstallForceListPolicyWithAppFallbackNameManifestTest& operator=( + const WebAppInstallForceListPolicyWithAppFallbackNameManifestTest&) = + delete; +}; + +IN_PROC_BROWSER_TEST_F( + WebAppInstallForceListPolicyWithAppFallbackNameManifestTest, + StartUpInstallationPWAFallbackName) { + const web_app::AppRegistrar& registrar = + web_app::WebAppProviderBase::GetProviderBase(browser()->profile()) + ->registrar(); + web_app::WebAppInstallObserver install_observer(browser()->profile()); + base::Optional<web_app::AppId> app_id = + registrar.FindAppWithUrlInScope(policy_app_url_); + if (!app_id) + app_id = install_observer.AwaitNextInstall(); + EXPECT_EQ(policy_app_url_, registrar.GetAppStartUrl(*app_id)); + + // We specifically don't expect the fallback name to be used for a PWA + // except for the placeholder app. + EXPECT_NE(fallback_app_name_, registrar.GetAppShortName(*app_id)); +} + +// SAA == Site as App (a non-PWA installed as an app) +class WebAppInstallForceListPolicySAATest + : public WebAppInstallForceListPolicyTest { + public: + WebAppInstallForceListPolicySAATest() { + test_page_ = "/banners/no_manifest_test_page.html"; + } + + ~WebAppInstallForceListPolicySAATest() override = default; + WebAppInstallForceListPolicySAATest( + const WebAppInstallForceListPolicySAATest&) = delete; + WebAppInstallForceListPolicySAATest& operator=( + const WebAppInstallForceListPolicySAATest&) = delete; +}; + +IN_PROC_BROWSER_TEST_F(WebAppInstallForceListPolicySAATest, + StartUpInstallationSAA) { + const web_app::AppRegistrar& registrar = + web_app::WebAppProviderBase::GetProviderBase(browser()->profile()) + ->registrar(); + web_app::WebAppInstallObserver install_observer(browser()->profile()); + base::Optional<web_app::AppId> app_id = + registrar.FindAppWithUrlInScope(policy_app_url_); + if (!app_id) + app_id = install_observer.AwaitNextInstall(); + EXPECT_EQ(policy_app_url_, registrar.GetAppStartUrl(*app_id)); + EXPECT_NE(fallback_app_name_, registrar.GetAppShortName(*app_id)); +} + +class WebAppInstallForceListPolicyWithAppFallbackNameSAATest + : public WebAppInstallForceListPolicyTest { + public: + WebAppInstallForceListPolicyWithAppFallbackNameSAATest() { + test_page_ = "/banners/no_manifest_test_page.html"; + fallback_app_name_ = "fallback app name"; + } + + ~WebAppInstallForceListPolicyWithAppFallbackNameSAATest() override = default; + WebAppInstallForceListPolicyWithAppFallbackNameSAATest( + const WebAppInstallForceListPolicyWithAppFallbackNameSAATest&) = delete; + WebAppInstallForceListPolicyWithAppFallbackNameSAATest& operator=( + const WebAppInstallForceListPolicyWithAppFallbackNameSAATest&) = delete; +}; + +IN_PROC_BROWSER_TEST_F(WebAppInstallForceListPolicyWithAppFallbackNameSAATest, + StartUpInstallationSAAFallbackName) { + const web_app::AppRegistrar& registrar = + web_app::WebAppProviderBase::GetProviderBase(browser()->profile()) + ->registrar(); + web_app::WebAppInstallObserver install_observer(browser()->profile()); + base::Optional<web_app::AppId> app_id = + registrar.FindAppWithUrlInScope(policy_app_url_); + if (!app_id) + app_id = install_observer.AwaitNextInstall(); + EXPECT_EQ(policy_app_url_, registrar.GetAppStartUrl(*app_id)); + EXPECT_EQ(fallback_app_name_, registrar.GetAppShortName(*app_id)); +} + +class WebAppInstallForceListPolicyPlaceholderWithAppFallbackNameTest + : public WebAppInstallForceListPolicyTest { + public: + WebAppInstallForceListPolicyPlaceholderWithAppFallbackNameTest() { + test_page_ = "/close-socket"; + fallback_app_name_ = "fallback app name"; + } + + ~WebAppInstallForceListPolicyPlaceholderWithAppFallbackNameTest() override = + default; + WebAppInstallForceListPolicyPlaceholderWithAppFallbackNameTest( + const WebAppInstallForceListPolicyPlaceholderWithAppFallbackNameTest&) = + delete; + WebAppInstallForceListPolicyPlaceholderWithAppFallbackNameTest& operator=( + const WebAppInstallForceListPolicyPlaceholderWithAppFallbackNameTest&) = + delete; +}; + +IN_PROC_BROWSER_TEST_F( + WebAppInstallForceListPolicyPlaceholderWithAppFallbackNameTest, + StartUpInstallationPlaceholderFallbackName) { + const web_app::AppRegistrar& registrar = + web_app::WebAppProviderBase::GetProviderBase(browser()->profile()) + ->registrar(); + web_app::WebAppInstallObserver install_observer(browser()->profile()); + base::Optional<web_app::AppId> app_id = + registrar.FindAppWithUrlInScope(policy_app_url_); + if (!app_id) + app_id = install_observer.AwaitNextInstall(); + EXPECT_EQ(policy_app_url_, registrar.GetAppStartUrl(*app_id)); + EXPECT_EQ(fallback_app_name_, registrar.GetAppShortName(*app_id)); + + std::unique_ptr<web_app::ExternallyInstalledWebAppPrefs> + externally_installed_app_prefs = + std::make_unique<web_app::ExternallyInstalledWebAppPrefs>( + browser()->profile()->GetPrefs()); + ASSERT_TRUE( + externally_installed_app_prefs->LookupPlaceholderAppId(policy_app_url_) + .has_value()); +} + // Fixture for tests that have two profiles with a different policy for each. class ExtensionPolicyTest2Contexts : public PolicyTest { public:
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc index 83a30c4..405a01f6 100644 --- a/chrome/browser/policy/policy_browsertest.cc +++ b/chrome/browser/policy/policy_browsertest.cc
@@ -175,9 +175,9 @@ #include "ash/public/cpp/ash_pref_names.h" #include "ash/public/cpp/ash_switches.h" #include "ash/shell.h" +#include "chrome/browser/ash/system/timezone_resolver_manager.h" #include "chrome/browser/chromeos/login/test/js_checker.h" #include "chrome/browser/chromeos/note_taking_helper.h" -#include "chrome/browser/chromeos/system/timezone_resolver_manager.h" #include "chrome/browser/ui/ash/chrome_screenshot_grabber.h" #include "chrome/browser/ui/ash/chrome_screenshot_grabber_test_observer.h" #include "chromeos/cryptohome/cryptohome_parameters.h"
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc index 0b69c0d..a47827b 100644 --- a/chrome/browser/prefs/browser_prefs.cc +++ b/chrome/browser/prefs/browser_prefs.cc
@@ -277,6 +277,8 @@ #include "chrome/browser/chromeos/extensions/printing/printing_api_handler.h" #endif #include "chrome/browser/ash/account_manager/account_manager_edu_coexistence_controller.h" +#include "chrome/browser/ash/system/automatic_reboot_manager.h" +#include "chrome/browser/ash/system/input_device_settings.h" #include "chrome/browser/chromeos/borealis/borealis_prefs.h" #include "chrome/browser/chromeos/child_accounts/secondary_account_consent_logger.h" #include "chrome/browser/chromeos/file_system_provider/registry.h" @@ -325,8 +327,6 @@ #include "chrome/browser/chromeos/printing/enterprise_printers_provider.h" #include "chrome/browser/chromeos/release_notes/release_notes_storage.h" #include "chrome/browser/chromeos/settings/device_settings_cache.h" -#include "chrome/browser/chromeos/system/automatic_reboot_manager.h" -#include "chrome/browser/chromeos/system/input_device_settings.h" #include "chrome/browser/device_identity/chromeos/device_oauth2_token_store_chromeos.h" #include "chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.h" #include "chrome/browser/extensions/extension_assets_manager_chromeos.h"
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc index 774117c1..9c582f49 100644 --- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc +++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -50,6 +50,7 @@ #include "chrome/browser/net/profile_network_context_service_factory.h" #include "chrome/browser/notifications/notifier_state_tracker_factory.h" #include "chrome/browser/page_load_metrics/observers/https_engagement_metrics/https_engagement_service_factory.h" +#include "chrome/browser/page_load_metrics/page_load_metrics_memory_tracker_factory.h" #include "chrome/browser/password_manager/password_store_factory.h" #include "chrome/browser/permissions/adaptive_quiet_notification_permission_ui_enabler.h" #include "chrome/browser/permissions/last_tab_standing_tracker_factory.h" @@ -348,6 +349,7 @@ #if !defined(OS_ANDROID) NTPResourceCacheFactory::GetInstance(); #endif + page_load_metrics::PageLoadMetricsMemoryTrackerFactory::GetInstance(); PasswordStoreFactory::GetInstance(); PermissionAuditingServiceFactory::GetInstance(); ProfileProtoDBFactory<
diff --git a/chrome/browser/resource_coordinator/tab_lifecycle_unit_unittest.cc b/chrome/browser/resource_coordinator/tab_lifecycle_unit_unittest.cc index 27b7e58..e752e01 100644 --- a/chrome/browser/resource_coordinator/tab_lifecycle_unit_unittest.cc +++ b/chrome/browser/resource_coordinator/tab_lifecycle_unit_unittest.cc
@@ -260,7 +260,8 @@ usage_clock_.get(), web_contents_, tab_strip_model_.get()); - web_contents_->SetIsCrashed(base::TERMINATION_STATUS_PROCESS_CRASHED, 0); + auto* tester = content::WebContentsTester::For(web_contents_); + tester->SetIsCrashed(base::TERMINATION_STATUS_PROCESS_CRASHED, 0); ExpectCanDiscardFalseTrivialAllReasons(&tab_lifecycle_unit); }
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn index 0abb7ac..e571c77 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn
@@ -474,6 +474,7 @@ "$externs_path/chromeos_info_private.js", "$externs_path/chrome.js", "$externs_path/chrome_extensions.js", + "$externs_path/clipboard.js", "$externs_path/command_line_private.js", "$externs_path/login_state.js", "$externs_path/metrics_private.js",
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/background.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/background.js index 10334ff..3e5dd5d 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/background.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/background.js
@@ -72,12 +72,12 @@ /** @type {!LiveRegions} @private */ this.liveRegions_ = new LiveRegions(this); - document.addEventListener('copy', this.onClipboardEvent_); - document.addEventListener('cut', this.onClipboardEvent_); - document.addEventListener('paste', this.onClipboardEvent_); + /** @private {string|undefined} */ + this.lastClipboardEvent_; - /** @private {boolean} */ - this.preventPasteOutput_ = false; + chrome.clipboard.onClipboardDataChanged.addListener( + this.onClipboardDataChanged_.bind(this)); + document.addEventListener('copy', this.onClipboardCopyEvent_.bind(this)); /** * Maps a non-desktop root automation node to a range position suitable for @@ -356,36 +356,36 @@ } /** - * Detects various clipboard events and provides spoken output. - * - * Note that paste is explicitly skipped sometimes because during a copy or - * cut, the copied or cut text is retrieved by pasting into a fake text - * area. To prevent this from triggering paste output, this staste is - * tracked via a field. + * Processes the copy clipboard event. * @param {!Event} evt * @private */ - onClipboardEvent_(evt) { - let text = ''; - if (evt.type === 'paste') { - if (this.preventPasteOutput_) { - this.preventPasteOutput_ = false; - return; - } - text = evt.clipboardData.getData('text'); - ChromeVox.tts.speak(Msgs.getMsg(evt.type, [text]), QueueMode.QUEUE); - } else if (evt.type === 'copy' || evt.type === 'cut') { - this.preventPasteOutput_ = true; - const textarea = document.createElement('textarea'); - document.body.appendChild(textarea); - textarea.focus(); - document.execCommand('paste'); - const clipboardContent = textarea.value; - textarea.remove(); - ChromeVox.tts.speak( - Msgs.getMsg(evt.type, [clipboardContent]), QueueMode.FLUSH); - ChromeVoxState.instance.pageSel_ = null; + onClipboardCopyEvent_(evt) { + // This should always be 'copy', but is still important to set for the below + // extension event. + this.lastClipboardEvent_ = evt.type; + } + + /** @private */ + onClipboardDataChanged_() { + // A DOM-based clipboard event always comes before this Chrome extension + // clipboard event. We only care about 'copy' events, which gets set above. + if (!this.lastClipboardEvent_) { + return; } + + const eventType = this.lastClipboardEvent_; + this.lastClipboardEvent_ = undefined; + + const textarea = document.createElement('textarea'); + document.body.appendChild(textarea); + textarea.focus(); + document.execCommand('paste'); + const clipboardContent = textarea.value; + textarea.remove(); + ChromeVox.tts.speak( + Msgs.getMsg(eventType, [clipboardContent]), QueueMode.FLUSH); + ChromeVoxState.instance.pageSel_ = null; } /** @private */
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/background_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/background_test.js index 846e1e34..3136e817 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/background_test.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/background_test.js
@@ -22,9 +22,9 @@ this.forceContextualLastOutput(); } - doGesture(gesture) { + doGesture(gesture, opt_x, opt_y) { return () => { - GestureCommandHandler.onAccessibilityGesture_(gesture); + GestureCommandHandler.onAccessibilityGesture_(gesture, opt_x, opt_y); }; } @@ -3290,3 +3290,45 @@ .replay(); }); }); + +TEST_F('ChromeVoxBackgroundTest', 'TouchEditingState', function() { + const mockFeedback = this.createMockFeedback(); + const site = ` + <p>Start</p> + <input type="text"></input> + `; + this.runWithLoadedTree(site, function(rootNode) { + const bounds = rootNode.find({role: RoleType.TEXT_FIELD}).location; + mockFeedback.expectSpeech('Start') + .call(doGesture( + chrome.accessibilityPrivate.Gesture.TOUCH_EXPLORE, bounds.left, + bounds.top)) + .expectSpeech('Edit text', 'Double tap to start editing') + .call(doGesture( + chrome.accessibilityPrivate.Gesture.CLICK, bounds.left, bounds.top)) + .expectSpeech('Edit text', 'is editing') + .replay(); + }); +}); + +TEST_F('ChromeVoxBackgroundTest', 'TouchGesturesProducesEarcons', function() { + const mockFeedback = this.createMockFeedback(); + const site = ` + <p>Start</p> + <button>ok</button> + <a href="chromevox.com">cancel</a> + `; + this.runWithLoadedTree(site, function(rootNode) { + mockFeedback.expectSpeech('Start') + .call(doGesture(chrome.accessibilityPrivate.Gesture.SWIPE_RIGHT1)) + .expectSpeech('ok', 'Button') + .expectEarcon(Earcon.BUTTON) + .call(doGesture(chrome.accessibilityPrivate.Gesture.SWIPE_RIGHT1)) + .expectSpeech('cancel', 'Link') + .expectEarcon(Earcon.LINK) + .call(doGesture(chrome.accessibilityPrivate.Gesture.SWIPE_LEFT1)) + .expectSpeech('ok', 'Button') + .expectEarcon(Earcon.BUTTON) + .replay(); + }); +});
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/base_automation_handler.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/base_automation_handler.js index e8ae4e8..496d90b 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/base_automation_handler.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/base_automation_handler.js
@@ -99,12 +99,8 @@ } // Decide whether to announce and sync this event. - const isFocusOnRoot = - evt.type === 'focus' && evt.target === evt.target.root; if (!DesktopAutomationHandler.announceActions && - evt.eventFrom === 'action' && - (EventSourceState.get() !== EventSourceType.TOUCH_GESTURE || - isFocusOnRoot)) { + evt.eventFrom === 'action') { return; }
diff --git a/chrome/browser/resources/chromeos/emoji_picker/BUILD.gn b/chrome/browser/resources/chromeos/emoji_picker/BUILD.gn index 0899010..853a065 100644 --- a/chrome/browser/resources/chromeos/emoji_picker/BUILD.gn +++ b/chrome/browser/resources/chromeos/emoji_picker/BUILD.gn
@@ -16,47 +16,40 @@ "icons.js", ] +processed_json_files = [ + "emoji_13_1_ordering.json", + "emoji_test_ordering.json", +] + resources_grd_file = "$target_gen_dir/resources.grd" -components_grdp_file = "$target_gen_dir/components.grdp" -data_grdp_file = "$target_gen_dir/data.grdp" +preprocessed_grdp_file = "$target_gen_dir/preprocessed.grdp" generate_grd("build_grd") { deps = [ - ":build_components_grdp", - ":build_data_grdp", + ":build_preprocessed_grdp", + ":emoji_data", ] grd_prefix = "emoji_picker" out_grd = resources_grd_file input_files = [ "constants.js", - "emoji_test_ordering.json", "events.js", "index.html", "store.js", "types.js", ] - grdp_files = [ - components_grdp_file, - data_grdp_file, - ] + grdp_files = [ preprocessed_grdp_file ] input_files_base_dir = rebase_path(".", "//") } -generate_grd("build_components_grdp") { +generate_grd("build_preprocessed_grdp") { deps = [ ":web_components" ] grd_prefix = "emoji_picker" - out_grd = components_grdp_file - input_files = component_js_files + out_grd = preprocessed_grdp_file + input_files = component_js_files + processed_json_files input_files_base_dir = rebase_path(target_gen_dir, root_build_dir) } -generate_grd("build_data_grdp") { - grd_prefix = "emoji_picker" - out_grd = data_grdp_file - input_files = [ "emoji_13_1_ordering.json" ] - input_files_base_dir = rebase_path("//third_party/emoji-metadata/src", "//") -} - grit("resources") { # These arguments are needed since the grd is generated at build time. enable_input_discovery_for_gn_analyze = false
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_button.html b/chrome/browser/resources/chromeos/emoji_picker/emoji_button.html index d5ed32d..d350f0a 100644 --- a/chrome/browser/resources/chromeos/emoji_picker/emoji_button.html +++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_button.html
@@ -52,7 +52,7 @@ on-contextmenu="onContextMenu" on-mouseup="onMouseUp" disabled="[[disabled]]"> - [[_renderEmoji(emoji)]] + [[emoji]] </button> <template is="dom-if" if="[[variantsVisible]]"> <emoji-variants variants="[[variants]]"></emoji-variants>
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_button.js b/chrome/browser/resources/chromeos/emoji_picker/emoji_button.js index 03c901a..b745ed3 100644 --- a/chrome/browser/resources/chromeos/emoji_picker/emoji_button.js +++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_button.js
@@ -7,7 +7,7 @@ import {beforeNextRender, html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {createCustomEvent, EMOJI_BUTTON_CLICK, EMOJI_VARIANTS_SHOWN} from './events.js'; -import {Codepoints} from './types.js'; +import {Emoji} from './types.js'; export class EmojiButton extends PolymerElement { static get is() { @@ -20,9 +20,9 @@ static get properties() { return { - /** @type {!Codepoints} */ - emoji: {type: Array, readonly: true}, - /** @type {!Array<Codepoints>} */ + /** @type {!string} */ + emoji: {type: String, readonly: true}, + /** @type {Array<Emoji>} */ variants: {type: Array, readonly: true}, /** @type {!boolean} */ variantsVisible: {type: Boolean, value: false}, @@ -38,8 +38,8 @@ onClick(ev) { if (this.disabled) return; - this.dispatchEvent(createCustomEvent( - EMOJI_BUTTON_CLICK, {emoji: this._renderEmoji(this.emoji)})); + this.dispatchEvent( + createCustomEvent(EMOJI_BUTTON_CLICK, {emoji: this.emoji})); } onContextMenu(ev) { @@ -72,13 +72,6 @@ _className(variants) { return variants && variants.length > 0 ? 'has-variants' : ''; } - - /** - * @param {Codepoints} codepoints - */ - _renderEmoji(codepoints) { - return String.fromCodePoint(...codepoints); - } } customElements.define(EmojiButton.is, EmojiButton);
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_group.html b/chrome/browser/resources/chromeos/emoji_picker/emoji_group.html index b2f8499d..1853ba7 100644 --- a/chrome/browser/resources/chromeos/emoji_picker/emoji_group.html +++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_group.html
@@ -19,7 +19,7 @@ <div id="heading">[[data.group]]</div> <div id="emoji"> <template is="dom-repeat" items="[[data.emoji]]"> - <emoji-button emoji="[[item.base]]" variants="[[item.alternates]]"> + <emoji-button emoji="[[item.base.string]]" variants="[[item.alternates]]"> </emoji-button> </template> </div> \ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.js b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.js index dd6dc23..bc4e1432 100644 --- a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.js +++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.js
@@ -14,7 +14,7 @@ import {EmojiButton} from './emoji_button.js'; import {createCustomEvent, EMOJI_BUTTON_CLICK, EMOJI_DATA_LOADED, EMOJI_VARIANTS_SHOWN, EmojiVariantsShownEvent, GROUP_BUTTON_CLICK} from './events.js'; import {RecentEmojiStore} from './store.js'; -import {Codepoints, Emoji, EmojiData, EmojiGroup} from './types.js'; +import {Emoji, EmojiGroup, EmojiGroupData, EmojiVariants} from './types.js'; const EMOJI_ORDERING_JSON = '/emoji_13_1_ordering.json'; @@ -35,11 +35,13 @@ * Constructs the emoji group data structure from a given list of emoji * strings. Note: returned emoji have no variants. * - * @param {!Array<Codepoints>} recentEmoji list of recently used emoji strings. - * @return {!Array<!Emoji>} list of emoji data structures + * @param {!Array<string>} recentEmoji list of recently used emoji strings. + * @return {!Array<EmojiVariants>} list of emoji data structures */ function makeRecentlyUsed(recentEmoji) { - return recentEmoji.map(emoji => ({base: emoji, alternates: []})); + return recentEmoji.map( + emoji => + ({base: {string: emoji, name: '', keywords: []}, alternates: []})); } export class EmojiPicker extends PolymerElement { @@ -56,7 +58,7 @@ /** @type {!string} */ emojiDataUrl: {type: String, value: EMOJI_ORDERING_JSON}, emojiGroupTabs: {type: Array}, - /** @private {?EmojiData} */ + /** @private {?EmojiGroupData} */ emojiData: { type: Object, observer: 'onEmojiDataChanged', @@ -214,7 +216,7 @@ onEmojiDataLoaded(data) { - this.emojiData = /** @type {!EmojiData} */ (JSON.parse(data)); + this.emojiData = /** @type {!EmojiGroupData} */ (JSON.parse(data)); } /**
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_variants.html b/chrome/browser/resources/chromeos/emoji_picker/emoji_variants.html index 0cf216a8..a4d86b3 100644 --- a/chrome/browser/resources/chromeos/emoji_picker/emoji_variants.html +++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_variants.html
@@ -67,7 +67,7 @@ --> <div id="grid-base-emoji"> - <template is="dom-if" if="[[baseEmoji.length]]"> + <template is="dom-if" if="[[baseEmoji]]"> <emoji-button emoji="[[baseEmoji]]"></emoji-button> </template> </div> @@ -82,21 +82,21 @@ U+1F3FE EMOJI MODIFIER FITZPATRICK TYPE-5 U+1F3FF EMOJI MODIFIER FITZPATRICK TYPE-6 --> - <emoji-button emoji="[127995]" disabled></emoji-button> - <emoji-button emoji="[127996]" disabled></emoji-button> - <emoji-button emoji="[127997]" disabled></emoji-button> - <emoji-button emoji="[127998]" disabled></emoji-button> - <emoji-button emoji="[127999]" disabled></emoji-button> + <emoji-button emoji="🏻" disabled></emoji-button> + <emoji-button emoji="🏼" disabled></emoji-button> + <emoji-button emoji="🏽" disabled></emoji-button> + <emoji-button emoji="🏾" disabled></emoji-button> + <emoji-button emoji="🏿" disabled></emoji-button> </template> </div> <div id="grid-skin-tone-left" class="skin-tone"> <template is="dom-if" if="[[showSkinTones]]"> - <emoji-button emoji="[127995]" disabled></emoji-button> - <emoji-button emoji="[127996]" disabled></emoji-button> - <emoji-button emoji="[127997]" disabled></emoji-button> - <emoji-button emoji="[127998]" disabled></emoji-button> - <emoji-button emoji="[127999]" disabled></emoji-button> + <emoji-button emoji="🏻" disabled></emoji-button> + <emoji-button emoji="🏼" disabled></emoji-button> + <emoji-button emoji="🏽" disabled></emoji-button> + <emoji-button emoji="🏾" disabled></emoji-button> + <emoji-button emoji="🏿" disabled></emoji-button> </template> </div> @@ -104,7 +104,7 @@ <template is="dom-repeat" items="[[variantRows]]" as="row"> <div class="variant-row"> <template is="dom-repeat" items="[[row]]" as="emoji"> - <emoji-button emoji="[[emoji]]"></emoji-button> + <emoji-button emoji="[[emoji.string]]"></emoji-button> </template> </div> </template>
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_variants.js b/chrome/browser/resources/chromeos/emoji_picker/emoji_variants.js index 0911d6a..a8f259b0 100644 --- a/chrome/browser/resources/chromeos/emoji_picker/emoji_variants.js +++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_variants.js
@@ -3,7 +3,7 @@ // found in the LICENSE file. import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -import {Codepoints} from './types.js'; +import {Emoji} from './types.js'; const GENDER_FEMALE = 9792; // U+2640 FEMALE_SIGN const SKIN_TONE_MEDIUM = 127997; // U+1F3FD EMOJI MODIFIER FITZPATRICK TYPE-4 @@ -13,12 +13,13 @@ /** * Determines if the given list of variants has any variant which contains * the given codepoint. - * @param {!Array<Codepoints>} variants + * @param {!Array<!Emoji>} variants * @param {!number} codepoint * @return {boolean} */ function hasVariation(variants, codepoint) { - return variants.findIndex(x => x.includes(codepoint)) !== -1; + const codepointString = String.fromCodePoint(codepoint); + return variants.findIndex(x => x.string.includes(codepointString)) !== -1; } @@ -57,11 +58,11 @@ static get properties() { return { - /** @type {!Array<Codepoints>} */ + /** @type {!Array<Emoji>} */ variants: {type: Array, readonly: true}, - /** @private {!Array<!Array<Codepoints>>} */ + /** @private {!Array<!Array<Emoji>>} */ variantRows: {type: Array}, - /** @private {?Codepoints} */ + /** @private {?string} */ baseEmoji: {type: Array}, /** @private {boolean} */ showSkinTones: {type: Boolean}, @@ -83,7 +84,7 @@ if (isFamily || isTwoPeople) { // for these cases, the first variant is the generic one. - this.baseEmoji = this.variants[0]; + this.baseEmoji = this.variants[0].string; } else { this.baseEmoji = null; }
diff --git a/chrome/browser/resources/chromeos/emoji_picker/store.js b/chrome/browser/resources/chromeos/emoji_picker/store.js index 0f9aebb..6196031 100644 --- a/chrome/browser/resources/chromeos/emoji_picker/store.js +++ b/chrome/browser/resources/chromeos/emoji_picker/store.js
@@ -2,15 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import {Codepoints} from './types.js'; - const LOCALSTORAGE_KEY = 'emoji-recently-used'; -const MAX_RECENTS = 14; +const MAX_RECENTS = 18; /** - * Recently used emoji, most recent first. Each emoji is stored as an array - * of codepoints. - * @typedef {!Array<Codepoints>} + * Recently used emoji, most recent first. Each emoji is stored as a string. + * @typedef {!Array<string>} RecentlyUsedEmoji */ let RecentlyUsedEmoji; @@ -22,7 +19,13 @@ if (!stored) { return []; } - return /** @type {?} */ (JSON.parse(stored)); + const parsed = /** @type {?} */ (JSON.parse(stored)); + if (parsed[0] && Array.isArray(parsed[0])) { + // if stored data is in older codepoint format, ignore it. + return []; + } + + return parsed; } /** @@ -44,15 +47,12 @@ */ bumpEmoji(newEmoji) { // find and remove newEmoji from array if it previously existed. - const oldIndex = - this.data.findIndex(x => String.fromCodePoint(...x) === newEmoji); + const oldIndex = this.data.findIndex(x => x === newEmoji); if (oldIndex !== -1) { this.data.splice(oldIndex, 1); } - // insert newEmoji's codepoints to front of array. - // first, split newEmoji into an array of strings where each string is - // one codepoint. then, convert each codepoint to its numerical value. - this.data.unshift([...newEmoji].map(x => x.codePointAt(0))); + // insert newEmoji to the front of the array. + this.data.unshift(newEmoji); // slice from end of array if it exceeds MAX_RECENTS. if (this.data.length > MAX_RECENTS) { // setting length is sufficient to truncate an array.
diff --git a/chrome/browser/resources/chromeos/emoji_picker/types.js b/chrome/browser/resources/chromeos/emoji_picker/types.js index 7b768da4..2ee89635 100644 --- a/chrome/browser/resources/chromeos/emoji_picker/types.js +++ b/chrome/browser/resources/chromeos/emoji_picker/types.js
@@ -3,21 +3,21 @@ // found in the LICENSE file. /** - * @typedef {!Array<!number>} - */ -export let Codepoints; - -/** - * @typedef {{base: Codepoints, alternates: !Array<Codepoints>}} + * @typedef {{string: string, name: string, keywords: !Array<!string>}} Emoji */ export let Emoji; /** - * @typedef {{group: string, emoji: Array<Emoji>}} + * @typedef {{base: Emoji, alternates: !Array<Emoji>}} EmojiVariants + */ +export let EmojiVariants; + +/** + * @typedef {{group: string, emoji: !Array<EmojiVariants>}} EmojiGroup */ export let EmojiGroup; /** - * @typedef {Array<EmojiGroup>} EmojiData + * @typedef {Array<EmojiGroup>} EmojiGroupData */ -export let EmojiData; +export let EmojiGroupData;
diff --git a/chrome/browser/resources/commander/app.js b/chrome/browser/resources/commander/app.js index d305893..410119c 100644 --- a/chrome/browser/resources/commander/app.js +++ b/chrome/browser/resources/commander/app.js
@@ -92,6 +92,8 @@ this.browserProxy_.promptCancelled(); this.promptText_ = null; this.$.input.value = this.savedInput_; + e.preventDefault(); + this.onInput_(); } } @@ -119,6 +121,7 @@ this.promptText_ = viewModel.promptText || null; this.savedInput_ = this.$.input.value; this.$.input.value = ''; + this.onInput_(); } }
diff --git a/chrome/browser/resources/supervised_user_internals/DIR_METADATA b/chrome/browser/resources/family_link_user_internals/DIR_METADATA similarity index 100% rename from chrome/browser/resources/supervised_user_internals/DIR_METADATA rename to chrome/browser/resources/family_link_user_internals/DIR_METADATA
diff --git a/chrome/browser/resources/supervised_user_internals/OWNERS b/chrome/browser/resources/family_link_user_internals/OWNERS similarity index 100% rename from chrome/browser/resources/supervised_user_internals/OWNERS rename to chrome/browser/resources/family_link_user_internals/OWNERS
diff --git a/chrome/browser/resources/supervised_user_internals/supervised_user_internals.css b/chrome/browser/resources/family_link_user_internals/family_link_user_internals.css similarity index 100% rename from chrome/browser/resources/supervised_user_internals/supervised_user_internals.css rename to chrome/browser/resources/family_link_user_internals/family_link_user_internals.css
diff --git a/chrome/browser/resources/supervised_user_internals/supervised_user_internals.html b/chrome/browser/resources/family_link_user_internals/family_link_user_internals.html similarity index 80% rename from chrome/browser/resources/supervised_user_internals/supervised_user_internals.html rename to chrome/browser/resources/family_link_user_internals/family_link_user_internals.html index ab6ee64..c6e8a82 100644 --- a/chrome/browser/resources/supervised_user_internals/supervised_user_internals.html +++ b/chrome/browser/resources/family_link_user_internals/family_link_user_internals.html
@@ -7,13 +7,10 @@ <html lang="en"> <head> <meta charset="utf-8"> -<title>Supervised User Internals</title> +<title>Family Link User Internals</title> <link rel="stylesheet" href="chrome://resources/css/text_defaults.css"> <link rel="stylesheet" href="chrome://resources/css/list.css"> -<link rel="stylesheet" href="supervised_user_internals.css"> -<script src="chrome://resources/js/cr.js"></script> -<script src="chrome://resources/js/assert.js"></script> -<script src="chrome://resources/js/util.js"></script> +<link rel="stylesheet" href="family_link_user_internals.css"> </head> <body> @@ -23,7 +20,7 @@ <table class="section-details"> <tr jsselect="data" jsvalues="class:$this.is_valid ? '' : 'uninitialized'" - jseval='chrome.supervised_user_internals.highlightIfChanged( + jseval='highlightIfChanged( this, this.children[1].innerText, stat_value)'> <td class="detail" jscontent="stat_name" width=50%></td> <td class="value" jscontent="stat_value" width=50%></td> @@ -53,7 +50,7 @@ </div> <div id='user-settings' class="section"> - <h2>Supervised User Settings</h2> + <h2>Family Link User Settings</h2> <table class="section-details"> <tr jsselect="settings"> <td jscontent="key"></td> @@ -74,7 +71,6 @@ </div> </div> -<script src="chrome://resources/js/jstemplate_compiled.js"></script> -<script src="supervised_user_internals.js"></script> +<script type="module" src="family_link_user_internals.js"></script> </body> </html>
diff --git a/chrome/browser/resources/family_link_user_internals/family_link_user_internals.js b/chrome/browser/resources/family_link_user_internals/family_link_user_internals.js new file mode 100644 index 0000000..530c8f48 --- /dev/null +++ b/chrome/browser/resources/family_link_user_internals/family_link_user_internals.js
@@ -0,0 +1,125 @@ +// 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. + +import 'chrome://resources/js/jstemplate_compiled.js'; + +import {addWebUIListener, sendWithPromise} from 'chrome://resources/js/cr.m.js'; +import {$} from 'chrome://resources/js/util.m.js'; + +function initialize() { + function submitURL(event) { + $('try-url-result').textContent = ''; + $('manual-allowlist').textContent = ''; + $('allowlists').textContent = ''; + sendWithPromise('tryURL', $('try-url-input').value) + .then(({allowResult, manual, allowLists}) => { + $('try-url-result').textContent = allowResult; + $('manual-allowlist').textContent = manual; + $('allowlists').textContent = allowlists; + }); + event.preventDefault(); + } + + $('try-url').addEventListener('submit', submitURL); + + // Make the prototype jscontent element disappear. + jstProcess({}, $('filtering-results-container')); + + addWebUIListener('basic-info-received', receiveBasicInfo); + addWebUIListener('user-settings-received', receiveUserSettings); + addWebUIListener('filtering-result-received', receiveFilteringResult); + + chrome.send('registerForEvents'); + + chrome.send('getBasicInfo'); +} + +function highlightIfChanged(node, oldVal, newVal) { + function clearHighlight() { + node.removeAttribute('highlighted'); + } + + const oldStr = oldVal.toString(); + const newStr = newVal.toString(); + if (oldStr != '' && oldStr != newStr) { + // Note the addListener function does not end up creating duplicate + // listeners. There can be only one listener per event at a time. + // See https://developer.mozilla.org/en/DOM/element.addEventListener + node.addEventListener('animationend', clearHighlight, false); + node.setAttribute('highlighted', ''); + } +} + +function receiveBasicInfo(info) { + jstProcess(new JsEvalContext(info), $('basic-info')); + + // Hack: Schedule another refresh after a while. + setTimeout(function() { + chrome.send('getBasicInfo'); + }, 5000); +} + +function receiveUserSettings(settings) { + if (settings === null) { + $('user-settings').classList.add('hidden'); + return; + } + + $('user-settings').classList.remove('hidden'); + + // The user settings are returned as an object, flatten them into a + // list of key/value pairs for easier consumption by the HTML template. + // This is not done recursively, values are passed as their JSON + // representation. + const kvpairs = Object.keys(settings).map(function(key) { + return {key: key, value: JSON.stringify(settings[key], null, 2)}; + }); + + jstProcess(new JsEvalContext({settings: kvpairs}), $('user-settings')); +} + +/** + * Helper to determine if an element is scrolled to its bottom limit. + * @param {Element} elem element to check + * @return {boolean} true if the element is scrolled to the bottom + */ +function isScrolledToBottom(elem) { + return elem.scrollHeight - elem.scrollTop == elem.clientHeight; +} + +/** + * Helper to scroll an element to its bottom limit. + * @param {Element} elem element to be scrolled + */ +function scrollToBottom(elem) { + elem.scrollTop = elem.scrollHeight - elem.clientHeight; +} + +/** Container for accumulated filtering results. */ +const filteringResults = []; + +/** + * Callback for incoming filtering results. + * @param {Object} result The result. + */ +function receiveFilteringResult(result) { + filteringResults.push(result); + + const container = $('filtering-results-container'); + + // Scroll to the bottom if we were already at the bottom. Otherwise, leave + // the scrollbar alone. + const shouldScrollDown = isScrolledToBottom(container); + + jstProcess(new JsEvalContext({results: filteringResults}), container); + + if (shouldScrollDown) { + scrollToBottom(container); + } +} + +// Export on window since it is called with jseval. +window.highlightIfChanged = highlightIfChanged; + +document.addEventListener('DOMContentLoaded', initialize);
diff --git a/chrome/browser/resources/local_ntp/externs.js b/chrome/browser/resources/local_ntp/externs.js index e730896..c9a2e099 100644 --- a/chrome/browser/resources/local_ntp/externs.js +++ b/chrome/browser/resources/local_ntp/externs.js
@@ -189,6 +189,19 @@ window.chrome.embeddedSearch.newTabPage.blacklistSearchSuggestionWithHash; /** + * @param {number} task_version + * @param {number} task_id + */ +window.chrome.embeddedSearch.newTabPage.blocklistSearchSuggestion; + +/** + * @param {number} task_version + * @param {number} task_id + * @param {string} hash + */ +window.chrome.embeddedSearch.newTabPage.blocklistSearchSuggestionWithHash; + +/** * No params. */ window.chrome.embeddedSearch.newTabPage.confirmThemeChanges;
diff --git a/chrome/browser/resources/settings/chromeos/BUILD.gn b/chrome/browser/resources/settings/chromeos/BUILD.gn index 4d972e7..5d33377 100644 --- a/chrome/browser/resources/settings/chromeos/BUILD.gn +++ b/chrome/browser/resources/settings/chromeos/BUILD.gn
@@ -505,12 +505,16 @@ "chromeos/os_settings_icons_css.m.js", "chromeos/os_settings_page/main_page_behavior.m.js", "chromeos/os_settings_routes.m.js", + "chromeos/os_settings_search_box/os_search_result_row.m.js", + "chromeos/os_settings_search_box/os_settings_search_box.m.js", + "chromeos/os_toolbar/os_toolbar.m.js", "chromeos/parental_controls_page/parental_controls_browser_proxy.m.js", "chromeos/parental_controls_page/parental_controls_page.m.js", "chromeos/personalization_page/change_picture.m.js", "chromeos/personalization_page/change_picture_browser_proxy.m.js", "chromeos/personalization_page/personalization_page.m.js", "chromeos/personalization_page/wallpaper_browser_proxy.m.js", + "chromeos/personalization_page/wallpaper_constants.m.js", "chromeos/personalization_page/wallpaper_subpage.m.js", "chromeos/pref_to_setting_metric_converter.m.js", "chromeos/route_origin_behavior.m.js", @@ -1008,6 +1012,8 @@ "chromeos/personalization_page/personalization_page.js", "chromeos/personalization_page/wallpaper_browser_proxy.html", "chromeos/personalization_page/wallpaper_browser_proxy.js", + "chromeos/personalization_page/wallpaper_constants.html", + "chromeos/personalization_page/wallpaper_constants.js", "chromeos/personalization_page/wallpaper_subpage.js", "chromeos/personalization_page/wallpaper_subpage.html", "chromeos/pref_to_setting_metric_converter.html", @@ -1240,10 +1246,10 @@ #"os_settings_main:closure_compile_module", #"os_settings_menu:closure_compile_module", "os_settings_page:closure_compile_module", + "os_settings_search_box:closure_compile_module", - #"os_settings_search_box:closure_compile_module", #"os_settings_ui:closure_compile_module", - #"os_toolbar:closure_compile_module", + "os_toolbar:closure_compile_module", "parental_controls_page:closure_compile_module", "personalization_page:closure_compile_module", ] @@ -1342,6 +1348,10 @@ js_library("search_handler.m") { sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/search_handler.m.js" ] + deps = [ + "//chrome/browser/ui/webui/settings/chromeos/search:mojo_bindings_js_library_for_compile", + "//ui/webui/resources/js:cr.m", + ] extra_deps = [ ":modulize" ] }
diff --git a/chrome/browser/resources/settings/chromeos/os_settings.gni b/chrome/browser/resources/settings/chromeos/os_settings.gni index 107d8cd..51e32e8 100644 --- a/chrome/browser/resources/settings/chromeos/os_settings.gni +++ b/chrome/browser/resources/settings/chromeos/os_settings.gni
@@ -91,6 +91,8 @@ "settings.printing.sortPrinters|sortPrinters", "settings.recordLockScreenProgress|recordLockScreenProgress", "settings.recordSettingChange|recordSettingChange", + "settings.setUserActionRecorderForTesting|setUserActionRecorderForTesting", + "settings.recordSearch|recordSearch", "settings.Router|Router", "settings.routes|routes", "settings.setSearchHandlerForTesting|setSearchHandlerForTesting", @@ -146,7 +148,7 @@ "chrome/browser/resources/settings/chromeos/google_assistant_page/google_assistant_browser_proxy.html|GoogleAssistantBrowserProxy,GoogleAssistantBrowserProxyImpl", "chrome/browser/resources/settings/chromeos/guest_os/guest_os_browser_proxy.html|GuestOsBrowserProxy, GuestOsBrowserProxyImpl, GuestOsSharedUsbDevice, CROSTINI_TYPE, PLUGIN_VM_TYPE", "chrome/browser/resources/settings/chromeos/kerberos_page/kerberos_accounts_browser_proxy.html|KerberosAccount,KerberosAccountsBrowserProxyImpl,KerberosAccountsBrowserProxy,KerberosErrorType,KerberosConfigErrorCode,ValidateKerberosConfigResult", - "chrome/browser/resources/settings/chromeos/metrics_recorder.html|recordSettingChange", + "chrome/browser/resources/settings/chromeos/metrics_recorder.html|recordSettingChange, recordSearch, setUserActionRecorderForTesting", "chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_browser_proxy.html|MultiDeviceBrowserProxy,MultiDeviceBrowserProxyImpl", "chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_constants.html|MultiDeviceSettingsMode,MultiDeviceFeature,MultiDeviceFeatureState,MultiDevicePageContentData,PhoneHubNotificationAccessStatus,SmartLockSignInEnabledState", "chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_feature_behavior.html|MultiDeviceFeatureBehavior", @@ -171,6 +173,7 @@ "chrome/browser/resources/settings/chromeos/os_settings_routes.html|OsSettingsRoutes", "chrome/browser/resources/settings/chromeos/personalization_page/change_picture_browser_proxy.html|ChangePictureBrowserProxy,ChangePictureBrowserProxyImpl,DefaultImage", "chrome/browser/resources/settings/chromeos/personalization_page/wallpaper_browser_proxy.html|WallpaperBrowserProxy,WallpaperBrowserProxyImpl", + "chrome/browser/resources/settings/chromeos/personalization_page/wallpaper_constants.html|WallpaperCollection", "chrome/browser/resources/settings/chromeos/parental_controls_page/parental_controls_browser_proxy.html|ParentalControlsBrowserProxy,ParentalControlsBrowserProxyImpl", "chrome/browser/resources/settings/chromeos/route_origin_behavior.html|RouteOriginBehaviorImpl,RouteOriginBehavior", "chrome/browser/resources/settings/appearance_page/fonts_browser_proxy.html|FontsBrowserProxy,FontsBrowserProxyImpl", @@ -192,7 +195,7 @@ "chrome/browser/resources/settings/about_page/about_page_browser_proxy.html|AboutPageBrowserProxyImpl,AboutPageUpdateInfo,AboutPageBrowserProxy,browserChannelToI18nId,VersionInfo,ChannelInfo,BrowserChannel,isTargetChannelMoreStable,UpdateStatus,UpdateStatusChangedEvent,RegulatoryInfo,TPMFirmwareUpdateStatusChangedEvent", "chrome/browser/resources/settings/chromeos/os_about_page/device_name_browser_proxy.html|DeviceNameBrowserProxy,DeviceNameBrowserProxyImpl", "chrome/browser/resources/settings/chromeos/os_settings_page/main_page_behavior.html|MainPageBehavior", - "chrome/browser/resources/settings/chromeos/searh_handler.html|getSearchHandler, setSearchHandlerForTesting", + "chrome/browser/resources/settings/chromeos/search_handler.html|getSearchHandler, setSearchHandlerForTesting", "ui/webui/resources/cr_components/chromeos/network/network_listener_behavior.html|NetworkListenerBehavior", "ui/webui/resources/cr_elements/cr_slider/cr_slider.html|SliderTick", "ui/webui/resources/html/assert.html|assert,assertNotReached",
diff --git a/chrome/browser/resources/settings/chromeos/os_settings.js b/chrome/browser/resources/settings/chromeos/os_settings.js index 78c0274..5965c119 100644 --- a/chrome/browser/resources/settings/chromeos/os_settings.js +++ b/chrome/browser/resources/settings/chromeos/os_settings.js
@@ -52,6 +52,7 @@ import '../prefs/prefs.m.js'; import './personalization_page/personalization_page.m.js'; import './personalization_page/change_picture.m.js'; +import './personalization_page/wallpaper_subpage.m.js'; import './os_a11y_page/tts_subpage.m.js'; import './os_people_page/account_manager.m.js'; import './parental_controls_page/parental_controls_page.m.js'; @@ -60,7 +61,10 @@ import './os_about_page/channel_switcher_dialog.m.js'; import './os_about_page/detailed_build_info.m.js'; import './os_about_page/update_warning_dialog.m.js'; +import './os_toolbar/os_toolbar.m.js'; import './os_search_page/os_search_page.m.js'; +import './os_settings_search_box/os_search_result_row.m.js'; +import './os_settings_search_box/os_settings_search_box.m.js'; import './os_icons.m.js'; import './os_settings_icons_css.m.js'; import './os_apps_page/android_apps_subpage.m.js'; @@ -131,3 +135,4 @@ export {ChangePictureBrowserProxy, ChangePictureBrowserProxyImpl} from './personalization_page/change_picture_browser_proxy.m.js'; export {WallpaperBrowserProxyImpl} from './personalization_page/wallpaper_browser_proxy.m.js'; export {getSearchHandler, setSearchHandlerForTesting} from './search_handler.m.js'; +export {setUserActionRecorderForTesting, recordPageFocus, recordPageBlur, recordClick, recordNavigation, recordSearch, recordSettingChange} from './metrics_recorder.m.js';
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_search_box/BUILD.gn b/chrome/browser/resources/settings/chromeos/os_settings_search_box/BUILD.gn index cf181cb5..a089311 100644 --- a/chrome/browser/resources/settings/chromeos/os_settings_search_box/BUILD.gn +++ b/chrome/browser/resources/settings/chromeos/os_settings_search_box/BUILD.gn
@@ -3,6 +3,7 @@ # found in the LICENSE file. import("//third_party/closure_compiler/compile_js.gni") +import("../os_settings.gni") js_type_check("closure_compile") { uses_legacy_modules = true @@ -39,19 +40,26 @@ externs_list = [ "$externs_path/metrics_private.js" ] } -# TODO: Uncomment as the Polymer3 migration makes progress. -#js_type_check("closure_compile_module") { -# is_polymer3 = true -# deps = [ -# ":os_search_result_row.m", -# ":os_settings_search_box.m" -# ] -#} +js_type_check("closure_compile_module") { + is_polymer3 = true + deps = [ + ":os_search_result_row.m", + ":os_settings_search_box.m", + ] +} js_library("os_search_result_row.m") { sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_search_result_row.m.js" ] deps = [ - # TODO: Fill those in. + "..:os_icons.m", + "..:os_route.m", + "..:search_handler.m", + "../..:router.m", + "//third_party/polymer/v3_0/components-chromium/iron-a11y-announcer:iron-a11y-announcer", + "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", + "//ui/webui/resources/js:assert.m", + "//ui/webui/resources/js:i18n_behavior.m", + "//ui/webui/resources/js/cr/ui:focus_row_behavior.m", ] extra_deps = [ ":os_search_result_row_module" ] externs_list = [ "$externs_path/metrics_private.js" ] @@ -60,7 +68,18 @@ js_library("os_settings_search_box.m") { sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_settings_search_box.m.js" ] deps = [ - # TODO: Fill those in. + ":os_search_result_row.m", + "..:metrics_recorder.m", + "..:os_route.m", + "..:search_handler.m", + "../..:router.m", + "//third_party/polymer/v3_0/components-chromium/iron-a11y-announcer:iron-a11y-announcer", + "//third_party/polymer/v3_0/components-chromium/iron-dropdown:iron-dropdown", + "//third_party/polymer/v3_0/components-chromium/iron-list:iron-list", + "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", + "//ui/webui/resources/cr_elements/cr_toolbar:cr_toolbar_search_field.m", + "//ui/webui/resources/js:assert.m", + "//ui/webui/resources/js:i18n_behavior.m", ] extra_deps = [ ":os_settings_search_box_module" ] externs_list = [ "$externs_path/metrics_private.js" ] @@ -79,10 +98,14 @@ js_file = "os_search_result_row.js" html_file = "os_search_result_row.html" html_type = "dom-module" + auto_imports = os_settings_auto_imports + namespace_rewrites = os_settings_namespace_rewrites } polymer_modulizer("os_settings_search_box") { js_file = "os_settings_search_box.js" html_file = "os_settings_search_box.html" html_type = "dom-module" + auto_imports = os_settings_auto_imports + namespace_rewrites = os_settings_namespace_rewrites }
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_settings_search_box.html b/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_settings_search_box.html index 118d6c6..9c12745 100644 --- a/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_settings_search_box.html +++ b/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_settings_search_box.html
@@ -4,7 +4,6 @@ <link rel="import" href="chrome://resources/html/assert.html"> <link rel="import" href="chrome://resources/html/cr/ui/focus_row.html"> <link rel="import" href="chrome://resources/html/i18n_behavior.html"> -<link rel="import" href="chrome://resources/mojo/mojo/public/mojom/base/string16.mojom.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-a11y-announcer/iron-a11y-announcer.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-dropdown/iron-dropdown.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.html"> @@ -13,6 +12,7 @@ <link rel="import" href="../search_handler.html"> <link rel="import" href="../../settings_shared_css.html"> <link rel="import" href="../../router.html"> +<link rel="import" href="../os_route.html"> <dom-module id="os-settings-search-box"> <template>
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_settings_search_box.js b/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_settings_search_box.js index a4b4bcb2..eea0a0ed 100644 --- a/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_settings_search_box.js +++ b/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_settings_search_box.js
@@ -2,11 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -(function() { -'use strict'; - -const mojom = chromeos.settings.mojom; - const MAX_NUM_SEARCH_RESULTS = 5; const SEARCH_REQUEST_METRIC_NAME = 'ChromeOS.Settings.SearchRequests'; @@ -82,7 +77,7 @@ * <os-search-result-row>. This property is bound to the <iron-list>. Note * that when an item is selected, its associated <os-search-result-row> * is not focus()ed at the same time unless it is explicitly clicked/tapped. - * @private {!mojom.SearchResult} + * @private {!chromeos.settings.mojom.SearchResult} */ selectedItem_: { type: Object, @@ -92,7 +87,7 @@ * Prevent user deselection by tracking last item selected. This item must * only be assigned to an item within |this.$.searchResultList|, and not * directly to |this.selectedItem_| or an item within |this.searchResults_|. - * @private {!mojom.SearchResult} + * @private {!chromeos.settings.mojom.SearchResult} */ lastSelectedItem_: { type: Object, @@ -100,7 +95,7 @@ /** * Passed into <iron-list>. Exactly one result is the selectedItem_. - * @private {!Array<!mojom.SearchResult>} + * @private {!Array<!chromeos.settings.mojom.SearchResult>} */ searchResults_: { type: Array, @@ -215,7 +210,9 @@ */ getSelectedOsSearchResultRow_() { return assert( - this.$.searchResultList.querySelector('os-search-result-row[selected]'), + /** @type {!OsSearchResultRowElement} */ ( + this.$.searchResultList.querySelector( + 'os-search-result-row[selected]')), 'No OsSearchResultRow is selected.'); }, @@ -259,7 +256,7 @@ settings.getSearchHandler() .search( queryMojoString16, MAX_NUM_SEARCH_RESULTS, - mojom.ParentResultBehavior.kAllowParentResults) + chromeos.settings.mojom.ParentResultBehavior.kAllowParentResults) .then(response => { const latencyMs = Date.now() - timeOfSearchRequest; chrome.metricsPrivate.recordTime( @@ -280,7 +277,8 @@ /** * Updates search results UI when settings search results are fetched. * @param {string} query The string used to find search results. - * @param {!Array<!mojom.SearchResult>} results Array of search results. + * @param {!Array<!chromeos.settings.mojom.SearchResult>} results Array of + * search results. * @private */ onSearchResultsReceived_(query, results) { @@ -378,7 +376,8 @@ }, /** - * @param {!mojom.SearchResult} item The search result item in searchResults_. + * @param {!chromeos.settings.mojom.SearchResult} item The search result item + * in searchResults_. * @return {boolean} True if the item is selected. * @private */ @@ -399,7 +398,8 @@ * Returns the correct tab index since <iron-list>'s default tabIndex property * does not automatically add selectedItem_'s <os-search-result-row> to the * default navigation flow, unless the user explicitly clicks on the row. - * @param {!mojom.SearchResult} item The search result item in searchResults_. + * @param {!chromeos.settings.mojom.SearchResult} item The search result item + * in searchResults_. * @return {number} A 0 if the row should be in the navigation flow, or a -1 * if the row should not be in the navigation flow. * @private @@ -512,4 +512,3 @@ } }, }); -})();
diff --git a/chrome/browser/resources/settings/chromeos/os_toolbar/BUILD.gn b/chrome/browser/resources/settings/chromeos/os_toolbar/BUILD.gn index 519c798..4f6cd29 100644 --- a/chrome/browser/resources/settings/chromeos/os_toolbar/BUILD.gn +++ b/chrome/browser/resources/settings/chromeos/os_toolbar/BUILD.gn
@@ -3,6 +3,7 @@ # found in the LICENSE file. import("//third_party/closure_compiler/compile_js.gni") +import("../os_settings.gni") js_type_check("closure_compile") { uses_legacy_modules = true @@ -16,18 +17,19 @@ ] } -# TODO: Uncomment as the Polymer3 migration makes progress. -#js_type_check("closure_compile_module") { -# is_polymer3 = true -# deps = [ -# ":os_toolbar.m" -# ] -#} +js_type_check("closure_compile_module") { + is_polymer3 = true + deps = [ ":os_toolbar.m" ] +} js_library("os_toolbar.m") { sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/os_toolbar/os_toolbar.m.js" ] deps = [ - # TODO: Fill those in. + "../os_settings_search_box:os_settings_search_box.m", + "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", + "//ui/webui/resources/cr_elements/cr_icon_button:cr_icon_button.m", + "//ui/webui/resources/cr_elements/cr_toolbar:cr_toolbar_search_field.m", + "//ui/webui/resources/js:load_time_data.m", ] extra_deps = [ ":os_toolbar_module" ] } @@ -42,4 +44,6 @@ js_file = "os_toolbar.js" html_file = "os_toolbar.html" html_type = "dom-module" + auto_imports = os_settings_auto_imports + namespace_rewrites = os_settings_namespace_rewrites }
diff --git a/chrome/browser/resources/settings/chromeos/os_toolbar/os_toolbar.html b/chrome/browser/resources/settings/chromeos/os_toolbar/os_toolbar.html index 34c14c6..7088da69 100644 --- a/chrome/browser/resources/settings/chromeos/os_toolbar/os_toolbar.html +++ b/chrome/browser/resources/settings/chromeos/os_toolbar/os_toolbar.html
@@ -6,6 +6,7 @@ <link rel="import" href="chrome://resources/cr_elements/hidden_style_css.html"> <link rel="import" href="chrome://resources/cr_elements/icons.html"> <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> +<link rel="import" href="chrome://resources/html/load_time_data.html"> <link rel="import" href="chrome://resources/html/assert.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-media-query/iron-media-query.html"> <link rel="import" href="../os_settings_search_box/os_settings_search_box.html">
diff --git a/chrome/browser/resources/settings/chromeos/personalization_page/BUILD.gn b/chrome/browser/resources/settings/chromeos/personalization_page/BUILD.gn index 685eef8..bd057c5 100644 --- a/chrome/browser/resources/settings/chromeos/personalization_page/BUILD.gn +++ b/chrome/browser/resources/settings/chromeos/personalization_page/BUILD.gn
@@ -13,6 +13,7 @@ ":change_picture", ":change_picture_browser_proxy", ":personalization_page", + ":wallpaper_constants", ":wallpaper_subpage", ] } @@ -55,14 +56,22 @@ } js_library("wallpaper_browser_proxy") { - deps = [ "//ui/webui/resources/js:cr" ] + deps = [ + ":wallpaper_constants", + "//ui/webui/resources/js:cr", + ] externs_list = [ "$externs_path/chrome_send.js" ] } +js_library("wallpaper_constants") { +} + js_library("wallpaper_subpage") { deps = [ ":wallpaper_browser_proxy", + ":wallpaper_constants", "//ui/webui/resources/js:cr", + "//ui/webui/resources/js:i18n_behavior", ] } @@ -73,6 +82,7 @@ ":change_picture_browser_proxy.m", ":personalization_page.m", ":wallpaper_browser_proxy.m", + ":wallpaper_constants.m", ":wallpaper_subpage.m", ] } @@ -124,15 +134,23 @@ js_library("wallpaper_browser_proxy.m") { sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/personalization_page/wallpaper_browser_proxy.m.js" ] + deps = [ ":wallpaper_constants.m" ] externs_list = [ "$externs_path/chrome_send.js" ] extra_deps = [ ":modulize" ] } +js_library("wallpaper_constants.m") { + sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/personalization_page/wallpaper_constants.m.js" ] + extra_deps = [ ":modulize" ] +} + js_library("wallpaper_subpage.m") { sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/personalization_page/wallpaper_subpage.m.js" ] deps = [ ":wallpaper_browser_proxy.m", + ":wallpaper_constants.m", "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", + "//ui/webui/resources/js:i18n_behavior.m", ] extra_deps = [ ":wallpaper_subpage_module" ] } @@ -180,6 +198,7 @@ input_files = [ "change_picture_browser_proxy.js", "wallpaper_browser_proxy.js", + "wallpaper_constants.js", ] namespace_rewrites = os_settings_namespace_rewrites }
diff --git a/chrome/browser/resources/settings/chromeos/personalization_page/wallpaper_browser_proxy.js b/chrome/browser/resources/settings/chromeos/personalization_page/wallpaper_browser_proxy.js index c4526d0..7af99d2 100644 --- a/chrome/browser/resources/settings/chromeos/personalization_page/wallpaper_browser_proxy.js +++ b/chrome/browser/resources/settings/chromeos/personalization_page/wallpaper_browser_proxy.js
@@ -4,6 +4,7 @@ // clang-format off // #import {addSingletonGetter, sendWithPromise} from 'chrome://resources/js/cr.m.js'; +// #import {WallpaperCollection} from './wallpaper_constants.m.js'; // clang-format on cr.define('settings', function() { @@ -21,6 +22,12 @@ isWallpaperPolicyControlled() {} openWallpaperManager() {} + + /** + * @return {!Promise<?Array<!WallpaperCollection>>} Returns a promise to + * an array of wallpaper collections. Will reject with null on error. + */ + fetchWallpaperCollections() {} } /** @@ -41,6 +48,11 @@ openWallpaperManager() { chrome.send('openWallpaperManager'); } + + /** @override */ + fetchWallpaperCollections() { + return cr.sendWithPromise('fetchWallpaperCollections'); + } } cr.addSingletonGetter(WallpaperBrowserProxyImpl);
diff --git a/chrome/browser/resources/settings/chromeos/personalization_page/wallpaper_constants.html b/chrome/browser/resources/settings/chromeos/personalization_page/wallpaper_constants.html new file mode 100644 index 0000000..8915f5e --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/personalization_page/wallpaper_constants.html
@@ -0,0 +1 @@ +<script src="wallpaper_constants.js"></script> \ No newline at end of file
diff --git a/chrome/browser/resources/settings/chromeos/personalization_page/wallpaper_constants.js b/chrome/browser/resources/settings/chromeos/personalization_page/wallpaper_constants.js new file mode 100644 index 0000000..cf76b1c --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/personalization_page/wallpaper_constants.js
@@ -0,0 +1,13 @@ +// Copyright 2021 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. + +/** + * WallpaperCollection describes a collection of wallpapers. + * + * @typedef {{ + * id: !string, + * name: !string, + * }} + */ +/* #export */ let WallpaperCollection;
diff --git a/chrome/browser/resources/settings/chromeos/personalization_page/wallpaper_subpage.html b/chrome/browser/resources/settings/chromeos/personalization_page/wallpaper_subpage.html index 204a483..009cbc03 100644 --- a/chrome/browser/resources/settings/chromeos/personalization_page/wallpaper_subpage.html +++ b/chrome/browser/resources/settings/chromeos/personalization_page/wallpaper_subpage.html
@@ -1,14 +1,37 @@ <link rel="import" href="chrome://resources/html/polymer.html"> +<link rel="import" href="chrome://resources/html/i18n_behavior.html"> <link rel="import" href="chrome://resources/cr_elements/shared_style_css.html"> <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> -<link rel="import" href="../personalization_page/wallpaper_browser_proxy.html"> +<link rel="import" href="wallpaper_browser_proxy.html"> +<link rel="import" href="wallpaper_constants.html"> <link rel="import" href="../../settings_shared_css.html"> <dom-module id="settings-wallpaper-page"> <template> <style include="cr-shared-style settings-shared"> + paper-spinner-lite { + display: block; + height: 28px; + margin: 150px auto; + width: 28px; + } </style> + <paper-spinner-lite active="[[loading_]]" + hidden="[[!loading_]]"> + </paper-spinner-lite> + <p hidden="[[!error_]]" id="error">$i18n{wallpaperCollectionsError}</p> + <template is="dom-if" + if="[[success_]]"> + <iron-list items="[[collections_]]"> + <template> + <p class="wallpaper-collection-title" + data-id$="[[item.id]]"> + [[item.name]] + </p> + </template> + </iron-list> + </template> </template> <script src="wallpaper_subpage.js"></script> </dom-module>
diff --git a/chrome/browser/resources/settings/chromeos/personalization_page/wallpaper_subpage.js b/chrome/browser/resources/settings/chromeos/personalization_page/wallpaper_subpage.js index 5f23582..d197ee6 100644 --- a/chrome/browser/resources/settings/chromeos/personalization_page/wallpaper_subpage.js +++ b/chrome/browser/resources/settings/chromeos/personalization_page/wallpaper_subpage.js
@@ -9,9 +9,44 @@ Polymer({ is: 'settings-wallpaper-page', - behaviors: [], + behaviors: [ + I18nBehavior, + ], - properties: {}, + properties: { + /** + * @private + * @type {?Array<!WallpaperCollection>} + */ + collections_: { + type: Array, + value: null, + }, + + /** @private */ + loading_: { + type: Boolean, + value: false, + }, + + /** + * @private + * @type {boolean} + */ + error_: { + type: Boolean, + computed: 'computeError_(collections_, loading_)', + }, + + /** + * @private + * @type {boolean} + */ + success_: { + type: Boolean, + computed: 'computeSuccess_(collections_, loading_)', + }, + }, /** @private {?settings.WallpaperBrowserProxy} */ browserProxy_: null, @@ -21,5 +56,41 @@ this.browserProxy_ = settings.WallpaperBrowserProxyImpl.getInstance(); }, - ready() {}, + /** @override */ + ready() { + this.fetchWallpaperCollections_(); + }, + + /** @private */ + async fetchWallpaperCollections_() { + this.loading_ = true; + this.collections_ = null; + try { + this.collections_ = await this.browserProxy_.fetchWallpaperCollections(); + } catch (e) { + console.warn('Fetching wallpaper collections failed'); + } finally { + this.loading_ = false; + } + }, + + /** + * @private + * @param {?Array<!WallpaperCollection>} collections + * @param {boolean} loading + * @return {boolean} + */ + computeError_(collections, loading) { + return !loading && !this.computeSuccess_(collections, loading); + }, + + /** + * @private + * @param {?Array<!WallpaperCollection>} collections + * @param {boolean} loading + * @return {boolean} + */ + computeSuccess_(collections, loading) { + return !loading && Array.isArray(collections) && collections.length > 0; + }, });
diff --git a/chrome/browser/resources/settings/chromeos/search_handler.html b/chrome/browser/resources/settings/chromeos/search_handler.html index f8a5578..e7e30bf 100644 --- a/chrome/browser/resources/settings/chromeos/search_handler.html +++ b/chrome/browser/resources/settings/chromeos/search_handler.html
@@ -1,8 +1,10 @@ <link rel="import" href="chrome://resources/html/cr.html"> <link rel="import" href="chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.html"> +<link rel="import" href="chrome://resources/mojo/mojo/public/mojom/base/string16.mojom.html"> <script src="chrome://os-settings/constants/routes.mojom-lite.js"></script> <script src="chrome://os-settings/constants/setting.mojom-lite.js"></script> <script src="chrome://os-settings/search/search_result_icon.mojom-lite.js"></script> +<script src="chrome://os-settings/search/user_action_recorder.mojom-lite.js"></script> <script src="chrome://os-settings/search/search.mojom-lite.js"></script> <script src="search_handler.js"></script>
diff --git a/chrome/browser/resources/settings/chromeos/search_handler.js b/chrome/browser/resources/settings/chromeos/search_handler.js index ae23ff9..a952e30 100644 --- a/chrome/browser/resources/settings/chromeos/search_handler.js +++ b/chrome/browser/resources/settings/chromeos/search_handler.js
@@ -3,7 +3,12 @@ // found in the LICENSE file. // #import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js'; +// #import 'chrome://resources/mojo/mojo/public/mojom/base/string16.mojom-lite.js'; // #import '../constants/routes.mojom-lite.js'; +// #import '../constants/setting.mojom-lite.js'; +// #import '../search/search_result_icon.mojom-lite.js'; +// #import '../search/user_action_recorder.mojom-lite.js'; +// #import '../search/search.mojom-lite.js'; /** * @fileoverview
diff --git a/chrome/browser/resources/supervised_user_internals/supervised_user_internals.js b/chrome/browser/resources/supervised_user_internals/supervised_user_internals.js deleted file mode 100644 index 1c71824..0000000 --- a/chrome/browser/resources/supervised_user_internals/supervised_user_internals.js +++ /dev/null
@@ -1,129 +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. - -cr.define('chrome.supervised_user_internals', function() { - 'use strict'; - - function initialize() { - function submitURL(event) { - $('try-url-result').textContent = ''; - $('manual-allowlist').textContent = ''; - $('allowlists').textContent = ''; - chrome.send('tryURL', [$('try-url-input').value]); - event.preventDefault(); - } - - $('try-url').addEventListener('submit', submitURL); - - // Make the prototype jscontent element disappear. - jstProcess({}, $('filtering-results-container')); - - chrome.send('registerForEvents'); - - chrome.send('getBasicInfo'); - } - - function highlightIfChanged(node, oldVal, newVal) { - function clearHighlight() { - this.removeAttribute('highlighted'); - } - - const oldStr = oldVal.toString(); - const newStr = newVal.toString(); - if (oldStr != '' && oldStr != newStr) { - // Note the addListener function does not end up creating duplicate - // listeners. There can be only one listener per event at a time. - // See https://developer.mozilla.org/en/DOM/element.addEventListener - node.addEventListener('animationend', clearHighlight, false); - node.setAttribute('highlighted', ''); - } - } - - function receiveBasicInfo(info) { - jstProcess(new JsEvalContext(info), $('basic-info')); - - // Hack: Schedule another refresh after a while. - setTimeout(function() { - chrome.send('getBasicInfo'); - }, 5000); - } - - function receiveUserSettings(settings) { - if (settings === null) { - $('user-settings').classList.add('hidden'); - return; - } - - $('user-settings').classList.remove('hidden'); - - // The user settings are returned as an object, flatten them into a - // list of key/value pairs for easier consumption by the HTML template. - // This is not done recursively, values are passed as their JSON - // representation. - const kvpairs = Object.keys(settings).map(function(key) { - return {key: key, value: JSON.stringify(settings[key], null, 2)}; - }); - - jstProcess(new JsEvalContext({settings: kvpairs}), $('user-settings')); - } - - function receiveTryURLResult(result) { - $('try-url-result').textContent = result['allowResult']; - $('manual-allowlist').textContent = result['manual']; - $('allowlists').textContent = result['allowlists']; - } - - /** - * Helper to determine if an element is scrolled to its bottom limit. - * @param {Element} elem element to check - * @return {boolean} true if the element is scrolled to the bottom - */ - function isScrolledToBottom(elem) { - return elem.scrollHeight - elem.scrollTop == elem.clientHeight; - } - - /** - * Helper to scroll an element to its bottom limit. - * @param {Element} elem element to be scrolled - */ - function scrollToBottom(elem) { - elem.scrollTop = elem.scrollHeight - elem.clientHeight; - } - - /** Container for accumulated filtering results. */ - const filteringResults = []; - - /** - * Callback for incoming filtering results. - * @param {Object} result The result. - */ - function receiveFilteringResult(result) { - filteringResults.push(result); - - const container = $('filtering-results-container'); - - // Scroll to the bottom if we were already at the bottom. Otherwise, leave - // the scrollbar alone. - const shouldScrollDown = isScrolledToBottom(container); - - jstProcess(new JsEvalContext({results: filteringResults}), container); - - if (shouldScrollDown) { - scrollToBottom(container); - } - } - - // Return an object with all of the exports. - return { - initialize: initialize, - highlightIfChanged: highlightIfChanged, - receiveBasicInfo: receiveBasicInfo, - receiveUserSettings: receiveUserSettings, - receiveTryURLResult: receiveTryURLResult, - receiveFilteringResult: receiveFilteringResult, - }; -}); - -document.addEventListener( - 'DOMContentLoaded', chrome.supervised_user_internals.initialize);
diff --git a/chrome/browser/safe_browsing/safe_browsing_metrics_collector.cc b/chrome/browser/safe_browsing/safe_browsing_metrics_collector.cc index be4c5f5b..29d036c 100644 --- a/chrome/browser/safe_browsing/safe_browsing_metrics_collector.cc +++ b/chrome/browser/safe_browsing/safe_browsing_metrics_collector.cc
@@ -140,8 +140,7 @@ } void SafeBrowsingMetricsCollector::OnEnhancedProtectionPrefChanged() { - if (safe_browsing::GetSafeBrowsingState(*pref_service_) != - SafeBrowsingState::ENHANCED_PROTECTION) { + if (!pref_service_->GetBoolean(prefs::kSafeBrowsingEnhanced)) { LogEnhancedProtectionDisabledMetrics(); } }
diff --git a/chrome/browser/safe_browsing/safe_browsing_metrics_collector_unittest.cc b/chrome/browser/safe_browsing/safe_browsing_metrics_collector_unittest.cc index 4e3f8be7..b7b4023 100644 --- a/chrome/browser/safe_browsing/safe_browsing_metrics_collector_unittest.cc +++ b/chrome/browser/safe_browsing/safe_browsing_metrics_collector_unittest.cc
@@ -263,6 +263,11 @@ "SafeBrowsing.EsbDisabled.LastBypassEventType", /* sample */ EventType::REAL_TIME_INTERSTITIAL_BYPASS, /* expected_count */ 1); + + // Changing no protection to enhanced protection shouldn't log the metric. + SetSafeBrowsingState(&pref_service_, SafeBrowsingState::ENHANCED_PROTECTION); + histograms.ExpectTotalCount("SafeBrowsing.EsbDisabled.LastBypassEventType", + /* expected_count */ 2); } TEST_F(SafeBrowsingMetricsCollectorTest,
diff --git a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc index a1d2985b..10e2bcc 100644 --- a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc +++ b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc
@@ -1137,13 +1137,13 @@ ui_test_utils::NavigateToURL( browser(), embedded_test_server()->GetURL(kSingleFrameTestURL)); GURL initial_url = embedded_test_server()->GetURL(kSingleFrameTestURL); - ClickTestLink("new_tab_download", 2, initial_url); + ClickTestLink("new_tab_download", 3, initial_url); GURL download_url = embedded_test_server()->GetURL(kDownloadItemURL); GURL blank_url = GURL(url::kAboutBlankURL); std::string test_server_ip(embedded_test_server()->host_port_pair().host()); auto* nav_list = navigation_event_list(); ASSERT_TRUE(nav_list); - ASSERT_EQ(4U, nav_list->Size()); + ASSERT_EQ(5U, nav_list->Size()); VerifyNavigationEvent(GURL(), // source_url GURL(), // source_main_frame_url initial_url, // original_request_url @@ -1171,31 +1171,53 @@ false, // has_server_redirect nav_list->Get(2)); EXPECT_EQ(nav_list->Get(2)->source_tab_id, nav_list->Get(2)->target_tab_id); - VerifyNavigationEvent(blank_url, // source_url - blank_url, // source_main_frame_url + // This navigation is done by the document.write() call. + VerifyNavigationEvent(blank_url, // source_url + blank_url, // source_main_frame_url + initial_url, // original_request_url + initial_url, // destination_url + false, // is_user_initiated, + false, // has_committed + false, // has_server_redirect + nav_list->Get(3)); + VerifyNavigationEvent(initial_url, // source_url + initial_url, // source_main_frame_url download_url, // original_request_url download_url, // destination_url false, // is_user_initiated, false, // has_committed false, // has_server_redirect - nav_list->Get(3)); - EXPECT_EQ(nav_list->Get(3)->source_tab_id, nav_list->Get(3)->target_tab_id); + nav_list->Get(4)); + EXPECT_EQ(nav_list->Get(4)->source_tab_id, nav_list->Get(3)->target_tab_id); VerifyHostToIpMap(); ReferrerChain referrer_chain; IdentifyReferrerChainForDownload(GetDownload(), &referrer_chain); - ASSERT_EQ(3, referrer_chain.size()); + ASSERT_EQ(4, referrer_chain.size()); VerifyReferrerChainEntry( download_url, // url GURL(), // main_frame_url ReferrerChainEntry::EVENT_URL, // type test_server_ip, // ip_address - blank_url, // referrer_url + initial_url, // referrer_url GURL(), // referrer_main_frame_url false, // is_retargeting std::vector<GURL>(), // server redirects ReferrerChainEntry::RENDERER_INITIATED_WITHOUT_USER_GESTURE, referrer_chain.Get(0)); + // This is the document.write() call, which changes the URL of the new tab to + // be the same as the initial URL. + VerifyReferrerChainEntry( + initial_url, // url + GURL(), // main_frame_url + ReferrerChainEntry::CLIENT_REDIRECT, // type + test_server_ip, // ip_address + blank_url, // referrer_url + GURL(), // referrer_main_frame_url + false, // is_retargeting + std::vector<GURL>(), // server redirects + ReferrerChainEntry::RENDERER_INITIATED_WITHOUT_USER_GESTURE, + referrer_chain.Get(1)); VerifyReferrerChainEntry( blank_url, // url GURL(), // main_frame_url @@ -1206,7 +1228,7 @@ true, // is_retargeting std::vector<GURL>(), // server redirects ReferrerChainEntry::RENDERER_INITIATED_WITH_USER_GESTURE, - referrer_chain.Get(1)); + referrer_chain.Get(2)); VerifyReferrerChainEntry(initial_url, // url GURL(), // main_frame_url ReferrerChainEntry::LANDING_PAGE, // type @@ -1216,7 +1238,7 @@ false, // is_retargeting std::vector<GURL>(), // server redirects ReferrerChainEntry::BROWSER_INITIATED, - referrer_chain.Get(2)); + referrer_chain.Get(3)); } // Use javascript to open download in a new tab and download has a data url. @@ -1225,14 +1247,14 @@ ui_test_utils::NavigateToURL( browser(), embedded_test_server()->GetURL(kSingleFrameTestURL)); GURL initial_url = embedded_test_server()->GetURL(kSingleFrameTestURL); - ClickTestLink("new_tab_download_with_data_url", 2, initial_url); + ClickTestLink("new_tab_download_with_data_url", 3, initial_url); GURL download_url = GURL(kDownloadDataURL); GURL short_download_url = GURL(kShortDataURL); GURL blank_url = GURL(url::kAboutBlankURL); std::string test_server_ip(embedded_test_server()->host_port_pair().host()); auto* nav_list = navigation_event_list(); ASSERT_TRUE(nav_list); - ASSERT_EQ(4U, nav_list->Size()); + ASSERT_EQ(5U, nav_list->Size()); VerifyNavigationEvent(GURL(), // source_url GURL(), // source_main_frame_url initial_url, // original_request_url @@ -1261,33 +1283,54 @@ false, // has_committed false, // has_server_redirect nav_list->Get(2)); + // This navigation is done by the document.write() call. + VerifyNavigationEvent(blank_url, // source_url + blank_url, // source_main_frame_url + initial_url, // original_request_url + initial_url, // destination_url + false, // is_user_initiated, + false, // has_committed + false, // has_server_redirect + nav_list->Get(3)); EXPECT_EQ(nav_list->Get(2)->source_tab_id, nav_list->Get(2)->target_tab_id); - VerifyNavigationEvent(blank_url, // source_url - blank_url, // source_main_frame_url + VerifyNavigationEvent(initial_url, // source_url + initial_url, // source_main_frame_url download_url, // original_request_url download_url, // destination_url false, // is_user_initiated, false, // has_committed false, // has_server_redirect - nav_list->Get(3)); - EXPECT_TRUE(nav_list->Get(3)->source_tab_id == - nav_list->Get(3)->target_tab_id); + nav_list->Get(4)); + EXPECT_EQ(nav_list->Get(4)->source_tab_id, nav_list->Get(4)->target_tab_id); VerifyHostToIpMap(); ReferrerChain referrer_chain; IdentifyReferrerChainForDownload(GetDownload(), &referrer_chain); - ASSERT_EQ(3, referrer_chain.size()); + ASSERT_EQ(4, referrer_chain.size()); VerifyReferrerChainEntry( short_download_url, // url GURL(), // main_frame_url ReferrerChainEntry::EVENT_URL, // type "", // ip_address - blank_url, // referrer_url + initial_url, // referrer_url GURL(), // referrer_main_frame_url false, // is_retargeting std::vector<GURL>(), // server redirects ReferrerChainEntry::RENDERER_INITIATED_WITHOUT_USER_GESTURE, referrer_chain.Get(0)); + // This is the document.write() call, which changes the URL of the new tab to + // be the same as the initial URL. + VerifyReferrerChainEntry( + initial_url, // url + GURL(), // main_frame_url + ReferrerChainEntry::CLIENT_REDIRECT, // type + test_server_ip, // ip_address + blank_url, // referrer_url + GURL(), // referrer_main_frame_url + false, // is_retargeting + std::vector<GURL>(), // server redirects + ReferrerChainEntry::RENDERER_INITIATED_WITHOUT_USER_GESTURE, + referrer_chain.Get(1)); VerifyReferrerChainEntry( blank_url, // url GURL(), // main_frame_url @@ -1298,7 +1341,7 @@ true, // is_retargeting std::vector<GURL>(), // server redirects ReferrerChainEntry::RENDERER_INITIATED_WITH_USER_GESTURE, - referrer_chain.Get(1)); + referrer_chain.Get(2)); VerifyReferrerChainEntry(initial_url, // url GURL(), // main_frame_url ReferrerChainEntry::LANDING_PAGE, // type @@ -1308,7 +1351,7 @@ false, // is_retargeting std::vector<GURL>(), // server redirects ReferrerChainEntry::BROWSER_INITIATED, - referrer_chain.Get(2)); + referrer_chain.Get(3)); } // Click a link in a subframe and start download. @@ -1452,13 +1495,13 @@ GURL iframe_url = embedded_test_server()->GetURL(kIframeDirectDownloadURL); GURL iframe_retargeting_url = embedded_test_server()->GetURL(kIframeRetargetingURL); - ClickTestLink("iframe_new_tab_download", 2, iframe_retargeting_url, 1); + ClickTestLink("iframe_new_tab_download", 3, iframe_retargeting_url, 1); GURL blank_url = GURL(url::kAboutBlankURL); GURL download_url = embedded_test_server()->GetURL(kDownloadItemURL); std::string test_server_ip(embedded_test_server()->host_port_pair().host()); auto* nav_list = navigation_event_list(); ASSERT_TRUE(nav_list); - ASSERT_EQ(7U, nav_list->Size()); + ASSERT_EQ(8U, nav_list->Size()); VerifyNavigationEvent(GURL(), // source_url GURL(), // source_main_frame_url initial_url, // original_request_url @@ -1528,30 +1571,53 @@ false, // has_committed false, // has_server_redirect nav_list->Get(5)); - VerifyNavigationEvent(blank_url, // source_url - blank_url, // source_main_frame_url - download_url, // original_request_url - download_url, // destination_url - false, // is_user_initiated, - false, // has_committed - false, // has_server_redirect + // This navigation is done by the document.write() call. + VerifyNavigationEvent(blank_url, // source_url + blank_url, // source_main_frame_url + iframe_retargeting_url, // original_request_url + iframe_retargeting_url, // destination_url + false, // is_user_initiated, + false, // has_committed + false, // has_server_redirect nav_list->Get(6)); + VerifyNavigationEvent(iframe_retargeting_url, // source_url + iframe_retargeting_url, // source_main_frame_url + download_url, // original_request_url + download_url, // destination_url + false, // is_user_initiated, + false, // has_committed + false, // has_server_redirect + nav_list->Get(7)); VerifyHostToIpMap(); ReferrerChain referrer_chain; IdentifyReferrerChainForDownload(GetDownload(), &referrer_chain); - EXPECT_EQ(5, referrer_chain.size()); + EXPECT_EQ(6, referrer_chain.size()); VerifyReferrerChainEntry( download_url, // url GURL(), // main_frame_url ReferrerChainEntry::EVENT_URL, // type test_server_ip, // ip_address - blank_url, // referrer_url + iframe_retargeting_url, // referrer_url GURL(), // referrer_main_frame_url false, // is_retargeting std::vector<GURL>(), // server redirects ReferrerChainEntry::RENDERER_INITIATED_WITHOUT_USER_GESTURE, referrer_chain.Get(0)); + // This is the document.write() call, which changes the URL of the new tab to + // be the same as the URL of the document that called the function, which is + // iframe_retargeting.html. + VerifyReferrerChainEntry( + iframe_retargeting_url, // url + GURL(), // main_frame_url + ReferrerChainEntry::CLIENT_REDIRECT, // type + test_server_ip, // ip_address + blank_url, // referrer_url + GURL(), // referrer_main_frame_url + false, // is_retargeting + std::vector<GURL>(), // server redirects + ReferrerChainEntry::RENDERER_INITIATED_WITHOUT_USER_GESTURE, + referrer_chain.Get(1)); VerifyReferrerChainEntry( blank_url, // url GURL(), // main_frame_url @@ -1562,7 +1628,7 @@ true, // is_retargeting std::vector<GURL>(), // server redirects ReferrerChainEntry::RENDERER_INITIATED_WITH_USER_GESTURE, - referrer_chain.Get(1)); + referrer_chain.Get(2)); VerifyReferrerChainEntry( iframe_retargeting_url, // url multi_frame_test_url, // main_frame_url @@ -1573,7 +1639,7 @@ false, // is_retargeting std::vector<GURL>(), // server redirects ReferrerChainEntry::RENDERER_INITIATED_WITHOUT_USER_GESTURE, - referrer_chain.Get(2)); + referrer_chain.Get(3)); VerifyReferrerChainEntry( multi_frame_test_url, // url GURL(), // main_frame_url @@ -1584,7 +1650,7 @@ false, // is_retargeting std::vector<GURL>(), // server redirects ReferrerChainEntry::RENDERER_INITIATED_WITH_USER_GESTURE, - referrer_chain.Get(3)); + referrer_chain.Get(4)); VerifyReferrerChainEntry(initial_url, // url GURL(), // main_frame_url ReferrerChainEntry::LANDING_REFERRER, // type @@ -1594,7 +1660,7 @@ false, // is_retargeting std::vector<GURL>(), // server redirects ReferrerChainEntry::BROWSER_INITIATED, - referrer_chain.Get(4)); + referrer_chain.Get(5)); } // Click a link which redirects to the landing page, and then click on the
diff --git a/chrome/browser/search/background/ntp_background.proto b/chrome/browser/search/background/ntp_background.proto index 7aac003..a38b9a4 100644 --- a/chrome/browser/search/background/ntp_background.proto +++ b/chrome/browser/search/background/ntp_background.proto
@@ -48,14 +48,15 @@ } message GetCollectionsRequest { - // Deprecated or unused tag numbers - reserved 3; - // The language that should be used for content. e.g. "en-US" optional string language = 1; // The approximate permanent location of the user. e.g. "us". optional string region = 2; + + // Label (e.g. "chrome_desktop_ntp") used to return exclusive content or + // filter unwanted collections from the corpus. + repeated string filtering_label = 3; } message GetCollectionsResponse {
diff --git a/chrome/browser/search/background/ntp_background_service.cc b/chrome/browser/search/background/ntp_background_service.cc index abe378d..85f1fc45 100644 --- a/chrome/browser/search/background/ntp_background_service.cc +++ b/chrome/browser/search/background/ntp_background_service.cc
@@ -5,11 +5,13 @@ #include "chrome/browser/search/background/ntp_background_service.h" #include "base/bind.h" +#include "base/strings/strcat.h" #include "base/strings/stringprintf.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/net/system_network_context_manager.h" #include "chrome/browser/search/background/ntp_background.pb.h" #include "chrome/browser/search/background/ntp_backgrounds.h" +#include "components/version_info/version_info.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" #include "net/base/load_flags.h" @@ -39,6 +41,9 @@ // TODO(crbug.com/874339): Set options based on display resolution capability. constexpr char kImageOptions[] = "=w3840-h2160-p-k-no-nd-mv"; +// Label added to request to filter out unwanted collections. +constexpr char kFilteringLabel[] = "chrome_desktop_ntp"; + } // namespace NtpBackgroundService::NtpBackgroundService( @@ -98,6 +103,11 @@ ntp::background::GetCollectionsRequest request; // The language field may include the country code (e.g. "en-US"). request.set_language(g_browser_process->GetApplicationLocale()); + request.add_filtering_label(kFilteringLabel); + // Add some extra filtering information in case we need to target a specific + // milestone post release. + request.add_filtering_label(base::StrCat( + {kFilteringLabel, ".M", version_info::GetMajorVersionNumber()})); std::string serialized_proto; request.SerializeToString(&serialized_proto);
diff --git a/chrome/browser/search/background/ntp_background_service_unittest.cc b/chrome/browser/search/background/ntp_background_service_unittest.cc index a5b8190..5ddb17f 100644 --- a/chrome/browser/search/background/ntp_background_service_unittest.cc +++ b/chrome/browser/search/background/ntp_background_service_unittest.cc
@@ -10,8 +10,11 @@ #include "base/run_loop.h" #include "base/test/bind.h" #include "base/test/task_environment.h" +#include "chrome/browser/browser_process.h" #include "chrome/browser/search/background/ntp_background_data.h" +#include "components/version_info/version_info.h" #include "content/public/test/browser_task_environment.h" +#include "services/network/public/cpp/data_element.h" #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" #include "services/network/test/test_url_loader_factory.h" #include "testing/gmock/include/gmock/gmock.h" @@ -52,6 +55,9 @@ } NtpBackgroundService* service() { return service_.get(); } + network::TestURLLoaderFactory* test_url_loader_factory() { + return &test_url_loader_factory_; + } private: // Required to run tests from UI and threads. @@ -63,6 +69,29 @@ std::unique_ptr<NtpBackgroundService> service_; }; +TEST_F(NtpBackgroundServiceTest, CorrectCollectionRequest) { + g_browser_process->SetApplicationLocale("foo"); + service()->FetchCollectionInfo(); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(1u, test_url_loader_factory()->pending_requests()->size()); + std::string request_body = test_url_loader_factory() + ->pending_requests() + ->at(0) + .request.request_body->elements() + ->at(0) + .As<network::DataElementBytes>() + .AsStringPiece() + .as_string(); + ntp::background::GetCollectionsRequest collection_request; + EXPECT_TRUE(collection_request.ParseFromString(request_body)); + EXPECT_EQ("foo", collection_request.language()); + EXPECT_EQ(2, collection_request.filtering_label_size()); + EXPECT_EQ("chrome_desktop_ntp", collection_request.filtering_label(0)); + EXPECT_EQ("chrome_desktop_ntp.M" + version_info::GetMajorVersionNumber(), + collection_request.filtering_label(1)); +} + TEST_F(NtpBackgroundServiceTest, CollectionInfoNetworkError) { SetUpResponseWithNetworkError(service()->GetCollectionsLoadURLForTesting());
diff --git a/chrome/browser/sharesheet/sharesheet_service.cc b/chrome/browser/sharesheet/sharesheet_service.cc index 7c3bc62..36038814 100644 --- a/chrome/browser/sharesheet/sharesheet_service.cc +++ b/chrome/browser/sharesheet/sharesheet_service.cc
@@ -194,7 +194,8 @@ apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerWindow, WindowOpenDisposition::NEW_WINDOW, /*prefer_container=*/true), - std::move(intent), launch_source, display::kDefaultDisplayId); + std::move(intent), launch_source, + apps::MakeWindowInfo(display::kDefaultDisplayId)); } void SharesheetService::OnIconLoaded(
diff --git a/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/ProfileDataCache.java b/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/ProfileDataCache.java index 7f3d29c..252fce56 100644 --- a/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/ProfileDataCache.java +++ b/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/ProfileDataCache.java
@@ -265,14 +265,9 @@ @Override public void onExtendedAccountInfoUpdated(AccountInfo accountInfo) { final String accountEmail = accountInfo.getEmail(); - DisplayableProfileData profileData = mCachedProfileData.get(accountEmail); - // if profileData is null, we will fetch monogram when generating - // the cache so that different sources will be handled in order. - if (profileData != null && profileData.getImage() == mPlaceholderImage) { - updateCachedProfileDataAndNotifyObservers(new DisplayableProfileData(accountEmail, - prepareAvatar(accountInfo.getAccountImage(), accountEmail), - profileData.getFullName(), profileData.getGivenName())); - } + updateCachedProfileDataAndNotifyObservers(new DisplayableProfileData(accountEmail, + prepareAvatar(accountInfo.getAccountImage(), accountEmail), + accountInfo.getFullName(), accountInfo.getGivenName())); } /**
diff --git a/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/ProfileDataCacheRenderTest.java b/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/ProfileDataCacheRenderTest.java index 5ea4988..95f91bd4 100644 --- a/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/ProfileDataCacheRenderTest.java +++ b/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/ProfileDataCacheRenderTest.java
@@ -6,8 +6,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; import static org.mockito.MockitoAnnotations.initMocks; @@ -136,14 +134,8 @@ @Test @MediumTest @Feature("RenderTest") - public void testProfileDataUpdatedFromIdentityManager() throws IOException { - String accountEmail = "test@example.com"; - when(mIdentityManagerNativeMock - .findExtendedAccountInfoForAccountWithRefreshTokenByEmailAddress( - anyLong(), eq(accountEmail))) - .thenReturn(new AccountInfo(new CoreAccountId("gaia-id-test"), accountEmail, - "gaia-id-test", "full name", "given name", null)); - + public void testProfileDataUpdatedFromIdentityManagerObserver() throws IOException { + final String accountEmail = "test@example.com"; mAccountManagerTestRule.addAccount( new ProfileDataSource.ProfileData(accountEmail, null, "Full Name", "Given Name")); mIdentityManager.onExtendedAccountInfoUpdated( @@ -156,6 +148,18 @@ @Test @MediumTest @Feature("RenderTest") + public void testProfileDataPopulatedFromIdentityManagerObserver() throws IOException { + final String accountEmail = "test@example.com"; + mIdentityManager.onExtendedAccountInfoUpdated( + new AccountInfo(new CoreAccountId("gaia-id-test"), accountEmail, "gaia-id-test", + "full name", "given name", createAvatar())); + TestThreadUtils.runOnUiThreadBlocking(() -> { checkImageIsScaled(accountEmail); }); + mRenderTestRule.render(mImageView, "profile_data_cache_avatar" + mImageSize); + } + + @Test + @MediumTest + @Feature("RenderTest") public void testPlaceholderIsScaled() throws IOException { TestThreadUtils.runOnUiThreadBlocking( () -> { checkImageIsScaled("no.data.for.this.account@example.com"); });
diff --git a/chrome/browser/speech/speech_recognition_service.cc b/chrome/browser/speech/chrome_speech_recognition_service.cc similarity index 87% rename from chrome/browser/speech/speech_recognition_service.cc rename to chrome/browser/speech/chrome_speech_recognition_service.cc index 075e6e99..d2faad1 100644 --- a/chrome/browser/speech/speech_recognition_service.cc +++ b/chrome/browser/speech/chrome_speech_recognition_service.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/speech/speech_recognition_service.h" +#include "chrome/browser/speech/chrome_speech_recognition_service.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/component_updater/soda_language_pack_component_installer.h" @@ -22,15 +22,15 @@ constexpr base::TimeDelta kIdleProcessTimeout = base::TimeDelta::FromSeconds(5); -SpeechRecognitionService::SpeechRecognitionService( +ChromeSpeechRecognitionService::ChromeSpeechRecognitionService( content::BrowserContext* context) : context_(context), enable_soda_( base::FeatureList::IsEnabled(media::kUseSodaForLiveCaption)) {} -SpeechRecognitionService::~SpeechRecognitionService() = default; +ChromeSpeechRecognitionService::~ChromeSpeechRecognitionService() = default; -void SpeechRecognitionService::Create( +void ChromeSpeechRecognitionService::Create( mojo::PendingReceiver<media::mojom::SpeechRecognitionContext> receiver) { LaunchIfNotRunning(); @@ -38,7 +38,7 @@ speech_recognition_service_->BindContext(std::move(receiver)); } -void SpeechRecognitionService::OnNetworkServiceDisconnect() { +void ChromeSpeechRecognitionService::OnNetworkServiceDisconnect() { if (!enable_soda_) { // If the Speech On-Device API // is not enabled, pass the URL @@ -61,7 +61,7 @@ } } -void SpeechRecognitionService::LaunchIfNotRunning() { +void ChromeSpeechRecognitionService::LaunchIfNotRunning() { if (speech_recognition_service_.is_bound()) return; @@ -74,7 +74,8 @@ return; auto binary_path = global_prefs->GetFilePath(prefs::kSodaBinaryPath); - auto config_path = SpeechRecognitionService::GetSodaConfigPath(profile_prefs); + auto config_path = + ChromeSpeechRecognitionService::GetSodaConfigPath(profile_prefs); if (enable_soda_ && (binary_path.empty() || config_path.empty())) { LOG(ERROR) << "Unable to find SODA files on the device."; return; @@ -96,15 +97,17 @@ speech_recognition_service_client_.reset(); - if (enable_soda_) + if (enable_soda_) { speech_recognition_service_->SetSodaPath(binary_path, config_path); + } speech_recognition_service_->BindSpeechRecognitionServiceClient( speech_recognition_service_client_.BindNewPipeAndPassRemote()); OnNetworkServiceDisconnect(); } -base::FilePath SpeechRecognitionService::GetSodaConfigPath(PrefService* prefs) { +base::FilePath ChromeSpeechRecognitionService::GetSodaConfigPath( + PrefService* prefs) { base::Optional<component_updater::SodaLanguagePackComponentConfig> language_config = component_updater:: SodaLanguagePackComponentInstallerPolicy::GetLanguageComponentConfig( @@ -114,7 +117,6 @@ return g_browser_process->local_state()->GetFilePath( language_config.value().config_path_pref); } - return base::FilePath(); } } // namespace speech
diff --git a/chrome/browser/speech/chrome_speech_recognition_service.h b/chrome/browser/speech/chrome_speech_recognition_service.h new file mode 100644 index 0000000..d90f23b --- /dev/null +++ b/chrome/browser/speech/chrome_speech_recognition_service.h
@@ -0,0 +1,67 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_SPEECH_CHROME_SPEECH_RECOGNITION_SERVICE_H_ +#define CHROME_BROWSER_SPEECH_CHROME_SPEECH_RECOGNITION_SERVICE_H_ + +#include "chrome/browser/speech/speech_recognition_service.h" +#include "components/keyed_service/core/keyed_service.h" +#include "media/mojo/mojom/speech_recognition_service.mojom.h" +#include "mojo/public/cpp/bindings/receiver.h" +#include "mojo/public/cpp/bindings/remote.h" + +class PrefService; + +namespace content { +class BrowserContext; +} // namespace content + +namespace speech { + +// Provides a mojo endpoint in the browser that allows the renderer process to +// launch and initialize the sandboxed speech recognition service +// process. +class ChromeSpeechRecognitionService + : public SpeechRecognitionService, + public media::mojom::SpeechRecognitionServiceClient { + public: + explicit ChromeSpeechRecognitionService(content::BrowserContext* context); + ChromeSpeechRecognitionService(const ChromeSpeechRecognitionService&) = + delete; + ChromeSpeechRecognitionService& operator=(const SpeechRecognitionService&) = + delete; + ~ChromeSpeechRecognitionService() override; + + void Create(mojo::PendingReceiver<media::mojom::SpeechRecognitionContext> + receiver) override; + + // media::mojom::SpeechRecognitionServiceClient + void OnNetworkServiceDisconnect() override; + + private: + // Launches the speech recognition service in a sandboxed utility process. + void LaunchIfNotRunning(); + + // Gets the path of the SODA configuration file for the selected language. + base::FilePath GetSodaConfigPath(PrefService* prefs); + + // The browser context associated with the keyed service. + content::BrowserContext* const context_; + + // A flag indicating whether to use the Speech On-Device API (SODA) for speech + // recognition. + const bool enable_soda_; + + // The remote to the speech recognition service. The browser will not launch a + // new speech recognition service process if this remote is already bound. + mojo::Remote<media::mojom::SpeechRecognitionService> + speech_recognition_service_; + + mojo::Receiver<media::mojom::SpeechRecognitionServiceClient> + speech_recognition_service_client_{this}; +}; + +} // namespace speech + +#endif // CHROME_BROWSER_SPEECH_CHROME_SPEECH_RECOGNITION_SERVICE_H_
diff --git a/chrome/browser/speech/cros_speech_recognition_service.cc b/chrome/browser/speech/cros_speech_recognition_service.cc new file mode 100644 index 0000000..c7dc56e9 --- /dev/null +++ b/chrome/browser/speech/cros_speech_recognition_service.cc
@@ -0,0 +1,43 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/speech/cros_speech_recognition_service.h" + +#include "chrome/services/speech/cros_speech_recognition_recognizer_impl.h" +#include "components/soda/constants.h" +#include "media/base/media_switches.h" + +namespace speech { + +CrosSpeechRecognitionService::CrosSpeechRecognitionService( + content::BrowserContext* context) + : ChromeSpeechRecognitionService(context), + enable_soda_( + base::FeatureList::IsEnabled(media::kUseSodaForLiveCaption)) {} + +CrosSpeechRecognitionService::~CrosSpeechRecognitionService() {} + +void CrosSpeechRecognitionService::Create( + mojo::PendingReceiver<media::mojom::SpeechRecognitionContext> receiver) { + if (enable_soda_) { + speech_recognition_contexts_.Add(this, std::move(receiver)); + } else { + // If soda is not enabled, do the same thing as chrome. + ChromeSpeechRecognitionService::Create(std::move(receiver)); + } +} + +void CrosSpeechRecognitionService::BindRecognizer( + mojo::PendingReceiver<media::mojom::SpeechRecognitionRecognizer> receiver, + mojo::PendingRemote<media::mojom::SpeechRecognitionRecognizerClient> client, + BindRecognizerCallback callback) { + // TODO(robsc): Create this with appropriate file locations. + CrosSpeechRecognitionRecognizerImpl::Create( + std::move(receiver), std::move(client), nullptr, base::FilePath(), + base::FilePath()); + std::move(callback).Run( + CrosSpeechRecognitionRecognizerImpl::IsMultichannelSupported()); +} + +} // namespace speech
diff --git a/chrome/browser/speech/cros_speech_recognition_service.h b/chrome/browser/speech/cros_speech_recognition_service.h new file mode 100644 index 0000000..3da167b5 --- /dev/null +++ b/chrome/browser/speech/cros_speech_recognition_service.h
@@ -0,0 +1,49 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_SPEECH_CROS_SPEECH_RECOGNITION_SERVICE_H_ +#define CHROME_BROWSER_SPEECH_CROS_SPEECH_RECOGNITION_SERVICE_H_ + +#include "chrome/browser/speech/chrome_speech_recognition_service.h" +#include "media/mojo/mojom/speech_recognition_service.mojom.h" +#include "mojo/public/cpp/bindings/receiver_set.h" +#include "mojo/public/cpp/bindings/remote.h" + +namespace content { +class BrowserContext; +} // namespace content + +namespace speech { + +// Provides a Mojo endpoint in the browser for the CROS system. This uses ML +// Service, so is actually executing a little more in the +// browser then regular chrome. +class CrosSpeechRecognitionService + : public ChromeSpeechRecognitionService, + public media::mojom::SpeechRecognitionContext { + public: + explicit CrosSpeechRecognitionService(content::BrowserContext* context); + CrosSpeechRecognitionService(const CrosSpeechRecognitionService&) = delete; + CrosSpeechRecognitionService& operator=(const SpeechRecognitionService&) = + delete; + ~CrosSpeechRecognitionService() override; + void Create(mojo::PendingReceiver<media::mojom::SpeechRecognitionContext> + receiver) override; + + // media::mojom::SpeechRecognitionContext + void BindRecognizer( + mojo::PendingReceiver<media::mojom::SpeechRecognitionRecognizer> receiver, + mojo::PendingRemote<media::mojom::SpeechRecognitionRecognizerClient> + client, + BindRecognizerCallback callback) override; + + private: + mojo::ReceiverSet<media::mojom::SpeechRecognitionContext> + speech_recognition_contexts_; + const bool enable_soda_; +}; + +} // namespace speech + +#endif // CHROME_BROWSER_SPEECH_CROS_SPEECH_RECOGNITION_SERVICE_H_
diff --git a/chrome/browser/speech/cros_speech_recognition_service_factory.cc b/chrome/browser/speech/cros_speech_recognition_service_factory.cc new file mode 100644 index 0000000..ba9ff96b --- /dev/null +++ b/chrome/browser/speech/cros_speech_recognition_service_factory.cc
@@ -0,0 +1,46 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/speech/cros_speech_recognition_service_factory.h" + +#include "base/no_destructor.h" +#include "chrome/browser/profiles/incognito_helpers.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/speech/cros_speech_recognition_service.h" +#include "chrome/browser/speech/speech_recognition_service.h" +#include "components/keyed_service/content/browser_context_dependency_manager.h" + +// static +speech::SpeechRecognitionService* +CrosSpeechRecognitionServiceFactory::GetForProfile(Profile* profile) { + return static_cast<speech::SpeechRecognitionService*>( + GetInstance()->GetServiceForBrowserContext(profile, true)); +} + +// static +CrosSpeechRecognitionServiceFactory* +CrosSpeechRecognitionServiceFactory::GetInstance() { + static base::NoDestructor<CrosSpeechRecognitionServiceFactory> instance; + return instance.get(); +} + +CrosSpeechRecognitionServiceFactory::CrosSpeechRecognitionServiceFactory() + : BrowserContextKeyedServiceFactory( + "SpeechRecognitionService", + BrowserContextDependencyManager::GetInstance()) {} + +CrosSpeechRecognitionServiceFactory::~CrosSpeechRecognitionServiceFactory() = + default; + +KeyedService* CrosSpeechRecognitionServiceFactory::BuildServiceInstanceFor( + content::BrowserContext* context) const { + return new speech::CrosSpeechRecognitionService(context); +} + +// Incognito profiles should use their own instance of the browser context. +content::BrowserContext* +CrosSpeechRecognitionServiceFactory::GetBrowserContextToUse( + content::BrowserContext* context) const { + return chrome::GetBrowserContextOwnInstanceInIncognito(context); +}
diff --git a/chrome/browser/speech/cros_speech_recognition_service_factory.h b/chrome/browser/speech/cros_speech_recognition_service_factory.h new file mode 100644 index 0000000..616e4dd --- /dev/null +++ b/chrome/browser/speech/cros_speech_recognition_service_factory.h
@@ -0,0 +1,42 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_SPEECH_CROS_SPEECH_RECOGNITION_SERVICE_FACTORY_H_ +#define CHROME_BROWSER_SPEECH_CROS_SPEECH_RECOGNITION_SERVICE_FACTORY_H_ + +#include "components/keyed_service/content/browser_context_keyed_service_factory.h" + +class Profile; + +namespace base { +template <class T> +class NoDestructor; +} // namespace base + +namespace speech { +class SpeechRecognitionService; +} // namespace speech + +// Factory to get or create an instance of CrosSpeechRecognitionServiceFactory +// from a Profile. +class CrosSpeechRecognitionServiceFactory + : public BrowserContextKeyedServiceFactory { + public: + static speech::SpeechRecognitionService* GetForProfile(Profile* profile); + + private: + friend class base::NoDestructor<CrosSpeechRecognitionServiceFactory>; + static CrosSpeechRecognitionServiceFactory* GetInstance(); + + CrosSpeechRecognitionServiceFactory(); + ~CrosSpeechRecognitionServiceFactory() override; + + // BrowserContextKeyedServiceFactory: + KeyedService* BuildServiceInstanceFor( + content::BrowserContext* context) const override; + content::BrowserContext* GetBrowserContextToUse( + content::BrowserContext* context) const override; +}; + +#endif // CHROME_BROWSER_SPEECH_CROS_SPEECH_RECOGNITION_SERVICE_FACTORY_H_
diff --git a/chrome/browser/speech/cros_speech_recognition_service_factory_unittest.cc b/chrome/browser/speech/cros_speech_recognition_service_factory_unittest.cc new file mode 100644 index 0000000..fe1159a --- /dev/null +++ b/chrome/browser/speech/cros_speech_recognition_service_factory_unittest.cc
@@ -0,0 +1,28 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/speech/cros_speech_recognition_service_factory.h" + +#include "chrome/test/base/testing_profile.h" +#include "content/public/test/browser_task_environment.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace { + +using testing::IsNull; +using testing::Not; + +// Verifies that the service factory supports incognito profiles. +TEST(CrosSpeechRecognitionServiceFactoryTest, IncognitoProfile) { + content::BrowserTaskEnvironment task_environment; + + TestingProfile profile; + + const speech::SpeechRecognitionService* const service = + CrosSpeechRecognitionServiceFactory::GetForProfile( + profile.GetPrimaryOTRProfile()); + EXPECT_THAT(service, Not(IsNull())); +} + +} // namespace
diff --git a/chrome/browser/speech/speech_recognition_service.h b/chrome/browser/speech/speech_recognition_service.h index 41ad6beb..dfea36f 100644 --- a/chrome/browser/speech/speech_recognition_service.h +++ b/chrome/browser/speech/speech_recognition_service.h
@@ -7,55 +7,15 @@ #include "components/keyed_service/core/keyed_service.h" #include "media/mojo/mojom/speech_recognition_service.mojom.h" -#include "mojo/public/cpp/bindings/remote.h" - -class PrefService; - -namespace content { -class BrowserContext; -} // namespace content +#include "mojo/public/cpp/bindings/pending_receiver.h" namespace speech { -// Provides a mojo endpoint in the browser that allows the renderer process to -// launch and initialize the sandboxed speech recognition service -// process. -class SpeechRecognitionService - : public KeyedService, - public media::mojom::SpeechRecognitionServiceClient { +class SpeechRecognitionService : public KeyedService { public: - explicit SpeechRecognitionService(content::BrowserContext* context); - SpeechRecognitionService(const SpeechRecognitionService&) = delete; - SpeechRecognitionService& operator=(const SpeechRecognitionService&) = delete; - ~SpeechRecognitionService() override; - - void Create( - mojo::PendingReceiver<media::mojom::SpeechRecognitionContext> receiver); - - // media::mojom::SpeechRecognitionServiceClient - void OnNetworkServiceDisconnect() override; - - private: - // Launches the speech recognition service in a sandboxed utility process. - void LaunchIfNotRunning(); - - // Gets the path of the SODA configuration file for the selected language. - base::FilePath GetSodaConfigPath(PrefService* prefs); - - // The browser context associated with the keyed service. - content::BrowserContext* const context_; - - // A flag indicating whether to use the Speech On-Device API (SODA) for speech - // recognition. - bool enable_soda_ = false; - - // The remote to the speech recognition service. The browser will not launch a - // new speech recognition service process if this remote is already bound. - mojo::Remote<media::mojom::SpeechRecognitionService> - speech_recognition_service_; - - mojo::Receiver<media::mojom::SpeechRecognitionServiceClient> - speech_recognition_service_client_{this}; + virtual void Create( + mojo::PendingReceiver<media::mojom::SpeechRecognitionContext> + receiver) = 0; }; } // namespace speech
diff --git a/chrome/browser/speech/speech_recognition_service_factory.cc b/chrome/browser/speech/speech_recognition_service_factory.cc index 227263d..f3b390e 100644 --- a/chrome/browser/speech/speech_recognition_service_factory.cc +++ b/chrome/browser/speech/speech_recognition_service_factory.cc
@@ -7,6 +7,7 @@ #include "base/no_destructor.h" #include "chrome/browser/profiles/incognito_helpers.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/speech/chrome_speech_recognition_service.h" #include "chrome/browser/speech/speech_recognition_service.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" @@ -33,7 +34,7 @@ KeyedService* SpeechRecognitionServiceFactory::BuildServiceInstanceFor( content::BrowserContext* context) const { - return new speech::SpeechRecognitionService(context); + return new speech::ChromeSpeechRecognitionService(context); } // Incognito profiles should use their own instance of the browser context.
diff --git a/chrome/browser/subresource_filter/ad_tagging_browsertest.cc b/chrome/browser/subresource_filter/ad_tagging_browsertest.cc index fc6d7e4..95d82bb 100644 --- a/chrome/browser/subresource_filter/ad_tagging_browsertest.cc +++ b/chrome/browser/subresource_filter/ad_tagging_browsertest.cc
@@ -287,9 +287,13 @@ name.c_str()); // The executed scripts set the title to be the frame name when they have // finished loading. + content::TestNavigationObserver navigation_observer(GetWebContents(), 1); content::TitleWatcher title_watcher(GetWebContents(), base::ASCIIToUTF16(name)); EXPECT_TRUE(content::ExecuteScript(rfh, script)); + // The document.write() will implicitly call document.open(), which will send + // a same-document navigation notification. Wait for it. + navigation_observer.Wait(); EXPECT_EQ(base::ASCIIToUTF16(name), title_watcher.WaitAndGetTitle()); return content::FrameMatchingPredicate( content::WebContents::FromRenderFrameHost(rfh), @@ -569,13 +573,18 @@ CreateDocWrittenFrame(GetWebContents()); EXPECT_FALSE(observer.GetIsAdSubframe(vanilla_frame->GetFrameTreeNodeId())); + // When the main frame invoked document.write() on |vanilla_frame|, + // |vanilla_frame|'s url was changed to match the main frame's url. Load + // |vanilla_frame|'s child frames with a query to ensure the urls are not + // identical, since outside of document.open() we refuse to navigate an iframe + // to its parent's url. content::RenderFrameHost* vanilla_child_of_vanilla = - CreateSrcFrame(vanilla_frame, GetURL("frame_factory.html")); + CreateSrcFrame(vanilla_frame, GetURL("frame_factory.html?1")); EXPECT_FALSE( observer.GetIsAdSubframe(vanilla_child_of_vanilla->GetFrameTreeNodeId())); content::RenderFrameHost* ad_child_of_vanilla = - CreateSrcFrameFromAdScript(vanilla_frame, GetURL("frame_factory.html")); + CreateSrcFrameFromAdScript(vanilla_frame, GetURL("frame_factory.html?2")); EXPECT_TRUE( observer.GetIsAdSubframe(ad_child_of_vanilla->GetFrameTreeNodeId())); observer.VerifyEvidenceForAdSubframe( @@ -591,7 +600,7 @@ ScriptHeuristicEvidence::kCreatedByAdScript); content::RenderFrameHost* vanilla_child_of_ad = - CreateSrcFrame(ad_frame, GetURL("frame_factory.html")); + CreateSrcFrame(ad_frame, GetURL("frame_factory.html?3")); EXPECT_TRUE( observer.GetIsAdSubframe(vanilla_child_of_ad->GetFrameTreeNodeId())); observer.VerifyEvidenceForAdSubframe( @@ -600,7 +609,7 @@ ScriptHeuristicEvidence::kCreatedByAdScript); content::RenderFrameHost* ad_child_of_ad = - CreateSrcFrameFromAdScript(ad_frame, GetURL("frame_factory.html")); + CreateSrcFrameFromAdScript(ad_frame, GetURL("frame_factory.html?4")); EXPECT_TRUE(observer.GetIsAdSubframe(ad_child_of_ad->GetFrameTreeNodeId())); observer.VerifyEvidenceForAdSubframe( ad_child_of_ad, /*parent_is_ad=*/true, FilterListEvidence::kNotChecked, @@ -700,13 +709,19 @@ content::RenderFrameHost* vanilla_frame_with_aborted_load = CreateFrameWithDocWriteAbortedLoad(GetWebContents()); + // When the main frame invoked document.write() on + // |vanilla_frame_with_aborted_load|, |vanilla_frame_with_aborted_load|'s url + // was changed to match the main frame's url. Load + // |vanilla_frame_with_aborted_load|'s child frames with a query to ensure the + // urls are not identical, since outside of document.open() we refuse to + // navigate an iframe to its parent's url. content::RenderFrameHost* vanilla_child_of_vanilla = CreateSrcFrame( - vanilla_frame_with_aborted_load, GetURL("frame_factory.html")); + vanilla_frame_with_aborted_load, GetURL("frame_factory.html?1")); EXPECT_FALSE( observer.GetIsAdSubframe(vanilla_child_of_vanilla->GetFrameTreeNodeId())); content::RenderFrameHost* ad_child_of_vanilla = CreateSrcFrameFromAdScript( - vanilla_frame_with_aborted_load, GetURL("frame_factory.html")); + vanilla_frame_with_aborted_load, GetURL("frame_factory.html?2")); EXPECT_TRUE( observer.GetIsAdSubframe(ad_child_of_vanilla->GetFrameTreeNodeId())); observer.VerifyEvidenceForAdSubframe( @@ -725,8 +740,8 @@ FilterListEvidence::kNotChecked, ScriptHeuristicEvidence::kCreatedByAdScript); - content::RenderFrameHost* vanilla_child_of_ad = - CreateSrcFrame(ad_frame_with_aborted_load, GetURL("frame_factory.html")); + content::RenderFrameHost* vanilla_child_of_ad = CreateSrcFrame( + ad_frame_with_aborted_load, GetURL("frame_factory.html?3")); EXPECT_TRUE( observer.GetIsAdSubframe(vanilla_child_of_ad->GetFrameTreeNodeId())); observer.VerifyEvidenceForAdSubframe( @@ -735,7 +750,7 @@ ScriptHeuristicEvidence::kCreatedByAdScript); content::RenderFrameHost* ad_child_of_ad = CreateSrcFrameFromAdScript( - ad_frame_with_aborted_load, GetURL("frame_factory.html")); + ad_frame_with_aborted_load, GetURL("frame_factory.html?4")); EXPECT_TRUE(observer.GetIsAdSubframe(ad_child_of_ad->GetFrameTreeNodeId())); observer.VerifyEvidenceForAdSubframe( ad_child_of_ad, /*parent_is_ad=*/true, FilterListEvidence::kNotChecked,
diff --git a/chrome/browser/tabmodel/BUILD.gn b/chrome/browser/tabmodel/BUILD.gn index 9444bc1..2ed0b2939 100644 --- a/chrome/browser/tabmodel/BUILD.gn +++ b/chrome/browser/tabmodel/BUILD.gn
@@ -34,6 +34,7 @@ "android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelector.java", "android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorFactory.java", "android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorObserver.java", + "android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorSupplier.java", "android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorTabModelObserver.java", "android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorTabObserver.java", "android/java/src/org/chromium/chrome/browser/tabmodel/TabModelUtils.java", @@ -48,6 +49,7 @@ "//components/embedder_support/android:util_java", "//content/public/android:content_java", "//third_party/android_deps:androidx_annotation_annotation_java", + "//ui/android:ui_full_java", "//url:gurl_java", ] }
diff --git a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorSupplier.java b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorSupplier.java new file mode 100644 index 0000000..7dddfcb7 --- /dev/null +++ b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorSupplier.java
@@ -0,0 +1,29 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.tabmodel; + +import org.chromium.base.UnownedUserDataKey; +import org.chromium.base.supplier.ObservableSupplier; +import org.chromium.base.supplier.UnownedUserDataSupplier; +import org.chromium.ui.base.WindowAndroid; + +/** + * A {@link UnownedUserDataSupplier} which manages the supplier and UnownedUserData for a + * {@link TabModelSelector}. + */ +public class TabModelSelectorSupplier extends UnownedUserDataSupplier<TabModelSelector> { + private static final UnownedUserDataKey<TabModelSelectorSupplier> KEY = + new UnownedUserDataKey<TabModelSelectorSupplier>(TabModelSelectorSupplier.class); + + /** Return {@link TabModelSelector} supplier associated with the given {@link WindowAndroid}. */ + public static ObservableSupplier<TabModelSelector> from(WindowAndroid windowAndroid) { + return KEY.retrieveDataFromHost(windowAndroid.getUnownedUserDataHost()); + } + + /** Constructs a TabModelSelectorSupplier and attaches it to the {@link WindowAndroid} */ + public TabModelSelectorSupplier() { + super(KEY); + } +} \ No newline at end of file
diff --git a/chrome/browser/translate/chrome_translate_client.cc b/chrome/browser/translate/chrome_translate_client.cc index d8b3a415..ee2a0e1 100644 --- a/chrome/browser/translate/chrome_translate_client.cc +++ b/chrome/browser/translate/chrome_translate_client.cc
@@ -19,7 +19,9 @@ #include "chrome/browser/language/language_model_manager_factory.h" #include "chrome/browser/language/url_language_histogram_factory.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/profiles/profile_key.h" #include "chrome/browser/translate/translate_accept_languages_factory.h" +#include "chrome/browser/translate/translate_model_service_factory.h" #include "chrome/browser/translate/translate_ranker_factory.h" #include "chrome/browser/translate/translate_service.h" #include "chrome/browser/ui/translate/translate_bubble_factory.h" @@ -30,6 +32,7 @@ #include "components/language/core/browser/language_model_manager.h" #include "components/language/core/browser/pref_names.h" #include "components/prefs/pref_service.h" +#include "components/translate/content/browser/translate_model_service.h" #include "components/translate/core/browser/language_state.h" #include "components/translate/core/browser/page_translated_details.h" #include "components/translate/core/browser/translate_accept_languages.h" @@ -97,7 +100,10 @@ translate_driver_ = std::make_unique<translate::ContentTranslateDriver>( &web_contents->GetController(), UrlLanguageHistogramFactory::GetForBrowserContext( - web_contents->GetBrowserContext())); + web_contents->GetBrowserContext()), + TranslateModelServiceFactory::GetOrBuildForKey( + Profile::FromBrowserContext(web_contents->GetBrowserContext()) + ->GetProfileKey())); } translate_manager_ = std::make_unique<translate::TranslateManager>( this,
diff --git a/chrome/browser/translate/translate_model_service_browsertest.cc b/chrome/browser/translate/translate_model_service_browsertest.cc index 7984dfe..107fd65 100644 --- a/chrome/browser/translate/translate_model_service_browsertest.cc +++ b/chrome/browser/translate/translate_model_service_browsertest.cc
@@ -25,8 +25,10 @@ #include "components/optimization_guide/core/optimization_guide_features.h" #include "components/optimization_guide/proto/models.pb.h" #include "components/translate/core/common/translate_util.h" +#include "components/translate/core/language_detection/language_detection_model.h" #include "content/public/test/browser_test.h" #include "content/public/test/browser_test_utils.h" +#include "net/test/embedded_test_server/embedded_test_server.h" #include "testing/gtest/include/gtest/gtest.h" namespace { @@ -119,6 +121,15 @@ {}); } + void SetUp() override { + origin_server_ = std::make_unique<net::EmbeddedTestServer>( + net::EmbeddedTestServer::TYPE_HTTPS); + origin_server_->ServeFilesFromSourceDirectory("chrome/test/data/translate"); + ASSERT_TRUE(origin_server_->Start()); + english_url_ = origin_server_->GetURL("/english_page.html"); + InProcessBrowserTest::SetUp(); + } + ~TranslateModelServiceBrowserTest() override = default; translate::TranslateModelService* translate_model_service() { @@ -126,8 +137,12 @@ browser()->profile()->GetProfileKey()); } + const GURL& english_url() const { return english_url_; } + private: base::test::ScopedFeatureList scoped_feature_list_; + GURL english_url_; + std::unique_ptr<net::EmbeddedTestServer> origin_server_; }; base::FilePath model_file_path() { @@ -223,10 +238,33 @@ IN_PROC_BROWSER_TEST_F(TranslateModelServiceBrowserTest, LanguageDetectionModelCreated) { base::HistogramTester histogram_tester; - ui_test_utils::NavigateToURL(browser(), GURL("https://test.com")); + ui_test_utils::NavigateToURL(browser(), english_url()); RetryForHistogramUntilCountReached( &histogram_tester, "LanguageDetection.TFLiteModel.WasModelAvailableForDetection", 1); histogram_tester.ExpectUniqueSample( "LanguageDetection.TFLiteModel.WasModelAvailableForDetection", false, 1); } + +IN_PROC_BROWSER_TEST_F(TranslateModelServiceBrowserTest, + LanguageDetectionModelAvailableForDetection) { + base::HistogramTester histogram_tester; + OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile()) + ->OverrideTargetModelFileForTesting( + optimization_guide::proto::OPTIMIZATION_TARGET_LANGUAGE_DETECTION, + /*model_metadata=*/base::nullopt, model_file_path()); + RetryForHistogramUntilCountReached( + &histogram_tester, + "LanguageDetection.TFLiteModel.LanguageDetectionModelState", 1); + histogram_tester.ExpectUniqueSample( + "LanguageDetection.TFLiteModel.LanguageDetectionModelState", + translate::LanguageDetectionModelState::kModelFileValidAndMemoryMapped, + 1); + + ui_test_utils::NavigateToURL(browser(), english_url()); + RetryForHistogramUntilCountReached( + &histogram_tester, + "LanguageDetection.TFLiteModel.WasModelAvailableForDetection", 1); + histogram_tester.ExpectBucketCount( + "LanguageDetection.TFLiteModel.WasModelAvailableForDetection", true, 1); +}
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 2eaa2857..ff832fd 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -1638,10 +1638,10 @@ if (enable_supervised_users) { sources += [ - "webui/supervised_user_internals_message_handler.cc", - "webui/supervised_user_internals_message_handler.h", - "webui/supervised_user_internals_ui.cc", - "webui/supervised_user_internals_ui.h", + "webui/family_link_user_internals/family_link_user_internals_message_handler.cc", + "webui/family_link_user_internals/family_link_user_internals_message_handler.h", + "webui/family_link_user_internals/family_link_user_internals_ui.cc", + "webui/family_link_user_internals/family_link_user_internals_ui.h", ] deps += [ "//chrome/browser/supervised_user/supervised_user_error_page" ] } @@ -2228,6 +2228,8 @@ "webui/chromeos/cryptohome_ui.h", "webui/chromeos/cryptohome_web_ui_handler.cc", "webui/chromeos/cryptohome_web_ui_handler.h", + "webui/chromeos/diagnostics_dialog.cc", + "webui/chromeos/diagnostics_dialog.h", "webui/chromeos/drive_internals_ui.cc", "webui/chromeos/drive_internals_ui.h", "webui/chromeos/edu_account_login_handler_chromeos.cc", @@ -3431,8 +3433,9 @@ "autofill/payments/save_upi_bubble_controller.h", "autofill/payments/save_upi_bubble_controller_impl.cc", "autofill/payments/save_upi_bubble_controller_impl.h", - "autofill/save_address_profile_bubble_controller.cc", "autofill/save_address_profile_bubble_controller.h", + "autofill/save_address_profile_bubble_controller_impl.cc", + "autofill/save_address_profile_bubble_controller_impl.h", "bubble_anchor_util.h", "manifest_web_app_browser_controller.cc", "manifest_web_app_browser_controller.h",
diff --git a/chrome/browser/ui/app_list/app_list_client_impl_browsertest.cc b/chrome/browser/ui/app_list/app_list_client_impl_browsertest.cc index f51e5ca..e7c63c64 100644 --- a/chrome/browser/ui/app_list/app_list_client_impl_browsertest.cc +++ b/chrome/browser/ui/app_list/app_list_client_impl_browsertest.cc
@@ -90,7 +90,8 @@ WindowOpenDisposition::NEW_WINDOW, false /* preferred_containner */), apps::mojom::LaunchSource::kFromTest, - display::Screen::GetScreen()->GetPrimaryDisplay().id()); + apps::MakeWindowInfo( + display::Screen::GetScreen()->GetPrimaryDisplay().id())); app_loaded_observer.Wait(); } EXPECT_TRUE(delegate->IsAppOpen(extension_app->id()));
diff --git a/chrome/browser/ui/app_list/app_service/app_service_app_item.cc b/chrome/browser/ui/app_list/app_service/app_service_app_item.cc index 38f9ff2..9c59074 100644 --- a/chrome/browser/ui/app_list/app_service/app_service_app_item.cc +++ b/chrome/browser/ui/app_list/app_service/app_service_app_item.cc
@@ -13,6 +13,7 @@ #include "base/notreached.h" #include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" +#include "chrome/browser/apps/app_service/launch_utils.h" #include "chrome/browser/chromeos/crostini/crostini_util.h" #include "chrome/browser/chromeos/remote_apps/remote_apps_manager.h" #include "chrome/browser/chromeos/remote_apps/remote_apps_manager_factory.h" @@ -155,7 +156,7 @@ apps::AppServiceProxy* proxy = apps::AppServiceProxyFactory::GetForProfile(profile()); proxy->Launch(id(), event_flags, launch_source, - GetController()->GetAppListDisplayId()); + apps::MakeWindowInfo(GetController()->GetAppListDisplayId())); } void AppServiceAppItem::CallLoadIcon(bool allow_placeholder_icon) {
diff --git a/chrome/browser/ui/app_list/search/app_service_app_result.cc b/chrome/browser/ui/app_list/search/app_service_app_result.cc index f1b6e82..b685b3ed 100644 --- a/chrome/browser/ui/app_list/search/app_service_app_result.cc +++ b/chrome/browser/ui/app_list/search/app_service_app_result.cc
@@ -14,6 +14,7 @@ #include "chrome/browser/apps/app_service/app_service_metrics.h" #include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" +#include "chrome/browser/apps/app_service/launch_utils.h" #include "chrome/browser/favicon/large_icon_service_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/app_list/app_list_client_impl.h" @@ -189,7 +190,7 @@ controller()->GetAppListDisplayId()); } else { proxy->Launch(app_id(), event_flags, launch_source, - controller()->GetAppListDisplayId()); + apps::MakeWindowInfo(controller()->GetAppListDisplayId())); } }
diff --git a/chrome/browser/ui/app_list/search/help_app_provider.cc b/chrome/browser/ui/app_list/search/help_app_provider.cc index 9c034ae7..fb9326c 100644 --- a/chrome/browser/ui/app_list/search/help_app_provider.cc +++ b/chrome/browser/ui/app_list/search/help_app_provider.cc
@@ -12,6 +12,7 @@ #include "base/metrics/user_metrics.h" #include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" +#include "chrome/browser/apps/app_service/launch_utils.h" #include "chrome/browser/chromeos/release_notes/release_notes_storage.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/web_applications/components/web_app_id_constants.h" @@ -56,7 +57,7 @@ proxy->LaunchAppWithUrl(web_app::kHelpAppId, event_flags, GURL("chrome://help-app/updates"), apps::mojom::LaunchSource::kFromAppListRecommendation, - display::kDefaultDisplayId); + apps::MakeWindowInfo(display::kDefaultDisplayId)); chromeos::ReleaseNotesStorage(profile_).StopShowingSuggestionChip(); }
diff --git a/chrome/browser/ui/app_list/search/score_normalizer/score_normalizer.h b/chrome/browser/ui/app_list/search/score_normalizer/score_normalizer.h index 7cd643a6..3187357 100644 --- a/chrome/browser/ui/app_list/search/score_normalizer/score_normalizer.h +++ b/chrome/browser/ui/app_list/search/score_normalizer/score_normalizer.h
@@ -16,10 +16,38 @@ namespace app_list { -// The launcher takes scores from providers, these all have different -// distributions and ranges, which makes them difficult to compare. Here we have -// implemented a way to normalize ChromeSearchResults so relevance scores can be -// compared for the launcher. +// ScoreNormalizer is responsible for normalizing relevance scores of search +// results from providers. It learns to transform all scores to a uniformly +// distributed normalized score between 0 to 1. The launcher takes scores of +// results from many providers, these all have different distributions and +// ranges, which makes them difficult to compare. After normalizing the +// relevance scores can be compared and ranked in the launcher. This class +// should only be initialized in a provider class where it can be called to +// record and normalize scores. +// +// To normalize scores the ScoreNormalizer uses a BalancedReservoir. The +// BalancedReservoir stores a subset of the search result scores, this subset of +// scores is called dividers. To normalize a score, the quantile of that score +// in the dividers is returned, this is always a value in (0,1). If a normalized +// score of 1 is returned, this is either due to empty dividers or index out of +// range when finding which index the score is in the dividers. The dividers are +// updated such that the counts of scores observed between each divider remains +// balanced. Each pair of adjacent dividers forms a histogram bin. To ensure +// bins remain balanced with each new score added bins are: +// 1. Split by adding the new score in between dividers. +// 2. Smallest bins are then merged. +// The L2 error is calculated to ensure splits and merges improve the balance of +// the reservoir. +// +// Use of the ScoreNormalizer: +// - Initialization. A profile is required since information about the provider +// scores in the BalancedReservoir class are stored in prefs. The reservoir size +// can be set to 25, or any other positive integer. +// - RecordResults() should be called right before new results are swapped in +// for old results in the providers. This updates the BalancedReservoir with the +// provider's score distribution. +// - NormalizeResults() should then be called. This changes the relevance scores +// of the ChromeSearchResult in place with the normalized score. class ScoreNormalizer { public: using Results = std::vector<std::unique_ptr<ChromeSearchResult>>;
diff --git a/chrome/browser/ui/ash/chrome_new_window_client.cc b/chrome/browser/ui/ash/chrome_new_window_client.cc index c7bec7c..8d9d964 100644 --- a/chrome/browser/ui/ash/chrome_new_window_client.cc +++ b/chrome/browser/ui/ash/chrome_new_window_client.cc
@@ -73,7 +73,6 @@ #include "ui/aura/window.h" #include "ui/base/page_transition_types.h" #include "ui/base/window_open_disposition.h" -#include "ui/display/types/display_constants.h" #include "url/url_constants.h" using arc::mojom::ChromePage; @@ -374,7 +373,7 @@ apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerNone, WindowOpenDisposition::NEW_FOREGROUND_TAB, /*preferred_containner=*/true), - apps::mojom::LaunchSource::kFromKeyboard, display::kInvalidDisplayId); + apps::mojom::LaunchSource::kFromKeyboard); }; bool result = proxy->AppRegistryCache().ForOneApp( @@ -538,8 +537,7 @@ apps::AppServiceProxy* proxy = apps::AppServiceProxyFactory::GetForProfile(profile); proxy->LaunchAppWithUrl(*app_id, event_flags, url, - apps::mojom::LaunchSource::kFromArc, - display::kInvalidDisplayId); + apps::mojom::LaunchSource::kFromArc); chromeos::ApkWebAppService* apk_web_app_service = chromeos::ApkWebAppService::Get(profile);
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc index 7985b3b1..a76289f 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
@@ -289,7 +289,8 @@ proxy->FlushMojoCallsForTesting(); proxy->Launch(extension->id(), event_flags, apps::mojom::LaunchSource::kFromTest, - display::Screen::GetScreen()->GetPrimaryDisplay().id()); + apps::MakeWindowInfo( + display::Screen::GetScreen()->GetPrimaryDisplay().id())); proxy->FlushMojoCallsForTesting(); return extension; } @@ -1618,7 +1619,8 @@ WindowOpenDisposition::NEW_FOREGROUND_TAB, true /* prefer_containner */), apps::mojom::LaunchSource::kFromTest, - display::Screen::GetScreen()->GetPrimaryDisplay().id()); + apps::MakeWindowInfo( + display::Screen::GetScreen()->GetPrimaryDisplay().id())); proxy->FlushMojoCallsForTesting(); // A new browser should get detected and one more should be running. @@ -2211,7 +2213,8 @@ WindowOpenDisposition::NEW_FOREGROUND_TAB, true /* prefer_containner */), apps::mojom::LaunchSource::kFromTest, - display::Screen::GetScreen()->GetPrimaryDisplay().id()); + apps::MakeWindowInfo( + display::Screen::GetScreen()->GetPrimaryDisplay().id())); EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(id)->status); // Find the browser which holds our app.
diff --git a/chrome/browser/ui/ash/launcher/launcher_controller_helper.cc b/chrome/browser/ui/ash/launcher/launcher_controller_helper.cc index 4f7dd08..fa5e823 100644 --- a/chrome/browser/ui/ash/launcher/launcher_controller_helper.cc +++ b/chrome/browser/ui/ash/launcher/launcher_controller_helper.cc
@@ -9,6 +9,7 @@ #include "base/strings/utf_string_conversions.h" #include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" +#include "chrome/browser/apps/app_service/launch_utils.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/arc/arc_util.h" #include "chrome/browser/chromeos/arc/session/arc_session_manager.h" @@ -256,7 +257,8 @@ // Launch apps with AppServiceProxy.Launch. if (proxy->AppRegistryCache().GetAppType(app_id) != apps::mojom::AppType::kUnknown) { - proxy->Launch(app_id, event_flags, ConvertLaunchSource(source), display_id); + proxy->Launch(app_id, event_flags, ConvertLaunchSource(source), + apps::MakeWindowInfo(display_id)); return; }
diff --git a/chrome/browser/ui/ash/system_tray_client.cc b/chrome/browser/ui/ash/system_tray_client.cc index b3f1b8b3..e674f4cf 100644 --- a/chrome/browser/ui/ash/system_tray_client.cc +++ b/chrome/browser/ui/ash/system_tray_client.cc
@@ -14,14 +14,15 @@ #include "base/metrics/user_metrics.h" #include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" +#include "chrome/browser/apps/app_service/launch_utils.h" #include "chrome/browser/ash/accessibility/accessibility_manager.h" +#include "chrome/browser/ash/system/system_clock.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process_platform_part.h" #include "chrome/browser/chromeos/login/help_app_launcher.h" #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" #include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h" #include "chrome/browser/chromeos/set_time_dialog.h" -#include "chrome/browser/chromeos/system/system_clock.h" #include "chrome/browser/lifetime/application_lifetime.h" #include "chrome/browser/lifetime/termination_notification.h" #include "chrome/browser/profiles/profile_manager.h" @@ -323,7 +324,7 @@ proxy->LaunchAppWithUrl(web_app::kHelpAppId, ui::EventFlags::EF_NONE, GURL(chrome::kChromeOSGestureEducationHelpURL), apps::mojom::LaunchSource::kFromOtherApp, - display::kDefaultDisplayId); + apps::MakeWindowInfo(display::kDefaultDisplayId)); } void SystemTrayClient::ShowPaletteHelp() {
diff --git a/chrome/browser/ui/ash/system_tray_client.h b/chrome/browser/ui/ash/system_tray_client.h index 8fbd329..952d7f8 100644 --- a/chrome/browser/ui/ash/system_tray_client.h +++ b/chrome/browser/ui/ash/system_tray_client.h
@@ -7,7 +7,7 @@ #include "ash/public/cpp/system_tray_client.h" #include "base/macros.h" -#include "chrome/browser/chromeos/system/system_clock_observer.h" +#include "chrome/browser/ash/system/system_clock_observer.h" #include "chrome/browser/upgrade_detector/upgrade_observer.h" #include "components/policy/core/common/cloud/cloud_policy_store.h"
diff --git a/chrome/browser/ui/ash/wallpaper_controller_client.cc b/chrome/browser/ui/ash/wallpaper_controller_client.cc index e5e2f8e..7f12fce 100644 --- a/chrome/browser/ui/ash/wallpaper_controller_client.cc +++ b/chrome/browser/ui/ash/wallpaper_controller_client.cc
@@ -33,7 +33,6 @@ #include "extensions/browser/extension_registry.h" #include "extensions/common/constants.h" #include "extensions/common/extension.h" -#include "ui/display/types/display_constants.h" namespace { @@ -501,8 +500,7 @@ apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerWindow, WindowOpenDisposition::NEW_WINDOW, false /* preferred_containner */), - apps::mojom::LaunchSource::kFromChromeInternal, - display::kInvalidDisplayId); + apps::mojom::LaunchSource::kFromChromeInternal); } void WallpaperControllerClient::MaybeClosePreviewWallpaper() {
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc index 71aab1ce0..4fa6a5d 100644 --- a/chrome/browser/ui/autofill/chrome_autofill_client.cc +++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -31,7 +31,7 @@ #include "chrome/browser/ui/autofill/autofill_popup_controller_impl.h" #include "chrome/browser/ui/autofill/payments/create_card_unmask_prompt_view.h" #include "chrome/browser/ui/autofill/payments/credit_card_scanner_controller.h" -#include "chrome/browser/ui/autofill/save_address_profile_bubble_controller.h" +#include "chrome/browser/ui/autofill/save_address_profile_bubble_controller_impl.h" #include "chrome/browser/ui/chrome_pages.h" #include "chrome/browser/ui/page_info/page_info_dialog.h" #include "chrome/browser/ui/passwords/manage_passwords_view_utils.h" @@ -524,9 +524,9 @@ #if defined(OS_ANDROID) // TODO(crbug.com/1167061): Implement. #else - SaveAddressProfileBubbleController::CreateForWebContents(web_contents()); - SaveAddressProfileBubbleController* controller = - SaveAddressProfileBubbleController::FromWebContents(web_contents()); + SaveAddressProfileBubbleControllerImpl::CreateForWebContents(web_contents()); + SaveAddressProfileBubbleControllerImpl* controller = + SaveAddressProfileBubbleControllerImpl::FromWebContents(web_contents()); controller->OfferSave(profile, std::move(callback)); #endif } @@ -637,6 +637,11 @@ popup_controller_->Hide(reason); } +void ChromeAutofillClient::ShowOfferNotificationIfApplicable( + const std::vector<GURL>& domains_to_display_bubble) { + // TODO(crbug.com/1093057): Finish bubble controller/view and wire it up. +} + bool ChromeAutofillClient::IsAutocompleteEnabled() { return prefs::IsAutocompleteEnabled(GetPrefs()); }
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.h b/chrome/browser/ui/autofill/chrome_autofill_client.h index 4176595..b77d322e 100644 --- a/chrome/browser/ui/autofill/chrome_autofill_client.h +++ b/chrome/browser/ui/autofill/chrome_autofill_client.h
@@ -144,6 +144,8 @@ void UpdatePopup(const std::vector<Suggestion>& suggestions, PopupType popup_type) override; void HideAutofillPopup(PopupHidingReason reason) override; + void ShowOfferNotificationIfApplicable( + const std::vector<GURL>& domains_to_display_bubble) override; bool IsAutocompleteEnabled() override; void PropagateAutofillPredictions( content::RenderFrameHost* rfh,
diff --git a/chrome/browser/ui/autofill/save_address_profile_bubble_controller.h b/chrome/browser/ui/autofill/save_address_profile_bubble_controller.h index 4251312..1c7bc4f4 100644 --- a/chrome/browser/ui/autofill/save_address_profile_bubble_controller.h +++ b/chrome/browser/ui/autofill/save_address_profile_bubble_controller.h
@@ -1,62 +1,24 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2021 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CHROME_BROWSER_UI_AUTOFILL_SAVE_ADDRESS_PROFILE_BUBBLE_CONTROLLER_H_ #define CHROME_BROWSER_UI_AUTOFILL_SAVE_ADDRESS_PROFILE_BUBBLE_CONTROLLER_H_ -#include "base/strings/string16.h" -#include "chrome/browser/ui/autofill/autofill_bubble_controller_base.h" #include "components/autofill/core/browser/autofill_client.h" -#include "components/autofill/core/browser/data_model/autofill_profile.h" -#include "content/public/browser/web_contents_user_data.h" namespace autofill { -class SaveAddressProfileView; - -// The controller functionality for SaveAddressProfileView. -class SaveAddressProfileBubbleController - : public AutofillBubbleControllerBase, - public content::WebContentsUserData<SaveAddressProfileBubbleController> { +// Interface that exposes controller functionality to SaveAddressProfileView +// bubble. +class SaveAddressProfileBubbleController { public: - SaveAddressProfileBubbleController( - const SaveAddressProfileBubbleController&) = delete; - SaveAddressProfileBubbleController& operator=( - const SaveAddressProfileBubbleController&) = delete; - ~SaveAddressProfileBubbleController() override; + virtual ~SaveAddressProfileBubbleController() = default; - base::string16 GetWindowTitle() const; - - // Sets up the controller and offers to save the |profile|. - // |address_profile_save_prompt_callback| will be invoked once the user makes - // a decision with respect to the offer-to-save prompt. - void OfferSave(const AutofillProfile& profile, - AutofillClient::AddressProfileSavePromptCallback - address_profile_save_prompt_callback); - - void OnBubbleClosed(); - - protected: - // AutofillBubbleControllerBase:: - PageActionIconType GetPageActionIconType() override; - void DoShowBubble() override; - - private: - explicit SaveAddressProfileBubbleController( - content::WebContents* web_contents); - friend class content::WebContentsUserData<SaveAddressProfileBubbleController>; - - // Callback to run once the user makes a decision with respect to the saving - // the address profile. - AutofillClient::AddressProfileSavePromptCallback - address_profile_save_prompt_callback_; - - // Contains the details of the address profile that will be saved if the user - // accepts. - AutofillProfile address_profile_; - - WEB_CONTENTS_USER_DATA_KEY_DECL(); + virtual base::string16 GetWindowTitle() const = 0; + virtual void OnUserDecision( + AutofillClient::SaveAddressProfileOfferUserDecision decision) = 0; + virtual void OnBubbleClosed() = 0; }; } // namespace autofill
diff --git a/chrome/browser/ui/autofill/save_address_profile_bubble_controller.cc b/chrome/browser/ui/autofill/save_address_profile_bubble_controller_impl.cc similarity index 66% rename from chrome/browser/ui/autofill/save_address_profile_bubble_controller.cc rename to chrome/browser/ui/autofill/save_address_profile_bubble_controller_impl.cc index 18c7ffd..5acb9d7 100644 --- a/chrome/browser/ui/autofill/save_address_profile_bubble_controller.cc +++ b/chrome/browser/ui/autofill/save_address_profile_bubble_controller_impl.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/autofill/save_address_profile_bubble_controller.h" +#include "chrome/browser/ui/autofill/save_address_profile_bubble_controller_impl.h" #include "chrome/browser/ui/autofill/autofill_bubble_handler.h" #include "chrome/browser/ui/browser.h" @@ -12,21 +12,17 @@ namespace autofill { -SaveAddressProfileBubbleController::SaveAddressProfileBubbleController( +SaveAddressProfileBubbleControllerImpl::SaveAddressProfileBubbleControllerImpl( content::WebContents* web_contents) : AutofillBubbleControllerBase(web_contents) { DCHECK(base::FeatureList::IsEnabled( features::kAutofillAddressProfileSavePrompt)); } -SaveAddressProfileBubbleController::~SaveAddressProfileBubbleController() = - default; +SaveAddressProfileBubbleControllerImpl:: + ~SaveAddressProfileBubbleControllerImpl() = default; -base::string16 SaveAddressProfileBubbleController::GetWindowTitle() const { - return base::string16(); -} - -void SaveAddressProfileBubbleController::OfferSave( +void SaveAddressProfileBubbleControllerImpl::OfferSave( const AutofillProfile& profile, AutofillClient::AddressProfileSavePromptCallback address_profile_save_prompt_callback) { @@ -39,16 +35,29 @@ Show(); } -void SaveAddressProfileBubbleController::OnBubbleClosed() { +base::string16 SaveAddressProfileBubbleControllerImpl::GetWindowTitle() const { + return base::string16(); +} + +void SaveAddressProfileBubbleControllerImpl::OnUserDecision( + AutofillClient::SaveAddressProfileOfferUserDecision decision) { + set_bubble_view(nullptr); + + std::move(address_profile_save_prompt_callback_) + .Run(decision, address_profile_); +} + +void SaveAddressProfileBubbleControllerImpl::OnBubbleClosed() { set_bubble_view(nullptr); UpdatePageActionIcon(); } -PageActionIconType SaveAddressProfileBubbleController::GetPageActionIconType() { +PageActionIconType +SaveAddressProfileBubbleControllerImpl::GetPageActionIconType() { return PageActionIconType::kSaveCard; } -void SaveAddressProfileBubbleController::DoShowBubble() { +void SaveAddressProfileBubbleControllerImpl::DoShowBubble() { DCHECK(!bubble_view()); Browser* browser = chrome::FindBrowserWithWebContents(web_contents()); set_bubble_view( @@ -59,6 +68,6 @@ DCHECK(bubble_view()); } -WEB_CONTENTS_USER_DATA_KEY_IMPL(SaveAddressProfileBubbleController) +WEB_CONTENTS_USER_DATA_KEY_IMPL(SaveAddressProfileBubbleControllerImpl) } // namespace autofill
diff --git a/chrome/browser/ui/autofill/save_address_profile_bubble_controller_impl.h b/chrome/browser/ui/autofill/save_address_profile_bubble_controller_impl.h new file mode 100644 index 0000000..1c1e83b --- /dev/null +++ b/chrome/browser/ui/autofill/save_address_profile_bubble_controller_impl.h
@@ -0,0 +1,70 @@ +// 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 CHROME_BROWSER_UI_AUTOFILL_SAVE_ADDRESS_PROFILE_BUBBLE_CONTROLLER_IMPL_H_ +#define CHROME_BROWSER_UI_AUTOFILL_SAVE_ADDRESS_PROFILE_BUBBLE_CONTROLLER_IMPL_H_ + +#include "base/strings/string16.h" +#include "chrome/browser/ui/autofill/autofill_bubble_controller_base.h" +#include "chrome/browser/ui/autofill/save_address_profile_bubble_controller.h" +#include "components/autofill/core/browser/autofill_client.h" +#include "components/autofill/core/browser/data_model/autofill_profile.h" +#include "content/public/browser/web_contents_user_data.h" + +namespace autofill { + +class SaveAddressProfileView; + +// The controller functionality for SaveAddressProfileView. +class SaveAddressProfileBubbleControllerImpl + : public AutofillBubbleControllerBase, + public SaveAddressProfileBubbleController, + public content::WebContentsUserData< + SaveAddressProfileBubbleControllerImpl> { + public: + SaveAddressProfileBubbleControllerImpl( + const SaveAddressProfileBubbleControllerImpl&) = delete; + SaveAddressProfileBubbleControllerImpl& operator=( + const SaveAddressProfileBubbleControllerImpl&) = delete; + ~SaveAddressProfileBubbleControllerImpl() override; + + // Sets up the controller and offers to save the |profile|. + // |address_profile_save_prompt_callback| will be invoked once the user makes + // a decision with respect to the offer-to-save prompt. + void OfferSave(const AutofillProfile& profile, + AutofillClient::AddressProfileSavePromptCallback + address_profile_save_prompt_callback); + + // SaveAddressProfileBubbleController: + base::string16 GetWindowTitle() const override; + void OnUserDecision( + AutofillClient::SaveAddressProfileOfferUserDecision decision) override; + void OnBubbleClosed() override; + + protected: + // AutofillBubbleControllerBase: + PageActionIconType GetPageActionIconType() override; + void DoShowBubble() override; + + private: + explicit SaveAddressProfileBubbleControllerImpl( + content::WebContents* web_contents); + friend class content::WebContentsUserData< + SaveAddressProfileBubbleControllerImpl>; + + // Callback to run once the user makes a decision with respect to the saving + // the address profile. + AutofillClient::AddressProfileSavePromptCallback + address_profile_save_prompt_callback_; + + // Contains the details of the address profile that will be saved if the user + // accepts. + AutofillProfile address_profile_; + + WEB_CONTENTS_USER_DATA_KEY_DECL(); +}; + +} // namespace autofill + +#endif // CHROME_BROWSER_UI_AUTOFILL_SAVE_ADDRESS_PROFILE_BUBBLE_CONTROLLER_IMPL_H_
diff --git a/chrome/browser/ui/autofill/save_address_profile_bubble_controller_browsertest.cc b/chrome/browser/ui/autofill/save_address_profile_bubble_controller_impl_browsertest.cc similarity index 74% rename from chrome/browser/ui/autofill/save_address_profile_bubble_controller_browsertest.cc rename to chrome/browser/ui/autofill/save_address_profile_bubble_controller_impl_browsertest.cc index b436d43..f6fa2d4 100644 --- a/chrome/browser/ui/autofill/save_address_profile_bubble_controller_browsertest.cc +++ b/chrome/browser/ui/autofill/save_address_profile_bubble_controller_impl_browsertest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/autofill/save_address_profile_bubble_controller.h" +#include "chrome/browser/ui/autofill/save_address_profile_bubble_controller_impl.h" #include "chrome/browser/ui/autofill/chrome_autofill_client.h" #include "chrome/browser/ui/browser.h" @@ -14,9 +14,9 @@ namespace autofill { -class SaveAddressProfileBubbleControllerTest : public DialogBrowserTest { +class SaveAddressProfileBubbleControllerImplTest : public DialogBrowserTest { public: - SaveAddressProfileBubbleControllerTest() { + SaveAddressProfileBubbleControllerImplTest() { feature_list_.InitAndEnableFeature( features::kAutofillAddressProfileSavePrompt); } @@ -34,29 +34,30 @@ autofill_client->ConfirmSaveAddressProfile(test::GetFullProfile(), base::DoNothing()); controller_ = - SaveAddressProfileBubbleController::FromWebContents(web_contents); + SaveAddressProfileBubbleControllerImpl::FromWebContents(web_contents); DCHECK(controller_); } - SaveAddressProfileBubbleController* controller() { return controller_; } + SaveAddressProfileBubbleControllerImpl* controller() { return controller_; } private: - SaveAddressProfileBubbleController* controller_ = nullptr; + SaveAddressProfileBubbleControllerImpl* controller_ = nullptr; base::test::ScopedFeatureList feature_list_; }; -IN_PROC_BROWSER_TEST_F(SaveAddressProfileBubbleControllerTest, InvokeUi_Save) { +IN_PROC_BROWSER_TEST_F(SaveAddressProfileBubbleControllerImplTest, + InvokeUi_Save) { ShowAndVerifyUi(); } -IN_PROC_BROWSER_TEST_F(SaveAddressProfileBubbleControllerTest, +IN_PROC_BROWSER_TEST_F(SaveAddressProfileBubbleControllerImplTest, InvokeUi_SaveCloseThenReopen) { ShowAndVerifyUi(); controller()->OnBubbleClosed(); ShowAndVerifyUi(); } -IN_PROC_BROWSER_TEST_F(SaveAddressProfileBubbleControllerTest, +IN_PROC_BROWSER_TEST_F(SaveAddressProfileBubbleControllerImplTest, CloseTabWhileBubbleIsOpen) { ShowAndVerifyUi(); content::WebContents* tab =
diff --git a/chrome/browser/ui/autofill/save_address_profile_bubble_controller_impl_unittest.cc b/chrome/browser/ui/autofill/save_address_profile_bubble_controller_impl_unittest.cc new file mode 100644 index 0000000..edc8f1af --- /dev/null +++ b/chrome/browser/ui/autofill/save_address_profile_bubble_controller_impl_unittest.cc
@@ -0,0 +1,66 @@ +// 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 "chrome/browser/ui/autofill/save_address_profile_bubble_controller_impl.h" + +#include "base/test/mock_callback.h" +#include "base/test/scoped_feature_list.h" +#include "chrome/test/base/browser_with_test_window_test.h" +#include "components/autofill/core/browser/autofill_test_utils.h" +#include "components/autofill/core/common/autofill_features.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace autofill { + +class SaveAddressProfileBubbleControllerImplTest + : public BrowserWithTestWindowTest { + public: + SaveAddressProfileBubbleControllerImplTest() = default; + void SetUp() override { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature( + features::kAutofillAddressProfileSavePrompt); + + BrowserWithTestWindowTest::SetUp(); + AddTab(browser(), GURL("about:blank")); + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + SaveAddressProfileBubbleControllerImpl::CreateForWebContents(web_contents); + } + + SaveAddressProfileBubbleControllerImpl* controller() { + return SaveAddressProfileBubbleControllerImpl::FromWebContents( + browser()->tab_strip_model()->GetActiveWebContents()); + } +}; + +TEST_F(SaveAddressProfileBubbleControllerImplTest, + DialogAcceptedInvokesCallback) { + AutofillProfile profile = test::GetFullProfile(); + base::MockCallback<AutofillClient::AddressProfileSavePromptCallback> callback; + controller()->OfferSave(profile, callback.Get()); + + EXPECT_CALL( + callback, + Run(AutofillClient::SaveAddressProfileOfferUserDecision::kAccepted, + profile)); + controller()->OnUserDecision( + AutofillClient::SaveAddressProfileOfferUserDecision::kAccepted); +} + +TEST_F(SaveAddressProfileBubbleControllerImplTest, + DialogCancelledInvokesCallback) { + AutofillProfile profile = test::GetFullProfile(); + base::MockCallback<AutofillClient::AddressProfileSavePromptCallback> callback; + controller()->OfferSave(profile, callback.Get()); + + EXPECT_CALL( + callback, + Run(AutofillClient::SaveAddressProfileOfferUserDecision::kDeclined, + testing::_)); + controller()->OnUserDecision( + AutofillClient::SaveAddressProfileOfferUserDecision::kDeclined); +} + +} // namespace autofill
diff --git a/chrome/browser/ui/autofill/save_address_profile_bubble_controller_unittest.cc b/chrome/browser/ui/autofill/save_address_profile_bubble_controller_unittest.cc deleted file mode 100644 index c692076..0000000 --- a/chrome/browser/ui/autofill/save_address_profile_bubble_controller_unittest.cc +++ /dev/null
@@ -1,33 +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 "chrome/browser/ui/autofill/save_address_profile_bubble_controller.h" - -#include "base/test/scoped_feature_list.h" -#include "chrome/test/base/browser_with_test_window_test.h" -#include "components/autofill/core/common/autofill_features.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace autofill { - -class SaveAddressProfileBubbleControllerTest - : public BrowserWithTestWindowTest { - public: - SaveAddressProfileBubbleControllerTest() = default; - void SetUp() override { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature( - features::kAutofillAddressProfileSavePrompt); - - BrowserWithTestWindowTest::SetUp(); - AddTab(browser(), GURL("about:blank")); - content::WebContents* web_contents = - browser()->tab_strip_model()->GetActiveWebContents(); - SaveAddressProfileBubbleController::CreateForWebContents(web_contents); - } -}; - -TEST_F(SaveAddressProfileBubbleControllerTest, NoCrash) {} - -} // namespace autofill
diff --git a/chrome/browser/ui/autofill/test/test_autofill_bubble_handler.cc b/chrome/browser/ui/autofill/test/test_autofill_bubble_handler.cc index 239daf9..5fc1a22 100644 --- a/chrome/browser/ui/autofill/test/test_autofill_bubble_handler.cc +++ b/chrome/browser/ui/autofill/test/test_autofill_bubble_handler.cc
@@ -43,8 +43,9 @@ content::WebContents* contents, SaveAddressProfileBubbleController* controller, bool is_user_gesture) { - NOTIMPLEMENTED(); - return nullptr; + if (!save_address_profile_bubble_view_) + save_address_profile_bubble_view_ = std::make_unique<TestAutofillBubble>(); + return save_address_profile_bubble_view_.get(); } void TestAutofillBubbleHandler::OnPasswordSaved() {}
diff --git a/chrome/browser/ui/autofill/test/test_autofill_bubble_handler.h b/chrome/browser/ui/autofill/test/test_autofill_bubble_handler.h index 9537a36..693c614 100644 --- a/chrome/browser/ui/autofill/test/test_autofill_bubble_handler.h +++ b/chrome/browser/ui/autofill/test/test_autofill_bubble_handler.h
@@ -49,6 +49,7 @@ std::unique_ptr<TestAutofillBubble> local_card_migration_bubble_view_; std::unique_ptr<TestAutofillBubble> save_card_bubble_view_; std::unique_ptr<TestSaveUPIBubble> save_upi_bubble_; + std::unique_ptr<TestAutofillBubble> save_address_profile_bubble_view_; DISALLOW_COPY_AND_ASSIGN(TestAutofillBubbleHandler); };
diff --git a/chrome/browser/ui/browser_command_controller.cc b/chrome/browser/ui/browser_command_controller.cc index 1921076..e640dcc 100644 --- a/chrome/browser/ui/browser_command_controller.cc +++ b/chrome/browser/ui/browser_command_controller.cc
@@ -842,6 +842,7 @@ // UI debug commands case IDC_DEBUG_TOGGLE_TABLET_MODE: case IDC_DEBUG_PRINT_VIEW_TREE: + case IDC_DEBUG_PRINT_VIEW_TREE_DETAILS: ExecuteUIDebugCommand(id, browser_); break; @@ -1140,6 +1141,8 @@ if (base::FeatureList::IsEnabled(features::kUIDebugTools)) { command_updater_.UpdateCommandEnabled(IDC_DEBUG_TOGGLE_TABLET_MODE, true); command_updater_.UpdateCommandEnabled(IDC_DEBUG_PRINT_VIEW_TREE, true); + command_updater_.UpdateCommandEnabled(IDC_DEBUG_PRINT_VIEW_TREE_DETAILS, + true); } // Initialize other commands whose state changes based on various conditions.
diff --git a/chrome/browser/ui/browser_navigator_browsertest.cc b/chrome/browser/ui/browser_navigator_browsertest.cc index 027153e..4afbc64 100644 --- a/chrome/browser/ui/browser_navigator_browsertest.cc +++ b/chrome/browser/ui/browser_navigator_browsertest.cc
@@ -3,7 +3,6 @@ // found in the LICENSE file. #include "chrome/browser/ui/browser_navigator_browsertest.h" -#include "content/public/test/browser_test.h" #include <memory> @@ -46,9 +45,11 @@ #include "content/public/browser/render_view_host.h" #include "content/public/browser/web_contents.h" #include "content/public/common/bindings_policy.h" +#include "content/public/test/browser_test.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/test_frame_navigation_observer.h" #include "content/public/test/test_navigation_observer.h" +#include "content/public/test/test_utils.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "services/network/public/cpp/resource_request_body.h" @@ -1368,9 +1369,7 @@ } // This test makes sure a crashed singleton tab reloads from a new navigation. -// TODO(https://crbug.com/396371): Disabled due to flakiness. -IN_PROC_BROWSER_TEST_F(BrowserNavigatorTest, - DISABLED_NavigateToCrashedSingletonTab) { +IN_PROC_BROWSER_TEST_F(BrowserNavigatorTest, NavigateToCrashedSingletonTab) { const GURL singleton_url(GetContentSettingsURL()); WebContents* web_contents = chrome::AddSelectedTabWithURL( browser(), singleton_url, ui::PAGE_TRANSITION_LINK); @@ -1381,7 +1380,14 @@ EXPECT_EQ(1, browser()->tab_strip_model()->active_index()); // Kill the singleton tab. - web_contents->SetIsCrashed(base::TERMINATION_STATUS_PROCESS_CRASHED, -1); + { + content::ScopedAllowRendererCrashes scoped_allow_renderer_crashes; + + content::RenderFrameDeletedObserver crash_observer( + web_contents->GetMainFrame()); + web_contents->GetMainFrame()->GetProcess()->Shutdown(1); + crash_observer.WaitUntilDeleted(); + } EXPECT_TRUE(web_contents->IsCrashed()); NavigateParams params(MakeNavigateParams());
diff --git a/chrome/browser/ui/browser_unittest.cc b/chrome/browser/ui/browser_unittest.cc index 1b314e6..6f87e02 100644 --- a/chrome/browser/ui/browser_unittest.cc +++ b/chrome/browser/ui/browser_unittest.cc
@@ -69,7 +69,8 @@ EXPECT_FALSE(raw_contents2->IsLoading()); // Simulate the second tab crashing. - raw_contents2->SetIsCrashed(base::TERMINATION_STATUS_PROCESS_CRASHED, -1); + WebContentsTester::For(raw_contents2) + ->SetIsCrashed(base::TERMINATION_STATUS_PROCESS_CRASHED, -1); EXPECT_TRUE(raw_contents2->IsCrashed()); // Selecting the second tab does not cause a load or clear the crash. @@ -125,7 +126,8 @@ EXPECT_TRUE(command_updater->IsCommandEnabled(IDC_PRINT)); EXPECT_TRUE(chrome::CanPrint(browser())); - raw_contents->SetIsCrashed(base::TERMINATION_STATUS_PROCESS_CRASHED, -1); + WebContentsTester::For(raw_contents) + ->SetIsCrashed(base::TERMINATION_STATUS_PROCESS_CRASHED, -1); EXPECT_TRUE(raw_contents->IsCrashed()); EXPECT_FALSE(command_updater->IsCommandEnabled(IDC_PRINT)); @@ -154,7 +156,8 @@ EXPECT_TRUE(chrome::CanZoomIn(raw_contents)); EXPECT_TRUE(chrome::CanZoomOut(raw_contents)); - raw_contents->SetIsCrashed(base::TERMINATION_STATUS_PROCESS_CRASHED, -1); + WebContentsTester::For(raw_contents) + ->SetIsCrashed(base::TERMINATION_STATUS_PROCESS_CRASHED, -1); EXPECT_TRUE(raw_contents->IsCrashed()); EXPECT_FALSE(command_updater->IsCommandEnabled(IDC_ZOOM_PLUS));
diff --git a/chrome/browser/ui/chrome_pages.cc b/chrome/browser/ui/chrome_pages.cc index e1adfc11..307313f 100644 --- a/chrome/browser/ui/chrome_pages.cc +++ b/chrome/browser/ui/chrome_pages.cc
@@ -22,6 +22,7 @@ #include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/apps/app_service/browser_app_launcher.h" +#include "chrome/browser/apps/app_service/launch_utils.h" #include "chrome/browser/bookmarks/bookmark_model_factory.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/download/download_shelf.h" @@ -115,7 +116,7 @@ apps::AppServiceProxyFactory::GetForProfileRedirectInIncognito(profile); proxy->LaunchAppWithUrl(web_app::kHelpAppId, ui::EventFlags::EF_NONE, GURL("chrome://help-app/updates"), source, - display::kDefaultDisplayId); + apps::MakeWindowInfo(display::kDefaultDisplayId)); } #endif @@ -145,7 +146,7 @@ apps::AppServiceProxy* proxy = apps::AppServiceProxyFactory::GetForProfileRedirectInIncognito(profile); proxy->Launch(web_app::kHelpAppId, ui::EventFlags::EF_NONE, app_launch_source, - display::kDefaultDisplayId); + apps::MakeWindowInfo(display::kDefaultDisplayId)); #else GURL url; switch (source) {
diff --git a/chrome/browser/ui/extensions/extension_enable_flow.cc b/chrome/browser/ui/extensions/extension_enable_flow.cc index 3a693485..882c82e 100644 --- a/chrome/browser/ui/extensions/extension_enable_flow.cc +++ b/chrome/browser/ui/extensions/extension_enable_flow.cc
@@ -14,8 +14,6 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profiles_state.h" #include "chrome/browser/ui/extensions/extension_enable_flow_delegate.h" -#include "content/public/browser/notification_details.h" -#include "content/public/browser/notification_source.h" #include "extensions/browser/extension_prefs.h" #include "extensions/browser/extension_system.h" @@ -198,20 +196,18 @@ void ExtensionEnableFlow::StartObserving() { extension_registry_observer_.Add( extensions::ExtensionRegistry::Get(profile_)); - registrar_.Add(this, - extensions::NOTIFICATION_EXTENSION_LOAD_ERROR, - content::Source<Profile>(profile_)); + load_error_observation_.Observe(extensions::LoadErrorReporter::GetInstance()); } void ExtensionEnableFlow::StopObserving() { - registrar_.RemoveAll(); extension_registry_observer_.RemoveAll(); + load_error_observation_.Reset(); } -void ExtensionEnableFlow::Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) { - DCHECK_EQ(extensions::NOTIFICATION_EXTENSION_LOAD_ERROR, type); +void ExtensionEnableFlow::OnLoadFailure( + content::BrowserContext* browser_context, + const base::FilePath& file_path, + const std::string& error) { StopObserving(); delegate_->ExtensionEnableFlowAborted( /*user_initiated=*/false); // |delegate_| may delete us.
diff --git a/chrome/browser/ui/extensions/extension_enable_flow.h b/chrome/browser/ui/extensions/extension_enable_flow.h index 165d3816..1478b9f1 100644 --- a/chrome/browser/ui/extensions/extension_enable_flow.h +++ b/chrome/browser/ui/extensions/extension_enable_flow.h
@@ -12,11 +12,11 @@ #include "base/compiler_specific.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" +#include "base/scoped_observation.h" #include "base/scoped_observer.h" #include "chrome/browser/extensions/extension_install_prompt.h" +#include "chrome/browser/extensions/load_error_reporter.h" #include "chrome/common/buildflags.h" -#include "content/public/browser/notification_observer.h" -#include "content/public/browser/notification_registrar.h" #include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_registry_observer.h" @@ -37,7 +37,7 @@ // extension is enabled already). Otherwise, a re-enable install prompt is // shown to user. The extension is enabled when user acknowledges it or the // flow is aborted when user declines it. -class ExtensionEnableFlow : public content::NotificationObserver, +class ExtensionEnableFlow : public extensions::LoadErrorReporter::Observer, public extensions::ExtensionRegistryObserver { public: ExtensionEnableFlow(Profile* profile, @@ -58,6 +58,11 @@ const std::string& extension_id() const { return extension_id_; } + // LoadErrorReporter::Observer: + void OnLoadFailure(content::BrowserContext* browser_context, + const base::FilePath& file_path, + const std::string& error) override; + private: // Runs the enable flow. It starts by checking if the extension is loaded. // If not, it tries to reload it. If the load is asynchronous, wait for the @@ -89,11 +94,6 @@ void StartObserving(); void StopObserving(); - // content::NotificationObserver overrides: - void Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) override; - // extensions::ExtensionRegistryObserver overrides: void OnExtensionLoaded(content::BrowserContext* browser_context, const extensions::Extension* extension) override; @@ -118,13 +118,16 @@ gfx::NativeWindow parent_window_ = nullptr; std::unique_ptr<ExtensionInstallPrompt> prompt_; - content::NotificationRegistrar registrar_; // Listen to extension load notification. ScopedObserver<extensions::ExtensionRegistry, extensions::ExtensionRegistryObserver> extension_registry_observer_{this}; + base::ScopedObservation<extensions::LoadErrorReporter, + extensions::LoadErrorReporter::Observer> + load_error_observation_{this}; + base::WeakPtrFactory<ExtensionEnableFlow> weak_ptr_factory_{this}; DISALLOW_COPY_AND_ASSIGN(ExtensionEnableFlow);
diff --git a/chrome/browser/ui/extensions/extension_installed_notification.cc b/chrome/browser/ui/extensions/extension_installed_notification.cc index ea7f89df..7a414ff 100644 --- a/chrome/browser/ui/extensions/extension_installed_notification.cc +++ b/chrome/browser/ui/extensions/extension_installed_notification.cc
@@ -22,7 +22,6 @@ #include "extensions/common/extension.h" #include "extensions/common/extension_urls.h" #include "ui/base/l10n/l10n_util.h" -#include "ui/display/types/display_constants.h" #include "ui/gfx/color_palette.h" #include "ui/message_center/public/cpp/notification.h" @@ -81,6 +80,5 @@ apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerNone, WindowOpenDisposition::NEW_FOREGROUND_TAB, true /* preferred_containner */), - apps::mojom::LaunchSource::kFromInstalledNotification, - display::kInvalidDisplayId); + apps::mojom::LaunchSource::kFromInstalledNotification); }
diff --git a/chrome/browser/ui/startup/startup_browser_creator.cc b/chrome/browser/ui/startup/startup_browser_creator.cc index e42fba28..e098885 100644 --- a/chrome/browser/ui/startup/startup_browser_creator.cc +++ b/chrome/browser/ui/startup/startup_browser_creator.cc
@@ -1258,7 +1258,8 @@ base::FilePath GetStartupProfilePath(const base::FilePath& user_data_dir, const base::FilePath& cur_dir, - const base::CommandLine& command_line) { + const base::CommandLine& command_line, + bool ignore_profile_picker) { // If the browser is launched due to activation on Windows native notification, // the profile id encoded in the notification launch id should be chosen over // all others. @@ -1285,7 +1286,8 @@ ProfileManager* profile_manager = g_browser_process->profile_manager(); #if !BUILDFLAG(IS_CHROMEOS_ASH) - if (ShouldShowProfilePickerAtProcessLaunch(profile_manager, command_line)) { + if (!ignore_profile_picker && + ShouldShowProfilePickerAtProcessLaunch(profile_manager, command_line)) { // Open the picker only if no URLs have been provided to launch Chrome. If // URLs are provided, open them in the last profile, instead. Profile* guest_profile = @@ -1315,8 +1317,8 @@ const base::FilePath& cur_dir, const base::CommandLine& command_line) { ProfileManager* profile_manager = g_browser_process->profile_manager(); - base::FilePath profile_path = - GetStartupProfilePath(user_data_dir, cur_dir, command_line); + base::FilePath profile_path = GetStartupProfilePath( + user_data_dir, cur_dir, command_line, /*ignore_profile_picker=*/false); Profile* profile = profile_manager->GetProfile(profile_path); // If there is no entry in profile attributes storage, the profile is deleted,
diff --git a/chrome/browser/ui/startup/startup_browser_creator.h b/chrome/browser/ui/startup/startup_browser_creator.h index 7f4b56f9..7fa3fc7c 100644 --- a/chrome/browser/ui/startup/startup_browser_creator.h +++ b/chrome/browser/ui/startup/startup_browser_creator.h
@@ -210,9 +210,15 @@ // Returns the path that contains the profile that should be loaded on process // startup. +// When the profile picker is shown on startup, this returns the Guest profile +// path. On Mac, the startup profile path is also used to open URLs at startup, +// bypassing the profile picker, because the profile picker does not support it. +// TODO(https://crbug.com/1155158): Remove this parameter once the picker +// supports opening URLs. base::FilePath GetStartupProfilePath(const base::FilePath& user_data_dir, const base::FilePath& cur_dir, - const base::CommandLine& command_line); + const base::CommandLine& command_line, + bool ignore_profile_picker); #if !BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OS_ANDROID) // Returns the profile that should be loaded on process startup. This is either
diff --git a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc index 4a970a80..efdf507 100644 --- a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc +++ b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
@@ -2300,7 +2300,8 @@ base::CommandLine command_line(base::CommandLine::NO_PROGRAM); StartupBrowserCreator::ProcessCommandLineAlreadyRunning( command_line, current_dir, - GetStartupProfilePath(user_data_dir, current_dir, command_line)); + GetStartupProfilePath(user_data_dir, current_dir, command_line, + /*ignore_profile_picker=*/false)); base::RunLoop().RunUntilIdle(); // The picker is shown again if no profile was previously opened.
diff --git a/chrome/browser/ui/ui_features.cc b/chrome/browser/ui/ui_features.cc index 7d7530d1..0dfe4e5 100644 --- a/chrome/browser/ui/ui_features.cc +++ b/chrome/browser/ui/ui_features.cc
@@ -59,6 +59,7 @@ // Enables tabs to scroll in the tabstrip. https://crbug.com/951078 const base::Feature kScrollableTabStrip{"ScrollableTabStrip", base::FEATURE_DISABLED_BY_DEFAULT}; +const char kMinimumTabWidthFeatureParameterName[] = "minTabWidth"; // Enables buttons to permanently appear on the tabstrip when // scrollable-tabstrip is enabled. https://crbug.com/1116118 @@ -168,7 +169,7 @@ // Enables a separate group of settings (speed, button swap, and acceleration) // for pointing sticks (such as TrackPoints). const base::Feature kSeparatePointingStickSettings{ - "SeparatePointingStickSettings", base::FEATURE_DISABLED_BY_DEFAULT}; + "SeparatePointingStickSettings", base::FEATURE_ENABLED_BY_DEFAULT}; #endif // BUILDFLAG(IS_CHROMEOS_ASH) } // namespace features
diff --git a/chrome/browser/ui/ui_features.h b/chrome/browser/ui/ui_features.h index 044ec21..37b4dde 100644 --- a/chrome/browser/ui/ui_features.h +++ b/chrome/browser/ui/ui_features.h
@@ -44,6 +44,7 @@ extern const base::Feature kProminentDarkModeActiveTabTitle; extern const base::Feature kScrollableTabStrip; +extern const char kMinimumTabWidthFeatureParameterName[]; extern const base::Feature kScrollableTabStripButtons;
diff --git a/chrome/browser/ui/views/accelerator_table.cc b/chrome/browser/ui/views/accelerator_table.cc index bb9107a..c036aa5 100644 --- a/chrome/browser/ui/views/accelerator_table.cc +++ b/chrome/browser/ui/views/accelerator_table.cc
@@ -243,12 +243,13 @@ #endif constexpr int kDebugModifier = - ui::EF_PLATFORM_ACCELERATOR | ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN; + ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN; // Accelerators to enable if features::UIDebugTools is true. constexpr AcceleratorMapping kUIDebugAcceleratorMap[] = { {ui::VKEY_T, kDebugModifier, IDC_DEBUG_TOGGLE_TABLET_MODE}, {ui::VKEY_V, kDebugModifier, IDC_DEBUG_PRINT_VIEW_TREE}, + {ui::VKEY_M, kDebugModifier, IDC_DEBUG_PRINT_VIEW_TREE_DETAILS}, }; const int kRepeatableCommandIds[] = {
diff --git a/chrome/browser/ui/views/apps/app_dialog/app_dialog_view_browsertest.cc b/chrome/browser/ui/views/apps/app_dialog/app_dialog_view_browsertest.cc index 518060a..2d14be0 100644 --- a/chrome/browser/ui/views/apps/app_dialog/app_dialog_view_browsertest.cc +++ b/chrome/browser/ui/views/apps/app_dialog/app_dialog_view_browsertest.cc
@@ -25,7 +25,6 @@ #include "components/arc/test/connection_holder_util.h" #include "components/arc/test/fake_app_instance.h" #include "content/public/test/browser_test.h" -#include "ui/display/types/display_constants.h" class AppDialogViewBrowserTest : public DialogBrowserTest { public: @@ -109,9 +108,9 @@ app_instance_->SendRefreshAppList( std::vector<arc::mojom::AppInfo>(1, app)); app_service_proxy_->FlushMojoCallsForTesting(); - app_service_proxy_->Launch(app_id_, ui::EventFlags::EF_NONE, - apps::mojom::LaunchSource::kFromChromeInternal, - display::kInvalidDisplayId); + app_service_proxy_->Launch( + app_id_, ui::EventFlags::EF_NONE, + apps::mojom::LaunchSource::kFromChromeInternal); } else { std::map<std::string, apps::PauseData> pause_data; pause_data[app_id_].hours = 3;
diff --git a/chrome/browser/ui/views/autofill/save_address_profile_view.cc b/chrome/browser/ui/views/autofill/save_address_profile_view.cc index 1cd6cac5..19a46146 100644 --- a/chrome/browser/ui/views/autofill/save_address_profile_view.cc +++ b/chrome/browser/ui/views/autofill/save_address_profile_view.cc
@@ -17,6 +17,14 @@ controller_(controller) { DCHECK(base::FeatureList::IsEnabled( features::kAutofillAddressProfileSavePrompt)); + SetAcceptCallback(base::BindOnce( + &SaveAddressProfileBubbleController::OnUserDecision, + base::Unretained(controller_), + AutofillClient::SaveAddressProfileOfferUserDecision::kAccepted)); + SetCancelCallback(base::BindOnce( + &SaveAddressProfileBubbleController::OnUserDecision, + base::Unretained(controller_), + AutofillClient::SaveAddressProfileOfferUserDecision::kDeclined)); } bool SaveAddressProfileView::ShouldShowCloseButton() const {
diff --git a/chrome/browser/ui/views/autofill/save_address_profile_view.h b/chrome/browser/ui/views/autofill/save_address_profile_view.h index 9aae948..842d90ea 100644 --- a/chrome/browser/ui/views/autofill/save_address_profile_view.h +++ b/chrome/browser/ui/views/autofill/save_address_profile_view.h
@@ -28,6 +28,9 @@ content::WebContents* web_contents, SaveAddressProfileBubbleController* controller); + SaveAddressProfileView(const SaveAddressProfileView&) = delete; + SaveAddressProfileView& operator=(const SaveAddressProfileView&) = delete; + // views::WidgetDelegate: bool ShouldShowCloseButton() const override; base::string16 GetWindowTitle() const override;
diff --git a/chrome/browser/ui/views/autofill/save_address_profile_view_unittest.cc b/chrome/browser/ui/views/autofill/save_address_profile_view_unittest.cc index fd6c888b..25089c5 100644 --- a/chrome/browser/ui/views/autofill/save_address_profile_view_unittest.cc +++ b/chrome/browser/ui/views/autofill/save_address_profile_view_unittest.cc
@@ -5,14 +5,28 @@ #include "chrome/browser/ui/views/autofill/save_address_profile_view.h" #include "base/test/scoped_feature_list.h" +#include "chrome/browser/ui/autofill/save_address_profile_bubble_controller.h" #include "chrome/test/base/testing_profile.h" #include "chrome/test/views/chrome_views_test_base.h" #include "components/autofill/core/common/autofill_features.h" #include "content/public/test/test_renderer_host.h" #include "content/public/test/web_contents_tester.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" namespace autofill { +class MockSaveAddressProfileBubbleController + : public SaveAddressProfileBubbleController { + public: + MOCK_METHOD(base::string16, GetWindowTitle, (), (const, override)); + MOCK_METHOD(void, + OnUserDecision, + (AutofillClient::SaveAddressProfileOfferUserDecision decision), + (override)); + MOCK_METHOD(void, OnBubbleClosed, (), (override)); +}; + class SaveAddressProfileViewTest : public ChromeViewsTestBase { public: SaveAddressProfileViewTest(); @@ -29,6 +43,9 @@ } SaveAddressProfileView* view() { return view_; } + MockSaveAddressProfileBubbleController* mock_controller() { + return &mock_controller_; + } private: base::test::ScopedFeatureList feature_list_; @@ -38,6 +55,7 @@ std::unique_ptr<content::WebContents> test_web_contents_; std::unique_ptr<views::Widget> anchor_widget_; SaveAddressProfileView* view_; + testing::NiceMock<MockSaveAddressProfileBubbleController> mock_controller_; }; SaveAddressProfileViewTest::SaveAddressProfileViewTest() { @@ -49,6 +67,9 @@ } void SaveAddressProfileViewTest::CreateViewAndShow() { + ON_CALL(*mock_controller(), GetWindowTitle()) + .WillByDefault(testing::Return(base::string16())); + // The bubble needs the parent as an anchor. views::Widget::InitParams params = CreateParams(views::Widget::InitParams::TYPE_WINDOW); @@ -58,9 +79,9 @@ anchor_widget_->Init(std::move(params)); anchor_widget_->Show(); - view_ = new SaveAddressProfileView(anchor_widget_->GetContentsView(), - test_web_contents_.get(), - /*controller=*/nullptr); + view_ = + new SaveAddressProfileView(anchor_widget_->GetContentsView(), + test_web_contents_.get(), mock_controller()); views::BubbleDialogDelegateView::CreateBubble(view_)->Show(); } @@ -69,4 +90,22 @@ EXPECT_TRUE(view()->ShouldShowCloseButton()); } +TEST_F(SaveAddressProfileViewTest, AcceptInvokesTheController) { + CreateViewAndShow(); + EXPECT_CALL( + *mock_controller(), + OnUserDecision( + AutofillClient::SaveAddressProfileOfferUserDecision::kAccepted)); + view()->AcceptDialog(); +} + +TEST_F(SaveAddressProfileViewTest, CancelInvokesTheController) { + CreateViewAndShow(); + EXPECT_CALL( + *mock_controller(), + OnUserDecision( + AutofillClient::SaveAddressProfileOfferUserDecision::kDeclined)); + view()->CancelDialog(); +} + } // namespace autofill
diff --git a/chrome/browser/ui/views/browser_commands_views.cc b/chrome/browser/ui/views/browser_commands_views.cc index fe9d1fa..be720cd 100644 --- a/chrome/browser/ui/views/browser_commands_views.cc +++ b/chrome/browser/ui/views/browser_commands_views.cc
@@ -9,7 +9,38 @@ #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/tabs/tab_strip.h" #include "ui/base/ui_base_features.h" -#include "ui/views/debug_utils.h" +#include "ui/views/view.h" +#include "ui/views/view_utils.h" +#include "ui/views/widget/widget.h" + +#if defined(USE_AURA) +#include "ui/aura/window.h" +#include "ui/wm/public/activation_client.h" +#endif + +#if defined(OS_MAC) +#include "chrome/browser/platform_util.h" +#endif + +namespace { +views::View* GetActiveWindowRootView(const Browser* browser) { +#if defined(USE_AURA) + wm::ActivationClient* client = wm::GetActivationClient( + browser->window()->GetNativeWindow()->GetRootWindow()); + if (!client) + return nullptr; + gfx::NativeWindow active_window = client->GetActiveWindow(); +#elif defined(OS_MAC) + NSWindow* active_window = platform_util::GetActiveWindow(); + if (!active_window) + return nullptr; +#endif + + views::Widget* widget = + views::Widget::GetWidgetForNativeWindow(active_window); + return widget ? widget->GetRootView() : nullptr; +} +} // namespace namespace chrome { @@ -33,11 +64,13 @@ break; } case IDC_DEBUG_PRINT_VIEW_TREE: - // TODO(weili): replace with a new tree dumping utility which can show - // detailed property info. - PrintViewHierarchy(BrowserView::GetBrowserViewForBrowser(browser)); + if (views::View* view = GetActiveWindowRootView(browser)) + PrintViewHierarchy(view); break; - + case IDC_DEBUG_PRINT_VIEW_TREE_DETAILS: + if (views::View* view = GetActiveWindowRootView(browser)) + PrintViewHierarchy(view, /* verbose= */ true); + break; default: NOTREACHED() << "Unimplemented UI Debug command: " << id; break;
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc index 5a4c76cb..d569861d 100644 --- a/chrome/browser/ui/views/frame/browser_view.cc +++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -156,6 +156,7 @@ #include "components/prefs/pref_service.h" #include "components/safe_browsing/core/password_protection/metrics_util.h" #include "components/sessions/core/tab_restore_service.h" +#include "components/startup_metric_utils/browser/startup_metric_utils.h" #include "components/translate/core/browser/language_state.h" #include "components/translate/core/browser/translate_manager.h" #include "components/version_info/channel.h" @@ -2955,11 +2956,10 @@ void BrowserView::PaintChildren(const views::PaintInfo& paint_info) { views::ClientView::PaintChildren(paint_info); - // Don't reset the instance before it had a chance to get compositor callback. - if (!histogram_helper_) { - histogram_helper_ = BrowserWindowHistogramHelper:: - MaybeRecordValueAndCreateInstanceOnBrowserPaint( - GetWidget()->GetCompositor()); + static bool did_first_paint = false; + if (!did_first_paint) { + did_first_paint = true; + startup_metric_utils::RecordBrowserWindowFirstPaint(base::TimeTicks::Now()); } }
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h index 9ba858b8..e4955cc 100644 --- a/chrome/browser/ui/views/frame/browser_view.h +++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -22,7 +22,6 @@ #include "chrome/browser/devtools/devtools_window.h" #include "chrome/browser/extensions/extension_commands_global_registry.h" #include "chrome/browser/extensions/extension_keybinding_registry.h" -#include "chrome/browser/metrics/browser_window_histogram_helper.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/exclusive_access/exclusive_access_context.h" @@ -937,8 +936,6 @@ std::unique_ptr<ExtensionKeybindingRegistryViews> extension_keybinding_registry_; - std::unique_ptr<BrowserWindowHistogramHelper> histogram_helper_; - std::unique_ptr<FullscreenControlHost> fullscreen_control_host_; // If the Window Placement experiment is enabled and fullscreen is requested
diff --git a/chrome/browser/ui/views/page_action/pwa_install_view_browsertest.cc b/chrome/browser/ui/views/page_action/pwa_install_view_browsertest.cc index 4a4671a..29b6525 100644 --- a/chrome/browser/ui/views/page_action/pwa_install_view_browsertest.cc +++ b/chrome/browser/ui/views/page_action/pwa_install_view_browsertest.cc
@@ -39,6 +39,7 @@ #include "components/webapps/browser/installable/installable_metrics.h" #include "content/public/common/referrer.h" #include "content/public/test/browser_test.h" +#include "content/public/test/test_utils.h" #include "extensions/common/extension.h" #include "net/test/embedded_test_server/http_request.h" #include "net/test/embedded_test_server/http_response.h" @@ -397,7 +398,13 @@ ASSERT_TRUE(app_banner_manager_->WaitForInstallableCheck()); EXPECT_TRUE(pwa_install_view_->GetVisible()); - web_contents_->SetIsCrashed(base::TERMINATION_STATUS_PROCESS_CRASHED, -1); + { + content::ScopedAllowRendererCrashes scoped_allow_renderer_crashes; + content::RenderFrameDeletedObserver crash_observer( + web_contents_->GetMainFrame()); + web_contents_->GetMainFrame()->GetProcess()->Shutdown(1); + crash_observer.WaitUntilDeleted(); + } ASSERT_TRUE(web_contents_->IsCrashed()); PwaInstallIconChangeWaiter::VerifyIconVisibility(pwa_install_view_, false); }
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc index 9e9c088..e2c0105 100644 --- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc +++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -1387,7 +1387,8 @@ } // namespace -#if defined(OS_MAC) && defined(ARCH_CPU_ARM64) +// Flaky. https://crbug.com/1176998 +#if (defined(OS_MAC) && defined(ARCH_CPU_ARM64)) || defined(OS_LINUX) // Bulk-disabled for arm64 bot stabilization: https://crbug.com/1154345 #define MAYBE_DragToSeparateWindow DISABLED_DragToSeparateWindow #else @@ -2059,8 +2060,8 @@ } // namespace -// Flaky. http://crbug.com/1128774 -#if defined(OS_MAC) || defined(OS_WIN) +// Flaky. http://crbug.com/1128774 and http://crbug.com/1176998 +#if defined(OS_MAC) || defined(OS_WIN) || defined(OS_LINUX) // Bulk-disabled for arm64 bot stabilization: https://crbug.com/1154345 // These were flaking on all macs, so commented out ARCH_ above for // crbug.com/1160917 too. @@ -2696,7 +2697,8 @@ browser2->window()->GetBounds().ToString()); } -#if defined(OS_MAC) && defined(ARCH_CPU_ARM64) +// Flaky. https://crbug.com/1176998 +#if (defined(OS_MAC) && defined(ARCH_CPU_ARM64)) || defined(OS_LINUX) // Bulk-disabled for arm64 bot stabilization: https://crbug.com/1154345 #define MAYBE_DragSingleTabToSeparateWindow \ DISABLED_DragSingleTabToSeparateWindow
diff --git a/chrome/browser/ui/views/tabs/tab_style_views.cc b/chrome/browser/ui/views/tabs/tab_style_views.cc index 70a78509..052a824 100644 --- a/chrome/browser/ui/views/tabs/tab_style_views.cc +++ b/chrome/browser/ui/views/tabs/tab_style_views.cc
@@ -988,19 +988,33 @@ // static int TabStyleViews::GetMinimumActiveWidth() { - if (base::FeatureList::IsEnabled(features::kScrollableTabStrip)) - return 72; - return TabCloseButton::GetGlyphSize() + GetContentsHorizontalInsetSize() * 2; + int min_active_width = + TabCloseButton::GetGlyphSize() + GetContentsHorizontalInsetSize() * 2; + if (base::FeatureList::IsEnabled(features::kScrollableTabStrip)) { + return std::max(min_active_width, + base::GetFieldTrialParamByFeatureAsInt( + features::kScrollableTabStrip, + features::kMinimumTabWidthFeatureParameterName, 72)); + } + return min_active_width; } // static int TabStyleViews::GetMinimumInactiveWidth() { - if (base::FeatureList::IsEnabled(features::kScrollableTabStrip)) - return 72; // Allow tabs to shrink until they appear to be 16 DIP wide excluding // outer corners. constexpr int kInteriorWidth = 16; // The overlap contains the trailing separator that is part of the interior // width; avoid double-counting it. - return kInteriorWidth - GetSeparatorSize().width() + GetTabOverlap(); + int min_inactive_width = + kInteriorWidth - GetSeparatorSize().width() + GetTabOverlap(); + + if (base::FeatureList::IsEnabled(features::kScrollableTabStrip)) { + return std::max(min_inactive_width, + base::GetFieldTrialParamByFeatureAsInt( + features::kScrollableTabStrip, + features::kMinimumTabWidthFeatureParameterName, 72)); + } + + return min_inactive_width; }
diff --git a/chrome/browser/ui/views/window_name_prompt.cc b/chrome/browser/ui/views/window_name_prompt.cc index 02cf79c..0ec2d64 100644 --- a/chrome/browser/ui/views/window_name_prompt.cc +++ b/chrome/browser/ui/views/window_name_prompt.cc
@@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/metrics/user_metrics.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/ui/views/chrome_layout_provider.h" #include "chrome/browser/ui/views/frame/browser_view.h" @@ -20,8 +21,13 @@ void SetBrowserTitleFromTextfield(Browser* browser, ui::DialogModel* dialog_model) { - browser->SetWindowUserTitle(base::UTF16ToUTF8( - dialog_model->GetTextfieldByUniqueId(kWindowNameFieldId)->text())); + std::string text = base::UTF16ToUTF8( + dialog_model->GetTextfieldByUniqueId(kWindowNameFieldId)->text()); + if (text.empty()) + base::RecordAction(base::UserMetricsAction("WindowNaming_Cleared")); + else + base::RecordAction(base::UserMetricsAction("WindowNaming_Set")); + browser->SetWindowUserTitle(text); } std::unique_ptr<views::DialogDelegate> CreateWindowNamePrompt( @@ -50,6 +56,8 @@ void DoShowWindowNamePrompt(Browser* browser, gfx::NativeView anchor, gfx::NativeWindow context) { + base::RecordAction(base::UserMetricsAction("WindowNaming_DialogShown")); + auto prompt = CreateWindowNamePrompt(browser); prompt->SetOwnedByWidget(true); views::DialogDelegate::CreateDialogWidget(std::move(prompt), context, anchor)
diff --git a/chrome/browser/ui/web_applications/system_web_app_ui_utils.cc b/chrome/browser/ui/web_applications/system_web_app_ui_utils.cc index 4d1ae0c..d737f75 100644 --- a/chrome/browser/ui/web_applications/system_web_app_ui_utils.cc +++ b/chrome/browser/ui/web_applications/system_web_app_ui_utils.cc
@@ -37,7 +37,6 @@ #include "chrome/browser/web_launch/web_launch_files_helper.h" #include "chrome/common/webui_url_constants.h" #include "ui/base/window_open_disposition.h" -#include "ui/display/types/display_constants.h" #if BUILDFLAG(IS_CHROMEOS_ASH) #include "chrome/browser/ui/ash/multi_user/multi_user_util.h" @@ -205,15 +204,13 @@ auto event_flags = apps::GetEventFlags( apps::mojom::LaunchContainer::kLaunchContainerNone, WindowOpenDisposition::NEW_WINDOW, /* prefer_container */ false); - auto display_id = display::kInvalidDisplayId; if (params.url.is_empty()) { - app_service->Launch(app_id.value(), event_flags, params.launch_source, - display_id); + app_service->Launch(app_id.value(), event_flags, params.launch_source); } else { DCHECK(params.url.is_valid()); app_service->LaunchAppWithUrl(app_id.value(), event_flags, params.url, - params.launch_source, display_id); + params.launch_source); } }
diff --git a/chrome/browser/ui/web_applications/web_app_browsertest.cc b/chrome/browser/ui/web_applications/web_app_browsertest.cc index 1849ae70..c379a2bb 100644 --- a/chrome/browser/ui/web_applications/web_app_browsertest.cc +++ b/chrome/browser/ui/web_applications/web_app_browsertest.cc
@@ -17,6 +17,7 @@ #include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/apps/app_service/browser_app_launcher.h" +#include "chrome/browser/browser_features.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/devtools/protocol/browser_handler.h" #include "chrome/browser/sessions/tab_restore_service_factory.h" @@ -776,7 +777,14 @@ NavigateAndAwaitInstallabilityCheck(browser(), GetInstallableAppURL())); content::WebContents* tab_contents = browser()->tab_strip_model()->GetActiveWebContents(); - tab_contents->SetIsCrashed(base::TERMINATION_STATUS_PROCESS_CRASHED, -1); + + { + content::ScopedAllowRendererCrashes scoped_allow_renderer_crashes; + content::RenderFrameDeletedObserver crash_observer( + tab_contents->GetMainFrame()); + tab_contents->GetMainFrame()->GetProcess()->Shutdown(1); + crash_observer.WaitUntilDeleted(); + } ASSERT_TRUE(tab_contents->IsCrashed()); EXPECT_EQ(GetAppMenuCommandState(IDC_CREATE_SHORTCUT, browser()), kDisabled); @@ -968,26 +976,6 @@ "navigator.geolocation.getCurrentPosition(function(){});")); } -// Check that no web app is launched during shutdown. -IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, Shutdown) { - const GURL app_url = GetSecureAppURL(); - const AppId app_id = InstallPWA(app_url); - apps::AppLaunchParams params( - app_id, apps::mojom::LaunchContainer::kLaunchContainerWindow, - WindowOpenDisposition::NEW_WINDOW, - apps::mojom::AppLaunchSource::kSourceTest); - - BrowserHandler handler(nullptr, std::string()); - handler.Close(); - ui_test_utils::WaitForBrowserToClose(); - - content::WebContents* const web_contents = - apps::AppServiceProxyFactory::GetForProfile(profile()) - ->BrowserAppLauncher() - ->LaunchAppWithParams(std::move(params)); - EXPECT_EQ(web_contents, nullptr); -} - // Ensure that web app windows with blank titles don't display the URL as a // default window title. IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, EmptyTitlesDoNotDisplayUrl) { @@ -1271,4 +1259,37 @@ EXPECT_EQ(nullptr, app_browser->GetStatusBubbleForTesting()); } +class WebAppBrowserTest_NoDestroyProfile : public WebAppBrowserTest { + public: + WebAppBrowserTest_NoDestroyProfile() { + // This test only makes sense when DestroyProfileOnBrowserClose is + // disabled. + feature_list_.InitAndDisableFeature( + features::kDestroyProfileOnBrowserClose); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +// Check that no web app is launched during shutdown. +IN_PROC_BROWSER_TEST_F(WebAppBrowserTest_NoDestroyProfile, Shutdown) { + const GURL app_url = GetSecureAppURL(); + const AppId app_id = InstallPWA(app_url); + apps::AppLaunchParams params( + app_id, apps::mojom::LaunchContainer::kLaunchContainerWindow, + WindowOpenDisposition::NEW_WINDOW, + apps::mojom::AppLaunchSource::kSourceTest); + + BrowserHandler handler(nullptr, std::string()); + handler.Close(); + ui_test_utils::WaitForBrowserToClose(); + + content::WebContents* const web_contents = + apps::AppServiceProxyFactory::GetForProfile(profile()) + ->BrowserAppLauncher() + ->LaunchAppWithParams(std::move(params)); + EXPECT_EQ(web_contents, nullptr); +} + } // namespace web_app
diff --git a/chrome/browser/ui/webui/chrome_url_data_manager_browsertest.cc b/chrome/browser/ui/webui/chrome_url_data_manager_browsertest.cc index 0759493..70f454a 100644 --- a/chrome/browser/ui/webui/chrome_url_data_manager_browsertest.cc +++ b/chrome/browser/ui/webui/chrome_url_data_manager_browsertest.cc
@@ -302,6 +302,7 @@ "chrome://crostini-installer", "chrome://cryptohome", "chrome://drive-internals", + "chrome://family-link-user-internals", "chrome://help-app", "chrome://internet-config-dialog", "chrome://internet-detail-dialog", @@ -318,7 +319,6 @@ "chrome://slow", "chrome://smb-credentials-dialog", "chrome://smb-share-dialog", - "chrome://supervised-user-internals", "chrome://sys-internals", "chrome-untrusted://terminal", #endif
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc index 937c5f8..542424d4 100644 --- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc +++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -297,7 +297,7 @@ #endif #if BUILDFLAG(ENABLE_SUPERVISED_USERS) -#include "chrome/browser/ui/webui/supervised_user_internals_ui.h" +#include "chrome/browser/ui/webui/family_link_user_internals/family_link_user_internals_ui.h" #endif #if BUILDFLAG(ENABLE_DICE_SUPPORT) @@ -405,9 +405,9 @@ } template <> -WebUIController* NewWebUI<chromeos::DiagnosticsUI>(WebUI* web_ui, - const GURL& url) { - return new chromeos::DiagnosticsUI( +WebUIController* NewWebUI<chromeos::DiagnosticsDialogUI>(WebUI* web_ui, + const GURL& url) { + return new chromeos::DiagnosticsDialogUI( web_ui, base::BindRepeating(&CreateChromeSelectFilePolicy)); } @@ -740,7 +740,7 @@ return &NewWebUI<chromeos::PowerUI>; if (base::FeatureList::IsEnabled(chromeos::features::kDiagnosticsApp) && url.host_piece() == chromeos::kChromeUIDiagnosticsAppHost) { - return &NewWebUI<chromeos::DiagnosticsUI>; + return &NewWebUI<chromeos::DiagnosticsDialogUI>; } if (url.host_piece() == chromeos::kChromeUIPrintManagementHost) return &NewWebUI<chromeos::printing::printing_manager::PrintManagementUI>; @@ -989,8 +989,8 @@ #endif #if BUILDFLAG(ENABLE_SUPERVISED_USERS) - if (url.host_piece() == chrome::kChromeUISupervisedUserInternalsHost) - return &NewWebUI<SupervisedUserInternalsUI>; + if (url.host_piece() == chrome::kChromeUIFamilyLinkUserInternalsHost) + return &NewWebUI<FamilyLinkUserInternalsUI>; #endif #if BUILDFLAG(ENABLE_DICE_SUPPORT)
diff --git a/chrome/browser/ui/webui/chromeos/diagnostics_dialog.cc b/chrome/browser/ui/webui/chromeos/diagnostics_dialog.cc new file mode 100644 index 0000000..7978728f --- /dev/null +++ b/chrome/browser/ui/webui/chromeos/diagnostics_dialog.cc
@@ -0,0 +1,51 @@ +// Copyright (c) 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 "chrome/browser/ui/webui/chromeos/diagnostics_dialog.h" + +#include <string> + +#include "chromeos/components/diagnostics_ui/url_constants.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" + +namespace chromeos { + +// Scale factor for size of the diagnostics dialog, based on display size. +const float kDiagnosticsDialogScale = .8; + +// static +void DiagnosticsDialog::ShowDialog() { + DiagnosticsDialog* dialog = new DiagnosticsDialog(); + dialog->ShowSystemDialog(); +} + +DiagnosticsDialog::DiagnosticsDialog() + : SystemWebDialogDelegate(GURL(kChromeUIDiagnosticsAppUrl), + /*title=*/base::string16()) {} + +DiagnosticsDialog::~DiagnosticsDialog() = default; + +const std::string& DiagnosticsDialog::Id() { + return id_; +} + +void DiagnosticsDialog::GetDialogSize(gfx::Size* size) const { + const display::Display display = + display::Screen::GetScreen()->GetPrimaryDisplay(); + + gfx::Size display_size = display.size(); + + if (display.rotation() == display::Display::ROTATE_90 || + display.rotation() == display::Display::ROTATE_270) { + display_size = gfx::Size(display_size.height(), display_size.width()); + } + + display_size = gfx::Size(display_size.width() * kDiagnosticsDialogScale, + display_size.height() * kDiagnosticsDialogScale); + + *size = display_size; +} + +} // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/diagnostics_dialog.h b/chrome/browser/ui/webui/chromeos/diagnostics_dialog.h new file mode 100644 index 0000000..5a3aad6b --- /dev/null +++ b/chrome/browser/ui/webui/chromeos/diagnostics_dialog.h
@@ -0,0 +1,35 @@ +// Copyright (c) 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 CHROME_BROWSER_UI_WEBUI_CHROMEOS_DIAGNOSTICS_DIALOG_H_ +#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_DIAGNOSTICS_DIALOG_H_ + +#include "base/macros.h" +#include "chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.h" + +namespace chromeos { + +class DiagnosticsDialog : public SystemWebDialogDelegate { + public: + static void ShowDialog(); + + protected: + DiagnosticsDialog(); + ~DiagnosticsDialog() override; + + DiagnosticsDialog(const DiagnosticsDialog&) = delete; + DiagnosticsDialog& operator=(const DiagnosticsDialog&) = delete; + + // SystemWebDialogDelegate + const std::string& Id() override; + + // ui::WebDialogDelegate + void GetDialogSize(gfx::Size* size) const override; + + private: + const std::string id_ = "diagnostics-dialog"; +}; +} // namespace chromeos + +#endif // CHROME_BROWSER_UI_WEBUI_CHROMEOS_DIAGNOSTICS_DIALOG_H_
diff --git a/chrome/browser/ui/webui/chromeos/emoji/emoji_dialog.cc b/chrome/browser/ui/webui/chromeos/emoji/emoji_dialog.cc index db99acd..1756539d 100644 --- a/chrome/browser/ui/webui/chromeos/emoji/emoji_dialog.cc +++ b/chrome/browser/ui/webui/chromeos/emoji/emoji_dialog.cc
@@ -12,25 +12,39 @@ #include "chrome/browser/ui/webui/constrained_web_dialog_ui.h" #include "chrome/common/url_constants.h" +#include "ui/aura/window.h" #include "ui/base/ime/chromeos/ime_bridge.h" namespace chromeos { +constexpr gfx::Size kDefaultWindowSize(340, 390); + ui::TextInputClient* EmojiPickerDialog::input_client = nullptr; gfx::Range EmojiPickerDialog::selection_range = gfx::Range(); EmojiPickerDialog::EmojiPickerDialog() { - ui::InputMethod* input_method = - ui::IMEBridge::Get()->GetInputContextHandler()->GetInputMethod(); - input_client = input_method->GetTextInputClient(); - input_client->GetEditableSelectionRange(&selection_range); - set_can_resize(false); } void EmojiPickerDialog::Show() { - chrome::ShowWebDialog(nullptr, ProfileManager::GetActiveUserProfile(), - new EmojiPickerDialog()); + ui::InputMethod* input_method = + ui::IMEBridge::Get()->GetInputContextHandler()->GetInputMethod(); + if (input_method) { + input_client = input_method->GetTextInputClient(); + } + if (input_client) { + input_client->GetEditableSelectionRange(&selection_range); + } + const auto caret_bounds = + input_client ? input_client->GetCaretBounds() : gfx::Rect(); + gfx::NativeWindow window = chrome::ShowWebDialog( + nullptr, ProfileManager::GetActiveUserProfile(), new EmojiPickerDialog()); + // For now, this can overflow the screen. + if (input_client) { + window->SetBounds(gfx::Rect(caret_bounds.x(), caret_bounds.bottom(), + kDefaultWindowSize.width(), + kDefaultWindowSize.height())); + } } ui::ModalType EmojiPickerDialog::GetDialogModalType() const { @@ -49,9 +63,7 @@ std::vector<content::WebUIMessageHandler*>* handlers) const {} void EmojiPickerDialog::GetDialogSize(gfx::Size* size) const { - const int kDefaultWidth = 340; - const int kDefaultHeight = 390; - size->SetSize(kDefaultWidth, kDefaultHeight); + *size = kDefaultWindowSize; } std::string EmojiPickerDialog::GetDialogArgs() const {
diff --git a/chrome/browser/ui/webui/chromeos/emulator/device_emulator_message_handler.cc b/chrome/browser/ui/webui/chromeos/emulator/device_emulator_message_handler.cc index 182656e..9cfbc6d7 100644 --- a/chrome/browser/ui/webui/chromeos/emulator/device_emulator_message_handler.cc +++ b/chrome/browser/ui/webui/chromeos/emulator/device_emulator_message_handler.cc
@@ -12,8 +12,8 @@ #include "base/macros.h" #include "base/strings/string_number_conversions.h" #include "base/values.h" -#include "chrome/browser/chromeos/system/fake_input_device_settings.h" -#include "chrome/browser/chromeos/system/input_device_settings.h" +#include "chrome/browser/ash/system/fake_input_device_settings.h" +#include "chrome/browser/ash/system/input_device_settings.h" #include "chrome/browser/ui/webui/chromeos/bluetooth_pairing_dialog.h" #include "chromeos/dbus/audio/fake_cras_audio_client.h" #include "chromeos/dbus/dbus_thread_manager.h"
diff --git a/chrome/browser/ui/webui/chromeos/emulator/device_emulator_message_handler.h b/chrome/browser/ui/webui/chromeos/emulator/device_emulator_message_handler.h index 4d99b15..e30f5b61 100644 --- a/chrome/browser/ui/webui/chromeos/emulator/device_emulator_message_handler.h +++ b/chrome/browser/ui/webui/chromeos/emulator/device_emulator_message_handler.h
@@ -10,7 +10,7 @@ #include "base/macros.h" #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" -#include "chrome/browser/chromeos/system/pointer_device_observer.h" +#include "chrome/browser/ash/system/pointer_device_observer.h" #include "chromeos/dbus/power_manager/power_supply_properties.pb.h" #include "content/public/browser/web_ui_message_handler.h" #include "device/bluetooth/bluetooth_adapter.h"
diff --git a/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc b/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc index 6faa3c4..da8302f1 100644 --- a/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc
@@ -18,6 +18,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/values.h" #include "build/branding_buildflags.h" +#include "chrome/browser/ash/system/input_device_settings.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process_platform_part.h" #include "chrome/browser/chromeos/login/configuration_keys.h" @@ -29,7 +30,6 @@ #include "chrome/browser/chromeos/login/ui/login_display_host.h" #include "chrome/browser/chromeos/login/ui/oobe_dialog_size_utils.h" #include "chrome/browser/chromeos/login/wizard_controller.h" -#include "chrome/browser/chromeos/system/input_device_settings.h" #include "chrome/browser/ui/ash/ash_util.h" #include "chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client.h" #include "chrome/browser/ui/webui/chromeos/login/demo_setup_screen_handler.h"
diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc index aa5ac9d..4a99cd4 100644 --- a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc +++ b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
@@ -23,6 +23,7 @@ #include "base/system/sys_info.h" #include "base/values.h" #include "build/branding_buildflags.h" +#include "chrome/browser/ash/system/input_device_settings.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process_platform_part.h" #include "chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen_view.h" @@ -35,7 +36,6 @@ #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" #include "chrome/browser/chromeos/policy/enrollment_requisition_manager.h" #include "chrome/browser/chromeos/settings/shutdown_policy_handler.h" -#include "chrome/browser/chromeos/system/input_device_settings.h" #include "chrome/browser/extensions/tab_helper.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_manager.h"
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc index 3fcc442..f8dcd561 100644 --- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
@@ -28,6 +28,7 @@ #include "base/threading/thread_task_runner_handle.h" #include "base/trace_event/trace_event.h" #include "chrome/browser/ash/app_mode/kiosk_app_manager.h" +#include "chrome/browser/ash/system/system_clock.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process_platform_part_chromeos.h" #include "chrome/browser/chrome_notification_types.h" @@ -52,7 +53,6 @@ #include "chrome/browser/chromeos/policy/device_local_account.h" #include "chrome/browser/chromeos/policy/minimum_version_policy_handler.h" #include "chrome/browser/chromeos/settings/cros_settings.h" -#include "chrome/browser/chromeos/system/system_clock.h" #include "chrome/browser/lifetime/browser_shutdown.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_metrics.h"
diff --git a/chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.cc index f152655..ae7e2ea 100644 --- a/chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.cc
@@ -17,12 +17,12 @@ #include "base/values.h" #include "chrome/browser/ash/accessibility/accessibility_manager.h" #include "chrome/browser/ash/accessibility/magnification_manager.h" +#include "chrome/browser/ash/system/input_device_settings.h" +#include "chrome/browser/ash/system/timezone_util.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/login/demo_mode/demo_session.h" #include "chrome/browser/chromeos/login/screens/welcome_screen.h" #include "chrome/browser/chromeos/login/ui/input_events_blocker.h" -#include "chrome/browser/chromeos/system/input_device_settings.h" -#include "chrome/browser/chromeos/system/timezone_util.h" #include "chrome/browser/ui/webui/chromeos/login/core_oobe_handler.h" #include "chrome/browser/ui/webui/chromeos/login/l10n_util.h" #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
diff --git a/chrome/browser/ui/webui/chromeos/set_time_ui.cc b/chrome/browser/ui/webui/chromeos/set_time_ui.cc index c638d99..4f84d47 100644 --- a/chrome/browser/ui/webui/chromeos/set_time_ui.cc +++ b/chrome/browser/ui/webui/chromeos/set_time_ui.cc
@@ -16,10 +16,10 @@ #include "base/macros.h" #include "base/scoped_observation.h" #include "base/values.h" +#include "chrome/browser/ash/system/timezone_util.h" #include "chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service.h" #include "chrome/browser/chromeos/set_time_dialog.h" #include "chrome/browser/chromeos/settings/cros_settings.h" -#include "chrome/browser/chromeos/system/timezone_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/webui/webui_util.h" #include "chrome/common/url_constants.h"
diff --git a/chrome/browser/ui/webui/supervised_user_internals_message_handler.cc b/chrome/browser/ui/webui/family_link_user_internals/family_link_user_internals_message_handler.cc similarity index 80% rename from chrome/browser/ui/webui/supervised_user_internals_message_handler.cc rename to chrome/browser/ui/webui/family_link_user_internals/family_link_user_internals_message_handler.cc index 6429fa4e..2f71cd82 100644 --- a/chrome/browser/ui/webui/supervised_user_internals_message_handler.cc +++ b/chrome/browser/ui/webui/family_link_user_internals/family_link_user_internals_message_handler.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/webui/supervised_user_internals_message_handler.h" +#include "chrome/browser/ui/webui/family_link_user_internals/family_link_user_internals_message_handler.h" #include <memory> #include <utility> @@ -35,7 +35,7 @@ namespace { -// Creates a 'section' for display on about:supervised-user-internals, +// Creates a 'section' for display on about:family-link-user-internals, // consisting of a title and a list of fields. Returns a pointer to the new // section's contents, for use with |AddSectionEntry| below. Note that // |parent_list|, not the caller, owns the newly added section. @@ -89,7 +89,8 @@ } std::string FilteringBehaviorToString( - SupervisedUserURLFilter::FilteringBehavior behavior, bool uncertain) { + SupervisedUserURLFilter::FilteringBehavior behavior, + bool uncertain) { std::string result = FilteringBehaviorToString(behavior); if (uncertain) result += " (Uncertain)"; @@ -118,63 +119,70 @@ } // namespace -SupervisedUserInternalsMessageHandler::SupervisedUserInternalsMessageHandler() = +FamilyLinkUserInternalsMessageHandler::FamilyLinkUserInternalsMessageHandler() = default; -SupervisedUserInternalsMessageHandler:: - ~SupervisedUserInternalsMessageHandler() = default; +FamilyLinkUserInternalsMessageHandler:: + ~FamilyLinkUserInternalsMessageHandler() = default; -void SupervisedUserInternalsMessageHandler::RegisterMessages() { +void FamilyLinkUserInternalsMessageHandler::RegisterMessages() { DCHECK_CURRENTLY_ON(BrowserThread::UI); web_ui()->RegisterMessageCallback( "registerForEvents", base::BindRepeating( - &SupervisedUserInternalsMessageHandler::HandleRegisterForEvents, + &FamilyLinkUserInternalsMessageHandler::HandleRegisterForEvents, base::Unretained(this))); web_ui()->RegisterMessageCallback( "getBasicInfo", base::BindRepeating( - &SupervisedUserInternalsMessageHandler::HandleGetBasicInfo, + &FamilyLinkUserInternalsMessageHandler::HandleGetBasicInfo, base::Unretained(this))); web_ui()->RegisterMessageCallback( "tryURL", - base::BindRepeating(&SupervisedUserInternalsMessageHandler::HandleTryURL, + base::BindRepeating(&FamilyLinkUserInternalsMessageHandler::HandleTryURL, base::Unretained(this))); } -void SupervisedUserInternalsMessageHandler::OnURLFilterChanged() { +void FamilyLinkUserInternalsMessageHandler::OnJavascriptDisallowed() { + scoped_observation_.Reset(); + weak_factory_.InvalidateWeakPtrs(); +} + +void FamilyLinkUserInternalsMessageHandler::OnURLFilterChanged() { SendBasicInfo(); } SupervisedUserService* -SupervisedUserInternalsMessageHandler::GetSupervisedUserService() { +FamilyLinkUserInternalsMessageHandler::GetSupervisedUserService() { Profile* profile = Profile::FromWebUI(web_ui()); return SupervisedUserServiceFactory::GetForProfile( profile->GetOriginalProfile()); } -void SupervisedUserInternalsMessageHandler::HandleRegisterForEvents( +void FamilyLinkUserInternalsMessageHandler::HandleRegisterForEvents( const base::ListValue* args) { DCHECK(args->empty()); + AllowJavascript(); if (scoped_observation_.IsObserving()) return; scoped_observation_.Observe(GetSupervisedUserService()->GetURLFilter()); } -void SupervisedUserInternalsMessageHandler::HandleGetBasicInfo( +void FamilyLinkUserInternalsMessageHandler::HandleGetBasicInfo( const base::ListValue* args) { SendBasicInfo(); } -void SupervisedUserInternalsMessageHandler::HandleTryURL( +void FamilyLinkUserInternalsMessageHandler::HandleTryURL( const base::ListValue* args) { - DCHECK_EQ(1u, args->GetSize()); + DCHECK_EQ(2u, args->GetSize()); + std::string callback_id; std::string url_str; - if (!args->GetString(0, &url_str)) + if (!args->GetString(0, &callback_id) || !args->GetString(1, &url_str)) return; GURL url = url_formatter::FixupURL(url_str, std::string()); @@ -195,12 +203,12 @@ filter->GetMatchingAllowlistTitles(url); filter->GetFilteringBehaviorForURLWithAsyncChecks( url, - base::BindOnce(&SupervisedUserInternalsMessageHandler::OnTryURLResult, - weak_factory_.GetWeakPtr(), allowlists), + base::BindOnce(&FamilyLinkUserInternalsMessageHandler::OnTryURLResult, + weak_factory_.GetWeakPtr(), allowlists, callback_id), skip_manual_parent_filter); } -void SupervisedUserInternalsMessageHandler::SendBasicInfo() { +void FamilyLinkUserInternalsMessageHandler::SendBasicInfo() { std::unique_ptr<base::ListValue> section_list(new base::ListValue); base::ListValue* section_general = AddSection(section_list.get(), "General"); @@ -219,9 +227,9 @@ AddSectionEntry(section_filter, "Denylist active", filter->HasDenylist()); AddSectionEntry(section_filter, "Online checks active", filter->HasAsyncURLChecker()); - AddSectionEntry(section_filter, "Default behavior", - FilteringBehaviorToString( - filter->GetDefaultFilteringBehavior())); + AddSectionEntry( + section_filter, "Default behavior", + FilteringBehaviorToString(filter->GetDefaultFilteringBehavior())); signin::IdentityManager* identity_manager = IdentityManagerFactory::GetForProfile(profile); @@ -230,8 +238,8 @@ for (const auto& account : identity_manager ->GetExtendedAccountInfoForAccountsWithRefreshToken()) { - base::ListValue* section_user = AddSection(section_list.get(), - "User Information for " + account.full_name); + base::ListValue* section_user = AddSection( + section_list.get(), "User Information for " + account.full_name); AddSectionEntry(section_user, "Account id", account.account_id.ToString()); AddSectionEntry(section_user, "Gaia", account.gaia); @@ -246,27 +254,27 @@ base::DictionaryValue result; result.Set("sections", std::move(section_list)); - web_ui()->CallJavascriptFunctionUnsafe( - "chrome.supervised_user_internals.receiveBasicInfo", result); + FireWebUIListener("basic-info-received", result); // Trigger retrieval of the user settings SupervisedUserSettingsService* settings_service = SupervisedUserSettingsServiceFactory::GetForKey(profile->GetProfileKey()); user_settings_subscription_ = settings_service->SubscribeForSettingsChange(base::BindRepeating( - &SupervisedUserInternalsMessageHandler::SendSupervisedUserSettings, + &FamilyLinkUserInternalsMessageHandler::SendFamilyLinkUserSettings, weak_factory_.GetWeakPtr())); } -void SupervisedUserInternalsMessageHandler::SendSupervisedUserSettings( +void FamilyLinkUserInternalsMessageHandler::SendFamilyLinkUserSettings( const base::DictionaryValue* settings) { - web_ui()->CallJavascriptFunctionUnsafe( - "chrome.supervised_user_internals.receiveUserSettings", + FireWebUIListener( + "user-settings-received", *(settings ? settings : std::make_unique<base::Value>().get())); } -void SupervisedUserInternalsMessageHandler::OnTryURLResult( +void FamilyLinkUserInternalsMessageHandler::OnTryURLResult( const std::map<std::string, base::string16>& allowlists, + const std::string& callback_id, SupervisedUserURLFilter::FilteringBehavior behavior, supervised_user_error_page::FilteringBehaviorReason reason, bool uncertain) { @@ -283,13 +291,12 @@ result.SetBoolean("manual", reason == supervised_user_error_page::MANUAL && behavior == SupervisedUserURLFilter::ALLOW); result.SetString("allowlists", allowlists_str); - web_ui()->CallJavascriptFunctionUnsafe( - "chrome.supervised_user_internals.receiveTryURLResult", result); + ResolveJavascriptCallback(base::Value(callback_id), result); } -void SupervisedUserInternalsMessageHandler::OnSiteListUpdated() {} +void FamilyLinkUserInternalsMessageHandler::OnSiteListUpdated() {} -void SupervisedUserInternalsMessageHandler::OnURLChecked( +void FamilyLinkUserInternalsMessageHandler::OnURLChecked( const GURL& url, SupervisedUserURLFilter::FilteringBehavior behavior, supervised_user_error_page::FilteringBehaviorReason reason, @@ -299,6 +306,5 @@ result.SetString("url", url.possibly_invalid_spec()); result.SetString("result", FilteringBehaviorToString(behavior, uncertain)); result.SetString("reason", FilteringBehaviorReasonToString(reason)); - web_ui()->CallJavascriptFunctionUnsafe( - "chrome.supervised_user_internals.receiveFilteringResult", result); + FireWebUIListener("filtering-result-received", result); }
diff --git a/chrome/browser/ui/webui/supervised_user_internals_message_handler.h b/chrome/browser/ui/webui/family_link_user_internals/family_link_user_internals_message_handler.h similarity index 71% rename from chrome/browser/ui/webui/supervised_user_internals_message_handler.h rename to chrome/browser/ui/webui/family_link_user_internals/family_link_user_internals_message_handler.h index 40a96712..b21f6c8 100644 --- a/chrome/browser/ui/webui/supervised_user_internals_message_handler.h +++ b/chrome/browser/ui/webui/family_link_user_internals/family_link_user_internals_message_handler.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_WEBUI_SUPERVISED_USER_INTERNALS_MESSAGE_HANDLER_H_ -#define CHROME_BROWSER_UI_WEBUI_SUPERVISED_USER_INTERNALS_MESSAGE_HANDLER_H_ +#ifndef CHROME_BROWSER_UI_WEBUI_FAMILY_LINK_USER_INTERNALS_FAMILY_LINK_USER_INTERNALS_MESSAGE_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_FAMILY_LINK_USER_INTERNALS_FAMILY_LINK_USER_INTERNALS_MESSAGE_HANDLER_H_ #include "base/callback_list.h" #include "base/macros.h" @@ -19,18 +19,19 @@ class ListValue; } // namespace base -// The implementation for the chrome://supervised-user-internals page. -class SupervisedUserInternalsMessageHandler +// The implementation for the chrome://family-link-user-internals page. +class FamilyLinkUserInternalsMessageHandler : public content::WebUIMessageHandler, public SupervisedUserServiceObserver, public SupervisedUserURLFilter::Observer { public: - SupervisedUserInternalsMessageHandler(); - ~SupervisedUserInternalsMessageHandler() override; + FamilyLinkUserInternalsMessageHandler(); + ~FamilyLinkUserInternalsMessageHandler() override; private: // content::WebUIMessageHandler: void RegisterMessages() override; + void OnJavascriptDisallowed() override; // SupervisedUserServiceObserver: void OnURLFilterChanged() override; @@ -42,10 +43,11 @@ void HandleTryURL(const base::ListValue* args); void SendBasicInfo(); - void SendSupervisedUserSettings(const base::DictionaryValue* settings); + void SendFamilyLinkUserSettings(const base::DictionaryValue* settings); void OnTryURLResult( const std::map<std::string, base::string16>& allowlists, + const std::string& callback_id, SupervisedUserURLFilter::FilteringBehavior behavior, supervised_user_error_page::FilteringBehaviorReason reason, bool uncertain); @@ -63,10 +65,10 @@ SupervisedUserURLFilter::Observer> scoped_observation_{this}; - base::WeakPtrFactory<SupervisedUserInternalsMessageHandler> weak_factory_{ + base::WeakPtrFactory<FamilyLinkUserInternalsMessageHandler> weak_factory_{ this}; - DISALLOW_COPY_AND_ASSIGN(SupervisedUserInternalsMessageHandler); + DISALLOW_COPY_AND_ASSIGN(FamilyLinkUserInternalsMessageHandler); }; -#endif // CHROME_BROWSER_UI_WEBUI_SUPERVISED_USER_INTERNALS_MESSAGE_HANDLER_H_ +#endif // CHROME_BROWSER_UI_WEBUI_FAMILY_LINK_USER_INTERNALS_FAMILY_LINK_USER_INTERNALS_MESSAGE_HANDLER_H_
diff --git a/chrome/browser/ui/webui/family_link_user_internals/family_link_user_internals_ui.cc b/chrome/browser/ui/webui/family_link_user_internals/family_link_user_internals_ui.cc new file mode 100644 index 0000000..92b5d0a1 --- /dev/null +++ b/chrome/browser/ui/webui/family_link_user_internals/family_link_user_internals_ui.cc
@@ -0,0 +1,49 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/webui/family_link_user_internals/family_link_user_internals_ui.h" + +#include <memory> + +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/webui/family_link_user_internals/family_link_user_internals_message_handler.h" +#include "chrome/common/url_constants.h" +#include "chrome/grit/dev_ui_browser_resources.h" +#include "content/public/browser/web_ui.h" +#include "content/public/browser/web_ui_data_source.h" +#include "services/network/public/mojom/content_security_policy.mojom.h" + +namespace { + +content::WebUIDataSource* CreateFamilyLinkUserInternalsHTMLSource() { + content::WebUIDataSource* source = content::WebUIDataSource::Create( + chrome::kChromeUIFamilyLinkUserInternalsHost); + source->OverrideContentSecurityPolicy( + network::mojom::CSPDirectiveName::ScriptSrc, + "script-src chrome://resources 'self' 'unsafe-eval';"); + source->OverrideContentSecurityPolicy( + network::mojom::CSPDirectiveName::TrustedTypes, + "trusted-types jstemplate;"); + + source->AddResourcePath("family_link_user_internals.js", + IDR_FAMILY_LINK_USER_INTERNALS_JS); + source->AddResourcePath("family_link_user_internals.css", + IDR_FAMILY_LINK_USER_INTERNALS_CSS); + source->SetDefaultResource(IDR_FAMILY_LINK_USER_INTERNALS_HTML); + return source; +} + +} // namespace + +FamilyLinkUserInternalsUI::FamilyLinkUserInternalsUI(content::WebUI* web_ui) + : WebUIController(web_ui) { + Profile* profile = Profile::FromWebUI(web_ui); + content::WebUIDataSource::Add(profile, + CreateFamilyLinkUserInternalsHTMLSource()); + + web_ui->AddMessageHandler( + std::make_unique<FamilyLinkUserInternalsMessageHandler>()); +} + +FamilyLinkUserInternalsUI::~FamilyLinkUserInternalsUI() {}
diff --git a/chrome/browser/ui/webui/family_link_user_internals/family_link_user_internals_ui.h b/chrome/browser/ui/webui/family_link_user_internals/family_link_user_internals_ui.h new file mode 100644 index 0000000..0a129dfb --- /dev/null +++ b/chrome/browser/ui/webui/family_link_user_internals/family_link_user_internals_ui.h
@@ -0,0 +1,21 @@ +// 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. + +#ifndef CHROME_BROWSER_UI_WEBUI_FAMILY_LINK_USER_INTERNALS_FAMILY_LINK_USER_INTERNALS_UI_H_ +#define CHROME_BROWSER_UI_WEBUI_FAMILY_LINK_USER_INTERNALS_FAMILY_LINK_USER_INTERNALS_UI_H_ + +#include "base/macros.h" +#include "content/public/browser/web_ui_controller.h" + +// The implementation for the chrome://family-link-user-internals page. +class FamilyLinkUserInternalsUI : public content::WebUIController { + public: + explicit FamilyLinkUserInternalsUI(content::WebUI* web_ui); + ~FamilyLinkUserInternalsUI() override; + + private: + DISALLOW_COPY_AND_ASSIGN(FamilyLinkUserInternalsUI); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_FAMILY_LINK_USER_INTERNALS_FAMILY_LINK_USER_INTERNALS_UI_H_
diff --git a/chrome/browser/ui/webui/settings/chromeos/about_section.cc b/chrome/browser/ui/webui/settings/chromeos/about_section.cc index ec99cb4..8a8384d 100644 --- a/chrome/browser/ui/webui/settings/chromeos/about_section.cc +++ b/chrome/browser/ui/webui/settings/chromeos/about_section.cc
@@ -105,7 +105,10 @@ mojom::SearchResultDefaultRank::kMedium, mojom::SearchResultType::kSetting, {.setting = mojom::Setting::kDiagnostics}, - {IDS_OS_SETTINGS_TAG_ABOUT_DIAGNOSTICS_ALT1, SearchConcept::kAltTagEnd}}, + {IDS_OS_SETTINGS_TAG_ABOUT_DIAGNOSTICS_ALT1, + IDS_OS_SETTINGS_TAG_ABOUT_DIAGNOSTICS_ALT2, + IDS_OS_SETTINGS_TAG_ABOUT_DIAGNOSTICS_ALT3, + IDS_OS_SETTINGS_TAG_ABOUT_DIAGNOSTICS_ALT4, SearchConcept::kAltTagEnd}}, }); return *tags; }
diff --git a/chrome/browser/ui/webui/settings/chromeos/date_time_handler.cc b/chrome/browser/ui/webui/settings/chromeos/date_time_handler.cc index b9b9eb4..1c5867a6 100644 --- a/chrome/browser/ui/webui/settings/chromeos/date_time_handler.cc +++ b/chrome/browser/ui/webui/settings/chromeos/date_time_handler.cc
@@ -11,12 +11,12 @@ #include "base/command_line.h" #include "base/time/time.h" #include "base/values.h" +#include "chrome/browser/ash/system/timezone_resolver_manager.h" +#include "chrome/browser/ash/system/timezone_util.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process_platform_part.h" #include "chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service.h" #include "chrome/browser/chromeos/set_time_dialog.h" -#include "chrome/browser/chromeos/system/timezone_resolver_manager.h" -#include "chrome/browser/chromeos/system/timezone_util.h" #include "chrome/common/pref_names.h" #include "chromeos/dbus/system_clock/system_clock_client.h" #include "chromeos/settings/timezone_settings.h"
diff --git a/chrome/browser/ui/webui/settings/chromeos/date_time_section.cc b/chrome/browser/ui/webui/settings/chromeos/date_time_section.cc index 37705412..37af30c4 100644 --- a/chrome/browser/ui/webui/settings/chromeos/date_time_section.cc +++ b/chrome/browser/ui/webui/settings/chromeos/date_time_section.cc
@@ -7,8 +7,8 @@ #include "base/no_destructor.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" +#include "chrome/browser/ash/system/timezone_util.h" #include "chrome/browser/browser_process.h" -#include "chrome/browser/chromeos/system/timezone_util.h" #include "chrome/browser/ui/webui/settings/chromeos/date_time_handler.h" #include "chrome/browser/ui/webui/settings/chromeos/search/search_tag_registry.h" #include "chrome/browser/ui/webui/webui_util.h"
diff --git a/chrome/browser/ui/webui/settings/chromeos/device_pointer_handler.h b/chrome/browser/ui/webui/settings/chromeos/device_pointer_handler.h index adc1b28..676b25c 100644 --- a/chrome/browser/ui/webui/settings/chromeos/device_pointer_handler.h +++ b/chrome/browser/ui/webui/settings/chromeos/device_pointer_handler.h
@@ -8,7 +8,7 @@ #include <memory> #include "base/macros.h" -#include "chrome/browser/chromeos/system/pointer_device_observer.h" +#include "chrome/browser/ash/system/pointer_device_observer.h" #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h" namespace base {
diff --git a/chrome/browser/ui/webui/settings/chromeos/device_section.h b/chrome/browser/ui/webui/settings/chromeos/device_section.h index 47bae70..7f05679 100644 --- a/chrome/browser/ui/webui/settings/chromeos/device_section.h +++ b/chrome/browser/ui/webui/settings/chromeos/device_section.h
@@ -12,7 +12,7 @@ #include "base/memory/weak_ptr.h" #include "base/optional.h" #include "base/values.h" -#include "chrome/browser/chromeos/system/pointer_device_observer.h" +#include "chrome/browser/ash/system/pointer_device_observer.h" #include "chrome/browser/ui/webui/settings/chromeos/os_settings_section.h" #include "chromeos/dbus/power/power_manager_client.h" #include "mojo/public/cpp/bindings/associated_receiver.h"
diff --git a/chrome/browser/ui/webui/settings/chromeos/parental_controls_handler.cc b/chrome/browser/ui/webui/settings/chromeos/parental_controls_handler.cc index 5a3624c..70f09dd7 100644 --- a/chrome/browser/ui/webui/settings/chromeos/parental_controls_handler.cc +++ b/chrome/browser/ui/webui/settings/chromeos/parental_controls_handler.cc
@@ -9,6 +9,7 @@ #include "base/values.h" #include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" +#include "chrome/browser/apps/app_service/launch_utils.h" #include "chrome/browser/chromeos/child_accounts/child_user_service.h" #include "chrome/browser/ui/app_list/arc/arc_app_utils.h" #include "chrome/browser/ui/browser_navigator.h" @@ -71,7 +72,7 @@ // Launch FLH app since it is available. proxy->Launch(app_id, ui::EventFlags::EF_NONE, apps::mojom::LaunchSource::kFromParentalControls, - display::kDefaultDisplayId); + apps::MakeWindowInfo(display::kDefaultDisplayId)); return; } // No FLH app installed, so try to launch Play Store to FLH app install page.
diff --git a/chrome/browser/ui/webui/settings/chromeos/personalization_section.cc b/chrome/browser/ui/webui/settings/chromeos/personalization_section.cc index 1c0359a..94f0e039 100644 --- a/chrome/browser/ui/webui/settings/chromeos/personalization_section.cc +++ b/chrome/browser/ui/webui/settings/chromeos/personalization_section.cc
@@ -256,6 +256,8 @@ IDS_SETTINGS_PHOTO_DISCARD_ACCESSIBLE_TEXT}, {"photoModeAccessibleText", IDS_SETTINGS_PHOTO_MODE_ACCESSIBLE_TEXT}, {"videoModeAccessibleText", IDS_SETTINGS_VIDEO_MODE_ACCESSIBLE_TEXT}, + // TODO(b/178399962) finalize error string for WallpaperWebUI. + {"wallpaperCollectionsError", IDS_WALLPAPER_MANAGER_NETWORK_ERROR}, }; html_source->AddLocalizedStrings(kLocalizedStrings);
diff --git a/chrome/browser/ui/webui/settings/chromeos/wallpaper_handler.cc b/chrome/browser/ui/webui/settings/chromeos/wallpaper_handler.cc index 60153b0..a1f17aa 100644 --- a/chrome/browser/ui/webui/settings/chromeos/wallpaper_handler.cc +++ b/chrome/browser/ui/webui/settings/chromeos/wallpaper_handler.cc
@@ -5,6 +5,8 @@ #include "chrome/browser/ui/webui/settings/chromeos/wallpaper_handler.h" #include "base/bind.h" +#include "chrome/browser/chromeos/backdrop_wallpaper_handlers/backdrop_wallpaper.pb.h" +#include "chrome/browser/chromeos/backdrop_wallpaper_handlers/backdrop_wallpaper_handlers.h" #include "chrome/browser/ui/ash/wallpaper_controller_client.h" #include "content/public/browser/web_ui.h" @@ -33,6 +35,11 @@ "isWallpaperPolicyControlled", base::BindRepeating(&WallpaperHandler::HandleIsWallpaperPolicyControlled, base::Unretained(this))); + + web_ui()->RegisterMessageCallback( + "fetchWallpaperCollections", + base::BindRepeating(&WallpaperHandler::HandleFetchWallpaperCollections, + base::Unretained(this))); } void WallpaperHandler::HandleIsWallpaperSettingVisible( @@ -55,6 +62,36 @@ WallpaperControllerClient::Get()->OpenWallpaperPickerIfAllowed(); } +void WallpaperHandler::HandleFetchWallpaperCollections( + const base::ListValue* args) { + CHECK_EQ(args->GetSize(), 1U); + DCHECK(IsJavascriptAllowed()) << "Page should already be initialized"; + backdrop_api_weak_factory_.InvalidateWeakPtrs(); + collection_info_fetcher_.Start( + base::BindOnce(&WallpaperHandler::OnFetchWallpaperCollections, + backdrop_api_weak_factory_.GetWeakPtr(), + args->GetList().front().Clone())); +} + +void WallpaperHandler::OnFetchWallpaperCollections( + const base::Value& callback_id, + bool success, + const std::vector<backdrop::Collection>& collections) { + if (!success || collections.empty()) { + RejectJavascriptCallback(callback_id, base::Value(base::Value::Type::NONE)); + return; + } + + base::Value result(base::Value::Type::LIST); + for (const auto& collection : collections) { + base::Value item(base::Value::Type::DICTIONARY); + item.SetKey("id", base::Value(collection.collection_id())); + item.SetKey("name", base::Value(collection.collection_name())); + result.Append(std::move(item)); + } + ResolveJavascriptCallback(callback_id, result); +} + void WallpaperHandler::ResolveCallback(const base::Value& callback_id, bool result) { AllowJavascript();
diff --git a/chrome/browser/ui/webui/settings/chromeos/wallpaper_handler.h b/chrome/browser/ui/webui/settings/chromeos/wallpaper_handler.h index 90fa8c6c..645671d0 100644 --- a/chrome/browser/ui/webui/settings/chromeos/wallpaper_handler.h +++ b/chrome/browser/ui/webui/settings/chromeos/wallpaper_handler.h
@@ -6,11 +6,17 @@ #define CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_WALLPAPER_HANDLER_H_ #include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "chrome/browser/chromeos/backdrop_wallpaper_handlers/backdrop_wallpaper_handlers.h" #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h" +namespace backdrop { +class Collection; +} // namespace backdrop + namespace base { class ListValue; -} +} // namespace base namespace chromeos { namespace settings { @@ -36,9 +42,21 @@ // Open the wallpaper manager app. void HandleOpenWallpaperManager(const base::ListValue* args); + // Begin to fetch wallpaper collection info. + void HandleFetchWallpaperCollections(const base::ListValue* args); + + void OnFetchWallpaperCollections( + const base::Value& callback_id, + bool success, + const std::vector<backdrop::Collection>& collections); + // Helper function to resolve the Javascript callback. void ResolveCallback(const base::Value& callback_id, bool result); + backdrop_wallpaper_handlers::CollectionInfoFetcher collection_info_fetcher_; + + base::WeakPtrFactory<WallpaperHandler> backdrop_api_weak_factory_{this}; + DISALLOW_COPY_AND_ASSIGN(WallpaperHandler); };
diff --git a/chrome/browser/ui/webui/supervised_user_internals_ui.cc b/chrome/browser/ui/webui/supervised_user_internals_ui.cc deleted file mode 100644 index 2102059..0000000 --- a/chrome/browser/ui/webui/supervised_user_internals_ui.cc +++ /dev/null
@@ -1,49 +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. - -#include "chrome/browser/ui/webui/supervised_user_internals_ui.h" - -#include <memory> - -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/webui/supervised_user_internals_message_handler.h" -#include "chrome/common/url_constants.h" -#include "chrome/grit/dev_ui_browser_resources.h" -#include "content/public/browser/web_ui.h" -#include "content/public/browser/web_ui_data_source.h" -#include "services/network/public/mojom/content_security_policy.mojom.h" - -namespace { - -content::WebUIDataSource* CreateSupervisedUserInternalsHTMLSource() { - content::WebUIDataSource* source = content::WebUIDataSource::Create( - chrome::kChromeUISupervisedUserInternalsHost); - source->OverrideContentSecurityPolicy( - network::mojom::CSPDirectiveName::ScriptSrc, - "script-src chrome://resources 'self' 'unsafe-eval';"); - source->OverrideContentSecurityPolicy( - network::mojom::CSPDirectiveName::TrustedTypes, - "trusted-types jstemplate;"); - - source->AddResourcePath("supervised_user_internals.js", - IDR_SUPERVISED_USER_INTERNALS_JS); - source->AddResourcePath("supervised_user_internals.css", - IDR_SUPERVISED_USER_INTERNALS_CSS); - source->SetDefaultResource(IDR_SUPERVISED_USER_INTERNALS_HTML); - return source; -} - -} // namespace - -SupervisedUserInternalsUI::SupervisedUserInternalsUI(content::WebUI* web_ui) - : WebUIController(web_ui) { - Profile* profile = Profile::FromWebUI(web_ui); - content::WebUIDataSource::Add(profile, - CreateSupervisedUserInternalsHTMLSource()); - - web_ui->AddMessageHandler( - std::make_unique<SupervisedUserInternalsMessageHandler>()); -} - -SupervisedUserInternalsUI::~SupervisedUserInternalsUI() {}
diff --git a/chrome/browser/ui/webui/supervised_user_internals_ui.h b/chrome/browser/ui/webui/supervised_user_internals_ui.h deleted file mode 100644 index ff12e93..0000000 --- a/chrome/browser/ui/webui/supervised_user_internals_ui.h +++ /dev/null
@@ -1,21 +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. - -#ifndef CHROME_BROWSER_UI_WEBUI_SUPERVISED_USER_INTERNALS_UI_H_ -#define CHROME_BROWSER_UI_WEBUI_SUPERVISED_USER_INTERNALS_UI_H_ - -#include "base/macros.h" -#include "content/public/browser/web_ui_controller.h" - -// The implementation for the chrome://supervised-user-internals page. -class SupervisedUserInternalsUI : public content::WebUIController { - public: - explicit SupervisedUserInternalsUI(content::WebUI* web_ui); - ~SupervisedUserInternalsUI() override; - - private: - DISALLOW_COPY_AND_ASSIGN(SupervisedUserInternalsUI); -}; - -#endif // CHROME_BROWSER_UI_WEBUI_SUPERVISED_USER_INTERNALS_UI_H_
diff --git a/chrome/browser/web_applications/components/external_install_options.cc b/chrome/browser/web_applications/components/external_install_options.cc index 833d7b5..81d823c 100644 --- a/chrome/browser/web_applications/components/external_install_options.cc +++ b/chrome/browser/web_applications/components/external_install_options.cc
@@ -10,6 +10,7 @@ #include <vector> #include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/web_applications/components/system_web_app_types.h" @@ -43,6 +44,7 @@ options.install_url, options.user_display_mode, options.install_source, + options.fallback_app_name, options.add_to_applications_menu, options.add_to_desktop, options.add_to_quick_launch_bar, @@ -110,6 +112,8 @@ << "\n user_display_mode: " << install_options.user_display_mode << "\n install_source: " << static_cast<int32_t>(install_options.install_source) + << "\n fallback_app_name: " + << install_options.fallback_app_name.value_or("") << "\n add_to_applications_menu: " << install_options.add_to_applications_menu << "\n add_to_desktop: " << install_options.add_to_desktop @@ -165,6 +169,11 @@ params.user_display_mode = install_options.user_display_mode; + if (install_options.fallback_app_name.has_value()) { + params.fallback_app_name = + base::UTF8ToUTF16(install_options.fallback_app_name.value()); + } + params.fallback_start_url = install_options.install_url; params.add_to_applications_menu = install_options.add_to_applications_menu;
diff --git a/chrome/browser/web_applications/components/external_install_options.h b/chrome/browser/web_applications/components/external_install_options.h index 836b0f9..a87c03b 100644 --- a/chrome/browser/web_applications/components/external_install_options.h +++ b/chrome/browser/web_applications/components/external_install_options.h
@@ -39,6 +39,10 @@ DisplayMode user_display_mode; ExternalInstallSource install_source; + // App name to use for placeholder apps or web apps that have no name in + // their manifest. + base::Optional<std::string> fallback_app_name; + // If true, a shortcut is added to the Applications folder on macOS, and Start // Menu on Linux and Windows and launcher on Chrome OS. If false, we skip // adding a shortcut to desktop as well, regardless of the value of @@ -123,7 +127,7 @@ // metadata for the app. A placeholder app uses: // - The default Chrome App icon for the icon // - |url| as the start_url - // - |url| as the app name + // - |url| as the app name (unless fallback_app_name has been specified) bool install_placeholder = false; // Whether we should try to reinstall the app if there is a placeholder for
diff --git a/chrome/browser/web_applications/components/install_finalizer_unittest.cc b/chrome/browser/web_applications/components/install_finalizer_unittest.cc index 1139051..6198c720 100644 --- a/chrome/browser/web_applications/components/install_finalizer_unittest.cc +++ b/chrome/browser/web_applications/components/install_finalizer_unittest.cc
@@ -11,6 +11,7 @@ #include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" #include "base/test/bind.h" +#include "chrome/browser/web_applications/components/web_app_helpers.h" #include "chrome/browser/web_applications/components/web_app_prefs_utils.h" #include "chrome/browser/web_applications/components/web_application_info.h" #include "chrome/browser/web_applications/test/test_file_utils.h" @@ -112,7 +113,60 @@ FinalizeInstallResult result = AwaitFinalizeInstall(*info, options); EXPECT_EQ(InstallResultCode::kSuccessNewInstall, result.code); - EXPECT_FALSE(result.installed_app_id.empty()); + EXPECT_EQ(result.installed_app_id, + web_app::GenerateAppIdFromURL(info->start_url)); +} + +TEST_F(InstallFinalizerUnitTest, ConcurrentInstallSucceeds) { + auto info1 = std::make_unique<WebApplicationInfo>(); + info1->start_url = GURL("https://foo1.example"); + info1->title = base::ASCIIToUTF16("Foo1 Title"); + + auto info2 = std::make_unique<WebApplicationInfo>(); + info2->start_url = GURL("https://foo2.example"); + info2->title = base::ASCIIToUTF16("Foo2 Title"); + + InstallFinalizer::FinalizeOptions options; + options.install_source = webapps::WebappInstallSource::INTERNAL_DEFAULT; + + base::RunLoop run_loop; + bool callback1_called = false; + bool callback2_called = false; + + // Start install finalization for the 1st app. + { + finalizer().FinalizeInstall( + *info1, options, + base::BindLambdaForTesting([&](const web_app::AppId& installed_app_id, + web_app::InstallResultCode code) { + EXPECT_EQ(web_app::InstallResultCode::kSuccessNewInstall, code); + EXPECT_EQ(installed_app_id, + web_app::GenerateAppIdFromURL(info1->start_url)); + callback1_called = true; + if (callback2_called) + run_loop.Quit(); + })); + } + + // Start install finalization for the 2nd app. + { + finalizer().FinalizeInstall( + *info2, options, + base::BindLambdaForTesting([&](const web_app::AppId& installed_app_id, + web_app::InstallResultCode code) { + EXPECT_EQ(web_app::InstallResultCode::kSuccessNewInstall, code); + EXPECT_EQ(installed_app_id, + web_app::GenerateAppIdFromURL(info2->start_url)); + callback2_called = true; + if (callback1_called) + run_loop.Quit(); + })); + } + + run_loop.Run(); + + EXPECT_TRUE(callback1_called); + EXPECT_TRUE(callback2_called); } TEST_F(InstallFinalizerUnitTest, InstallStoresLatestWebAppInstallSource) {
diff --git a/chrome/browser/web_applications/components/policy/web_app_policy_constants.cc b/chrome/browser/web_applications/components/policy/web_app_policy_constants.cc index 40189a0a..ce72c39 100644 --- a/chrome/browser/web_applications/components/policy/web_app_policy_constants.cc +++ b/chrome/browser/web_applications/components/policy/web_app_policy_constants.cc
@@ -10,7 +10,8 @@ const char kDefaultLaunchContainerKey[] = "default_launch_container"; const char kDefaultLaunchContainerWindowValue[] = "window"; const char kDefaultLaunchContainerTabValue[] = "tab"; -const char kCreateDesktopShorcutKey[] = "create_desktop_shortcut"; +const char kCreateDesktopShortcutKey[] = "create_desktop_shortcut"; +const char kFallbackAppNameKey[] = "fallback_app_name"; const char kWildcard[] = "*";
diff --git a/chrome/browser/web_applications/components/policy/web_app_policy_constants.h b/chrome/browser/web_applications/components/policy/web_app_policy_constants.h index 4673c1e..4e0de4d 100644 --- a/chrome/browser/web_applications/components/policy/web_app_policy_constants.h +++ b/chrome/browser/web_applications/components/policy/web_app_policy_constants.h
@@ -12,7 +12,8 @@ extern const char kDefaultLaunchContainerKey[]; extern const char kDefaultLaunchContainerWindowValue[]; extern const char kDefaultLaunchContainerTabValue[]; -extern const char kCreateDesktopShorcutKey[]; +extern const char kCreateDesktopShortcutKey[]; +extern const char kFallbackAppNameKey[]; extern const char kWildcard[];
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer_unittest.cc b/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer_unittest.cc index 4fc9aa7..e4e13cb 100644 --- a/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer_unittest.cc +++ b/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer_unittest.cc
@@ -55,6 +55,8 @@ // Do not add tests to this class. Instead, add tests to // |InstallFinalizerUnitTest| so that both |InstallFinalizer| implementations // are tested. +// TODO(crbug.com/1068081): Migrate remaining tests to +// install_finalizer_unittest. class BookmarkAppInstallFinalizerTest : public ChromeRenderViewHostTestHarness { public: // Subclass that runs a closure when an extension is unpacked successfully. @@ -217,57 +219,6 @@ EXPECT_TRUE(callback_called); } -TEST_F(BookmarkAppInstallFinalizerTest, ConcurrentInstallSucceeds) { - base::RunLoop run_loop; - - const GURL url1("https://foo1.example"); - const GURL url2("https://foo2.example"); - - bool callback1_called = false; - bool callback2_called = false; - web_app::InstallFinalizer::FinalizeOptions options; - options.install_source = webapps::WebappInstallSource::INTERNAL_DEFAULT; - - // Start install finalization for the 1st app - { - WebApplicationInfo web_application_info; - web_application_info.start_url = url1; - - finalizer().FinalizeInstall( - web_application_info, options, - base::BindLambdaForTesting([&](const web_app::AppId& installed_app_id, - web_app::InstallResultCode code) { - EXPECT_EQ(web_app::InstallResultCode::kSuccessNewInstall, code); - EXPECT_EQ(installed_app_id, web_app::GenerateAppIdFromURL(url1)); - callback1_called = true; - if (callback2_called) - run_loop.Quit(); - })); - } - - // Start install finalization for the 2nd app - { - WebApplicationInfo web_application_info; - web_application_info.start_url = url2; - - finalizer().FinalizeInstall( - web_application_info, options, - base::BindLambdaForTesting([&](const web_app::AppId& installed_app_id, - web_app::InstallResultCode code) { - EXPECT_EQ(web_app::InstallResultCode::kSuccessNewInstall, code); - EXPECT_EQ(installed_app_id, web_app::GenerateAppIdFromURL(url2)); - callback2_called = true; - if (callback1_called) - run_loop.Quit(); - })); - } - - run_loop.Run(); - - EXPECT_TRUE(callback1_called); - EXPECT_TRUE(callback2_called); -} - TEST_F(BookmarkAppInstallFinalizerTest, DefaultInstalledSucceeds) { auto info = std::make_unique<WebApplicationInfo>(); info->start_url = WebAppUrl();
diff --git a/chrome/browser/web_applications/extensions/web_app_policy_manager_unittest.cc b/chrome/browser/web_applications/extensions/web_app_policy_manager_unittest.cc index d4f32f7..30c31ae 100644 --- a/chrome/browser/web_applications/extensions/web_app_policy_manager_unittest.cc +++ b/chrome/browser/web_applications/extensions/web_app_policy_manager_unittest.cc
@@ -64,6 +64,8 @@ } })"; +const char kDefaultFallbackAppName[] = "fallback app name"; + // TODO(https://crbug.com/1042727): Fix test GURL scoping and remove this getter // function. GURL WindowedUrl() { @@ -134,13 +136,13 @@ return options; } -base::Value GetCreateDesktopShorcutDefaultItem() { +base::Value GetCreateDesktopShortcutDefaultItem() { base::Value item(base::Value::Type::DICTIONARY); item.SetKey(kUrlKey, base::Value(NoContainerUrl().spec())); return item; } -ExternalInstallOptions GetCreateDesktopShorcutDefaultInstallOptions() { +ExternalInstallOptions GetCreateDesktopShortcutDefaultInstallOptions() { ExternalInstallOptions options(NoContainerUrl(), DisplayMode::kBrowser, ExternalInstallSource::kExternalPolicy); options.add_to_applications_menu = true; @@ -152,14 +154,14 @@ return options; } -base::Value GetCreateDesktopShorcutFalseItem() { +base::Value GetCreateDesktopShortcutFalseItem() { base::Value item(base::Value::Type::DICTIONARY); item.SetKey(kUrlKey, base::Value(NoContainerUrl().spec())); - item.SetKey(kCreateDesktopShorcutKey, base::Value(false)); + item.SetKey(kCreateDesktopShortcutKey, base::Value(false)); return item; } -ExternalInstallOptions GetCreateDesktopShorcutFalseInstallOptions() { +ExternalInstallOptions GetCreateDesktopShortcutFalseInstallOptions() { ExternalInstallOptions options(NoContainerUrl(), DisplayMode::kBrowser, ExternalInstallSource::kExternalPolicy); options.add_to_applications_menu = true; @@ -171,14 +173,14 @@ return options; } -base::Value GetCreateDesktopShorcutTrueItem() { +base::Value GetCreateDesktopShortcutTrueItem() { base::Value item(base::Value::Type::DICTIONARY); item.SetKey(kUrlKey, base::Value(NoContainerUrl().spec())); - item.SetKey(kCreateDesktopShorcutKey, base::Value(true)); + item.SetKey(kCreateDesktopShortcutKey, base::Value(true)); return item; } -ExternalInstallOptions GetCreateDesktopShorcutTrueInstallOptions() { +ExternalInstallOptions GetCreateDesktopShortcutTrueInstallOptions() { ExternalInstallOptions options(NoContainerUrl(), DisplayMode::kBrowser, ExternalInstallSource::kExternalPolicy); options.add_to_applications_menu = true; @@ -202,6 +204,28 @@ int on_policy_changed_call_count = 0; }; +base::Value GetFallbackAppNameItem() { + base::Value item(base::Value::Type::DICTIONARY); + item.SetKey(kUrlKey, base::Value(WindowedUrl().spec())); + item.SetKey(kDefaultLaunchContainerKey, + base::Value(kDefaultLaunchContainerWindowValue)); + item.SetKey(kFallbackAppNameKey, base::Value(kDefaultFallbackAppName)); + return item; +} + +ExternalInstallOptions GetFallbackAppNameInstallOptions() { + ExternalInstallOptions options(WindowedUrl(), DisplayMode::kStandalone, + ExternalInstallSource::kExternalPolicy); + options.add_to_applications_menu = true; + options.add_to_desktop = false; + options.add_to_quick_launch_bar = false; + options.install_placeholder = true; + options.reinstall_placeholder = true; + options.wait_for_windows_closed = true; + options.fallback_app_name = kDefaultFallbackAppName; + return options; +} + } // namespace class WebAppPolicyManagerTest : public ChromeRenderViewHostTestHarness { @@ -446,9 +470,9 @@ } TEST_F(WebAppPolicyManagerTest, - ForceInstallAppWithDefaultCreateDesktopShorcut) { + ForceInstallAppWithDefaultCreateDesktopShortcut) { base::Value list(base::Value::Type::LIST); - list.Append(GetCreateDesktopShorcutDefaultItem()); + list.Append(GetCreateDesktopShortcutDefaultItem()); profile()->GetPrefs()->Set(prefs::kWebAppInstallForceList, std::move(list)); policy_manager()->Start(); @@ -458,15 +482,15 @@ std::vector<ExternalInstallOptions> expected_install_options_list; expected_install_options_list.push_back( - GetCreateDesktopShorcutDefaultInstallOptions()); + GetCreateDesktopShortcutDefaultInstallOptions()); EXPECT_EQ(install_requests, expected_install_options_list); } TEST_F(WebAppPolicyManagerTest, ForceInstallAppWithCreateDesktopShortcut) { base::Value list(base::Value::Type::LIST); - list.Append(GetCreateDesktopShorcutFalseItem()); - list.Append(GetCreateDesktopShorcutTrueItem()); + list.Append(GetCreateDesktopShortcutFalseItem()); + list.Append(GetCreateDesktopShortcutTrueItem()); profile()->GetPrefs()->Set(prefs::kWebAppInstallForceList, std::move(list)); policy_manager()->Start(); @@ -476,9 +500,25 @@ std::vector<ExternalInstallOptions> expected_install_options_list; expected_install_options_list.push_back( - GetCreateDesktopShorcutFalseInstallOptions()); + GetCreateDesktopShortcutFalseInstallOptions()); expected_install_options_list.push_back( - GetCreateDesktopShorcutTrueInstallOptions()); + GetCreateDesktopShortcutTrueInstallOptions()); + + EXPECT_EQ(install_requests, expected_install_options_list); +} + +TEST_F(WebAppPolicyManagerTest, ForceInstallAppWithFallbackAppName) { + base::Value list(base::Value::Type::LIST); + list.Append(GetFallbackAppNameItem()); + profile()->GetPrefs()->Set(prefs::kWebAppInstallForceList, std::move(list)); + + policy_manager()->Start(); + base::RunLoop().RunUntilIdle(); + + const auto& install_requests = pending_app_manager()->install_requests(); + + std::vector<ExternalInstallOptions> expected_install_options_list; + expected_install_options_list.push_back(GetFallbackAppNameInstallOptions()); EXPECT_EQ(install_requests, expected_install_options_list); } @@ -607,6 +647,34 @@ EXPECT_EQ(expected_options_list, install_options_list); } +// Tests that we correctly reinstall a placeholder app when the placeholder +// is using a fallback name. +TEST_F(WebAppPolicyManagerTest, ReinstallPlaceholderAppWithFallbackAppName) { + base::Value list(base::Value::Type::LIST); + list.Append(GetFallbackAppNameItem()); + profile()->GetPrefs()->Set(prefs::kWebAppInstallForceList, std::move(list)); + + policy_manager()->Start(); + base::RunLoop().RunUntilIdle(); + + std::vector<ExternalInstallOptions> expected_options_list; + expected_options_list.push_back(GetFallbackAppNameInstallOptions()); + + const auto& install_options_list = pending_app_manager()->install_requests(); + EXPECT_EQ(expected_options_list, install_options_list); + + policy_manager()->ReinstallPlaceholderAppIfNecessary(WindowedUrl()); + base::RunLoop().RunUntilIdle(); + + auto reinstall_options = GetFallbackAppNameInstallOptions(); + reinstall_options.install_placeholder = false; + reinstall_options.reinstall_placeholder = true; + reinstall_options.wait_for_windows_closed = true; + expected_options_list.push_back(std::move(reinstall_options)); + + EXPECT_EQ(expected_options_list, install_options_list); +} + TEST_F(WebAppPolicyManagerTest, TryToInexistentPlaceholderApp) { base::Value list(base::Value::Type::LIST); list.Append(GetWindowedItem());
diff --git a/chrome/browser/web_applications/pending_app_install_task.cc b/chrome/browser/web_applications/pending_app_install_task.cc index 29fe541..f81d4bd7 100644 --- a/chrome/browser/web_applications/pending_app_install_task.cc +++ b/chrome/browser/web_applications/pending_app_install_task.cc
@@ -232,7 +232,10 @@ } WebApplicationInfo web_app_info; - web_app_info.title = base::UTF8ToUTF16(install_options_.install_url.spec()); + web_app_info.title = + install_options_.fallback_app_name + ? base::UTF8ToUTF16(install_options_.fallback_app_name.value()) + : base::UTF8ToUTF16(install_options_.install_url.spec()); web_app_info.start_url = install_options_.install_url; switch (install_options_.user_display_mode) {
diff --git a/chrome/browser/web_applications/policy/web_app_policy_manager.cc b/chrome/browser/web_applications/policy/web_app_policy_manager.cc index 3aeabad..f60991b 100644 --- a/chrome/browser/web_applications/policy/web_app_policy_manager.cc +++ b/chrome/browser/web_applications/policy/web_app_policy_manager.cc
@@ -43,7 +43,8 @@ const base::Value* default_launch_container = entry.FindKey(kDefaultLaunchContainerKey); const base::Value* create_desktop_shortcut = - entry.FindKey(kCreateDesktopShorcutKey); + entry.FindKey(kCreateDesktopShortcutKey); + const base::Value* fallback_app_name = entry.FindKey(kFallbackAppNameKey); DCHECK(!default_launch_container || default_launch_container->GetString() == @@ -72,6 +73,11 @@ // policy. install_options.add_to_quick_launch_bar = false; + // Allow administrators to override the name of the placeholder app, as well + // as the permanent name for Web Apps without a manifest. + if (fallback_app_name) + install_options.fallback_app_name = fallback_app_name->GetString(); + return install_options; }
diff --git a/chrome/browser/web_applications/system_web_app_manager_browsertest.cc b/chrome/browser/web_applications/system_web_app_manager_browsertest.cc index 8ceb14f..ddb30823 100644 --- a/chrome/browser/web_applications/system_web_app_manager_browsertest.cc +++ b/chrome/browser/web_applications/system_web_app_manager_browsertest.cc
@@ -21,6 +21,7 @@ #include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/apps/app_service/browser_app_launcher.h" +#include "chrome/browser/apps/app_service/launch_utils.h" #include "chrome/browser/file_system_access/file_system_access_permission_request_manager.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser_finder.h" @@ -328,7 +329,7 @@ proxy->Launch(GetManager().GetAppIdForSystemApp(GetMockAppType()).value(), ui::EventFlags::EF_NONE, apps::mojom::LaunchSource::kFromAppListGrid, - display::kDefaultDisplayId); + apps::MakeWindowInfo(display::kDefaultDisplayId)); navigation_observer.Wait(); histograms.ExpectTotalCount("Apps.DefaultAppLaunch.FromAppListGrid", 1); @@ -352,7 +353,8 @@ proxy->LaunchAppWithIntent( GetManager().GetAppIdForSystemApp(GetMockAppType()).value(), ui::EventFlags::EF_NONE, std::move(intent), - apps::mojom::LaunchSource::kFromAppListGrid, display::kDefaultDisplayId); + apps::mojom::LaunchSource::kFromAppListGrid, + apps::MakeWindowInfo(display::kDefaultDisplayId)); navigation_observer.Wait(); histograms.ExpectTotalCount("Apps.DefaultAppLaunch.FromAppListGrid", 1);
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index 82fb6d9..79a3670f 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-master-1612958227-41d24d7235743aac0398667eab01a70e18222ac3.profdata +chrome-linux-master-1613001202-6ef218cbf7480c8ae793fe9b5cc2ae6ec8870c75.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index d134033b..c9db1cf 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-master-1612958227-64f4414608b36e2c298433af63d65254883eddd6.profdata +chrome-mac-master-1612979846-d7c647575837d460d0c274770ac2364327206664.profdata
diff --git a/chrome/chrome_cleaner/executables/BUILD.gn b/chrome/chrome_cleaner/executables/BUILD.gn index 13ce260..67d5223 100644 --- a/chrome/chrome_cleaner/executables/BUILD.gn +++ b/chrome/chrome_cleaner/executables/BUILD.gn
@@ -90,6 +90,15 @@ if (defined(invoker.deps)) { deps += invoker.deps } + + data_deps = [] + if (is_internal_chrome_cleaner_build) { + # Official and devel builders need to upload symbols to the crash server. + data_deps += [ "//third_party/breakpad:symupload" ] + } + if (defined(invoker.data_deps)) { + data_deps += invoker.data_deps + } } }
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc index 3b4ac91f..8dd87dc 100644 --- a/chrome/common/chrome_features.cc +++ b/chrome/common/chrome_features.cc
@@ -994,4 +994,8 @@ } #endif // BUILDFLAG(IS_CHROMEOS_ASH) +// Enables link to text to be generated in advance. +const base::Feature kPreemtiveLinkToTextGeneration{ + "PreemtiveLinkToTextGeneration", base::FEATURE_DISABLED_BY_DEFAULT}; + } // namespace features
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h index f18a1d70..dac8736 100644 --- a/chrome/common/chrome_features.h +++ b/chrome/common/chrome_features.h
@@ -118,6 +118,9 @@ #endif COMPONENT_EXPORT(CHROME_FEATURES) +extern const base::Feature kPreemtiveLinkToTextGeneration; + +COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kPrivacySandboxSettings; #if defined(OS_ANDROID)
diff --git a/chrome/common/extensions/api/scripting.idl b/chrome/common/extensions/api/scripting.idl index ce1512ff..7607855 100644 --- a/chrome/common/extensions/api/scripting.idl +++ b/chrome/common/extensions/api/scripting.idl
@@ -37,8 +37,8 @@ // specified. [serializableFunction]InjectedFunction? function; - // The path of the JS files to inject, relative to the extension's root - // directory. + // The path of the JS or CSS files to inject, relative to the extension's + // root directory. // NOTE: Currently a maximum of one file is supported. // Exactly one of <code>files</code> and <code>function</code> must be // specified. @@ -96,5 +96,15 @@ // |callback|: Invoked upon completion of the insertion. static void insertCSS(CSSInjection injection, optional CSSInjectionCallback callback); + + // Removes a CSS stylesheet that was previously inserted by this extension + // from a target context. + // |injection|: The details of the styles to remove. Note that the + // <code>css</code>, <code>files</code>, and <code>origin</code> properties + // must exactly match the stylesheet inserted through $(ref:insertCSS). + // Attempting to remove a non-existent stylesheet is a no-op. + // |callback|: A callback to be invoked upon the completion of the removal. + static void removeCSS(CSSInjection injection, + optional CSSInjectionCallback callback); }; };
diff --git a/chrome/common/printing/printer_capabilities.cc b/chrome/common/printing/printer_capabilities.cc index 987ba2e..e89392e 100644 --- a/chrome/common/printing/printer_capabilities.cc +++ b/chrome/common/printing/printer_capabilities.cc
@@ -33,10 +33,8 @@ #endif // defined(OS_WIN) #if BUILDFLAG(IS_CHROMEOS_ASH) -#include "base/feature_list.h" #include "chrome/common/printing/ipp_l10n.h" #include "components/strings/grit/components_strings.h" -#include "printing/printing_features.h" #include "ui/base/l10n/l10n_util.h" #endif // BUILDFLAG(IS_CHROMEOS_ASH) @@ -122,8 +120,7 @@ if (!has_secure_protocol) caps->pin_supported = false; - if (base::FeatureList::IsEnabled(printing::features::kAdvancedPpdAttributes)) - PopulateAdvancedCapsLocalization(&caps->advanced_capabilities); + PopulateAdvancedCapsLocalization(&caps->advanced_capabilities); #endif // BUILDFLAG(IS_CHROMEOS_ASH) return cloud_print::PrinterSemanticCapsAndDefaultsToCdd(*caps);
diff --git a/chrome/common/webui_url_constants.cc b/chrome/common/webui_url_constants.cc index 767a9fd..72a1947 100644 --- a/chrome/common/webui_url_constants.cc +++ b/chrome/common/webui_url_constants.cc
@@ -77,6 +77,10 @@ const char kChromeUIExtensionsHost[] = "extensions"; const char kChromeUIExtensionsInternalsHost[] = "extensions-internals"; const char kChromeUIExtensionsURL[] = "chrome://extensions/"; +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) +const char kChromeUIFamilyLinkUserInternalsHost[] = + "family-link-user-internals"; +#endif // BUILDFLAG(ENABLE_SUPERVISED_USERS) const char kChromeUIFaviconHost[] = "favicon"; const char kChromeUIFaviconURL[] = "chrome://favicon/"; const char kChromeUIFavicon2Host[] = "favicon2"; @@ -159,7 +163,6 @@ const char kChromeUISiteEngagementHost[] = "site-engagement"; const char kChromeUISuggestionsHost[] = "suggestions"; const char kChromeUISuggestionsURL[] = "chrome://suggestions/"; -const char kChromeUISupervisedUserInternalsHost[] = "supervised-user-internals"; const char kChromeUISupervisedUserPassphrasePageHost[] = "managed-user-passphrase"; const char kChromeUISyncConfirmationHost[] = "sync-confirmation"; @@ -474,6 +477,9 @@ #endif kChromeUIDeviceLogHost, kChromeUIDownloadInternalsHost, +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) + kChromeUIFamilyLinkUserInternalsHost, +#endif // BUILDFLAG(ENABLE_SUPERVISED_USERS) kChromeUIFlagsHost, kChromeUIGCMInternalsHost, kChromeUIHistoryHost, @@ -502,7 +508,6 @@ kChromeUINTPTilesInternalsHost, safe_browsing::kChromeUISafeBrowsingHost, kChromeUISuggestionsHost, - kChromeUISupervisedUserInternalsHost, kChromeUISyncInternalsHost, #if !defined(OS_ANDROID) kChromeUITermsHost,
diff --git a/chrome/common/webui_url_constants.h b/chrome/common/webui_url_constants.h index 7c8b02a..1823d8ac 100644 --- a/chrome/common/webui_url_constants.h +++ b/chrome/common/webui_url_constants.h
@@ -79,6 +79,9 @@ extern const char kChromeUIExtensionsHost[]; extern const char kChromeUIExtensionsInternalsHost[]; extern const char kChromeUIExtensionsURL[]; +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) +extern const char kChromeUIFamilyLinkUserInternalsHost[]; +#endif // BUILDFLAG(ENABLE_SUPERVISED_USERS) extern const char kChromeUIFaviconHost[]; extern const char kChromeUIFaviconURL[]; extern const char kChromeUIFavicon2Host[]; @@ -159,7 +162,6 @@ extern const char kChromeUISiteEngagementHost[]; extern const char kChromeUISuggestionsHost[]; extern const char kChromeUISuggestionsURL[]; -extern const char kChromeUISupervisedUserInternalsHost[]; extern const char kChromeUISupervisedUserPassphrasePageHost[]; extern const char kChromeUISyncConfirmationHost[]; extern const char kChromeUISyncConfirmationURL[];
diff --git a/chrome/renderer/chrome_render_frame_observer_browsertest.cc b/chrome/renderer/chrome_render_frame_observer_browsertest.cc index a8f419d3..e3944ed6 100644 --- a/chrome/renderer/chrome_render_frame_observer_browsertest.cc +++ b/chrome/renderer/chrome_render_frame_observer_browsertest.cc
@@ -50,6 +50,8 @@ called_new_page_ = true; page_level_translation_critiera_met_ = page_level_translation_critiera_met; } + void GetLanguageDetectionModel( + GetLanguageDetectionModelCallback callback) override {} bool called_new_page_ = false; bool page_level_translation_critiera_met_ = false;
diff --git a/chrome/renderer/translate/translate_agent_browsertest.cc b/chrome/renderer/translate/translate_agent_browsertest.cc index 893e5361..4121cab 100644 --- a/chrome/renderer/translate/translate_agent_browsertest.cc +++ b/chrome/renderer/translate/translate_agent_browsertest.cc
@@ -51,6 +51,8 @@ details_ = details; page_level_translation_critiera_met_ = page_level_translation_critiera_met; } + void GetLanguageDetectionModel( + GetLanguageDetectionModelCallback callback) override {} void ResetNewPageValues() { called_new_page_ = false;
diff --git a/chrome/services/sharing/nearby/nearby_connections.cc b/chrome/services/sharing/nearby/nearby_connections.cc index 7e38b85..5b8b8d5 100644 --- a/chrome/services/sharing/nearby/nearby_connections.cc +++ b/chrome/services/sharing/nearby/nearby_connections.cc
@@ -290,7 +290,10 @@ } VLOG(1) << "Nearby Connections: waiting for Core objects to finish stopping " << "all endpoints."; - latch.Await(absl::Seconds(5)); + if (!latch.Await(absl::Seconds(5)).result()) { + LOG(FATAL) << __func__ << ": Failed to stop all endpoints on each Core in " + << "time. Look for deadlocks in the threads tab of this crash."; + } VLOG(1) << "Nearby Connections: shutting down the shared service controller " << "prior to taking down Core objects"; @@ -301,6 +304,8 @@ VLOG(1) << "Nearby Connections: cleaning up Core objects"; service_id_to_core_map_.clear(); g_instance = nullptr; + + VLOG(1) << "Nearby Connections: shutdown complete"; } void NearbyConnections::OnDisconnect(const std::string dependency_name) {
diff --git a/chrome/services/speech/BUILD.gn b/chrome/services/speech/BUILD.gn index 77e713e7..a6c39b5 100644 --- a/chrome/services/speech/BUILD.gn +++ b/chrome/services/speech/BUILD.gn
@@ -3,6 +3,7 @@ # found in the LICENSE file. import("//build/buildflag_header.gni") +import("//build/config/chromeos/ui_mode.gni") import("//chrome/services/speech/buildflags.gni") buildflag_header("buildflags") { @@ -20,6 +21,13 @@ "speech_recognition_service_impl.h", ] + if (is_chromeos_ash) { + sources += [ + "cros_speech_recognition_recognizer_impl.cc", + "cros_speech_recognition_recognizer_impl.h", + ] + } + public_deps = [ "//media/mojo/mojom", "//mojo/public/cpp/bindings", @@ -30,6 +38,7 @@ ":buildflags", "//base", "//chrome/services/speech/soda", + "//chrome/services/speech/soda:soda_api_proto", "//components/speech", "//content/public/browser:proto", "//google_apis",
diff --git a/chrome/services/speech/DEPS b/chrome/services/speech/DEPS index 8afeca3e..6b4b926 100644 --- a/chrome/services/speech/DEPS +++ b/chrome/services/speech/DEPS
@@ -1,5 +1,7 @@ include_rules = [ "+chrome/services/speech", + "+chromeos/services/machine_learning/public/cpp", + "+chromeos/services/machine_learning/public/mojom", "+components/speech", "+content/public/browser", "+google_apis",
diff --git a/chrome/services/speech/cros_speech_recognition_recognizer_impl.cc b/chrome/services/speech/cros_speech_recognition_recognizer_impl.cc new file mode 100644 index 0000000..344026f4 --- /dev/null +++ b/chrome/services/speech/cros_speech_recognition_recognizer_impl.cc
@@ -0,0 +1,97 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/services/speech/cros_speech_recognition_recognizer_impl.h" + +#include "chrome/services/speech/soda/cros_soda_client.h" +#include "google_apis/google_api_keys.h" +#include "media/base/audio_buffer.h" +#include "media/base/audio_sample_types.h" +#include "media/base/audio_timestamp_helper.h" +#include "media/base/bind_to_current_loop.h" +#include "media/base/limits.h" +#include "media/base/media_switches.h" +#include "mojo/public/cpp/bindings/self_owned_receiver.h" + +namespace speech { +constexpr char kNoClientError[] = "No cros soda client."; + +void CrosSpeechRecognitionRecognizerImpl::Create( + mojo::PendingReceiver<media::mojom::SpeechRecognitionRecognizer> receiver, + mojo::PendingRemote<media::mojom::SpeechRecognitionRecognizerClient> remote, + base::WeakPtr<SpeechRecognitionServiceImpl> speech_recognition_service_impl, + const base::FilePath& binary_path, + const base::FilePath& config_path) { + mojo::MakeSelfOwnedReceiver( + std::make_unique<CrosSpeechRecognitionRecognizerImpl>( + std::move(remote), std::move(speech_recognition_service_impl), + binary_path, config_path), + std::move(receiver)); +} +CrosSpeechRecognitionRecognizerImpl::~CrosSpeechRecognitionRecognizerImpl() = + default; + +CrosSpeechRecognitionRecognizerImpl::CrosSpeechRecognitionRecognizerImpl( + mojo::PendingRemote<media::mojom::SpeechRecognitionRecognizerClient> remote, + base::WeakPtr<SpeechRecognitionServiceImpl> speech_recognition_service_impl, + const base::FilePath& binary_path, + const base::FilePath& config_path) + : SpeechRecognitionRecognizerImpl( + std::move(remote), + std::move(speech_recognition_service_impl), + binary_path, + config_path), + enable_soda_( + base::FeatureList::IsEnabled(media::kUseSodaForLiveCaption)) { + recognition_event_callback_ = base::BindRepeating( + &CrosSpeechRecognitionRecognizerImpl::OnRecognitionEvent, + weak_factory_.GetWeakPtr()); + DCHECK(enable_soda_) << "This class is only expected to run with soda " + "enabled, but it can without."; + if (enable_soda_) { + cros_soda_client_ = std::make_unique<soda::CrosSodaClient>(); + } +} + +void CrosSpeechRecognitionRecognizerImpl:: + SendAudioToSpeechRecognitionServiceInternal( + media::mojom::AudioDataS16Ptr buffer) { + if (!enable_soda_) { + // Defer to the superclass. + LOG(DFATAL) << "This class is only expected to be used when soda is " + "enabled; Deferring to superclass."; + SpeechRecognitionRecognizerImpl:: + SendAudioToSpeechRecognitionServiceInternal(std::move(buffer)); + return; + } + + // Soda is on, let's send the audio to it. + int channel_count = buffer->channel_count; + int sample_rate = buffer->sample_rate; + size_t buffer_size = 0; + // Verify and calculate the buffer size. + if (!base::CheckMul(buffer->data.size(), sizeof(buffer->data[0])) + .AssignIfValid(&buffer_size)) { + LOG(DFATAL) << "Size check invalid."; + return; + } + if (cros_soda_client_ == nullptr) { + LOG(DFATAL) << "No soda client, stopping."; + mojo::ReportBadMessage(kNoClientError); + return; + } + + if (!cros_soda_client_->IsInitialized() || + cros_soda_client_->DidAudioPropertyChange(sample_rate, channel_count)) { + auto config = chromeos::machine_learning::mojom::SodaConfig::New(); + config->channel_count = channel_count; + config->sample_rate = sample_rate; + config->api_key = google_apis::GetSodaAPIKey(); + // TODO(robsc): add in library locations. + cros_soda_client_->Reset(std::move(config), recognition_event_callback_); + } + cros_soda_client_->AddAudio(reinterpret_cast<char*>(buffer->data.data()), + buffer_size); +} +} // namespace speech
diff --git a/chrome/services/speech/cros_speech_recognition_recognizer_impl.h b/chrome/services/speech/cros_speech_recognition_recognizer_impl.h new file mode 100644 index 0000000..61d7377 --- /dev/null +++ b/chrome/services/speech/cros_speech_recognition_recognizer_impl.h
@@ -0,0 +1,68 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_SERVICES_SPEECH_CROS_SPEECH_RECOGNITION_RECOGNIZER_IMPL_H_ +#define CHROME_SERVICES_SPEECH_CROS_SPEECH_RECOGNITION_RECOGNIZER_IMPL_H_ + +#include <memory> +#include <string> + +#include "base/memory/weak_ptr.h" +#include "chrome/services/speech/cloud_speech_recognition_client.h" +#include "chrome/services/speech/speech_recognition_recognizer_impl.h" +#include "media/mojo/mojom/speech_recognition_service.mojom.h" +#include "mojo/public/cpp/bindings/receiver.h" +#include "mojo/public/cpp/bindings/remote.h" + +namespace soda { +class CrosSodaClient; +} // namespace soda + +namespace speech { +// Implementation of SpeechRecognitionRecognizer specifically for ChromeOS and +// SODA. The implementation forwards and works with SODA that actually runs in +// the ML Service; The Web instantiation should not be used, and defers to the +// superclass. +class CrosSpeechRecognitionRecognizerImpl + : public SpeechRecognitionRecognizerImpl { + public: + CrosSpeechRecognitionRecognizerImpl( + mojo::PendingRemote<media::mojom::SpeechRecognitionRecognizerClient> + remote, + base::WeakPtr<SpeechRecognitionServiceImpl> + speech_recognition_service_impl, + const base::FilePath& binary_path, + const base::FilePath& config_path); + ~CrosSpeechRecognitionRecognizerImpl() override; + + static void Create( + mojo::PendingReceiver<media::mojom::SpeechRecognitionRecognizer> receiver, + mojo::PendingRemote<media::mojom::SpeechRecognitionRecognizerClient> + remote, + base::WeakPtr<SpeechRecognitionServiceImpl> + speech_recognition_service_impl, + const base::FilePath& binary_path, + const base::FilePath& config_path); + + OnRecognitionEventCallback recognition_event_callback() const { + return recognition_event_callback_; + } + // SpeechRecognitionRecognizerImpl: + void SendAudioToSpeechRecognitionServiceInternal( + media::mojom::AudioDataS16Ptr buffer) override; + + private: + std::unique_ptr<soda::CrosSodaClient> cros_soda_client_; + // The callback that is eventually executed on a speech recognition event + // which passes the transcribed audio back to the caller via the speech + // recognition event client remote. + OnRecognitionEventCallback recognition_event_callback_; + + const bool enable_soda_; + + base::WeakPtrFactory<CrosSpeechRecognitionRecognizerImpl> weak_factory_{this}; +}; +} // namespace speech + +#endif // CHROME_SERVICES_SPEECH_CROS_SPEECH_RECOGNITION_RECOGNIZER_IMPL_H_
diff --git a/chrome/services/speech/soda/BUILD.gn b/chrome/services/speech/soda/BUILD.gn index 6e4437d2..c2bfd00 100644 --- a/chrome/services/speech/soda/BUILD.gn +++ b/chrome/services/speech/soda/BUILD.gn
@@ -1,7 +1,13 @@ # 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. +import("//build/config/chromeos/ui_mode.gni") import("//chrome/services/speech/buildflags.gni") +import("//third_party/protobuf/proto_library.gni") + +proto_library("soda_api_proto") { + sources = [ "proto/soda_api.proto" ] +} source_set("soda") { sources = [ @@ -10,9 +16,24 @@ "soda_client.h", ] - deps = [ "//base" ] + deps = [ + ":soda_api_proto", + "//base", + ] + + if (is_chromeos_ash) { + sources += [ + "cros_soda_client.cc", + "cros_soda_client.h", + ] + deps += [ + "//chromeos/services/machine_learning/public/cpp", + "//chromeos/services/machine_learning/public/mojom", + ] + } } +# TODO(robsc): add unit test for cros_soda_client. source_set("unit_tests") { testonly = true
diff --git a/chrome/services/speech/soda/cros_soda_client.cc b/chrome/services/speech/soda/cros_soda_client.cc new file mode 100644 index 0000000..f29f2dbc --- /dev/null +++ b/chrome/services/speech/soda/cros_soda_client.cc
@@ -0,0 +1,87 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/services/speech/soda/cros_soda_client.h" +#include "base/run_loop.h" +#include "chromeos/services/machine_learning/public/cpp/service_connection.h" +#include "mojo/public/cpp/bindings/remote.h" + +namespace soda { +CrosSodaClient::CrosSodaClient() : soda_client_(this) {} +CrosSodaClient::~CrosSodaClient() = default; + +bool CrosSodaClient::DidAudioPropertyChange(int sample_rate, + int channel_count) { + return !is_initialized_ || sample_rate_ != sample_rate || + channel_count_ != channel_count; +} + +void CrosSodaClient::AddAudio(const char* audio_buffer, + int audio_buffer_size) const { + DCHECK(IsInitialized()) << "Unable to add audio before starting."; + const uint8_t* audio_buffer_casted = + reinterpret_cast<const uint8_t*>(audio_buffer); + std::vector<uint8_t> audio(audio_buffer_casted, + audio_buffer_casted + audio_buffer_size); + soda_recognizer_->AddAudio(audio); +} + +void CrosSodaClient::Reset( + chromeos::machine_learning::mojom::SodaConfigPtr soda_config, + base::RepeatingCallback<void(const std::string&, bool)> callback) { + sample_rate_ = soda_config->sample_rate; + channel_count_ = soda_config->channel_count; + if (is_initialized_) { + soda_recognizer_->Stop(); + } + soda_recognizer_.reset(); + soda_client_.reset(); + is_initialized_ = true; + auto mojom_config = chromeos::machine_learning::mojom::SodaConfig::New(); + mojom_config->channel_count = channel_count_; + mojom_config->sample_rate = sample_rate_; + + chromeos::machine_learning::ServiceConnection::GetInstance() + ->GetMachineLearningService() + .LoadSpeechRecognizer( + std::move(mojom_config), soda_client_.BindNewPipeAndPassRemote(), + soda_recognizer_.BindNewPipeAndPassReceiver(), + base::BindOnce( + [](chromeos::machine_learning::mojom::LoadModelResult result) { + if (result != + chromeos::machine_learning::mojom::LoadModelResult::OK) { + LOG(DFATAL) << "Could not load recognizer, error: " << result; + } + })); + + callback_ = callback; + // Ensure this one is started. + soda_recognizer_->Start(); +} +void CrosSodaClient::OnStop() { + // Do nothing OnStop. +} +void CrosSodaClient::OnStart() { + // Do nothing OnStart. +} +void CrosSodaClient::OnSpeechRecognizerEvent( + chromeos::machine_learning::mojom::SpeechRecognizerEventPtr event) { + if (event->is_final_result()) { + auto& final_result = event->get_final_result(); + if (!final_result->final_hypotheses.empty()) { + const std::string final_hyp = final_result->final_hypotheses.front(); + callback_.Run(final_hyp, true); + } + } else if (event->is_partial_result()) { + auto& partial_result = event->get_partial_result(); + if (!partial_result->partial_text.empty()) { + const std::string partial_hyp = partial_result->partial_text.front(); + callback_.Run(partial_hyp, false); + } + } else { + LOG(ERROR) << "Some kind of other soda event, ignoring completely."; + } +} + +} // namespace soda
diff --git a/chrome/services/speech/soda/cros_soda_client.h b/chrome/services/speech/soda/cros_soda_client.h new file mode 100644 index 0000000..dc0f714 --- /dev/null +++ b/chrome/services/speech/soda/cros_soda_client.h
@@ -0,0 +1,59 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_SERVICES_SPEECH_SODA_CROS_SODA_CLIENT_H_ +#define CHROME_SERVICES_SPEECH_SODA_CROS_SODA_CLIENT_H_ + +#include <memory> +#include <string> + +#include "base/callback.h" +#include "chromeos/services/machine_learning/public/mojom/soda.mojom.h" +#include "mojo/public/cpp/bindings/receiver.h" +#include "mojo/public/cpp/bindings/remote.h" + +namespace soda { + +// Client that wraps the ML Service connection for SODA on Chrome. +// TODO(robsc@chromium): Move this to +// chromeos/services/machine_learning/public/cpp as SodaClient. +class CrosSodaClient : public chromeos::machine_learning::mojom::SodaClient { + public: + CrosSodaClient(); + ~CrosSodaClient() override; + + // Adds audio to this soda client. Only makes sense when initialized. + // Eventually, asynchronous callbacks to the ::SodaClient overrides below are + // executed. + void AddAudio(const char* audio_buffer, int audio_buffer_size) const; + // Checks if the sample rate / channels changed between calls. + bool DidAudioPropertyChange(int sample_rate, int channel_count); + bool IsInitialized() const { return is_initialized_; } + + // chromeos::machine_learning::mojom::SodaClient: + void OnStop() override; + void OnStart() override; + void OnSpeechRecognizerEvent( + chromeos::machine_learning::mojom::SpeechRecognizerEventPtr event) + override; + + // Reset this client with the provided configuration, and send recognition + // callbacks of (text, is_final) to the given callback. + void Reset(chromeos::machine_learning::mojom::SodaConfigPtr soda_config, + base::RepeatingCallback<void(const std::string&, bool)> callback); + + private: + // This callback is called with (text, is_final) whenever soda responds + // appropriately. + base::RepeatingCallback<void(const std::string&, bool)> callback_; + bool is_initialized_ = false; + int sample_rate_ = 0; + int channel_count_ = 0; + + mojo::Remote<chromeos::machine_learning::mojom::SodaRecognizer> + soda_recognizer_; + mojo::Receiver<chromeos::machine_learning::mojom::SodaClient> soda_client_; +}; +} // namespace soda +#endif // CHROME_SERVICES_SPEECH_SODA_CROS_SODA_CLIENT_H_
diff --git a/chrome/services/speech/soda/proto/soda_api.proto b/chrome/services/speech/soda/proto/soda_api.proto new file mode 100644 index 0000000..177736f --- /dev/null +++ b/chrome/services/speech/soda/proto/soda_api.proto
@@ -0,0 +1,203 @@ +// DO NOT CHANGE THIS FILE! +// This proto is copied from +// http://google3/speech/soda/chrome/extended_soda_api.proto That is the source +// of truth, and any changes should be submitted and approved there before being +// copied into here. + +syntax = "proto2"; + +package speech.soda.api; + +// Optimize generated output for Lite, since it's going to be running on +// end-user devices. +option optimize_for = LITE_RUNTIME; +option java_multiple_files = true; + +// Next ID to use: 12 +message SerializedSodaConfigMsg { + // Number of channels in RAW audio that will be provided to SODA. + optional int32 channel_count = 1; + // Sample rate, in Hz. + optional int32 sample_rate = 2; + + // Maximum size of buffer to use in PipeStream. By default, is 0, which means + // unlimited. + optional int32 max_buffer_bytes = 4 [default = 0]; + + // If set to true, forces the audio provider to simulate realtime audio + // provision. This only makes sense during testing, to simulate realtime audio + // providing from a big chunk of audio. + // This slows down audio provided to SODA to a maximum of real-time, which + // means more accurate endpointer behavior, but is unsuitable for execution in + // real production environments. Set with caution! + optional bool simulate_realtime_testonly = 5 [default = false]; + + // config file location for languagepack. + optional string config_file_location = 3 [deprecated = true]; + + // API key used for call verification. + optional string api_key = 6; + + // Directory of the language pack to use. + optional string language_pack_directory = 7; + + enum RecognitionMode { + UNKNOWN = 0; + + // Intended for voice input for keyboard usage. + IME = 1; + + // Intended to caption a stream of audio. + CAPTION = 2; + } + // What kind of recognition to execute here. Impacts model usage. + optional RecognitionMode recognition_mode = 8 [default = IME]; + + // Whether terse_processor should force a new session after every final + // recognition result. + // This will cause the terse processor to stop processing new audio once an + // endpoint event is detected and wait for it to generate a final event using + // audio up to the endpoint. This will cause processing bursts when a new + // session starts. + optional bool reset_on_final_result = 9 [default = true]; + + // Whether to populate the timing_metrics field on Recognition and Endpoint + // events. + optional bool include_timing_metrics = 10 [default = true]; + + // Whether or not to request lang id events. + optional bool enable_lang_id = 11 [default = false]; +} + +// Next id: 5 +message TimingMetrics { + // Epoch time of first audio buffer of main query that is fed into ASR. + // This is the wall time read from the system clock when the first audio + // buffer is received by the terse processor. + optional int64 audio_start_epoch_usec = 1; + + // Start time in audio time from start of SODA session. + // This time measures the amount of audio input into SODA. + optional int64 audio_start_time_usec = 2; + + // Elapsed wall time usec since first frame. + optional int64 elapsed_wall_time_usec = 3; + + // Elapsed processed audio usec from first frame after preamble. + optional int64 event_end_time_usec = 4; +} + +// Next id: 5 +message SodaRecognitionResult { + // Hypothesis from recognition, in order of probability. We don't get the + // probability from SODA, so the only given is that the first is the "best". + repeated string hypothesis = 1; + enum ResultType { + UNKNOWN = 0; + // Partial result of a speech segment so far. + PARTIAL = 1; + // Final result for this segment. + FINAL = 2; + // Prefetch is only sent for likely query strings. This won't happen for + // non-query mode SODA, but we add here for completeness. + PREFETCH = 3; + } + + // What kind of result set this is. + optional ResultType result_type = 2; + + enum FinalResultEndpointReason { + ENDPOINT_UNKNOWN = 0; + // End of speech from endpointer. + ENDPOINT_END_OF_SPEECH = 1; + // End of utterance from endpointer. + ENDPOINT_END_OF_UTTERANCE = 2; + // No more audio. + ENDPOINT_END_OF_AUDIO = 3; + // Final was generated because a hotword was detected. + ENDPOINT_ASR_RESET_BY_HOTWORD = 4; + // ASR was reset via the external API. + ENDPOINT_ASR_RESET_EXTERNAL = 5; + // Final recognition result was generated due to an error in ASR. + ENDPOINT_ASR_ERROR = 6; + } + // If this is a final result, why was the recognition marked final. + optional FinalResultEndpointReason endpoint_reason = 3; + + // Timing information for the event. + optional TimingMetrics timing_metrics = 4; +} + +// Next id: 3 +message SodaEndpointEvent { + // What endpoint type we're referring to here. + enum EndpointType { + // A start-of-speech moment has been detected at this time. Audio currently + // contains speech. + START_OF_SPEECH = 0; + + // End of speech has been detected by the endpointer, audio does not contain + // speech right now. + END_OF_SPEECH = 1; + + // End of Audio due to an end-of-mic data event. + END_OF_AUDIO = 2; + + // End of Utterance detected from the endpointer. Not used in + // Caption/Transcription. + END_OF_UTTERANCE = 3; + + UNKNOWN = 4; + } + + optional EndpointType endpoint_type = 1 [default = UNKNOWN]; + + // Timing information for the event. + optional TimingMetrics timing_metrics = 2; +} + +message SodaAudioLevelInfo { + // Low-pass filtered RMS in range 0..1. + optional float rms = 1; + + // Speech likelihood score from in range 0..1. + optional float audio_level = 2; + + // Amount of audio seen from start of SODA session until an audio level event. + // This value is only set when audio_level is set. + optional int64 audio_time_usec = 3; +} + +message SodaLangIdEvent { + // Locale, e.g. "en-us" or "af-za" + optional string language = 1; + // Equal to the internal enum from langid confidence. + optional int32 confidence_level = 2; +} + +message SodaResponse { + enum SodaMessageType { + UNKNOWN = 0; + RECOGNITION = 1; + STOP = 2; + SHUTDOWN = 3; + START = 4; + ENDPOINT = 5; + AUDIO_LEVEL = 6; + LANGID = 7; + } + + optional SodaMessageType soda_type = 1 [default = UNKNOWN]; + + // Set when type is RECOGNITION + optional SodaRecognitionResult recognition_result = 2; + + // Set when type is ENDPOINT + optional SodaEndpointEvent endpoint_event = 3; + + // Set when type is AUDIO_LEVEL + optional SodaAudioLevelInfo audio_level_info = 4; + + // Set when type is LANGID + optional SodaLangIdEvent langid_event = 5; +} \ No newline at end of file
diff --git a/chrome/services/speech/soda/soda_async_impl.h b/chrome/services/speech/soda/soda_async_impl.h index 6e4e5096..f80ff0f9 100644 --- a/chrome/services/speech/soda/soda_async_impl.h +++ b/chrome/services/speech/soda/soda_async_impl.h
@@ -13,6 +13,7 @@ extern "C" { typedef void (*RecognitionResultHandler)(const char*, const bool, void*); +typedef void (*SerializedSodaEventHandler)(const char*, int, void*); typedef struct { // The channel count and sample rate of the audio stream. SODA does not @@ -26,19 +27,36 @@ // The callback that gets executed on a recognition event. It takes in a // char*, representing the transcribed text; a bool, representing whether the - // result is final or not; and a void* pointer to the SodaRecognizerImpl - // instance associated with the stream. + // result is final or not; and a void pointer to the object that is associated + // with the callback. RecognitionResultHandler callback; - // A void pointer to the SodaRecognizerImpl instance associated with the - // stream. + // A void pointer to the object that is associated with the callback. + // Ownership is not taken. void* callback_handle; + // The API key used to verify that the binary is called by Chrome. const char* api_key; } SodaConfig; -// Creates and instantiates an instance of SODA. -void* CreateSodaAsync(SodaConfig config); +typedef struct { + // A ExtendedSodaConfigMsg that's been serialized as a string. Not owned. + const char* soda_config; + + // length of char* in soda_config. + int soda_config_size; + + // The callback that gets executed on a SODA event. It takes in a + // char*, which is a serialized SodaResponse proto, an int specifying the + // length of the char* and a void pointer to the object that is associated + // with the callback. + SerializedSodaEventHandler callback; + + // A void pointer to the object that is associated with the callback. + void* callback_handle; +} SerializedSodaConfig; + +void* CreateSoda(SerializedSodaConfig config); // Destroys the instance of SODA, called on the destruction of the SodaClient. void DeleteSodaAsync(void* soda_async_handle);
diff --git a/chrome/services/speech/soda/soda_client.cc b/chrome/services/speech/soda/soda_client.cc index e1ffd08..8dfe3463 100644 --- a/chrome/services/speech/soda/soda_client.cc +++ b/chrome/services/speech/soda/soda_client.cc
@@ -11,11 +11,13 @@ SodaClient::SodaClient(base::FilePath library_path) : lib_(library_path), create_soda_func_(reinterpret_cast<CreateSodaFunction>( - lib_.GetFunctionPointer("CreateSodaAsync"))), + lib_.GetFunctionPointer("CreateExtendedSodaAsync"))), delete_soda_func_(reinterpret_cast<DeleteSodaFunction>( - lib_.GetFunctionPointer("DeleteSodaAsync"))), + lib_.GetFunctionPointer("DeleteExtendedSodaAsync"))), add_audio_func_(reinterpret_cast<AddAudioFunction>( - lib_.GetFunctionPointer("AddAudio"))), + lib_.GetFunctionPointer("ExtendedAddAudio"))), + soda_start_func_(reinterpret_cast<SodaStartFunction>( + lib_.GetFunctionPointer("ExtendedSodaStart"))), is_initialized_(false), sample_rate_(0), channel_count_(0) { @@ -29,6 +31,7 @@ DCHECK(create_soda_func_); DCHECK(delete_soda_func_); DCHECK(add_audio_func_); + DCHECK(soda_start_func_); } NO_SANITIZE("cfi-icall") @@ -47,15 +50,18 @@ } NO_SANITIZE("cfi-icall") -void SodaClient::Reset(const SodaConfig config) { +void SodaClient::Reset(const SerializedSodaConfig config, + int sample_rate, + int channel_count) { if (IsInitialized()) { delete_soda_func_(soda_async_handle_); } soda_async_handle_ = create_soda_func_(config); - sample_rate_ = config.sample_rate; - channel_count_ = config.channel_count; + sample_rate_ = sample_rate; + channel_count_ = channel_count; is_initialized_ = true; + soda_start_func_(soda_async_handle_); } } // namespace soda
diff --git a/chrome/services/speech/soda/soda_client.h b/chrome/services/speech/soda/soda_client.h index a36ff005..d15ae08 100644 --- a/chrome/services/speech/soda/soda_client.h +++ b/chrome/services/speech/soda/soda_client.h
@@ -27,7 +27,9 @@ bool DidAudioPropertyChange(int sample_rate, int channel_count); // Resets the SODA instance, initializing it with the provided config. - void Reset(const SodaConfig config); + void Reset(const SerializedSodaConfig config, + int sample_rate, + int channel_count); // Returns a flag indicating whether the client has been initialized. bool IsInitialized() { return is_initialized_; } @@ -35,7 +37,7 @@ private: base::ScopedNativeLibrary lib_; - typedef void* (*CreateSodaFunction)(SodaConfig); + typedef void* (*CreateSodaFunction)(SerializedSodaConfig); CreateSodaFunction create_soda_func_; typedef void (*DeleteSodaFunction)(void*); @@ -44,6 +46,9 @@ typedef void (*AddAudioFunction)(void*, const char*, int); AddAudioFunction add_audio_func_; + typedef void (*SodaStartFunction)(void*); + SodaStartFunction soda_start_func_; + // An opaque handle to the SODA async instance. void* soda_async_handle_;
diff --git a/chrome/services/speech/speech_recognition_recognizer_impl.cc b/chrome/services/speech/speech_recognition_recognizer_impl.cc index 0b0719b..20f3792a 100644 --- a/chrome/services/speech/speech_recognition_recognizer_impl.cc +++ b/chrome/services/speech/speech_recognition_recognizer_impl.cc
@@ -11,6 +11,7 @@ #include "base/containers/span.h" #include "base/files/file_util.h" #include "base/metrics/histogram_functions.h" +#include "chrome/services/speech/soda/proto/soda_api.pb.h" #include "chrome/services/speech/soda/soda_client.h" #include "google_apis/google_api_keys.h" #include "media/base/audio_buffer.h" @@ -44,13 +45,29 @@ // which owns the instance of SODA and their sequential destruction order // ensures that this callback will never be called with an invalid callback // handle to the SpeechRecognitionRecognizerImpl. -void RecognitionCallback(const char* result, - const bool is_final, - void* callback_handle) { +void OnSodaResponse(const char* serialized_proto, + int length, + void* callback_handle) { DCHECK(callback_handle); - static_cast<SpeechRecognitionRecognizerImpl*>(callback_handle) - ->recognition_event_callback() - .Run(std::string(result), is_final); + soda::api::SodaResponse response; + if (!response.ParseFromArray(serialized_proto, length)) { + LOG(ERROR) << "Unable to parse result from SODA."; + return; + } + + if (response.soda_type() == soda::api::SodaResponse::RECOGNITION) { + soda::api::SodaRecognitionResult result = response.recognition_result(); + DCHECK(result.hypothesis_size()); + static_cast<SpeechRecognitionRecognizerImpl*>(callback_handle) + ->recognition_event_callback() + .Run(std::string(result.hypothesis(0)), + result.result_type() == soda::api::SodaRecognitionResult::FINAL); + } + + if (response.soda_type() == soda::api::SodaResponse::LANGID) { + // TODO(crbug.com/1175357): Use the langid event to prompt users to switch + // languages. + } } } // namespace @@ -99,7 +116,7 @@ enable_soda_ = base::FeatureList::IsEnabled(media::kUseSodaForLiveCaption); if (enable_soda_) { DCHECK(base::PathExists(binary_path)); - soda_client_ = std::make_unique<soda::SodaClient>(binary_path); + soda_client_ = std::make_unique<::soda::SodaClient>(binary_path); } else { cloud_client_ = std::make_unique<CloudSpeechRecognitionClient>( recognition_event_callback(), @@ -145,6 +162,23 @@ return; } + // OK, everything is verified, let's send the audio. + SendAudioToSpeechRecognitionServiceInternal(std::move(buffer)); +} + +void SpeechRecognitionRecognizerImpl:: + SendAudioToSpeechRecognitionServiceInternal( + media::mojom::AudioDataS16Ptr buffer) { + int channel_count = buffer->channel_count; + int sample_rate = buffer->sample_rate; + size_t buffer_size = 0; + // Verify and calculate the buffer size. + if (!base::CheckMul(buffer->data.size(), sizeof(buffer->data[0])) + .AssignIfValid(&buffer_size)) { + mojo::ReportBadMessage(kInvalidAudioDataError); + return; + } + if (enable_soda_) { DCHECK(soda_client_); DCHECK(base::PathExists(config_path_)); @@ -153,14 +187,23 @@ // Initialize the SODA instance. auto api_key = google_apis::GetSodaAPIKey(); std::string language_pack_directory = config_path_.AsUTF8Unsafe(); - SodaConfig config; - config.channel_count = channel_count; - config.sample_rate = sample_rate; - config.language_pack_directory = language_pack_directory.c_str(); - config.callback = RecognitionCallback; + + // Initialize the SODA instance with the serialized config. + soda::api::SerializedSodaConfigMsg config_msg; + config_msg.set_channel_count(channel_count); + config_msg.set_sample_rate(sample_rate); + config_msg.set_api_key(api_key); + config_msg.set_language_pack_directory(language_pack_directory); + config_msg.set_simulate_realtime_testonly(false); + config_msg.set_enable_lang_id(false); + auto serialized = config_msg.SerializeAsString(); + + SerializedSodaConfig config; + config.soda_config = serialized.c_str(); + config.soda_config_size = serialized.size(); + config.callback = &OnSodaResponse; config.callback_handle = this; - config.api_key = api_key.c_str(); - soda_client_->Reset(config); + soda_client_->Reset(config, sample_rate, channel_count); } soda_client_->AddAudio(reinterpret_cast<char*>(buffer->data.data()),
diff --git a/chrome/services/speech/speech_recognition_recognizer_impl.h b/chrome/services/speech/speech_recognition_recognizer_impl.h index 3fc84e9..187958a 100644 --- a/chrome/services/speech/speech_recognition_recognizer_impl.h +++ b/chrome/services/speech/speech_recognition_recognizer_impl.h
@@ -54,6 +54,14 @@ return recognition_event_callback_; } + protected: + virtual void SendAudioToSpeechRecognitionServiceInternal( + media::mojom::AudioDataS16Ptr buffer); + + // Return the transcribed audio from the recognition event back to the caller + // via the recognition event client. + void OnRecognitionEvent(const std::string& result, const bool is_final); + private: // Convert the audio buffer into the appropriate format and feed the raw audio // into the speech recognition instance. @@ -64,10 +72,6 @@ void AudioReceivedAfterBubbleClosed(base::TimeDelta duration) final; - // Return the transcribed audio from the recognition event back to the caller - // via the recognition event client. - void OnRecognitionEvent(const std::string& result, const bool is_final); - void RecordDuration(); // The remote endpoint for the mojo pipe used to return transcribed audio from
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 84bd135d..d10e11d 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -45,6 +45,10 @@ import("//ui/webui/webui_features.gni") import("//v8/gni/v8.gni") +if (is_chromeos) { + import("//build/config/chromeos/rules.gni") +} + assert(!is_ios, "Chromium/iOS shouldn't use anything in //chrome") if (is_android) { @@ -1411,7 +1415,7 @@ "../browser/ui/autofill/payments/card_unmask_prompt_view_tester.h", "../browser/ui/autofill/payments/save_card_bubble_controller_impl_browsertest.cc", "../browser/ui/autofill/payments/save_upi_bubble_controller_impl_browsertest.cc", - "../browser/ui/autofill/save_address_profile_bubble_controller_browsertest.cc", + "../browser/ui/autofill/save_address_profile_bubble_controller_impl_browsertest.cc", "../browser/ui/blocked_content/popup_opener_tab_helper_browsertest.cc", "../browser/ui/blocked_content/popup_tracker_browsertest.cc", "../browser/ui/blocked_content/safe_browsing_triggered_popup_blocker_browsertest.cc", @@ -2189,6 +2193,8 @@ ] deps += [ "//chrome/browser/error_reporting:test_support" ] + } else { + sources += [ "../browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_browsertest.cc" ] } deps += [ @@ -2432,6 +2438,8 @@ "../browser/ash/app_mode/kiosk_crash_restore_browsertest.cc", "../browser/ash/app_mode/web_app/web_kiosk_app_data_browsertest.cc", "../browser/ash/profiles/profile_helper_browsertest.cc", + "../browser/ash/system/device_disabling_browsertest.cc", + "../browser/ash/system/tray_accessibility_browsertest.cc", "../browser/chrome_main_browsertest.cc", "../browser/chromeos/apps/apk_web_app_installer_browsertest.cc", "../browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_browsertest.cc", @@ -2741,8 +2749,6 @@ "../browser/chromeos/scoped_test_system_nss_key_slot_mixin.h", "../browser/chromeos/shutdown_policy_browsertest.cc", "../browser/chromeos/startup_settings_cache_browsertest.cc", - "../browser/chromeos/system/device_disabling_browsertest.cc", - "../browser/chromeos/system/tray_accessibility_browsertest.cc", "../browser/chromeos/web_applications/camera_app_integration_browsertest.cc", "../browser/chromeos/web_applications/diagnostics_app_integration_browsertest.cc", "../browser/chromeos/web_applications/eche_app_integration_browsertest.cc", @@ -3336,42 +3342,70 @@ # New target that will replace telemetry_perf_tests when testing # is done. -script_test("performance_test_suite") { - script = "//testing/scripts/run_performance_tests.py" - args = [ "../../tools/perf/run_benchmark" ] +template("performance_test_suite_template") { + forward_variables_from(invoker, [ "override_board" ]) + script_test(target_name) { + script = "//testing/scripts/run_performance_tests.py" + if (is_chromeos_device) { + if (defined(override_board)) { + args = [ "bin/cros_update_wrapper_${override_board} -- ../../tools/perf/run_benchmark" ] + } else { + args = [ "bin/cros_update_wrapper -- ../../tools/perf/run_benchmark" ] + } + } else { + args = [ "../../tools/perf/run_benchmark" ] + } - data_deps = [ - "//base:base_perftests", - "//chrome/test:telemetry_perf_tests", - "//components:components_perftests", - "//components/tracing:tracing_perftests", - "//gpu:command_buffer_perftests", - "//gpu:gpu_perftests", - "//media:media_perftests", - "//testing:run_perf_test", - ] - - if (build_dawn_tests && !is_chromeos_lacros) { - data_deps += [ "//third_party/dawn/src/tests:dawn_perf_tests" ] - } - - if (!is_chromeos_lacros) { - data_deps += [ "//third_party/angle/src/tests:angle_perftests" ] - } - - if (!is_android && !is_fuchsia) { - data_deps += [ - "//chrome/test:load_library_perf_tests", - "//ui/views:views_perftests", + data_deps = [ + "//base:base_perftests", + "//chrome/test:telemetry_perf_tests", + "//components:components_perftests", + "//components/tracing:tracing_perftests", + "//gpu:command_buffer_perftests", + "//gpu:gpu_perftests", + "//media:media_perftests", + "//testing:run_perf_test", ] - } - if (!is_android) { - data_deps += [ "//chrome/test:performance_browser_tests" ] - } + if (build_dawn_tests && !is_chromeos_lacros) { + data_deps += [ "//third_party/dawn/src/tests:dawn_perf_tests" ] + } - if (!is_ios && !is_fuchsia && !is_android) { - data_deps += [ "//net:net_perftests" ] + if (!is_chromeos_lacros) { + data_deps += [ "//third_party/angle/src/tests:angle_perftests" ] + } + + if (!is_android && !is_fuchsia) { + data_deps += [ + "//chrome/test:load_library_perf_tests", + "//ui/views:views_perftests", + ] + } + + if (!is_android) { + data_deps += [ "//chrome/test:performance_browser_tests" ] + } + + if (!is_ios && !is_fuchsia && !is_android) { + data_deps += [ "//net:net_perftests" ] + } + } +} + +performance_test_suite_template("performance_test_suite") { +} + +# Generate performance_test_suite_${board} targets. +# These set --board to ${board} instead of deriving it from the target. +# This is useful for Lacros, where the generic build is deployed to +# many different targets. +if (is_chromeos_device && cros_boards != "") { + foreach(_board, string_split(cros_boards, ":")) { + _board_underscore = string_replace(_board, "-", "_") + performance_test_suite_template( + "performance_test_suite_${_board_underscore}") { + override_board = _board + } } } @@ -4067,6 +4101,13 @@ "../browser/webauthn/chrome_authenticator_request_delegate_unittest.cc", ] } + + if (is_chromeos_ash) { + sources += [ + "../browser/speech/cros_speech_recognition_service_factory_unittest.cc", + ] + } + if (is_chromeos_ash) { sources += [ "../../chromeos/memory/userspace_swap/userspace_swap.cc", @@ -4869,7 +4910,7 @@ "../browser/sharing/sms/sms_remote_fetcher_unittest.cc", "../browser/ui/autofill/payments/local_card_migration_bubble_controller_impl_unittest.cc", "../browser/ui/autofill/payments/save_card_bubble_controller_impl_unittest.cc", - "../browser/ui/autofill/save_address_profile_bubble_controller_unittest.cc", + "../browser/ui/autofill/save_address_profile_bubble_controller_impl_unittest.cc", "../browser/ui/bluetooth/bluetooth_chooser_controller_unittest.cc", "../browser/ui/bluetooth/bluetooth_scanning_prompt_controller_unittest.cc", "../browser/ui/media_router/cast_modes_with_media_sources_unittest.cc",
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/signin/AccountManagerTestRule.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/signin/AccountManagerTestRule.java index fbff5e72..924e367 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/signin/AccountManagerTestRule.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/signin/AccountManagerTestRule.java
@@ -119,6 +119,13 @@ } /** + * Removes an account with the given account email. + */ + public void removeAccount(String accountEmail) { + mFakeAccountManagerFacade.removeAccount(AccountUtils.createAccountFromName(accountEmail)); + } + + /** * Waits for the AccountTrackerService to seed system accounts. */ public void waitForSeeding() { @@ -144,8 +151,8 @@ * * This method invokes native code. It shouldn't be called in a Robolectric test. */ - public void removeAccountAndWaitForSeeding(String accountName) { - mFakeAccountManagerFacade.removeAccount(AccountUtils.createAccountFromName(accountName)); + public void removeAccountAndWaitForSeeding(String accountEmail) { + removeAccount(accountEmail); waitForSeeding(); }
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py index fd05abd..93092907 100755 --- a/chrome/test/chromedriver/test/run_py_tests.py +++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -5104,7 +5104,8 @@ ChromeDriverBaseTestWithWebServer.GlobalSetUp() runner = unittest.TextTestRunner( - stream=sys.stdout, descriptions=False, verbosity=2) + stream=sys.stdout, descriptions=False, verbosity=2, + resultclass=unittest_util.AddSuccessTextTestResult) result = runner.run(test_suite) results = [result] @@ -5128,4 +5129,5 @@ if options.isolated_script_test_output: util.WriteResultToJSONFile(test_suites, results, options.isolated_script_test_output) + util.TryUploadingResultToResultSink(results) sys.exit(len(results[-1].failures) + len(results[-1].errors))
diff --git a/chrome/test/chromedriver/test/unittest_util.py b/chrome/test/chromedriver/test/unittest_util.py index 52363c2..6a3fcd1c 100644 --- a/chrome/test/chromedriver/test/unittest_util.py +++ b/chrome/test/chromedriver/test/unittest_util.py
@@ -128,3 +128,15 @@ else: tests += [test] return tests + + +class AddSuccessTextTestResult(unittest.runner.TextTestResult): + + def __init__(self, stream, descriptions, verbosity): + super(AddSuccessTextTestResult, self).__init__( + stream, descriptions, verbosity) + self.successes = [] + + def addSuccess(self, test): + super(AddSuccessTextTestResult, self).addSuccess(test) + self.successes.append(test)
diff --git a/chrome/test/chromedriver/util.py b/chrome/test/chromedriver/util.py index 32f3c578..16875fd 100644 --- a/chrome/test/chromedriver/util.py +++ b/chrome/test/chromedriver/util.py
@@ -5,11 +5,13 @@ """Generic utilities for all python scripts.""" import atexit +import base64 import httplib import json import os import platform import random +import requests import signal import socket import stat @@ -334,3 +336,59 @@ with open(json_path, 'w') as script_out_file: json.dump(output, script_out_file) script_out_file.write('\n') + + +def TryUploadingResultToResultSink(results): + + def parse(result): + test_results = [] + for test_case in result.successes: + test_results.append({ + 'testId': test_case.id(), + 'expected': True, + 'status': 'PASS', + }) + + for (test_case, stack_trace) in result.failures + result.errors: + test_results.append({ + 'testId': test_case.id(), + 'expected': False, + 'status': 'FAIL', + # Uses <text-artifact> tag to embed the artifact content + # in summaryHtml. + 'summaryHtml': '<p><text-artifact artifact-id="stack_trace"></p>', + # A map of artifacts. The keys are artifact ids which uniquely + # identify an artifact within the test result. + 'artifacts': { + 'stack_trace': { + 'contents': base64.b64encode(stack_trace), + }, + }, + }) + return test_results + + def getResultSinkTestResults(results): + test_results = [] + for r in results: + test_results.extend(parse(r)) + return test_results + + try: + with open(os.environ['LUCI_CONTEXT']) as f: + sink = json.load(f)['result_sink'] + except KeyError: + return + + test_results = getResultSinkTestResults(results) + # Uploads all test results at once. + res = requests.post( + url='http://%s/prpc/luci.resultsink.v1.Sink/ReportTestResults' % sink['address'], + headers={ + 'Content-Type': 'application/json', + 'Accept': 'application/json', + 'Authorization': 'ResultSink %s' % sink['auth_token'], + }, + data=json.dumps({'testResults': test_results}) + ) + res.raise_for_status() +
diff --git a/chrome/test/data/extensions/api_test/scripting/remove_css/file.css b/chrome/test/data/extensions/api_test/scripting/remove_css/file.css new file mode 100644 index 0000000..ff8fd1b --- /dev/null +++ b/chrome/test/data/extensions/api_test/scripting/remove_css/file.css
@@ -0,0 +1,7 @@ +/* Copyright 2021 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. */ + +#main { + color: green !important; +}
diff --git a/chrome/test/data/extensions/api_test/scripting/remove_css/frame1.html b/chrome/test/data/extensions/api_test/scripting/remove_css/frame1.html new file mode 100644 index 0000000..e366406 --- /dev/null +++ b/chrome/test/data/extensions/api_test/scripting/remove_css/frame1.html
@@ -0,0 +1,11 @@ +<html> + <style> + #main { + color: red; + } + </style> + <div id="main"> + Hello. + </div> + <iframe id="frame2" src="frame2.html"></iframe> +</html>
diff --git a/chrome/test/data/extensions/api_test/scripting/remove_css/frame2.html b/chrome/test/data/extensions/api_test/scripting/remove_css/frame2.html new file mode 100644 index 0000000..c6ab9ba --- /dev/null +++ b/chrome/test/data/extensions/api_test/scripting/remove_css/frame2.html
@@ -0,0 +1,11 @@ +<html> + <style> + #main { + color: red; + } + </style> + <div id="main"> + Hello. + </div> + <iframe id="frame3" src="frame3.html"></iframe> +</html>
diff --git a/chrome/test/data/extensions/api_test/scripting/remove_css/frame3.html b/chrome/test/data/extensions/api_test/scripting/remove_css/frame3.html new file mode 100644 index 0000000..70d813f7 --- /dev/null +++ b/chrome/test/data/extensions/api_test/scripting/remove_css/frame3.html
@@ -0,0 +1,11 @@ +<html> + <style> + #main { + color: red; + } + </style> + <div id="main"> + Hello. + </div> + <iframe id="frame4" srcdoc="<style>#main{color:red}</style><div id='main'>Hello.</div>"></iframe> +</html>
diff --git a/chrome/test/data/extensions/api_test/scripting/remove_css/manifest.json b/chrome/test/data/extensions/api_test/scripting/remove_css/manifest.json new file mode 100644 index 0000000..343d51f --- /dev/null +++ b/chrome/test/data/extensions/api_test/scripting/remove_css/manifest.json
@@ -0,0 +1,9 @@ +{ + "version": "1.0.0.0", + "manifest_version": 3, + "name": "removeCSS test", + "description": "Test extension API: scripting.removeCSS", + "background": { "service_worker": "worker.js" }, + "permissions": ["scripting", "webNavigation"], + "host_permissions": ["http://example.com/"] +}
diff --git a/chrome/test/data/extensions/api_test/scripting/remove_css/other.css b/chrome/test/data/extensions/api_test/scripting/remove_css/other.css new file mode 100644 index 0000000..ff8fd1b --- /dev/null +++ b/chrome/test/data/extensions/api_test/scripting/remove_css/other.css
@@ -0,0 +1,7 @@ +/* Copyright 2021 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. */ + +#main { + color: green !important; +}
diff --git a/chrome/test/data/extensions/api_test/scripting/remove_css/test.html b/chrome/test/data/extensions/api_test/scripting/remove_css/test.html new file mode 100644 index 0000000..6a501cf --- /dev/null +++ b/chrome/test/data/extensions/api_test/scripting/remove_css/test.html
@@ -0,0 +1,11 @@ +<html> + <style> + #main { + color: red; + } + </style> + <div id="main"> + Hello. + </div> + <iframe id="frame1" src="frame1.html"></iframe> +</html>
diff --git a/chrome/test/data/extensions/api_test/scripting/remove_css/worker.js b/chrome/test/data/extensions/api_test/scripting/remove_css/worker.js new file mode 100644 index 0000000..16986080 --- /dev/null +++ b/chrome/test/data/extensions/api_test/scripting/remove_css/worker.js
@@ -0,0 +1,317 @@ +// Copyright 2021 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. + +'use strict'; + +// The original color of the page that we're injecting into. +const ORIGINAL_COLOR = 'rgb(255, 0, 0)'; // red + +// The color we inject into the page (first). +const INJECTED_COLOR = 'rgb(0, 128, 0)'; // green + +// A secondary color we inject into the page (so that we can differentiate +// between the original and first injected color). +const INJECTED_COLOR2 = 'rgb(255, 255, 0)'; // yellow + +// CSS to inject, corresopnding to `INJECTED_COLOR`. +const CSS = '#main { color: green !important; }'; +// CSS to inject, corresponding to `INJECTED_COLOR2`. +const CSS2 = CSS.replace('green', 'yellow'); +// A file to inject. This also sets the color to `INJECTED_COLOR`. +const FILE = '/file.css'; + +// Returns the frame IDs from the tab with the given `tabId`. +async function getFrameIds(tabId) { + // TODO(devlin: Promise-ify webNavigation. + let frames = await new Promise(resolve => { + chrome.webNavigation.getAllFrames({tabId}, resolve); + }); + + // Sort frames by frameId. + let sortedFrames = frames.sort( + (a, b) => a.frameId < b.frameId ? -1 : a.frameId > b.frameId ? 1 : 0); + + // Validate the frames - there should be 5 total, and the main frame should + // be first. + chrome.test.assertEq(5, sortedFrames.length); + chrome.test.assertEq(sortedFrames[0].frameId, 0 /*main frame id*/); + chrome.test.assertTrue( + sortedFrames[1].frameId > 0 /* first non-main-frame id */); + + // Return the array of frame IDs. + return sortedFrames.map(frame => frame.frameId); +} + +// Returns the current color of the frame with `frameId` in the tab with +// `tabId`. +async function getCurrentColor(tabId, frameId) { + return await new Promise((resolve) => { + chrome.scripting.executeScript( + { + target: {tabId, frameIds: [frameId]}, + function: () => { + const element = document.getElementById('main'); + const style = getComputedStyle(element); + return style.getPropertyValue('color'); + }, + }, + (scriptResults) => { + chrome.test.assertEq(1, scriptResults.length) + resolve(scriptResults[0].result); + }); + }); +} + +let tabId = -1; +let frameIds = []; + +// `expectedColorsForFrames` holds a snapshot of expected values of the CSS +// colors being inserted/removed, for each of the frame ids. The array is +// sorted in the order of the frame IDs, such that the color at +// `expectedColorsForFrames[0] corresponds to the color for the frame with +// id `frameIds[0]`. Values get validated at the completion of the each test +// below. +// +// Each frame is a child of the frame preceding it. Frames 0 through 3 are +// <iframe src="..."> while frame 4 is <iframe srcdoc="..."> (about:srcdoc). +let expectedColorsForFrames = [ + ORIGINAL_COLOR, ORIGINAL_COLOR, ORIGINAL_COLOR, ORIGINAL_COLOR, + ORIGINAL_COLOR +]; + +// Updates the expected state in `expectedColorsForFrames`. Undefined values in +// `delta` correspond to "no change" in `expectedColorsForFrames`. +function updateExpectedState(delta) { + Object.assign(expectedColorsForFrames, delta); +} + +// Validates that the colors are as expected for each frame. +async function checkColors() { + for (let i = 0; i < frameIds.length; ++i) { + const frameId = frameIds[i]; + let color = await getCurrentColor(tabId, frameId); + chrome.test.assertEq( + expectedColorsForFrames[i], color, + `Improper color value for frame: ${frameId}`); + } +} + +// Helper function to insert CSS. +// TODO(devlin): Remove when chrome.scripting is promisified. +async function insertCSS(args) { + await new Promise(resolve => { + chrome.scripting.insertCSS(args, () => { + chrome.test.assertNoLastError(); + resolve(); + }); + }); +} + +// Helper function to remove CSS. +// TODO(devlin): Remove when chrome.scripting is promisified. +async function removeCSS(args) { + await new Promise(resolve => { + chrome.scripting.removeCSS(args, () => { + chrome.test.assertNoLastError(); + resolve(); + }); + }); +} + +// Loads `url` in a new tab, waits for it to finish loading, and returns the +// tabId of the newly-created tab. +// TODO(https://crbug.com/824647): Update this to use +// test_resources/tabs_util.js when extension service workers support +// modules. +async function createTab(url) { + return new Promise(resolve => { + // Wait for `url` to finish loading. + chrome.tabs.onUpdated.addListener( + async function listener(updatedTabId, {status}) { + if (status != 'complete') + return; + chrome.tabs.onUpdated.removeListener(listener); + + resolve(updatedTabId); + }); + + chrome.tabs.create({url}); + }); +} + +chrome.test.runTests([ + async function loadTab() { + const config = await new Promise(resolve => { + chrome.test.getConfig(resolve); + }); + const testUrl = `http://example.com:${config.testServer.port}` + + '/extensions/api_test/scripting/remove_css/test.html'; + tabId = await createTab(testUrl); + frameIds = await getFrameIds(tabId); + + chrome.test.succeed(); + }, + async function insertCSSShouldSucceed() { + // Insert CSS into every frame. + await insertCSS({target: {tabId, allFrames: true}, css: CSS}); + updateExpectedState( + [INJECTED_COLOR, INJECTED_COLOR, INJECTED_COLOR, + INJECTED_COLOR, INJECTED_COLOR]); + await checkColors(); + chrome.test.succeed(); + }, + async function removeCSSShouldSucceed() { + // When no frame ID is specified, the CSS is removed from the top frame + // Others should be unaffected (and keep the injected color). + await removeCSS({target: {tabId}, css: CSS}); + updateExpectedState([ORIGINAL_COLOR, , , , , ]); + await checkColors(); + chrome.test.succeed(); + }, + async function removeCSSWithDifferentCodeShouldDoNothing() { + // If the specified code differs by even one character, it does not + // match any inserted CSS and therefore nothing is removed. + const slightlyOffCSS = CSS + ' '; + // TODO(devlin): We don't currently return an error if the CSS to remove + // did not match an inserted stylesheet. We could, which would make it + // easier for developers to catch mistakes. + await removeCSS({target: {tabId, allFrames: true}, css: slightlyOffCSS}); + // Note: no change in expected state. + await checkColors(); + chrome.test.succeed(); + }, + async function removeCSSWithDifferentCSSOriginShouldDoNothing() { + // If only the CSS origin differs, nothing is removed. + await removeCSS({target: {tabId, frameIds}, css: CSS, origin: 'USER'}); + await checkColors(); + chrome.test.succeed(); + }, + async function removeCSSWithFrameIdShouldSucceed() { + // When a frame ID is specified, the CSS is removed only from the given + // frame. + await removeCSS( + {target: {tabId, frameIds: [frameIds[1]]}, css: CSS}); + updateExpectedState([ , ORIGINAL_COLOR, , , , ]); + await checkColors(); + chrome.test.succeed(); + }, + async function removeCSSWithAllFramesShouldSucceed() { + // When "allFrames" is set to true, the CSS is removed from all + // frames. + await removeCSS({target: {tabId, allFrames: true}, css: CSS}); + updateExpectedState([ORIGINAL_COLOR, ORIGINAL_COLOR, ORIGINAL_COLOR, + ORIGINAL_COLOR, ORIGINAL_COLOR]); + await checkColors(); + chrome.test.succeed(); + }, + async function insertCSSWithFileShouldSucceed() { + // Insert some CSS using a file (to then be removed). + await insertCSS({target: {tabId, allFrames: true}, files: [FILE]}); + updateExpectedState([INJECTED_COLOR, INJECTED_COLOR, INJECTED_COLOR, + INJECTED_COLOR, INJECTED_COLOR]); + await checkColors(); + chrome.test.succeed(); + }, + async function removeCSSWithFileShouldSucceed() { + // When no frame ID is specified, the CSS is removed from the top frame. + await removeCSS({target: {tabId}, files: [FILE]}); + updateExpectedState([ORIGINAL_COLOR, , , , , ]); + await checkColors(); + chrome.test.succeed(); + }, + async function removeCSSWithDifferentFileShouldDoNothing() { + // The CSS is not removed when passing a different file (even though the + // contents of /file.css and /other.css are identical). + await removeCSS( + {target: {tabId, allFrames: true}, files: ['/other.css']}); + await checkColors(); + chrome.test.succeed(); + }, + async function insertCSSWithDuplicateCodeShouldSucceed() { + // Start by inserting the second CSS (which is a different color) into the + // top frame. + await insertCSS({target: {tabId}, css: CSS2}); + updateExpectedState([INJECTED_COLOR2, , , , , ]); + await checkColors(); + // Then, re-insert the first CSS. The top frame should be updated. + await insertCSS({target: {tabId}, css: CSS}); + updateExpectedState([INJECTED_COLOR, , , , , ]); + await checkColors(); + chrome.test.succeed(); + }, + async function removeCSSWithDuplicateCodeShouldSucceed() { + // Remove the first CSS. The second-inserted CSS should take effect again. + await removeCSS({target: {tabId}, css: CSS}); + updateExpectedState([INJECTED_COLOR2, , , , , ]); + await checkColors(); + + // Remove the second CSS. The color should go back to the original color of + // the frame. + await removeCSS({target: {tabId}, css: CSS2}); + updateExpectedState([ORIGINAL_COLOR, , , , , ]); + await checkColors(); + chrome.test.succeed(); + }, + async function noSuchTab() { + const nonExistentTabId = 99999; + // NOTE(devlin): We can't use a fancy `await` here, because the lastError + // won't be properly set. This will work better with true promise support, + // where this could be wrapped in an e.g. expectThrows(). + chrome.scripting.removeCSS( + { + target: { + tabId: nonExistentTabId, + }, + css: CSS, + }, + async () => { + chrome.test.assertLastError(`No tab with id: ${nonExistentTabId}`); + await checkColors(); + chrome.test.succeed(); + }); + }, + async function noSuchFile() { + const noSuchFile = 'no_such_file.js'; + chrome.scripting.removeCSS( + { + target: {tabId}, + files: [noSuchFile], + }, + async () => { + // Edge case: When removing inserted files, we don't actually read + // the file content (because it's unnecessary, and would be wasteful). + // We also don't fire an error when there was no matching CSS inserted + // (see "removeCSSWithDifferentCodeShouldDoNothing()" test case). This + // combines to mean that even though there's no such file here, we + // don't actually fire an error. This will be fixed if/when we return + // an error for removing a non-existent stylesheet. + chrome.test.assertNoLastError(); + await checkColors(); + chrome.test.succeed(); + }); + }, + async function disallowedPermission() { + const config = await new Promise(resolve => { + chrome.test.getConfig(resolve); + }); + const testUrl = `http://google.com:${config.testServer.port}` + + '/extensions/api_test/scripting/remove_css/test.html'; + tabId = await createTab(testUrl); + // Note: We don't test the expected colors here, because that relies on the + // extension having access to the host (in order to inject the script to + // retrieve the colors), which it doesn't have here. + chrome.scripting.removeCSS( + { + target: {tabId}, + css: CSS, + }, + async () => { + chrome.test.assertLastError( + 'Cannot access contents of the page. ' + + 'Extension manifest must request permission to ' + + 'access the respective host.'); + chrome.test.succeed(); + }); + }, +]);
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json index 3ac4541b..8d41235 100644 --- a/chrome/test/data/policy/policy_test_cases.json +++ b/chrome/test/data/policy/policy_test_cases.json
@@ -6812,6 +6812,11 @@ { "url": "https://xyz.example", "create_desktop_shortcut": true + }, + { + "url": "https://foo.example", + "default_launch_container": "window", + "fallback_app_name": "Foo Example App" } ] },
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn index 387bf22..2989744 100644 --- a/chrome/test/data/webui/BUILD.gn +++ b/chrome/test/data/webui/BUILD.gn
@@ -351,6 +351,8 @@ "$root_gen_dir/chrome/test/data/webui/settings/chromeos/fake_bluetooth.m.js", "$root_gen_dir/chrome/test/data/webui/settings/chromeos/fake_receive_manager.m.js", "$root_gen_dir/chrome/test/data/webui/settings/chromeos/fake_quick_unlock_private.m.js", + "$root_gen_dir/chrome/test/data/webui/settings/chromeos/fake_settings_search_handler.m.js", + "$root_gen_dir/chrome/test/data/webui/settings/chromeos/fake_user_action_recorder.m.js", "$root_gen_dir/chrome/test/data/webui/settings/chromeos/google_assistant_page_test.m.js", "$root_gen_dir/chrome/test/data/webui/settings/chromeos/guest_os_shared_paths_test.m.js", "$root_gen_dir/chrome/test/data/webui/settings/chromeos/guest_os_shared_usb_devices_test.m.js", @@ -390,6 +392,7 @@ "$root_gen_dir/chrome/test/data/webui/settings/chromeos/lock_screen_tests.m.js", "$root_gen_dir/chrome/test/data/webui/settings/chromeos/os_printing_page_tests.m.js", "$root_gen_dir/chrome/test/data/webui/settings/chromeos/os_search_page_test.m.js", + "$root_gen_dir/chrome/test/data/webui/settings/chromeos/os_settings_search_box_test.m.js", "$root_gen_dir/chrome/test/data/webui/settings/chromeos/parental_controls_page_test.m.js", "$root_gen_dir/chrome/test/data/webui/settings/chromeos/people_page_account_manager_test.m.js", "$root_gen_dir/chrome/test/data/webui/settings/chromeos/people_page_change_picture_test.m.js",
diff --git a/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_store_test.js b/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_store_test.js index 1d0a88a..625b4276 100644 --- a/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_store_test.js +++ b/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_store_test.js
@@ -33,11 +33,11 @@ test('one emoji in recently used', () => { store.bumpEmoji(TEST_EMOJI.grin.string); - assertDeepEquals([TEST_EMOJI.grin.codepoints], store.data); + assertDeepEquals([TEST_EMOJI.grin.string], store.data); store.bumpEmoji(TEST_EMOJI.grin.string); assertDeepEquals( - [TEST_EMOJI.grin.codepoints], store.data, + [TEST_EMOJI.grin.string], store.data, 'clicking an existing emoji should not duplicate it'); }); @@ -45,11 +45,11 @@ store.bumpEmoji(TEST_EMOJI.grin.string); store.bumpEmoji(TEST_EMOJI.waving.string); assertDeepEquals( - [TEST_EMOJI.waving.codepoints, TEST_EMOJI.grin.codepoints], store.data); + [TEST_EMOJI.waving.string, TEST_EMOJI.grin.string], store.data); store.bumpEmoji(TEST_EMOJI.grin.string); assertDeepEquals( - [TEST_EMOJI.grin.codepoints, TEST_EMOJI.waving.codepoints], store.data, + [TEST_EMOJI.grin.string, TEST_EMOJI.waving.string], store.data, 'clicking an existing emoji should move it to the front'); }); });
diff --git a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/cellular_setup_test.js b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/cellular_setup_test.js index 4a662c23..f6ef600 100644 --- a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/cellular_setup_test.js +++ b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/cellular_setup_test.js
@@ -10,28 +10,86 @@ // #import {CellularSetupPageName} from 'chrome://resources/cr_components/chromeos/cellular_setup/cellular_types.m.js'; // #import {flush, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -// #import {assertTrue} from '../../../chai_assert.js'; +// #import {assertTrue, assertFalse} from '../../../chai_assert.js'; // #import {FakeCellularSetupDelegate} from './fake_cellular_setup_delegate.m.js'; +// #import {FakeNetworkConfig} from 'chrome://test/chromeos/fake_network_config_mojom.m.js'; +// #import {FakeESimManagerRemote} from 'chrome://test/cr_components/chromeos/cellular_setup/fake_esim_manager_remote.m.js'; +// #import {setESimManagerRemoteForTesting} from 'chrome://resources/cr_components/chromeos/cellular_setup/mojo_interface_provider.m.js'; +// #import {MojoInterfaceProviderImpl} from 'chrome://resources/cr_components/chromeos/network/mojo_interface_provider.m.js'; // clang-format on suite('CrComponentsCellularSetupTest', function() { let cellularSetupPage; + let eSimManagerRemote; + let networkConfigRemote; + setup(function() { + eSimManagerRemote = new cellular_setup.FakeESimManagerRemote(); + cellular_setup.setESimManagerRemoteForTesting(eSimManagerRemote); + + networkConfigRemote = new FakeNetworkConfig(); + network_config.MojoInterfaceProviderImpl.getInstance().remote_ = networkConfigRemote; + }); + + async function flushAsync() { + Polymer.dom.flush(); + // Use setTimeout to wait for the next macrotask. + return new Promise(resolve => setTimeout(resolve)); + } + + function init() { cellularSetupPage = document.createElement('cellular-setup'); cellularSetupPage.delegate = new cellular_setup.FakeCellularSetupDelegate(); document.body.appendChild(cellularSetupPage); Polymer.dom.flush(); + } + + test('Show pSim flow ui if now esim network is available', async function() { + const mojom = chromeos.networkConfig.mojom; + networkConfigRemote.setDeviceStateForTest({ + type: mojom.NetworkType.kCellular, + deviceState: chromeos.networkConfig.mojom.DeviceStateType.kEnabled, + simInfos: [{slot_id: 0, iccid: '1111111111111111'}], + }); + eSimManagerRemote.addEuiccForTest(2); + await flushAsync(); + init(); + + await flushAsync(); + const eSimFlow = cellularSetupPage.$$('esim-flow-ui'); + assertFalse(!!eSimFlow); + const pSimFlow = cellularSetupPage.$$('psim-flow-ui'); + assertTrue(!!pSimFlow); }); - test('Base test', function() { - const ironPage = cellularSetupPage.$$('iron-pages'); - assertTrue(!!ironPage); + test('Show eSIM flow ui if no pSIM networks is available', async function() { + const mojom = chromeos.networkConfig.mojom; + networkConfigRemote.setDeviceStateForTest({ + type: mojom.NetworkType.kCellular, + deviceState: chromeos.networkConfig.mojom.DeviceStateType.kEnabled, + simInfos: [{eid: '2221111112222', slot_id: 0, iccid: '1111111111111111'}], + }); + eSimManagerRemote.addEuiccForTest(2); + await flushAsync(); + + init(); + await flushAsync(); + const pSimFlow = cellularSetupPage.$$('psim-flow-ui'); + assertFalse(!!pSimFlow); + const eSimFlow = cellularSetupPage.$$('esim-flow-ui'); + assertTrue(!!eSimFlow); }); - test('Page selection change', function() { - assertTrue( - cellularSetupPage.currentPageName === - cellularSetup.CellularSetupPageName.SETUP_FLOW_SELECTION); + test('Page selection change', async function() { + const mojom = chromeos.networkConfig.mojom; + networkConfigRemote.setDeviceStateForTest({ + type: mojom.NetworkType.kCellular, + deviceState: chromeos.networkConfig.mojom.DeviceStateType.kEnabled, + simInfos: [{slot_id: 0, iccid: '1111111111111111'}], + }); + eSimManagerRemote.addEuiccForTest(2); + await flushAsync(); + init(); const selectionFlow = cellularSetupPage.$$('setup-selection-flow'); assertTrue(!!selectionFlow);
diff --git a/chrome/test/data/webui/cr_components/chromeos/cr_components_chromeos_browsertest.js b/chrome/test/data/webui/cr_components/chromeos/cr_components_chromeos_browsertest.js index 4d577da9..4cf049f 100644 --- a/chrome/test/data/webui/cr_components/chromeos/cr_components_chromeos_browsertest.js +++ b/chrome/test/data/webui/cr_components/chromeos/cr_components_chromeos_browsertest.js
@@ -71,6 +71,8 @@ ['ButtonBar', 'cellular_setup/button_bar_test.js',[]], ['CellularSetup', 'cellular_setup/cellular_setup_test.js', [ './cellular_setup/fake_cellular_setup_delegate.js', + './cellular_setup/fake_esim_manager_remote.js', + '../../chromeos/fake_network_config_mojom.js', ]], ['EsimFlowUi', 'cellular_setup/esim_flow_ui_test.js',[ './cellular_setup/fake_cellular_setup_delegate.js',
diff --git a/chrome/test/data/webui/histograms/histograms_internals_ui_browsertest.js b/chrome/test/data/webui/histograms/histograms_internals_ui_browsertest.js index af60a639..24954a2 100644 --- a/chrome/test/data/webui/histograms/histograms_internals_ui_browsertest.js +++ b/chrome/test/data/webui/histograms/histograms_internals_ui_browsertest.js
@@ -32,31 +32,39 @@ }; TEST_F('HistogramsInternalsUIBrowserTest', 'RefreshHistograms', function() { - test('check refresh button replaces existing histograms', function() { - return cr.sendWithPromise('requestHistograms', '') - .then(addHistograms) - .finally(() => { + test( + 'check refresh button replaces existing histograms', function() { + const whenRefreshed = new Promise((resolve, reject) => { + document.querySelector('#histograms') + .addEventListener('histograms-updated-for-test', resolve); + }); + document.querySelector('#refresh').click(); + return whenRefreshed.then(() => { const histogramHeader = 'Histogram: HTMLOut recorded 5 samples'; assertEquals( document.body.textContent.indexOf(histogramHeader), document.body.textContent.lastIndexOf(histogramHeader), 'refresh should replace existing histograms'); }); - }); + }); mocha.run(); }); TEST_F('HistogramsInternalsUIBrowserTest', 'NoDummyHistograms', function() { - test('check no dummy histogram is present', function() { - return cr.sendWithPromise('requestHistograms', '') - .then(addHistograms) - .finally(() => { + test( + 'check no dummy histogram is present', function() { + const whenRefreshed = new Promise((resolve, reject) => { + document.querySelector('#histograms') + .addEventListener('histograms-updated-for-test', resolve); + }); + document.querySelector('#refresh').click(); + return whenRefreshed.then(() => { document.querySelectorAll('h4').forEach(header => { assertNotEquals(header.textContent, ''); }); }); - }); + }); mocha.run(); -}); \ No newline at end of file +});
diff --git a/chrome/test/data/webui/invalidations/about_invalidations_browsertest.js b/chrome/test/data/webui/invalidations/about_invalidations_browsertest.js index 20504df..19b4ec5a 100644 --- a/chrome/test/data/webui/invalidations/about_invalidations_browsertest.js +++ b/chrome/test/data/webui/invalidations/about_invalidations_browsertest.js
@@ -25,6 +25,9 @@ '//chrome/test/data/webui/mocha_adapter.js', ], + /** @override */ + isAsync: true, + suiteName: 'invalidations_test', /** @param {string} testName The name of the test to run. */
diff --git a/chrome/test/data/webui/invalidations/invalidations_test.js b/chrome/test/data/webui/invalidations/invalidations_test.js index c02ef2b..3f28f6a 100644 --- a/chrome/test/data/webui/invalidations/invalidations_test.js +++ b/chrome/test/data/webui/invalidations/invalidations_test.js
@@ -62,13 +62,15 @@ {name: 'EXTENSIONS', source: 1004, totalCount: 0}, {name: 'FAVICON_IMAGE', source: 1004, totalCount: 0} ]; - var pattern1 = ['Fake', '1004', 'EXTENSIONS', '0', '0', '', '', '']; - var pattern2 = ['Fake', '1004', 'FAVICON_IMAGE', '0', '0', '', '', '']; + const registrarName = 'Fake'; + var pattern1 = [registrarName, '1004', 'EXTENSIONS', '0', '0', '', '', '']; + var pattern2 = + [registrarName, '1004', 'FAVICON_IMAGE', '0', '0', '', '', '']; // Register two objects ID with 'Fake' registrar - webUIListenerCallback('ids-updated', newDataType); + webUIListenerCallback('ids-updated', registrarName, newDataType); // Disable the Extensions ObjectId by only sending FAVICON_IMAGE newDataType = [{name: 'FAVICON_IMAGE', source: 1004}]; - webUIListenerCallback('ids-updated', newDataType); + webUIListenerCallback('ids-updated', registrarName, newDataType); // Test that the two patterns are contained in the table. var oidTable = $('objectsid-table-container'); @@ -116,7 +118,7 @@ // Test that an object showing internal state is correctly displayed. test(invalidations_test.TestNames.UpdateInternalDisplay, function() { - newDetailedStatus = {MessagesSent: 1}; + const newDetailedStatus = {MessagesSent: 1}; webUIListenerCallback('detailed-status-updated', newDetailedStatus); assertEquals($('internal-display').value, '{\n \"MessagesSent\": 1\n}'); });
diff --git a/chrome/test/data/webui/settings/chromeos/BUILD.gn b/chrome/test/data/webui/settings/chromeos/BUILD.gn index 857fdec..a87e43fa 100644 --- a/chrome/test/data/webui/settings/chromeos/BUILD.gn +++ b/chrome/test/data/webui/settings/chromeos/BUILD.gn
@@ -111,6 +111,7 @@ "os_people_page_test.js", "os_privacy_page_test.js", "os_search_page_test.js", + "os_settings_search_box_test.js", "parental_controls_page_test.js", "people_page_account_manager_test.js", "people_page_change_picture_test.js", @@ -139,6 +140,7 @@ "timezone_subpage_test.js", "tts_subpage_test.js", "user_page_tests.js", + "wallpaper_subpage_test.js", ] namespace_rewrites = os_settings_namespace_rewrites + os_test_namespace_rewrites +
diff --git a/chrome/test/data/webui/settings/chromeos/device_page_tests.js b/chrome/test/data/webui/settings/chromeos/device_page_tests.js index 39ab804..8aa8588 100644 --- a/chrome/test/data/webui/settings/chromeos/device_page_tests.js +++ b/chrome/test/data/webui/settings/chromeos/device_page_tests.js
@@ -676,6 +676,9 @@ let pointersPage; setup(function() { + // TODO(crbug.com/1114828): remove this flag setting once the flag has + // been removed and this suite merged with the PointingStick suite. + loadTimeData.overrideValues({separatePointingStickSettings: false}); return showAndGetDeviceSubpage('pointers', settings.routes.POINTERS) .then(function(page) { pointersPage = page;
diff --git a/chrome/test/data/webui/settings/chromeos/fake_settings_search_handler.js b/chrome/test/data/webui/settings/chromeos/fake_settings_search_handler.js index ca45fa6..45c0e33 100644 --- a/chrome/test/data/webui/settings/chromeos/fake_settings_search_handler.js +++ b/chrome/test/data/webui/settings/chromeos/fake_settings_search_handler.js
@@ -11,7 +11,7 @@ * * @implements {chromeos.settings.mojom.SearchHandlerInterface} */ - class FakeSettingsSearchHandler { + /* #export */ class FakeSettingsSearchHandler { constructor() { /** @private {!Array<chromeos.settings.mojom.SearchResult>} */ this.fakeResults_ = [];
diff --git a/chrome/test/data/webui/settings/chromeos/fake_user_action_recorder.js b/chrome/test/data/webui/settings/chromeos/fake_user_action_recorder.js index 9b70b41..a52879b 100644 --- a/chrome/test/data/webui/settings/chromeos/fake_user_action_recorder.js +++ b/chrome/test/data/webui/settings/chromeos/fake_user_action_recorder.js
@@ -13,7 +13,7 @@ * * @implements {chromeos.settings.mojom.UserActionRecorderInterface} */ - class FakeUserActionRecorder { + /* #export */ class FakeUserActionRecorder { constructor() { this.pageFocusCount = 0; this.pageBlurCount = 0;
diff --git a/chrome/test/data/webui/settings/chromeos/os_namespace_rewrites.gni b/chrome/test/data/webui/settings/chromeos/os_namespace_rewrites.gni index a6e3b36e..9fd7125 100644 --- a/chrome/test/data/webui/settings/chromeos/os_namespace_rewrites.gni +++ b/chrome/test/data/webui/settings/chromeos/os_namespace_rewrites.gni
@@ -12,6 +12,8 @@ "settings.FakeLanguageSettingsPrivate|FakeLanguageSettingsPrivate", "settings.FakeInputMethodPrivate|FakeInputMethodPrivate", "settings.FakeSettingsPrivate|FakeSettingsPrivate", + "settings.FakeSettingsSearchHandler|FakeSettingsSearchHandler", + "settings.FakeUserActionRecorder|FakeUserActionRecorder", "settings.getFakeLanguagePrefs|getFakeLanguagePrefs", "settings.MultiDeviceSettingsMode|MultiDeviceSettingsMode", "settings.TestGuestOsBrowserProxy|TestGuestOsBrowserProxy",
diff --git a/chrome/test/data/webui/settings/chromeos/os_settings_search_box_test.js b/chrome/test/data/webui/settings/chromeos/os_settings_search_box_test.js index 7eff352..b373587 100644 --- a/chrome/test/data/webui/settings/chromeos/os_settings_search_box_test.js +++ b/chrome/test/data/webui/settings/chromeos/os_settings_search_box_test.js
@@ -2,6 +2,18 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// clang-format off +// #import 'chrome://os-settings/chromeos/os_settings.js'; + +// #import {assertEquals, assertFalse, assertNotEquals, assertTrue} from '../../chai_assert.js'; +// #import {flush} from'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +// #import {Router, Route, routes} from 'chrome://os-settings/chromeos/os_settings.js'; +// #import {eventToPromise} from 'chrome://test/test_util.m.js'; +// #import {FakeUserActionRecorder} from './fake_user_action_recorder.m.js'; +// #import {FakeSettingsSearchHandler} from './fake_settings_search_handler.m.js'; +// #import {setSearchHandlerForTesting, setUserActionRecorderForTesting} from 'chrome://os-settings/chromeos/os_settings.js'; +// clang-format on + /** @fileoverview Runs tests for the OS settings search box. */ suite('OSSettingsSearchBox', () => {
diff --git a/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js b/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js index 41bcfd06..42e2fd3b 100644 --- a/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js +++ b/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js
@@ -231,6 +231,26 @@ mocha.run(); }); +// eslint-disable-next-line no-var +var OSSettingsWallpaperSubpageV3Test = class extends OSSettingsV3BrowserTest { + /** @override */ + get browsePreload() { + return 'chrome://os-settings/test_loader.html?module=settings/chromeos/wallpaper_subpage_test.m.js'; + } + + /** @override */ + get featureList() { + return { + enabled: super.featureList.enabled.concat( + ['chromeos::features::kWallpaperWebUI']), + }; + } +}; + +TEST_F('OSSettingsWallpaperSubpageV3Test', 'AllJsTests', () => { + mocha.run(); +}); + [['AccessibilityPage', 'os_a11y_page_tests.m.js'], ['AboutPage', 'os_about_page_tests.m.js'], ['AmbientModePage', 'ambient_mode_page_test.m.js'], @@ -299,6 +319,7 @@ ['OsEditDictionaryPage', 'os_edit_dictionary_page_test.m.js'], ['OsLanguagesPageV2', 'os_languages_page_v2_tests.m.js'], ['OsSearchPage', 'os_search_page_test.m.js'], + ['OsSettingsSearchBox', 'os_settings_search_box_test.m.js'], ['NearbyShareReceiveDialog', 'nearby_share_receive_dialog_tests.m.js'], ['ParentalControlsPage', 'parental_controls_page_test.m.js'], ['PeoplePage', 'os_people_page_test.m.js'],
diff --git a/chrome/test/data/webui/settings/chromeos/test_wallpaper_browser_proxy.js b/chrome/test/data/webui/settings/chromeos/test_wallpaper_browser_proxy.js index fd93225..1a05ec8a 100644 --- a/chrome/test/data/webui/settings/chromeos/test_wallpaper_browser_proxy.js +++ b/chrome/test/data/webui/settings/chromeos/test_wallpaper_browser_proxy.js
@@ -12,6 +12,7 @@ 'isWallpaperSettingVisible', 'isWallpaperPolicyControlled', 'openWallpaperManager', + 'fetchWallpaperCollections', ]); /** @private */ @@ -19,6 +20,13 @@ /** @private */ this.isWallpaperPolicyControlled_ = false; + + /** + * @private + * @type {Array<!WallpaperCollection>} + */ + this.wallpaperCollections_ = + [{id: '0', name: 'zero'}, {id: '1', name: 'one'}]; } /** @override */ @@ -38,10 +46,23 @@ this.methodCalled('openWallpaperManager'); } + /** @override */ + fetchWallpaperCollections() { + this.methodCalled('fetchWallpaperCollections'); + return this.wallpaperCollections_.length ? + Promise.resolve(this.wallpaperCollections_) : + Promise.reject(null); + } + /** @param {boolean} Whether the wallpaper is policy controlled. */ setIsWallpaperPolicyControlled(isPolicyControlled) { this.isWallpaperPolicyControlled_ = isPolicyControlled; } + + /** @param {Array<!WallpaperCollection>} */ + setWallpaperCollections(wallpaperCollections) { + this.wallpaperCollections_ = wallpaperCollections; + } } // #cr_define_end
diff --git a/chrome/test/data/webui/settings/chromeos/wallpaper_subpage_test.js b/chrome/test/data/webui/settings/chromeos/wallpaper_subpage_test.js new file mode 100644 index 0000000..84f7de7 --- /dev/null +++ b/chrome/test/data/webui/settings/chromeos/wallpaper_subpage_test.js
@@ -0,0 +1,100 @@ +// Copyright 2021 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. + +// clang-format off +// #import 'chrome://os-settings/chromeos/os_settings.js'; + +// #import {WallpaperBrowserProxyImpl, routes, Router} from 'chrome://os-settings/chromeos/os_settings.js'; +// #import {TestWallpaperBrowserProxy} from './test_wallpaper_browser_proxy.m.js'; +// #import {assertDeepEquals, assertEquals, assertFalse, assertTrue} from '../../chai_assert.js'; +// #import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +// clang-format on + +suite('All', function() { + /** @type {SettingsWallpaperSubpageElement} */ + let wallpaperSubpage = null; + + /** @type {?settings.TestWallpaperBrowserProxy} */ + let browserProxy = null; + + setup(function() { + browserProxy = new TestWallpaperBrowserProxy(); + settings.WallpaperBrowserProxyImpl.instance_ = browserProxy; + PolymerTest.clearBody(); + }); + + teardown(function() { + if (wallpaperSubpage) { + wallpaperSubpage.remove(); + } + settings.Router.getInstance().resetRouteForTesting(); + }); + + function initPage() { + wallpaperSubpage = document.createElement('settings-wallpaper-page'); + document.body.appendChild(wallpaperSubpage); + flush(); + } + + test( + 'fetches wallpaper collections and shows loading on startup', + async () => { + initPage(); + assertEquals(1, browserProxy.getCallCount('fetchWallpaperCollections')); + + const spinner = wallpaperSubpage.$$('paper-spinner-lite'); + assertTrue(!!spinner); + assertTrue(spinner.active); + assertFalse(spinner.hidden); + + const ironList = wallpaperSubpage.$$('iron-list'); + assertFalse(!!ironList); + }); + + test('shows wallpaper collections when loaded', async () => { + initPage(); + + const spinner = wallpaperSubpage.$$('paper-spinner-lite'); + assertTrue(!!spinner); + assertTrue(spinner.active); + + await browserProxy.whenCalled('fetchWallpaperCollections'); + flush(); + + assertFalse(spinner.active); + assertTrue(spinner.hidden); + + const ironList = wallpaperSubpage.$$('iron-list'); + assertTrue(!!ironList); + + const elements = ironList.querySelectorAll('.wallpaper-collection-title'); + assertEquals(2, elements.length); + + assertDeepEquals(wallpaperSubpage.collections_, [ + {id: '0', name: 'zero'}, + {id: '1', name: 'one'}, + ]); + }); + + test('shows error when fails to load', async () => { + browserProxy.setWallpaperCollections([]); + initPage(); + + const spinner = wallpaperSubpage.$$('paper-spinner-lite'); + assertTrue(spinner.active); + + // No error displayed while loading. + const error = wallpaperSubpage.$$('#error'); + assertTrue(error.hidden); + + await browserProxy.whenCalled('fetchWallpaperCollections'); + Polymer.dom.flush(); + + assertFalse(spinner.active); + assertFalse(error.hidden); + + // No elements should be displayed if there is an error. + assertFalse(!!wallpaperSubpage.$$('iron-list')); + }); +});
diff --git a/chromecast/browser/cast_web_contents.h b/chromecast/browser/cast_web_contents.h index b7fa8fb..437613d 100644 --- a/chromecast/browser/cast_web_contents.h +++ b/chromecast/browser/cast_web_contents.h
@@ -233,6 +233,9 @@ // activity hosted by this CastWebContents. // No filters implies no restrictions. base::Optional<std::vector<std::string>> url_filters = base::nullopt; + // Whether WebRTC peer connections are allowed to use legacy versions of the + // TLS/DTLS protocols. + bool webrtc_allow_legacy_tls_protocols = false; InitParams(); InitParams(const InitParams& other);
diff --git a/chromecast/browser/cast_web_contents_impl.cc b/chromecast/browser/cast_web_contents_impl.cc index 46052f0..046ef39 100644 --- a/chromecast/browser/cast_web_contents_impl.cc +++ b/chromecast/browser/cast_web_contents_impl.cc
@@ -37,6 +37,7 @@ #include "net/base/net_errors.h" #include "services/service_manager/public/cpp/interface_provider.h" #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h" +#include "third_party/blink/public/common/renderer_preferences/renderer_preferences.h" #include "third_party/blink/public/mojom/autoplay/autoplay.mojom.h" #include "third_party/blink/public/mojom/favicon/favicon_url.mojom.h" #include "third_party/blink/public/mojom/loader/resource_load_info.mojom.h" @@ -161,6 +162,11 @@ renderer_type_ == content::mojom::RendererType::MOJO_RENDERER) { renderer_type_ = content::mojom::RendererType::DEFAULT_RENDERER; } + + if (init_params.webrtc_allow_legacy_tls_protocols) { + web_contents_->GetMutableRendererPrefs() + ->webrtc_allow_legacy_tls_protocols = true; + } } CastWebContentsImpl::~CastWebContentsImpl() {
diff --git a/chromecast/browser/extensions/cast_extension_system.cc b/chromecast/browser/extensions/cast_extension_system.cc index d8bf9a7..b0682c4 100644 --- a/chromecast/browser/extensions/cast_extension_system.cc +++ b/chromecast/browser/extensions/cast_extension_system.cc
@@ -19,7 +19,6 @@ #include "extensions/browser/api/app_runtime/app_runtime_api.h" #include "extensions/browser/extension_prefs.h" #include "extensions/browser/extension_registry.h" -#include "extensions/browser/extension_user_script_manager.h" #include "extensions/browser/info_map.h" #include "extensions/browser/null_app_sorting.h" #include "extensions/browser/process_manager.h" @@ -28,6 +27,7 @@ #include "extensions/browser/runtime_data.h" #include "extensions/browser/service_worker_manager.h" #include "extensions/browser/unloaded_extension_reason.h" +#include "extensions/browser/user_script_manager.h" #include "extensions/browser/value_store/value_store_factory_impl.h" #include "extensions/common/api/app_runtime.h" #include "extensions/common/constants.h" @@ -186,8 +186,7 @@ RendererStartupHelperFactory::GetForBrowserContext(browser_context_); - extension_user_script_manager_ = - std::make_unique<ExtensionUserScriptManager>(browser_context_); + user_script_manager_ = std::make_unique<UserScriptManager>(browser_context_); extension_registrar_ = std::make_unique<ExtensionRegistrar>(browser_context_, this); @@ -209,9 +208,8 @@ return service_worker_manager_.get(); } -ExtensionUserScriptManager* -CastExtensionSystem::extension_user_script_manager() { - return extension_user_script_manager_.get(); +UserScriptManager* CastExtensionSystem::user_script_manager() { + return user_script_manager_.get(); } StateStore* CastExtensionSystem::state_store() {
diff --git a/chromecast/browser/extensions/cast_extension_system.h b/chromecast/browser/extensions/cast_extension_system.h index 4261b7f..75a668e 100644 --- a/chromecast/browser/extensions/cast_extension_system.h +++ b/chromecast/browser/extensions/cast_extension_system.h
@@ -68,7 +68,7 @@ RuntimeData* runtime_data() override; ManagementPolicy* management_policy() override; ServiceWorkerManager* service_worker_manager() override; - ExtensionUserScriptManager* extension_user_script_manager() override; + UserScriptManager* user_script_manager() override; StateStore* state_store() override; StateStore* rules_store() override; scoped_refptr<ValueStoreFactory> store_factory() override; @@ -124,7 +124,7 @@ std::unique_ptr<RuntimeData> runtime_data_; std::unique_ptr<QuotaService> quota_service_; std::unique_ptr<AppSorting> app_sorting_; - std::unique_ptr<ExtensionUserScriptManager> extension_user_script_manager_; + std::unique_ptr<UserScriptManager> user_script_manager_; std::unique_ptr<ExtensionRegistrar> extension_registrar_; scoped_refptr<ValueStoreFactory> store_factory_;
diff --git a/chromecast/external_mojo/broker_service/broker_service.cc b/chromecast/external_mojo/broker_service/broker_service.cc index 055f4d7..45606248 100644 --- a/chromecast/external_mojo/broker_service/broker_service.cc +++ b/chromecast/external_mojo/broker_service/broker_service.cc
@@ -76,8 +76,8 @@ } broker_ = base::SequenceBound<ExternalMojoBroker>(io_thread_->task_runner(), GetBrokerPath()); - broker_.Post(FROM_HERE, &ExternalMojoBroker::InitializeChromium, - connector->Clone(), external_services_to_proxy); + broker_.AsyncCall(&ExternalMojoBroker::InitializeChromium) + .WithArgs(connector->Clone(), external_services_to_proxy); } BrokerService::~BrokerService() { @@ -134,8 +134,8 @@ void BrokerService::BindConnector( mojo::PendingReceiver<mojom::ExternalConnector> receiver) { - broker_.Post(FROM_HERE, &ExternalMojoBroker::BindConnector, - std::move(receiver)); + broker_.AsyncCall(&ExternalMojoBroker::BindConnector) + .WithArgs(std::move(receiver)); } mojo::PendingRemote<mojom::ExternalConnector> BrokerService::CreateConnector() {
diff --git a/chromecast/media/audio/mixer_service/mixer_control.cc b/chromecast/media/audio/mixer_service/mixer_control.cc index 935135bcf..d8556c6 100644 --- a/chromecast/media/audio/mixer_service/mixer_control.cc +++ b/chromecast/media/audio/mixer_service/mixer_control.cc
@@ -28,29 +28,29 @@ MixerControl::MixerControl() : control_(AudioIoThread::Get()->task_runner()) { DCHECK(HaveFullMixer()); - control_.Post(FROM_HERE, &ControlConnection::Connect, - ControlConnection::ConnectedCallback()); + control_.AsyncCall(&ControlConnection::Connect) + .WithArgs(ControlConnection::ConnectedCallback()); } MixerControl::~MixerControl() = default; void MixerControl::ConfigurePostprocessor(std::string postprocessor_name, std::string config) { - control_.Post(FROM_HERE, &ControlConnection::ConfigurePostprocessor, - std::move(postprocessor_name), std::move(config)); + control_.AsyncCall(&ControlConnection::ConfigurePostprocessor) + .WithArgs(std::move(postprocessor_name), std::move(config)); } void MixerControl::ListPostprocessors(ListPostprocessorsCallback callback) { - control_.Post(FROM_HERE, &ControlConnection::ListPostprocessors, - std::move(callback)); + control_.AsyncCall(&ControlConnection::ListPostprocessors) + .WithArgs(std::move(callback)); } void MixerControl::ReloadPostprocessors() { - control_.Post(FROM_HERE, &ControlConnection::ReloadPostprocessors); + control_.AsyncCall(&ControlConnection::ReloadPostprocessors); } void MixerControl::SetNumOutputChannels(int num_channels) { - control_.Post(FROM_HERE, &ControlConnection::SetNumOutputChannels, - num_channels); + control_.AsyncCall(&ControlConnection::SetNumOutputChannels) + .WithArgs(num_channels); } } // namespace mixer_service
diff --git a/chromecast/media/cma/backend/cast_audio_json.cc b/chromecast/media/cma/backend/cast_audio_json.cc index b38e0b7b..f79f43f 100644 --- a/chromecast/media/cma/backend/cast_audio_json.cc +++ b/chromecast/media/cma/backend/cast_audio_json.cc
@@ -87,8 +87,8 @@ void CastAudioJsonProviderImpl::SetTuningChangedCallback( TuningChangedCallback callback) { if (cast_audio_watcher_) { - cast_audio_watcher_.Post(FROM_HERE, &FileWatcher::SetTuningChangedCallback, - std::move(callback)); + cast_audio_watcher_.AsyncCall(&FileWatcher::SetTuningChangedCallback) + .WithArgs(std::move(callback)); } }
diff --git a/chromecast/media/cma/backend/mixer/loopback_handler.cc b/chromecast/media/cma/backend/mixer/loopback_handler.cc index 9e6c3995..a972097 100644 --- a/chromecast/media/cma/backend/mixer/loopback_handler.cc +++ b/chromecast/media/cma/backend/mixer/loopback_handler.cc
@@ -160,7 +160,7 @@ void LoopbackHandler::AddConnection( std::unique_ptr<MixerLoopbackConnection> connection) { - io_.Post(FROM_HERE, &LoopbackIO::AddConnection, std::move(connection)); + io_.AsyncCall(&LoopbackIO::AddConnection).WithArgs(std::move(connection)); } void LoopbackHandler::SetDataSize(int data_size_bytes) { @@ -169,8 +169,8 @@ } if (SetDataSizeInternal(data_size_bytes) && sample_rate_ != 0) { - io_.Post(FROM_HERE, &LoopbackIO::SetStreamConfig, format_, sample_rate_, - num_channels_, data_size_); + io_.AsyncCall(&LoopbackIO::SetStreamConfig) + .WithArgs(format_, sample_rate_, num_channels_, data_size_); } } @@ -220,8 +220,8 @@ format_ = format; sample_rate_ = sample_rate; num_channels_ = num_channels; - io_.Post(FROM_HERE, &LoopbackIO::SetStreamConfig, format_, sample_rate_, - num_channels_, data_size_); + io_.AsyncCall(&LoopbackIO::SetStreamConfig) + .WithArgs(format_, sample_rate_, num_channels_, data_size_); } DCHECK_LE(data_size_bytes, data_size_); @@ -229,8 +229,8 @@ auto buffer = buffer_pool_->GetBuffer(); memcpy(buffer->data() + mixer_service::MixerSocket::kAudioMessageHeaderSize, data, data_size_bytes); - io_.Post(FROM_HERE, &LoopbackIO::SendData, std::move(buffer), data_size_bytes, - timestamp); + io_.AsyncCall(&LoopbackIO::SendData) + .WithArgs(std::move(buffer), data_size_bytes, timestamp); } void LoopbackHandler::SendInterruptInternal(LoopbackInterruptReason reason) { @@ -238,7 +238,7 @@ return; } - io_.Post(FROM_HERE, &LoopbackIO::SendInterrupt, reason); + io_.AsyncCall(&LoopbackIO::SendInterrupt).WithArgs(reason); } } // namespace media
diff --git a/chromecast/media/cma/backend/mixer/stream_mixer.cc b/chromecast/media/cma/backend/mixer/stream_mixer.cc index 1630cee..a150358 100644 --- a/chromecast/media/cma/backend/mixer/stream_mixer.cc +++ b/chromecast/media/cma/backend/mixer/stream_mixer.cc
@@ -825,8 +825,8 @@ sfx != last_sent_sfx_stream_count_) { last_sent_primary_stream_count_ = primary; last_sent_sfx_stream_count_ = sfx; - receiver_.Post(FROM_HERE, &MixerServiceReceiver::OnStreamCountChanged, - primary, sfx); + receiver_.AsyncCall(&MixerServiceReceiver::OnStreamCountChanged) + .WithArgs(primary, sfx); } }
diff --git a/chromecast/system/reboot/reboot_fuchsia_test.cc b/chromecast/system/reboot/reboot_fuchsia_test.cc index 8cf0087..d587142 100644 --- a/chromecast/system/reboot/reboot_fuchsia_test.cc +++ b/chromecast/system/reboot/reboot_fuchsia_test.cc
@@ -183,15 +183,15 @@ StateControlRebootReason GetLastRebootReason() { StateControlRebootReason reason; - admin_.Post(FROM_HERE, &FakeAdmin::GetLastRebootReason, &reason); + admin_.AsyncCall(&FakeAdmin::GetLastRebootReason).WithArgs(&reason); thread_.FlushForTesting(); return reason; } void SetLastReboot(fuchsia::feedback::LastReboot last_reboot) { - last_reboot_info_provider_.Post(FROM_HERE, - &FakeLastRebootInfoProvider::SetLastReboot, - std::move(last_reboot)); + last_reboot_info_provider_ + .AsyncCall(&FakeLastRebootInfoProvider::SetLastReboot) + .WithArgs(std::move(last_reboot)); thread_.FlushForTesting(); }
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd index d28da88e..46c5e500 100644 --- a/chromeos/chromeos_strings.grd +++ b/chromeos/chromeos_strings.grd
@@ -610,10 +610,10 @@ Looking for scanners </message> <message name="IDS_SCANNING_APP_NO_SCANNERS_TEXT" desc="The text displayed when there are no available scanners found for scanning"> - No scanner available + No scanners available </message> <message name="IDS_SCANNING_APP_NO_SCANNERS_SUBTEXT" desc="The subtext displayed when there are no available scanners found for scanning"> - Make sure the scanner is turned on and connected + Make sure the scanner is turned on and available via your network or a direct connection </message> <message name="IDS_SCANNING_APP_LEARN_MORE_BUTTON_LABEL" desc="The label for the button that leads to a help support article to learn more about scanning."> Learn more
diff --git a/chromeos/chromeos_strings_grd/IDS_SCANNING_APP_NO_SCANNERS_SUBTEXT.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SCANNING_APP_NO_SCANNERS_SUBTEXT.png.sha1 index b2b0e7b5..9db6b35 100644 --- a/chromeos/chromeos_strings_grd/IDS_SCANNING_APP_NO_SCANNERS_SUBTEXT.png.sha1 +++ b/chromeos/chromeos_strings_grd/IDS_SCANNING_APP_NO_SCANNERS_SUBTEXT.png.sha1
@@ -1 +1 @@ -1be8957ab5755b57bf03a9fa504e51e75cbee9f6 \ No newline at end of file +4a11a5e46357fe7cff90015616a1fdaa929a8b50 \ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SCANNING_APP_NO_SCANNERS_TEXT.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SCANNING_APP_NO_SCANNERS_TEXT.png.sha1 index 2d7d0ac..7a0596d 100644 --- a/chromeos/chromeos_strings_grd/IDS_SCANNING_APP_NO_SCANNERS_TEXT.png.sha1 +++ b/chromeos/chromeos_strings_grd/IDS_SCANNING_APP_NO_SCANNERS_TEXT.png.sha1
@@ -1 +1 @@ -699e14de0f66613efa43a0e36501353eee24cfc2 \ No newline at end of file +4406696638134a3675998d6618b4430cd5b03094 \ No newline at end of file
diff --git a/chromeos/components/diagnostics_ui/BUILD.gn b/chromeos/components/diagnostics_ui/BUILD.gn index 2d93eb1..39aeabb 100644 --- a/chromeos/components/diagnostics_ui/BUILD.gn +++ b/chromeos/components/diagnostics_ui/BUILD.gn
@@ -20,7 +20,7 @@ "//content/public/browser", "//ui/base", "//ui/resources", - "//ui/webui", + "//ui/web_dialogs", ] }
diff --git a/chromeos/components/diagnostics_ui/DEPS b/chromeos/components/diagnostics_ui/DEPS index 3788902..6ea0538 100644 --- a/chromeos/components/diagnostics_ui/DEPS +++ b/chromeos/components/diagnostics_ui/DEPS
@@ -10,5 +10,5 @@ "+ui/gfx", "+ui/resources", "+ui/shell_dialogs", - "+ui/webui", + "+ui/web_dialogs", ]
diff --git a/chromeos/components/diagnostics_ui/backend/system_routine_controller.cc b/chromeos/components/diagnostics_ui/backend/system_routine_controller.cc index 67271ac..e51e2a8 100644 --- a/chromeos/components/diagnostics_ui/backend/system_routine_controller.cc +++ b/chromeos/components/diagnostics_ui/backend/system_routine_controller.cc
@@ -674,9 +674,9 @@ // already disconnected. inflight_routine_runner_.reset(); - // Reset `inflight_routine_timer_` so that we do not attempt to fetch the + // Stop `inflight_routine_timer_` so that we do not attempt to fetch the // status of a cancelled routine. - inflight_routine_timer_.reset(); + inflight_routine_timer_->Stop(); // Make a best effort attempt to remove the routine. BindCrosHealthdDiagnosticsServiceIfNeccessary(); @@ -685,6 +685,10 @@ /*should_include_output=*/false, base::BindOnce(&SystemRoutineController::OnRoutineCancelAttempted, base::Unretained(this))); + + // Reset `inflight_routine_id_` to maintain invariant. + inflight_routine_id_ = kInvalidRoutineId; + if (IsLoggingEnabled()) { routine_log_ptr_->LogRoutineCancelled(); }
diff --git a/chromeos/components/diagnostics_ui/backend/system_routine_controller_unittest.cc b/chromeos/components/diagnostics_ui/backend/system_routine_controller_unittest.cc index 0d21e2b..c0bdf19 100644 --- a/chromeos/components/diagnostics_ui/backend/system_routine_controller_unittest.cc +++ b/chromeos/components/diagnostics_ui/backend/system_routine_controller_unittest.cc
@@ -783,5 +783,52 @@ /*expected_count=*/1); } +TEST_F(SystemRoutineControllerTest, CancelThenStartRoutine) { + const int32_t expected_id = 1; + SetRunRoutineResponse(expected_id, + healthd::DiagnosticRoutineStatusEnum::kRunning); + + auto routine_runner = std::make_unique<FakeRoutineRunner>(); + system_routine_controller_->RunRoutine( + mojom::RoutineType::kCpuStress, + routine_runner->receiver.BindNewPipeAndPassRemote()); + base::RunLoop().RunUntilIdle(); + + // Assert that the first routine is not complete. + EXPECT_TRUE(routine_runner->result.is_null()); + + // Update the status on cros_healthd. + SetNonInteractiveRoutineUpdateResponse( + /*percent_complete=*/0, healthd::DiagnosticRoutineStatusEnum::kCancelled, + mojo::ScopedHandle()); + + // Close the routine_runner + routine_runner.reset(); + base::RunLoop().RunUntilIdle(); + + SetRunRoutineResponse(/*id=*/1, + healthd::DiagnosticRoutineStatusEnum::kRunning); + + FakeRoutineRunner routine_runner_2; + system_routine_controller_->RunRoutine( + mojom::RoutineType::kCpuStress, + routine_runner_2.receiver.BindNewPipeAndPassRemote()); + base::RunLoop().RunUntilIdle(); + + // Assert that the first routine is not complete. + EXPECT_TRUE(routine_runner_2.result.is_null()); + + // Update the status on cros_healthd. + SetNonInteractiveRoutineUpdateResponse( + /*percent_complete=*/100, healthd::DiagnosticRoutineStatusEnum::kPassed, + mojo::ScopedHandle()); + + // After the update interval, the update is fetched and processed. + task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(60)); + EXPECT_FALSE(routine_runner_2.result.is_null()); + VerifyRoutineResult(*routine_runner_2.result, mojom::RoutineType::kCpuStress, + mojom::StandardRoutineResult::kTestPassed); +} + } // namespace diagnostics } // namespace chromeos
diff --git a/chromeos/components/diagnostics_ui/diagnostics_ui.cc b/chromeos/components/diagnostics_ui/diagnostics_ui.cc index 3e705e5e..3b70d05f 100644 --- a/chromeos/components/diagnostics_ui/diagnostics_ui.cc +++ b/chromeos/components/diagnostics_ui/diagnostics_ui.cc
@@ -127,11 +127,16 @@ } // namespace -DiagnosticsUI::DiagnosticsUI( +DiagnosticsDialogUI::DiagnosticsDialogUI( content::WebUI* web_ui, const chromeos::diagnostics::SessionLogHandler::SelectFilePolicyCreator& select_file_policy_creator) - : ui::MojoWebUIController(web_ui, /*enable_chrome_send=*/true) { + : ui::MojoWebDialogUI(web_ui), + session_log_handler_(std::make_unique<diagnostics::SessionLogHandler>( + select_file_policy_creator)) { + diagnostics_manager_ = std::make_unique<diagnostics::DiagnosticsManager>( + session_log_handler_.get()); + auto html_source = base::WrapUnique( content::WebUIDataSource::Create(kChromeUIDiagnosticsAppHost)); html_source->OverrideContentSecurityPolicy( @@ -157,12 +162,12 @@ open_timestamp_ = base::Time::Now(); } -DiagnosticsUI::~DiagnosticsUI() { +DiagnosticsDialogUI::~DiagnosticsDialogUI() { const base::TimeDelta time_open = base::Time::Now() - open_timestamp_; diagnostics::metrics::EmitAppOpenDuration(time_open); } -void DiagnosticsUI::BindInterface( +void DiagnosticsDialogUI::BindInterface( mojo::PendingReceiver<diagnostics::mojom::SystemDataProvider> receiver) { diagnostics::SystemDataProvider* system_data_provider = diagnostics_manager_->GetSystemDataProvider(); @@ -171,7 +176,7 @@ } } -void DiagnosticsUI::BindInterface( +void DiagnosticsDialogUI::BindInterface( mojo::PendingReceiver<diagnostics::mojom::SystemRoutineController> receiver) { diagnostics::SystemRoutineController* system_routine_controller = @@ -181,6 +186,6 @@ } } -WEB_UI_CONTROLLER_TYPE_IMPL(DiagnosticsUI) +WEB_UI_CONTROLLER_TYPE_IMPL(DiagnosticsDialogUI) } // namespace chromeos
diff --git a/chromeos/components/diagnostics_ui/diagnostics_ui.h b/chromeos/components/diagnostics_ui/diagnostics_ui.h index 002956d..b5a3590 100644 --- a/chromeos/components/diagnostics_ui/diagnostics_ui.h +++ b/chromeos/components/diagnostics_ui/diagnostics_ui.h
@@ -11,11 +11,7 @@ #include "chromeos/components/diagnostics_ui/mojom/system_data_provider.mojom-forward.h" #include "chromeos/components/diagnostics_ui/mojom/system_routine_controller.mojom-forward.h" #include "mojo/public/cpp/bindings/pending_receiver.h" -#include "ui/webui/mojo_web_ui_controller.h" - -namespace content { -class WebUI; -} // namespace content +#include "ui/web_dialogs/web_dialog_ui.h" namespace chromeos { namespace diagnostics { @@ -24,17 +20,17 @@ } // namespace diagnostics -// The WebUI for chrome://diagnostics. -class DiagnosticsUI : public ui::MojoWebUIController { +// The WebDialogUI for chrome://diagnostics. +class DiagnosticsDialogUI : public ui::MojoWebDialogUI { public: - DiagnosticsUI( + explicit DiagnosticsDialogUI( content::WebUI* web_ui, const chromeos::diagnostics::SessionLogHandler::SelectFilePolicyCreator& select_file_policy_creator); - ~DiagnosticsUI() override; + ~DiagnosticsDialogUI() override; - DiagnosticsUI(const DiagnosticsUI&) = delete; - DiagnosticsUI& operator=(const DiagnosticsUI&) = delete; + DiagnosticsDialogUI(const DiagnosticsDialogUI&) = delete; + DiagnosticsDialogUI& operator=(const DiagnosticsDialogUI&) = delete; void BindInterface( mojo::PendingReceiver<diagnostics::mojom::SystemDataProvider> receiver);
diff --git a/chromeos/components/diagnostics_ui/resources/battery_status_card.html b/chromeos/components/diagnostics_ui/resources/battery_status_card.html index c40f21e..9a85f29b 100644 --- a/chromeos/components/diagnostics_ui/resources/battery_status_card.html +++ b/chromeos/components/diagnostics_ui/resources/battery_status_card.html
@@ -5,8 +5,8 @@ </style> <diagnostics-card> - <div id="cardTitle" slot="title">[[i18n('batteryTitle')]]</div> - <div id="batteryStatusChipInfo" slot="chip" class="diagnostics-chip"> + <div id="cardTitle" slot="title" aria-describedby="batteryStatusChipInfo">[[i18n('batteryTitle')]]</div> + <div id="batteryStatusChipInfo" slot="chip" class="diagnostics-chip" aria-hidden="true"> [[getDesignedFullCharge_(batteryHealth_.chargeFullDesignMilliampHours)]] </div> <iron-icon slot="icon" icon="[[batteryIcon]]" class$="[[iconClass]]">
diff --git a/chromeos/components/diagnostics_ui/resources/cpu_card.html b/chromeos/components/diagnostics_ui/resources/cpu_card.html index d22e25b..8bf446c 100644 --- a/chromeos/components/diagnostics_ui/resources/cpu_card.html +++ b/chromeos/components/diagnostics_ui/resources/cpu_card.html
@@ -1,8 +1,8 @@ <style include="diagnostics-shared diagnostics-fonts"></style> <diagnostics-card> - <div id="cardTitle" slot="title">[[i18n('cpuTitle')]]</div> - <div id="cpuChipInfo" slot="chip">[[cpuChipInfo_]]</div> + <div id="cardTitle" slot="title" aria-describedby="cpuChipInfo">[[i18n('cpuTitle')]]</div> + <div id="cpuChipInfo" slot="chip" aria-hidden="true">[[cpuChipInfo_]]</div> <iron-icon slot="icon" icon="diagnostics:cpu"></iron-icon> <!-- TODO(michaelcheco): Add i18n string for percent number format --> <realtime-cpu-chart slot="left-panel" id="realtimeCpuChart"
diff --git a/chromeos/components/diagnostics_ui/resources/diagnostics_card.html b/chromeos/components/diagnostics_ui/resources/diagnostics_card.html index 0c45991..79d19d0 100644 --- a/chromeos/components/diagnostics_ui/resources/diagnostics_card.html +++ b/chromeos/components/diagnostics_ui/resources/diagnostics_card.html
@@ -36,13 +36,13 @@ } .card-wrapper { - border: 1px solid var(--diagnostics-border-color); - border-radius: 14px; + border-radius: 8px; + box-shadow: var(--diagnostics-box-shadow); margin: 10px 0; } .data-points { - border-bottom: 1px solid var(--diagnostics-border-color); + border-bottom: 1px solid var(--google-grey-200); display: grid; grid-template-columns: 1fr 0fr 1fr 0fr 1fr; padding-inline: var(--data-point-container-padding); @@ -59,7 +59,7 @@ } .top-section { - border-bottom: 1px solid var(--diagnostics-border-color); + border-bottom: 1px solid var(--google-grey-200); display: flex; margin-top: 16px; }
diff --git a/chromeos/components/diagnostics_ui/resources/diagnostics_shared_css.html b/chromeos/components/diagnostics_ui/resources/diagnostics_shared_css.html index 18354ee..f657794 100644 --- a/chromeos/components/diagnostics_ui/resources/diagnostics_shared_css.html +++ b/chromeos/components/diagnostics_ui/resources/diagnostics_shared_css.html
@@ -1,12 +1,12 @@ <link rel="stylesheet" href="chrome://resources/chromeos/colors/cros_colors.generated.css"> +<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css"> <link rel="stylesheet" href="chrome://resources/css/md_colors.css"> <template> <style include="cr-shared-style diagnostics-fonts"> :host { - /* TODO(michael) Replace temp hex code when colors are finalized. */ - --diagnostics-border-color: #c5c7ca; + --diagnostics-box-shadow: var(--cr-card-shadow); } html {
diff --git a/chromeos/components/scanning/resources/loading_page.html b/chromeos/components/scanning/resources/loading_page.html index ce8d1d8..8c099c5 100644 --- a/chromeos/components/scanning/resources/loading_page.html +++ b/chromeos/components/scanning/resources/loading_page.html
@@ -5,7 +5,6 @@ flex-direction: column; height: calc(100vh - var(--panel-container-margin-top)); justify-content: center; - margin-top: var(--panel-container-margin-top); text-align: center; } @@ -15,14 +14,18 @@ font-size: var(--scanning-scanners-loading-font-size); font-weight: var(--scanning-medium-font-weight); line-height: var(--scanning-scanners-loading-line-height); + margin-bottom: 0; + margin-top: 32px; } #noScannersSubtext { color: var(--scanning-no-scanners-subtext-color); + display: inline-block; font-family: var(--scanning-no-scanners-subtext-font-family); font-size: var(--scanning-no-scanners-subtext-font-size); font-weight: var(--scanning-regular-font-weight); line-height: var(--scanning-no-scanners-subtext-line-height); + margin-top: 16px; } paper-progress { @@ -30,20 +33,28 @@ --paper-progress-container-color: var(--google-blue-200); border-radius: 4px; height: 4px; - margin-top: 12px; - width: 300px; + margin-bottom: 80px; + margin-top: 32px; + width: 256px; } #buttonDiv { margin-top: 32px; + margin-bottom: 32px; + } + + img { + height: 256px; } </style> <div id="loadingContainer"> <div id="loadingDiv" hidden="[[noScannersAvailable_]]"> + <img src="scanners_loading.svg" alt="[[i18n('scannersLoadingText')]]"> <h1>[[i18n('scannersLoadingText')]]</h1> <paper-progress indeterminate></paper-progress> </div> <div id="noScannersDiv" hidden="[[!noScannersAvailable_]]"> + <img src="no_scanners.svg" alt="[[i18n('noScannersText')]]"> <h1>[[i18n('noScannersText')]]</h1> <span id="noScannersSubtext">[[i18n('noScannersSubtext')]]</span> <div id="buttonDiv">
diff --git a/chromeos/components/scanning/resources/no_scanners.svg b/chromeos/components/scanning/resources/no_scanners.svg new file mode 100644 index 0000000..3fee2246 --- /dev/null +++ b/chromeos/components/scanning/resources/no_scanners.svg
@@ -0,0 +1,3 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"> + <g id="Layer_2" data-name="Layer 2"><g><rect width="256" height="256" fill="#fff"/><path d="M101,174.4c.7.6,5,4.4,10.3,3.4s8.3-6.1,8.6-6.7c1.8-3.2,1.4-5.8,3.6-6.8a4,4,0,0,1,4.2.4c2.2,1.7,1.1,6.1.7,8.1a14.5,14.5,0,0,1-2.8,6,15.2,15.2,0,0,1-6.8,4.7,14.5,14.5,0,0,1-8.5,0" fill="none" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><path d="M96.4,201c6.6,0,13.2-.1,19.7-1.4s12.7-2.9,15.8-8.4c1.6-3,1.8-6.6,1.9-10.1a12.3,12.3,0,0,0-.2-2.7,3.3,3.3,0,0,0-1.8-2" fill="none" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><path d="M114.6,189.4a37.4,37.4,0,0,0,5-.7,15.3,15.3,0,0,0,6.7-2.7,14.3,14.3,0,0,0,2.9-3.6,21,21,0,0,0,2.3-6.5c.4-1.8.5-2.9-.1-4.2A5.9,5.9,0,0,0,129,169" fill="none" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><path d="M101,174.4a22.2,22.2,0,0,1,1.5-3.2l.4-.8.9-1.3c1.2-1.9,2.4-3.9,2.5-6.2a2.3,2.3,0,0,0-.4-1.8,2.3,2.3,0,0,0-2.6-.6,6.6,6.6,0,0,0-2.4,1.5c-1.5,1.8-5.8,7.1-11.5,14.4" fill="none" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><path d="M110.6,133l-5.8-12.7-12.2-.5-3.3,10.4" fill="none" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><circle cx="102.6" cy="111.7" r="12.3" fill="#fff" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><path d="M105.3,114.7a8,8,0,0,0,6.1-1.7" fill="none" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><path d="M109,101.9a9.5,9.5,0,0,0-8.6-2c-2.9.7-5.7,1.1-7.7,3.4s-2.2,4.5-2.8,6.3a9.3,9.3,0,0,0-.5,2.9c0,1.5.5,1.2,1.6.8a53.9,53.9,0,0,0,12.1-6.4A55.7,55.7,0,0,0,109,101.9Z" fill="#4285f4"/><path d="M97.1,102.8c-1.2.5-1.9,3-3.3,3.7.2-.1-2.4-1.8-1.4-3.1a17.5,17.5,0,0,1,3.8-3.4l4.8-3.5,4.6-3.6,2.1-1.3a6.5,6.5,0,0,1,2.7-.8A3.2,3.2,0,0,1,113,92a4.2,4.2,0,0,1-.2,3.6,11.2,11.2,0,0,1,3.5-1.2,2.8,2.8,0,0,1,2.2.4,3.1,3.1,0,0,1,.9,1.9c.3,3-1.6,5.7-3.5,8l-1.3,1.1c-.4.1-2-2.3-2.8-2.8-4-2.4-5.7-4.1-14.7-.2" fill="#4285f4"/><path d="M116.4,193.7a42.3,42.3,0,0,0,5.1-.6,16,16,0,0,0,6.7-2.8,10.6,10.6,0,0,0,2.8-3.5,18.9,18.9,0,0,0,2.4-6.5,7.3,7.3,0,0,0-.1-4.2,5.7,5.7,0,0,0-1.5-2" fill="none" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><path d="M100.3,214.2c-14.6,11.9-34.5,13.5-49.2,4.4-17.9-11-20.3-33.1-17.6-46.5,3.9-19.3,20.9-35.3,43.6-40.5a69,69,0,0,1,12.2-1.7,15,15,0,0,0,10.5,6.9,13.7,13.7,0,0,0,11.3-4.2,45.2,45.2,0,0,1,8.8,2.5c18.9,7.4,27.8,25.3,31,32.6l22.2-9.1,18,28.6c-15.3,17.4-35.7,25.4-52.1,19.9a35.1,35.1,0,0,1-14-9.1" fill="none" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><path d="M100.3,214.2c-3.6-12.9-7.3-25.7-11-38.6l-18.9,7.6-.8-16" fill="none" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><polyline points="98.6 206.7 115.5 206.7 117.9 199.3" fill="none" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><path d="M225.1,37.3C200,14,154.9,17.6,131.8,49.7l-.5,2.7,8.9-1.1a3.5,3.5,0,0,1,3.3,1.4l6.5,8.6a3.4,3.4,0,0,1,.5,3.5l-4.2,9.9a3.7,3.7,0,0,1-2.9,2.2l-10.7,1.3a3.2,3.2,0,0,1-3.2-1.4l-2-2.5-12,68.3,21,17.6L227.4,124C250.4,97.3,247.7,58.2,225.1,37.3Z" fill="#d2e3fc"/><path d="M129.5,52.6a3.7,3.7,0,0,0-2.8,2.2l-4.2,9.9a3.4,3.4,0,0,0,.5,3.5l4.5,6.1,3.8-21.9Z" fill="#fbbc05"/><path d="M104.9,166.9l8.7-10.5,3.5-14.8,21,17.5-14.8,5.6-7.6,9.4c-2.5,4-7.7,4.6-10.4,2.2A7.1,7.1,0,0,1,104.9,166.9Z" fill="#d2e3fc" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><circle cx="130.5" cy="146.5" r="14.7" fill="#d2e3fc" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><path d="M113.6,156.1a7.3,7.3,0,0,0,10.5,8.2" fill="#d2e3fc" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><path d="M111.8,74c-6.8-4.7-11.4-4.9-14.5-3.9-6.2,2-6.9,9-13.4,11.6s-10.8.2-15.3-2.1" fill="none" stroke="#e6e7ea" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.63"/><path d="M132.1,134.8a11.9,11.9,0,0,0-12,7.9c-1.9,5.6,1,12.1,6.9,14.7" fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><path d="M186.7,151.3l-.2.2c2.6-1.2,4.6-3.4,6.9-5.1l2.2-1.5a72.3,72.3,0,0,1,8.7-4.6c1.6-.6,4.1-1.7,5.4-.1a2.8,2.8,0,0,1,0,2.9,8.6,8.6,0,0,1-3.1,2.6l-3.8,2.6c-2.5,1.8-5.1,3.5-7.7,5.1l11.8-7.6c1.2-.7,3.3-2,4.7-2.1s2.9.8,2.3,2.5a5.8,5.8,0,0,1-1.8,2.3,61.6,61.6,0,0,1-6.3,4.1c-3.2,1.9-5.4,3.3-8.1,5.1q3.9-2.7,8.1-5.1l4.1-2.3c1.1-.6,3.1-2.2,4.2-1.5,2.6,1.6-.1,4.2-1.1,4.9L199.9,162l8.2-5.2a12.3,12.3,0,0,1,4.6-2.2,1.9,1.9,0,0,1,2.3,1.1,2.7,2.7,0,0,1-.2,2.6,11,11,0,0,1-3.1,2.6c-3.7,2.5-5.4,3.7-9,6.5s-4.2,5.2-7,7.7a19.1,19.1,0,0,1-8.2,4.3" fill="none" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><path d="M187,163.8a14.6,14.6,0,0,0-.9-12.4c-.3-.4,1.1-2.5,1.4-3s1.5-3.3,1.3-4.9a1.8,1.8,0,0,0-1.6-1.8c-1.1-.2-1.9.7-2.7,1.5a50.3,50.3,0,0,0-10.2,15.5" fill="none" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><path d="M208.8,106h0a7.3,7.3,0,0,1,10.2,2.4l9.2,14.9a7.5,7.5,0,0,1-2.5,10.3h0a7.4,7.4,0,0,1-10.3-2.5l-9.1-14.9A7.3,7.3,0,0,1,208.8,106Z" fill="none" stroke="#ea4335" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><circle cx="184.2" cy="73.8" r="30.1" fill="none" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" stroke-dasharray="6"/><path d="M179.8,77.4a8.4,8.4,0,0,1,2.5-3.4,18.3,18.3,0,0,1,4.7-2.4,29.3,29.3,0,0,0,3.8-1.7,5.6,5.6,0,0,0,2-2.5,5.1,5.1,0,0,0,0-4.2,5.7,5.7,0,0,0-3.4-3,5.2,5.2,0,0,0-4.2-.2,8.8,8.8,0,0,0-3.4,2.4l-3-3a11.9,11.9,0,0,1,5.3-3.4,9.8,9.8,0,0,1,6.9.4,12.2,12.2,0,0,1,4.4,3.2,9.2,9.2,0,0,1,1.4,9.4,8.5,8.5,0,0,1-3.1,3.8,23.8,23.8,0,0,1-4.8,2.2,12.6,12.6,0,0,0-3.3,1.7,7.7,7.7,0,0,0-1.9,2.7l-.8,1.9-4-1.7Zm-4.7,11.1a3.4,3.4,0,0,1,1.8-4.2,3.3,3.3,0,0,1,4.1,1.8,2.5,2.5,0,0,1,0,2.4,2.9,2.9,0,0,1-1.7,1.7,2.5,2.5,0,0,1-2.4,0A3.3,3.3,0,0,1,175.1,88.5Z" fill="#4285f4"/><circle cx="231.5" cy="152.7" r="4" fill="#f882ff"/><path d="M83.4,131.1c4.3,8.6,12.9,13.3,20.8,11.9s10.7-6.6,11.7-8" fill="none" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/></g></g> +</svg> \ No newline at end of file
diff --git a/chromeos/components/scanning/resources/scanners_loading.svg b/chromeos/components/scanning/resources/scanners_loading.svg new file mode 100644 index 0000000..8cddbed8 --- /dev/null +++ b/chromeos/components/scanning/resources/scanners_loading.svg
@@ -0,0 +1,3 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"><g id="Layer_2" data-name="Layer 2"> +<g><rect width="256" height="256" fill="#fff"/><path d="M95.5,186.8H28.8a3.8,3.8,0,0,1-3.9-3.9V41.6a3.8,3.8,0,0,1,3.9-3.9h95.9a3.9,3.9,0,0,1,4,3.9V154.9Z" fill="#d2e3fc"/><path d="M152,160.6l20.4-3.9a141.7,141.7,0,0,0,0,32,135.2,135.2,0,0,0,3.3,18H160.4a169.4,169.4,0,0,1-6-24.1A173.1,173.1,0,0,1,152,160.6Z" fill="#d2e3fc" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><path d="M171,156.3l-18.8,3.5c-2.9.1-8.9,2.8-13.4,6.2a62.6,62.6,0,0,0-12.6,12.8" fill="none" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><path d="M165.2,145.6c.7,1.8,1.7,4.7,3,8.3s2.1,4.9,1.8,6.6-3.2,6.1-6.9,5.7a6.5,6.5,0,0,1-5.7-6.2c-.2-2.2-.3-4.4-.5-6.6a8.4,8.4,0,0,0,4.9-1.5A8.9,8.9,0,0,0,165.2,145.6Z" fill="#fff" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><ellipse cx="155.2" cy="143.1" rx="10.9" ry="10.8" transform="translate(-6.8 278.4) rotate(-82.5)" fill="#fff" stroke="#4285f4" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M144.1,139.7l8.4-4.9,13.4,9c1.5-5.3-2.5-10.8-8.4-12.1S144.8,133.9,144.1,139.7Z" fill="#4285f4"/><path d="M149.1,146.1a4,4,0,0,0,2,2.3,3.2,3.2,0,0,0,3.5-1.1" fill="none" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><g id="Sleeve"><path d="M177.9,158.3c1.9-3.7,13.9-2.1,21.7.9,12,4.7,25.5,17.4,27,33.7,1.9,20.4-15.1,41.9-40.9,46.1l-13.5-34.8L194,196a33.7,33.7,0,0,0-1.7-10c-2.5-7-6.7-10.7-12.6-22C177.8,160.4,177.4,159.3,177.9,158.3Z" fill="#fff"/><path d="M169.4,156.6l1.6-.3c27.9-5.3,52.7,13.7,55.3,36.1,2.4,20.8-15,43.4-40.9,46.2l-13.5-34.8,21.8-8.3-2.3-10" fill="none" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/></g><path id="Had_Fill" data-name="Had Fill" d="M159.1,130.7c-.8-1.9-3.8-2.7-7-2.9a37.2,37.2,0,0,0-17-.2,36.2,36.2,0,0,0-12.1,5.1,40.1,40.1,0,0,0-13.9,14c-4.3,7.3-6.4,16.3-5.4,20.9a29.8,29.8,0,0,1,.7,4.4,24.3,24.3,0,0,1-.4,6l19.2-10c-.1-.5-.5-2-1.1-4s-.9-3.2-.6-4,.8-1.5,3-2.1a36.9,36.9,0,0,0,2.9-2.8,29.7,29.7,0,0,0,6.5-10.8,16.6,16.6,0,0,1,7.8-3.7c4.7-.8,9,1,10.6-1.2a2.4,2.4,0,0,0,.5-1.5,5.3,5.3,0,0,0,3.7-2.4,2.3,2.3,0,0,0,.5-1h.1a3.2,3.2,0,0,0,1.9-1.6A3.1,3.1,0,0,0,159.1,130.7Z" fill="#fff"/><g id="Hand_Srtoke" data-name="Hand Srtoke"><path d="M129.4,134.1a39.2,39.2,0,0,1,13.2-3.1c4.6-.3,13.3,0,14.1,3a3,3,0,0,1-.6,2.2,5.2,5.2,0,0,1-3.6,2.3" fill="#fff" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><path d="M121.1,160.1a30.9,30.9,0,0,0,5.1-3.6c7.1-6.1,5.6-10.8,10.5-13.8s13.7.4,15.6-3.3a2.7,2.7,0,0,0,.2-2.2c-1.4-3.4-11.6-2.1-13.4-1.8a38.9,38.9,0,0,0-9.8,2.5" fill="none" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><path d="M129.7,131.2a61.1,61.1,0,0,1,12.8-2.6c3.8-.3,14.7-1.2,16.2,2.7a2.9,2.9,0,0,1-.1,2.3,3,3,0,0,1-1.9,1.5" fill="none" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><path d="M150.9,127.5a36.7,36.7,0,0,0-29.3,4.8,40.2,40.2,0,0,0-14,15.7,36,36,0,0,0-3.6,11.1" fill="none" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/></g><path d="M127,182.7c-1.9-7.6-3.9-15.1-5.9-22.6l-27.5.5c-10,20.9-2.8,43,11.5,50.2s28.7-1.8,30.3-2.7" fill="#fff" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><g id="Scope"><path d="M121.1,216.4l-9.4-18.1a8.1,8.1,0,0,1,4-8.5,8.2,8.2,0,0,1,9.2.8c3.7,5.6,7.6,12.1,11.3,17.7" fill="#fff" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><path d="M140.3,209.2l-8.9-17.8a8.1,8.1,0,0,1,13.3-7.5l11.5,19.4" fill="#fff" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><path d="M127,195.9a3.5,3.5,0,0,1,1.6-3.9,3.7,3.7,0,0,1,4.7.8l4.2,7.8-6.1,3.3Z" fill="#fff" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><ellipse cx="134.6" cy="202.5" rx="3.5" ry="3.3" transform="translate(-29.1 22.7) rotate(-8.7)" fill="#fff" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><path d="M128.3,198.3a7.4,7.4,0,0,0-12.1,8.4" fill="none" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><path d="M148.9,191a7.6,7.6,0,0,0-8.6-2.9,7.8,7.8,0,0,0-4.5,9.5" fill="none" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><circle cx="129.3" cy="213.4" r="8.7" fill="#7cb1f2" stroke="#4285f4" stroke-miterlimit="10" stroke-width="2"/><circle cx="148.8" cy="207.8" r="8.7" fill="#7cb1f2" stroke="#4285f4" stroke-miterlimit="10" stroke-width="2"/></g><path id="Hand_Fill" data-name="Hand Fill" d="M149.9,224.8l-4.5,1.1.8,4.1,34.1-2.9c-2.2-5.5-4.3-11-6.5-16.4h-6.7c-9-.2-10.5-.9-14.1-.9-9.9.2-19.3,6.3-21.5,10.2a2.4,2.4,0,0,0-.4,1.9c0,.2.1.3.2.5l1.4-.4a6.3,6.3,0,0,0-1.2,2.6,3.2,3.2,0,0,0,0,2.5,4.7,4.7,0,0,0,.9,1l.4-.2a1.4,1.4,0,0,0-.2.6,3.6,3.6,0,0,0,1.5,3.1,4.5,4.5,0,0,0,4.7-.3,3.7,3.7,0,0,0,1,2.2c2.2,2.2,6.5-1.2,15.1-2.1,6.8-.6,8.3,0,13.8-1a53.5,53.5,0,0,0,11.6-3.2C172.5,224.5,161.8,222.3,149.9,224.8Z" fill="#fff"/><g id="Hand"><path d="M174.2,210.8h-7.1c-8.9-.2-10.5-.9-14-.9-9.9.2-19.3,6.3-21.5,10.2a3,3,0,0,0-.5,1.9l.3.5" fill="none" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><path d="M180.4,227.2a53.5,53.5,0,0,1-11.6,3.2c-5.5,1-7,.4-13.8,1-8.6.9-12.9,4.3-15.2,2.1a3.8,3.8,0,0,1-.9-2.8c.6-3.4,7.2-4.9,11.1-5.8a42.2,42.2,0,0,1,7.4-1" fill="none" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><path d="M154.4,218.9a55.1,55.1,0,0,0-10.2,2.4c-5,1.7-11.2,3.8-11.5,7.2a3.8,3.8,0,0,0,1.4,3.1,4.7,4.7,0,0,0,4.9-.4" fill="none" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><path d="M151.3,214.8a88.7,88.7,0,0,0-9.1,2c-4.3,1.2-6.1,2.1-7.7,3.4a8.8,8.8,0,0,0-2.9,4.4,3.2,3.2,0,0,0,0,2.5,4.7,4.7,0,0,0,.9,1" fill="none" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/></g><line x1="191.4" y1="185.5" x2="190.7" y2="196" fill="#4285f4" stroke="#4285f4" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M155.6,92.4l-1.2,6.2,3.7-1-.4-1.7A6.6,6.6,0,0,0,155.6,92.4Z" fill="#39b54a"/><path d="M159.3,103.2l-.9-4.3-3.6,1a1.4,1.4,0,0,1-1.3-.3h-.1a1.3,1.3,0,0,1-.3-1.2l1.3-6.7a6.7,6.7,0,0,0-4.2-.5l-7.3,1.6a6.4,6.4,0,0,0-4.8,7.5l1.7,7.3a6.3,6.3,0,0,0,7.4,4.8l7.4-1.6A6.3,6.3,0,0,0,159.3,103.2Z" fill="#34a853"/><path d="M157.5,82.6l12.8,11.6-12.2,3.4.3,1.3,12.3-3.4a1.5,1.5,0,0,0,.6-2.3.1.1,0,0,1-.1-.1L158.4,81.6a1.7,1.7,0,0,0-1.4-.3,1.7,1.7,0,0,0-.9,1.1l-1.7,9.2,1.2.8Z" fill="#4285f4"/><circle cx="241.2" cy="99.8" r="4" fill="#f882ff"/><line x1="24.2" y1="200.5" x2="94.4" y2="200.5" fill="none" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><line x1="157.8" y1="206.7" x2="172" y2="206.7" fill="none" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><line x1="225.5" y1="208" x2="235.9" y2="208" fill="none" stroke="#4285f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><path d="M171.7,85.3h0a6,6,0,0,1,3.6-7.8l13.3-5.2a6.1,6.1,0,0,1,7.9,3.4h0a6.2,6.2,0,0,1-3.6,7.9l-13.3,5.1A6.1,6.1,0,0,1,171.7,85.3Z" fill="#fbbc05"/><path d="M212.7,88a5.9,5.9,0,0,0,1.9-.5l2.1-.4a6.6,6.6,0,0,1,5.3.8,14.8,14.8,0,0,0,2.7,1.6,5.9,5.9,0,1,0,4.1-10.9,34.2,34.2,0,0,0-4.6-.4,6.8,6.8,0,0,1-4.2-2.1l-1.4-1.6-1.4-1.4a7.9,7.9,0,0,0-3.8-1.8,8.4,8.4,0,0,0-9.6,5.3,8.6,8.6,0,0,0,5.5,11.1A10,10,0,0,0,212.7,88Z" fill="#d2e3fc"/><path d="M162.1,122a8,8,0,0,1,12.2,8.6,5.8,5.8,0,0,1,1.4-1.3,8,8,0,0,1,11,1.9h0a2.9,2.9,0,0,0,4.1.5l.5-.3a8,8,0,0,1,9.9,1.1,6.6,6.6,0,0,1,1.4,2,2.7,2.7,0,0,0,4.1.9l4.7-3.5a5.9,5.9,0,0,1,9.4,3.7h0a5.9,5.9,0,0,1-7.7,6.7L206,140a2.7,2.7,0,0,0-3.3,1.5,8.5,8.5,0,0,1-2.6,3.1,8,8,0,0,1-11-1.9h0a2.8,2.8,0,0,0-4-.6l-.3.2a7.9,7.9,0,0,1-12.2-8.5,8.6,8.6,0,0,1-1.4,1.3,7.9,7.9,0,0,1-11-2A8,8,0,0,1,162.1,122Z" fill="#4285f4"/><path d="M33.4,31.9H25.7a7.6,7.6,0,0,0-7.8,7.3v7.3" fill="none" stroke="aqua" stroke-linecap="round" stroke-linejoin="round" stroke-width="3"/><path d="M120.9,32.4h7.7a7.6,7.6,0,0,1,7.8,7.3v7.2" fill="none" stroke="aqua" stroke-linecap="round" stroke-linejoin="round" stroke-width="3"/><path d="M34.2,192.3H26.4a7.6,7.6,0,0,1-7.7-7.3v-7.3" fill="none" stroke="aqua" stroke-linecap="round" stroke-linejoin="round" stroke-width="3"/><path d="M74.8,55.1A8.5,8.5,0,0,0,71,63.4a11,11,0,0,0,1.6,5.3,6.8,6.8,0,0,0,4.5,3,6.9,6.9,0,0,0,6.2-2.6,11.6,11.6,0,0,0,2.4-6.6,9.2,9.2,0,0,0-1.2-5.7,6.7,6.7,0,0,0-4.4-2.9,8,8,0,0,0-5.3,1.2" fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="3"/><path d="M71.5,59.3a24.6,24.6,0,0,1-4.8,7.6c-1.8,1.7-4.8,3.2-7.4,3" fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="3"/><path d="M89,55.9c-4.5,8.2-4,18-5.2,27.2a27,27,0,0,1-3.1,10.1c-2.3,3.7-7.2,6.8-11.6,5.2A6.7,6.7,0,0,1,65,90.6a14.6,14.6,0,0,1,3.3-5.8c4.8-5.2,11.9-7.2,18.6-9s14.3-3.3,20.5-7.1" fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="3"/><rect x="18.7" y="83.6" width="115.7" height="4.41" fill="#4285f4"/><line x1="47" y1="110.4" x2="110.5" y2="110.4" fill="#fff" stroke="#fff" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><line x1="47" y1="136.1" x2="110.5" y2="136.1" fill="#fff" stroke="#fff" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><line x1="47" y1="123" x2="110.5" y2="123" fill="#fff" stroke="#fff" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></g></g> +</svg> \ No newline at end of file
diff --git a/chromeos/components/scanning/resources/scanning_app_resources.grd b/chromeos/components/scanning/resources/scanning_app_resources.grd index aa24fb59..ccae2e2b 100644 --- a/chromeos/components/scanning/resources/scanning_app_resources.grd +++ b/chromeos/components/scanning/resources/scanning_app_resources.grd
@@ -47,6 +47,8 @@ <include name="IDR_SCANNING_APP_ICON_128" file="scanning_app_icon_128.png" type="BINDATA" /> <include name="IDR_SCANNING_APP_ICON_192" file="scanning_app_icon_192.png" type="BINDATA" /> <include name="IDR_SCANNING_APP_ICON_256" file="scanning_app_icon_256.png" type="BINDATA" /> + <include name="IDR_SCANNING_APP_SCANNERS_LOADING_SVG" file="scanners_loading.svg" type="BINDATA" /> + <include name="IDR_SCANNING_APP_NO_SCANNERS_SVG" file="no_scanners.svg" type="BINDATA" /> </includes> <structures>
diff --git a/chromeos/services/assistant/BUILD.gn b/chromeos/services/assistant/BUILD.gn index 92639d4..155ef69 100644 --- a/chromeos/services/assistant/BUILD.gn +++ b/chromeos/services/assistant/BUILD.gn
@@ -57,7 +57,6 @@ "//components/prefs", "//components/signin/public/identity_manager", "//components/user_manager", - "//media", "//services/media_session/public/cpp", "//ui/accessibility:ax_assistant", ] @@ -67,8 +66,8 @@ "//chromeos/services/assistant/public/cpp", "//chromeos/services/assistant/public/mojom", "//chromeos/services/assistant/public/shared", - "//mojo/public/cpp/bindings:bindings", - "//services/audio/public/cpp:cpp", + "//mojo/public/cpp/bindings", + "//services/audio/public/cpp", ] if (enable_cros_libassistant) { @@ -83,24 +82,10 @@ "assistant_settings_impl.h", "libassistant_service_host_impl.cc", "libassistant_service_host_impl.h", - "platform/audio_device_owner.cc", - "platform/audio_device_owner.h", - "platform/audio_input_impl.cc", - "platform/audio_input_impl.h", - "platform/audio_media_data_source.cc", - "platform/audio_media_data_source.h", - "platform/audio_output_provider_impl.cc", - "platform/audio_output_provider_impl.h", - "platform/audio_stream.cc", - "platform/audio_stream.h", - "platform/audio_stream_handler.cc", - "platform/audio_stream_handler.h", "platform/file_provider_impl.cc", "platform/file_provider_impl.h", "platform/network_provider_impl.cc", "platform/network_provider_impl.h", - "platform/volume_control_impl.cc", - "platform/volume_control_impl.h", "platform_api_impl.cc", "platform_api_impl.h", "utils.cc", @@ -144,7 +129,6 @@ ":test_support", "//ash/constants", "//ash/public/cpp/assistant/test_support", - "//ash/public/mojom", "//base", "//base/test:test_support", "//chromeos/audio", @@ -184,7 +168,6 @@ sources += [ "assistant_device_settings_delegate_unittest.cc", "assistant_manager_service_impl_unittest.cc", - "platform/audio_output_provider_impl_unittest.cc", "platform/network_provider_impl_unittest.cc", "test_support/fake_service_context.cc", "test_support/fake_service_context.h", @@ -200,7 +183,6 @@ "//chromeos/services/assistant/public/cpp/migration", "//chromeos/services/assistant/public/cpp/migration:test_support", "//chromeos/services/network_config/public/mojom", - "//services/audio/public/cpp:test_support", ] } }
diff --git a/chromeos/services/assistant/DEPS b/chromeos/services/assistant/DEPS index c2d8a0a8..8fcf8c8 100644 --- a/chromeos/services/assistant/DEPS +++ b/chromeos/services/assistant/DEPS
@@ -5,7 +5,6 @@ "+components/signin", "+google_apis/gaia", "+libassistant", - "+media/audio", "+media/base", "+mojo/public", "+services/audio/public",
diff --git a/chromeos/services/assistant/assistant_manager_service_delegate_impl.cc b/chromeos/services/assistant/assistant_manager_service_delegate_impl.cc index dab643f..1bf4d4b 100644 --- a/chromeos/services/assistant/assistant_manager_service_delegate_impl.cc +++ b/chromeos/services/assistant/assistant_manager_service_delegate_impl.cc
@@ -38,14 +38,10 @@ std::unique_ptr<CrosPlatformApi> AssistantManagerServiceDelegateImpl::CreatePlatformApi( - mojo::PendingRemote<chromeos::libassistant::mojom::AudioOutputDelegate> - audio_output_delegate, - chromeos::libassistant::mojom::PlatformDelegate* platform_delegate, - scoped_refptr<base::SingleThreadTaskRunner> background_thread_task_runner) { - return std::make_unique<PlatformApiImpl>( - std::move(audio_output_delegate), platform_delegate, - context_->power_manager_client(), context_->main_task_runner(), - background_thread_task_runner); + chromeos::libassistant::mojom::PlatformDelegate* platform_delegate) { + return std::make_unique<PlatformApiImpl>(platform_delegate, + context_->power_manager_client(), + context_->main_task_runner()); } std::unique_ptr<assistant_client::AssistantManager>
diff --git a/chromeos/services/assistant/assistant_manager_service_delegate_impl.h b/chromeos/services/assistant/assistant_manager_service_delegate_impl.h index 2684231..6bc7ee5 100644 --- a/chromeos/services/assistant/assistant_manager_service_delegate_impl.h +++ b/chromeos/services/assistant/assistant_manager_service_delegate_impl.h
@@ -26,10 +26,7 @@ mojo::PendingRemote<chromeos::libassistant::mojom::AudioInputController> pending_remote) override; std::unique_ptr<CrosPlatformApi> CreatePlatformApi( - mojo::PendingRemote<chromeos::libassistant::mojom::AudioOutputDelegate> - audio_output_delegate, - chromeos::libassistant::mojom::PlatformDelegate* platform_delegate, - scoped_refptr<base::SingleThreadTaskRunner> background_thread_task_runner) + chromeos::libassistant::mojom::PlatformDelegate* platform_delegate) override; std::unique_ptr<assistant_client::AssistantManager> CreateAssistantManager( assistant_client::PlatformApi* platform_api,
diff --git a/chromeos/services/assistant/assistant_manager_service_impl.cc b/chromeos/services/assistant/assistant_manager_service_impl.cc index 21a39a7..6d545e8 100644 --- a/chromeos/services/assistant/assistant_manager_service_impl.cc +++ b/chromeos/services/assistant/assistant_manager_service_impl.cc
@@ -244,10 +244,7 @@ device_id_override, ShouldPutLogsInHomeDirectory())), weak_factory_(this) { - platform_api_ = delegate_->CreatePlatformApi( - audio_output_delegate_->BindNewPipeAndPassRemote(), - platform_delegate_.get(), - assistant_proxy_->background_thread().task_runner()); + platform_api_ = delegate_->CreatePlatformApi(platform_delegate_.get()); if (libassistant_service_host) { // During unittests a custom host is passed in, so we'll use that one. @@ -271,8 +268,8 @@ assistant_proxy_->AddSpeechRecognitionObserver( speech_recognition_observer_->BindNewPipeAndPassRemote()); + audio_output_delegate_->Bind(assistant_proxy_->ExtractAudioOutputDelegate()); platform_delegate_->Bind(assistant_proxy_->ExtractPlatformDelegate()); - audio_input_host_ = delegate_->CreateAudioInputHost( assistant_proxy_->ExtractAudioInputController());
diff --git a/chromeos/services/assistant/platform/audio_input_impl.cc b/chromeos/services/assistant/platform/audio_input_impl.cc deleted file mode 100644 index ab9a4832..0000000 --- a/chromeos/services/assistant/platform/audio_input_impl.cc +++ /dev/null
@@ -1,464 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chromeos/services/assistant/platform/audio_input_impl.h" - -#include <utility> - -#include "base/bind.h" -#include "base/logging.h" -#include "base/memory/weak_ptr.h" -#include "base/metrics/histogram_functions.h" -#include "base/optional.h" -#include "base/stl_util.h" -#include "base/strings/string_util.h" -#include "base/timer/timer.h" -#include "chromeos/services/assistant/platform/audio_stream.h" -#include "chromeos/services/assistant/public/cpp/assistant_client.h" -#include "chromeos/services/assistant/public/cpp/features.h" -#include "chromeos/services/assistant/utils.h" -#include "libassistant/shared/public/platform_audio_buffer.h" -#include "media/audio/audio_device_description.h" -#include "media/base/audio_parameters.h" -#include "media/base/audio_sample_types.h" -#include "media/base/channel_layout.h" -#include "services/audio/public/cpp/device_factory.h" -#include "services/audio/public/mojom/stream_factory.mojom.h" - -namespace chromeos { -namespace assistant { - -namespace { - -constexpr assistant_client::BufferFormat kFormatMono{ - 16000 /* sample_rate */, assistant_client::INTERLEAVED_S16, 1 /* channels */ -}; - -constexpr assistant_client::BufferFormat kFormatStereo{ - 44100 /* sample_rate */, assistant_client::INTERLEAVED_S16, 2 /* channels */ -}; - -assistant_client::BufferFormat g_current_format = kFormatMono; - -class DspHotwordStateManager : public AudioInputImpl::HotwordStateManager { - public: - DspHotwordStateManager(AudioInputImpl* input, - scoped_refptr<base::SequencedTaskRunner> task_runner) - : AudioInputImpl::HotwordStateManager(input), task_runner_(task_runner) { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - } - - // HotwordStateManager overrides: - // Runs on main thread. - void OnConversationTurnStarted() override { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - if (second_phase_timer_.IsRunning()) { - DCHECK(stream_state_ == StreamState::HOTWORD); - second_phase_timer_.Stop(); - } else { - // Handles user click on mic button. - input_->RecreateAudioInputStream(false /* use_dsp */); - } - stream_state_ = StreamState::NORMAL; - } - - // Runs on main thread. - void OnConversationTurnFinished() override { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - input_->RecreateAudioInputStream(true /* use_dsp */); - if (stream_state_ == StreamState::HOTWORD) { - // If |stream_state_| remains unchanged, that indicates the first stage - // DSP hotword detection was rejected by Libassistant. - RecordDspHotwordDetection(DspHotwordDetectionStatus::SOFTWARE_REJECTED); - } - stream_state_ = StreamState::HOTWORD; - } - - // Runs on audio service thread - void OnCaptureDataArrived() override { - // Posting to main thread to avoid timer's sequence check error. - task_runner_->PostTask( - FROM_HERE, - base::BindOnce(&DspHotwordStateManager::OnCaptureDataArrivedMainThread, - weak_factory_.GetWeakPtr())); - } - - void RecreateAudioInputStream() override { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - input_->RecreateAudioInputStream(stream_state_ == StreamState::HOTWORD); - } - - // Runs on main thread. - void OnCaptureDataArrivedMainThread() { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - if (stream_state_ == StreamState::HOTWORD && - !second_phase_timer_.IsRunning()) { - RecordDspHotwordDetection(DspHotwordDetectionStatus::HARDWARE_ACCEPTED); - // 1s from now, if OnConversationTurnStarted is not called, we assume that - // libassistant has rejected the hotword supplied by DSP. Thus, we reset - // and reopen the device on hotword state. - second_phase_timer_.Start( - FROM_HERE, base::TimeDelta::FromSeconds(1), - base::BindRepeating( - &DspHotwordStateManager::OnConversationTurnFinished, - base::Unretained(this))); - } - } - - private: - enum class StreamState { - HOTWORD, - NORMAL, - }; - - // Defines possible detection states of Dsp hotword. These values are - // persisted to logs. Entries should not be renumbered and numeric values - // should never be reused. Only append to this enum is allowed if the possible - // source grows. - enum class DspHotwordDetectionStatus { - HARDWARE_ACCEPTED = 0, - SOFTWARE_REJECTED = 1, - kMaxValue = SOFTWARE_REJECTED - }; - - // Helper function to record UMA metrics for Dsp hotword detection. - void RecordDspHotwordDetection(DspHotwordDetectionStatus status) { - base::UmaHistogramEnumeration("Assistant.DspHotwordDetection", status); - } - - scoped_refptr<base::SequencedTaskRunner> task_runner_; - StreamState stream_state_ = StreamState::HOTWORD; - base::OneShotTimer second_phase_timer_; - base::WeakPtrFactory<DspHotwordStateManager> weak_factory_{this}; - - DISALLOW_COPY_AND_ASSIGN(DspHotwordStateManager); -}; - -class AudioInputBufferImpl : public assistant_client::AudioBuffer { - public: - AudioInputBufferImpl(const void* data, uint32_t frame_count) - : data_(data), frame_count_(frame_count) {} - ~AudioInputBufferImpl() override = default; - - // assistant_client::AudioBuffer overrides: - assistant_client::BufferFormat GetFormat() const override { - return g_current_format; - } - const void* GetData() const override { return data_; } - void* GetWritableData() override { - NOTREACHED(); - return nullptr; - } - int GetFrameCount() const override { return frame_count_; } - - private: - const void* data_; - int frame_count_; - DISALLOW_COPY_AND_ASSIGN(AudioInputBufferImpl); -}; - -} // namespace - -AudioInputImpl::HotwordStateManager::HotwordStateManager( - AudioInputImpl* audio_input) - : input_(audio_input) {} - -void AudioInputImpl::HotwordStateManager::RecreateAudioInputStream() { - input_->RecreateAudioInputStream(/*use_dsp=*/false); -} - -AudioInputImpl::AudioInputImpl( - chromeos::libassistant::mojom::PlatformDelegate* platform_delegate, - const std::string& device_id) - : task_runner_(base::SequencedTaskRunnerHandle::Get()), - platform_delegate_(platform_delegate), - preferred_device_id_(device_id), - weak_factory_(this) { - DETACH_FROM_SEQUENCE(observer_sequence_checker_); - - DCHECK(platform_delegate); - - RecreateStateManager(); - if (features::IsStereoAudioInputEnabled()) - g_current_format = kFormatStereo; - else - g_current_format = kFormatMono; -} - -AudioInputImpl::~AudioInputImpl() { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - StopRecording(); -} - -void AudioInputImpl::RecreateStateManager() { - if (IsHotwordAvailable()) { - state_manager_ = - std::make_unique<DspHotwordStateManager>(this, task_runner_); - } else { - state_manager_ = std::make_unique<HotwordStateManager>(this); - } -} - -// Runs on audio service thread. -void AudioInputImpl::Capture(const media::AudioBus* audio_source, - base::TimeTicks audio_capture_time, - double volume, - bool key_pressed) { - DCHECK_EQ(g_current_format.num_channels, audio_source->channels()); - - state_manager_->OnCaptureDataArrived(); - - std::vector<int16_t> buffer(audio_source->channels() * - audio_source->frames()); - audio_source->ToInterleaved<media::SignedInt16SampleTypeTraits>( - audio_source->frames(), buffer.data()); - int64_t time = 0; - // Only provide accurate timestamp when eraser is enabled, otherwise it seems - // break normal libassistant voice recognition. - if (features::IsAudioEraserEnabled()) - time = audio_capture_time.since_origin().InMicroseconds(); - AudioInputBufferImpl input_buffer(buffer.data(), audio_source->frames()); - { - base::AutoLock lock(lock_); - for (auto* observer : observers_) - observer->OnAudioBufferAvailable(input_buffer, time); - } - - captured_frames_count_ += audio_source->frames(); - if (VLOG_IS_ON(1)) { - auto now = base::TimeTicks::Now(); - if ((now - last_frame_count_report_time_) > - base::TimeDelta::FromMinutes(2)) { - VLOG(1) << "Captured frames: " << captured_frames_count_; - last_frame_count_report_time_ = now; - } - } -} - -// Runs on audio service thread. -void AudioInputImpl::OnCaptureError(const std::string& message) { - LOG(ERROR) << "Capture error " << message; - base::AutoLock lock(lock_); - for (auto* observer : observers_) - observer->OnAudioError(AudioInput::Error::FATAL_ERROR); -} - -// Runs on audio service thread. -void AudioInputImpl::OnCaptureMuted(bool is_muted) {} - -// Run on LibAssistant thread. -assistant_client::BufferFormat AudioInputImpl::GetFormat() const { - return g_current_format; -} - -// Run on LibAssistant thread. -void AudioInputImpl::AddObserver( - assistant_client::AudioInput::Observer* observer) { - DCHECK_CALLED_ON_VALID_SEQUENCE(observer_sequence_checker_); - VLOG(1) << " add observer"; - - bool have_first_observer = false; - { - base::AutoLock lock(lock_); - observers_.push_back(observer); - have_first_observer = observers_.size() == 1; - } - - if (have_first_observer) { - // Post to main thread runner to start audio recording. Assistant thread - // does not have thread context defined in //base and will fail sequence - // check in AudioCapturerSource::Start(). - task_runner_->PostTask(FROM_HERE, - base::BindOnce(&AudioInputImpl::UpdateRecordingState, - weak_factory_.GetWeakPtr())); - } -} - -// Run on LibAssistant thread. -void AudioInputImpl::RemoveObserver( - assistant_client::AudioInput::Observer* observer) { - DCHECK_CALLED_ON_VALID_SEQUENCE(observer_sequence_checker_); - VLOG(1) << "Remove observer"; - - bool have_no_observer = false; - { - base::AutoLock lock(lock_); - base::Erase(observers_, observer); - have_no_observer = observers_.size() == 0; - } - - if (have_no_observer) { - task_runner_->PostTask(FROM_HERE, - base::BindOnce(&AudioInputImpl::UpdateRecordingState, - weak_factory_.GetWeakPtr())); - - // Reset the sequence checker since assistant may call from different thread - // after restart. - DETACH_FROM_SEQUENCE(observer_sequence_checker_); - } -} - -void AudioInputImpl::SetMicState(bool mic_open) { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - if (mic_open_ == mic_open) - return; - - mic_open_ = mic_open; - UpdateRecordingState(); -} - -void AudioInputImpl::OnConversationTurnStarted() { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - state_manager_->OnConversationTurnStarted(); -} - -void AudioInputImpl::OnConversationTurnFinished() { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - state_manager_->OnConversationTurnFinished(); -} - -void AudioInputImpl::OnHotwordEnabled(bool enable) { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - - if (hotword_enabled_ == enable) - return; - - hotword_enabled_ = enable; - UpdateRecordingState(); -} - -void AudioInputImpl::SetDeviceId(const std::string& device_id) { - if (preferred_device_id_ == device_id) - return; - - preferred_device_id_ = device_id; - - UpdateRecordingState(); - if (HasOpenAudioStream()) - state_manager_->RecreateAudioInputStream(); -} - -void AudioInputImpl::SetHotwordDeviceId(const std::string& device_id) { - if (hotword_device_id_ == device_id) - return; - - hotword_device_id_ = device_id; - RecreateStateManager(); - if (HasOpenAudioStream()) - state_manager_->RecreateAudioInputStream(); -} - -void AudioInputImpl::OnLidStateChanged(LidState new_state) { - // Lid switch event still gets fired during system suspend, which enables - // us to stop DSP recording correctly when user closes lid after the device - // goes to sleep. - if (new_state != lid_state_) { - lid_state_ = new_state; - UpdateRecordingState(); - } -} - -void AudioInputImpl::RecreateAudioInputStream(bool use_dsp) { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - StopRecording(); - - open_audio_stream_ = std::make_unique<AudioStream>( - platform_delegate_, GetDeviceId(use_dsp), - ShouldEnableDeadStreamDetection(use_dsp), GetFormat(), - /*capture_callback=*/this); - - VLOG(1) << open_audio_stream_->device_id() << " start recording"; -} - -bool AudioInputImpl::IsHotwordAvailable() const { - return features::IsDspHotwordEnabled() && !hotword_device_id_.empty(); -} - -bool AudioInputImpl::IsRecordingForTesting() const { - return HasOpenAudioStream(); -} - -bool AudioInputImpl::IsUsingHotwordDeviceForTesting() const { - return IsRecordingForTesting() // IN-TEST - && GetOpenDeviceId() == hotword_device_id_ && IsHotwordAvailable(); -} - -base::Optional<std::string> AudioInputImpl::GetOpenDeviceIdForTesting() const { - return GetOpenDeviceId(); -} - -base::Optional<bool> AudioInputImpl::IsUsingDeadStreamDetectionForTesting() - const { - if (!open_audio_stream_) - return base::nullopt; - return open_audio_stream_->has_dead_stream_detection(); -} - -void AudioInputImpl::StartRecording() { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - DCHECK(!HasOpenAudioStream()); - RecreateAudioInputStream(IsHotwordAvailable()); -} - -void AudioInputImpl::StopRecording() { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - if (open_audio_stream_) { - VLOG(1) << open_audio_stream_->device_id() << " stop recording"; - VLOG(1) << open_audio_stream_->device_id() - << " ending captured frames: " << captured_frames_count_; - open_audio_stream_.reset(); - } -} - -void AudioInputImpl::UpdateRecordingState() { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - - bool has_observers = false; - { - base::AutoLock lock(lock_); - has_observers = observers_.size() > 0; - } - - bool is_lid_closed = (lid_state_ == LidState::kClosed); - bool should_enable_hotword = - hotword_enabled_ && (!preferred_device_id_.empty()); - bool should_start = - !is_lid_closed && (should_enable_hotword || mic_open_) && has_observers; - - if (!HasOpenAudioStream() && should_start) - StartRecording(); - else if (HasOpenAudioStream() && !should_start) - StopRecording(); -} - -std::string AudioInputImpl::GetDeviceId(bool use_dsp) const { - if (use_dsp && !hotword_device_id_.empty()) - return hotword_device_id_; - else if (!preferred_device_id_.empty()) - return preferred_device_id_; - else - return media::AudioDeviceDescription::kDefaultDeviceId; -} - -base::Optional<std::string> AudioInputImpl::GetOpenDeviceId() const { - if (!open_audio_stream_) - return base::nullopt; - return open_audio_stream_->device_id(); -} - -bool AudioInputImpl::ShouldEnableDeadStreamDetection(bool use_dsp) const { - if (use_dsp && !hotword_device_id_.empty()) { - // The DSP device won't provide data until it detects a hotword, so - // we disable its dead stream detection. - return false; - } - return true; -} - -bool AudioInputImpl::HasOpenAudioStream() const { - return open_audio_stream_ != nullptr; -} - -} // namespace assistant -} // namespace chromeos
diff --git a/chromeos/services/assistant/platform/audio_input_impl.h b/chromeos/services/assistant/platform/audio_input_impl.h deleted file mode 100644 index e81842dd..0000000 --- a/chromeos/services/assistant/platform/audio_input_impl.h +++ /dev/null
@@ -1,164 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROMEOS_SERVICES_ASSISTANT_PLATFORM_AUDIO_INPUT_IMPL_H_ -#define CHROMEOS_SERVICES_ASSISTANT_PLATFORM_AUDIO_INPUT_IMPL_H_ - -#include <memory> -#include <string> -#include <vector> - -#include "base/component_export.h" -#include "base/macros.h" -#include "base/observer_list.h" -#include "base/optional.h" -#include "base/sequence_checker.h" -#include "base/synchronization/lock.h" -#include "base/time/time.h" -#include "chromeos/services/assistant/public/cpp/assistant_service.h" -#include "chromeos/services/libassistant/public/mojom/platform_delegate.mojom-forward.h" -#include "libassistant/shared/public/platform_audio_input.h" -#include "media/base/audio_capturer_source.h" - -namespace chromeos { -namespace assistant { - -class AudioStream; - -class COMPONENT_EXPORT(ASSISTANT_SERVICE) AudioInputImpl - : public assistant_client::AudioInput, - public media::AudioCapturerSource::CaptureCallback { - public: - enum class LidState { - kOpen, - kClosed, - }; - - explicit AudioInputImpl( - chromeos::libassistant::mojom::PlatformDelegate* platform_delegate, - const std::string& device_id); - ~AudioInputImpl() override; - - class HotwordStateManager { - public: - explicit HotwordStateManager(AudioInputImpl* audio_input_); - virtual ~HotwordStateManager() = default; - virtual void OnConversationTurnStarted() {} - virtual void OnConversationTurnFinished() {} - virtual void OnCaptureDataArrived() {} - virtual void RecreateAudioInputStream(); - - protected: - AudioInputImpl* input_; - - private: - DISALLOW_COPY_AND_ASSIGN(HotwordStateManager); - }; - - void RecreateStateManager(); - - // media::AudioCapturerSource::CaptureCallback overrides: - void Capture(const media::AudioBus* audio_source, - base::TimeTicks audio_capture_time, - double volume, - bool key_pressed) override; - void OnCaptureError(const std::string& message) override; - void OnCaptureMuted(bool is_muted) override; - - // assistant_client::AudioInput overrides. These function are called by - // assistant from assistant thread, for which we should not assume any - // //base related thread context to be in place. - assistant_client::BufferFormat GetFormat() const override; - void AddObserver(assistant_client::AudioInput::Observer* observer) override; - void RemoveObserver( - assistant_client::AudioInput::Observer* observer) override; - - // Called when the mic state associated with the interaction is changed. - void SetMicState(bool mic_open); - void OnConversationTurnStarted(); - void OnConversationTurnFinished(); - - // Called when hotword enabled status changed. - void OnHotwordEnabled(bool enable); - - void SetDeviceId(const std::string& device_id); - void SetHotwordDeviceId(const std::string& device_id); - - // Called when the user opens/closes the lid. - void OnLidStateChanged(LidState new_state); - - void RecreateAudioInputStream(bool use_dsp); - - bool IsHotwordAvailable() const; - - // Returns the recording state used in unittests. - bool IsRecordingForTesting() const; - // Returns if the hotword device is used for recording now. - bool IsUsingHotwordDeviceForTesting() const; - // Returns the id of the device that is currently recording audio. - // Returns nullopt if no audio is being recorded. - base::Optional<std::string> GetOpenDeviceIdForTesting() const; - // Returns if dead stream detection is being used for the current audio - // recording. Returns nullopt if no audio is being recorded. - base::Optional<bool> IsUsingDeadStreamDetectionForTesting() const; - - private: - void StartRecording(); - void StopRecording(); - void UpdateRecordingState(); - - std::string GetDeviceId(bool use_dsp) const; - base::Optional<std::string> GetOpenDeviceId() const; - bool ShouldEnableDeadStreamDetection(bool use_dsp) const; - bool HasOpenAudioStream() const; - - // User explicitly requested to open microphone. - bool mic_open_ = false; - - // Whether hotword is currently enabled. - bool hotword_enabled_ = true; - - // Guards observers_; - base::Lock lock_; - std::vector<assistant_client::AudioInput::Observer*> observers_ - GUARDED_BY(lock_); - - // This is the total number of frames captured during the life time of this - // object. We don't worry about overflow because this count is only used for - // logging purposes. If in the future this changes, we should re-evaluate. - int captured_frames_count_ = 0; - base::TimeTicks last_frame_count_report_time_; - - // To be initialized on assistant thread the first call to AddObserver. - // It ensures that AddObserver / RemoveObserver are called on the same - // sequence. - SEQUENCE_CHECKER(observer_sequence_checker_); - - scoped_refptr<base::SequencedTaskRunner> task_runner_; - - std::unique_ptr<HotwordStateManager> state_manager_; - - // Owned by |AssistantManagerServiceImpl|. - chromeos::libassistant::mojom::PlatformDelegate* const platform_delegate_; - - // Preferred audio input device which will be used for capture. - std::string preferred_device_id_; - // Hotword input device used for hardware based hotword detection. - std::string hotword_device_id_; - - // Currently open audio stream. nullptr if no audio stream is open. - std::unique_ptr<AudioStream> open_audio_stream_; - - // Start with lidstate |kClosed| so we do not open the microphone before we - // know if the lid is open or closed. - LidState lid_state_ = LidState::kClosed; - - base::WeakPtrFactory<AudioInputImpl> weak_factory_; - DISALLOW_COPY_AND_ASSIGN(AudioInputImpl); -}; - -} // namespace assistant -} // namespace chromeos - -#endif // CHROMEOS_SERVICES_ASSISTANT_PLATFORM_AUDIO_INPUT_IMPL_H_
diff --git a/chromeos/services/assistant/platform/audio_output_delegate_impl.cc b/chromeos/services/assistant/platform/audio_output_delegate_impl.cc index f650424..701c4d64 100644 --- a/chromeos/services/assistant/platform/audio_output_delegate_impl.cc +++ b/chromeos/services/assistant/platform/audio_output_delegate_impl.cc
@@ -14,6 +14,11 @@ AudioOutputDelegateImpl::~AudioOutputDelegateImpl() = default; +void AudioOutputDelegateImpl::Bind( + mojo::PendingReceiver<AudioOutputDelegate> pending_receiver) { + receiver_.Bind(std::move(pending_receiver)); +} + void AudioOutputDelegateImpl::RequestAudioFocus( libassistant::mojom::AudioOutputStreamType stream_type) { // TODO(wutao): Fix the libassistant behavior. @@ -45,10 +50,5 @@ media_session_->AddObserver(std::move(observer)); } -mojo::PendingRemote<chromeos::libassistant::mojom::AudioOutputDelegate> -AudioOutputDelegateImpl::BindNewPipeAndPassRemote() { - return receiver_.BindNewPipeAndPassRemote(); -} - } // namespace assistant } // namespace chromeos
diff --git a/chromeos/services/assistant/platform/audio_output_delegate_impl.h b/chromeos/services/assistant/platform/audio_output_delegate_impl.h index 55d36ad..8b89e04 100644 --- a/chromeos/services/assistant/platform/audio_output_delegate_impl.h +++ b/chromeos/services/assistant/platform/audio_output_delegate_impl.h
@@ -23,6 +23,8 @@ AudioOutputDelegateImpl& operator=(const AudioOutputDelegateImpl&) = delete; ~AudioOutputDelegateImpl() override; + void Bind(mojo::PendingReceiver<AudioOutputDelegate> pending_receiver); + // libassistant::mojom::AudioOutputDelegate implementation: void RequestAudioFocus( libassistant::mojom::AudioOutputStreamType stream_type) override; @@ -31,9 +33,6 @@ mojo::PendingRemote<::media_session::mojom::MediaSessionObserver> observer) override; - mojo::PendingRemote<chromeos::libassistant::mojom::AudioOutputDelegate> - BindNewPipeAndPassRemote(); - private: mojo::Receiver<AudioOutputDelegate> receiver_{this}; AssistantMediaSession* const media_session_;
diff --git a/chromeos/services/assistant/platform/audio_stream.cc b/chromeos/services/assistant/platform/audio_stream.cc deleted file mode 100644 index 4fa1c5de..0000000 --- a/chromeos/services/assistant/platform/audio_stream.cc +++ /dev/null
@@ -1,109 +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 "chromeos/services/assistant/platform/audio_stream.h" -#include "base/notreached.h" -#include "chromeos/services/assistant/buildflags.h" -#include "chromeos/services/libassistant/public/mojom/platform_delegate.mojom.h" - -#if BUILDFLAG(ENABLE_FAKE_ASSISTANT_MICROPHONE) -#include "chromeos/services/assistant/platform/fake_input_device.h" -#endif // BUILDFLAG(ENABLE_FAKE_ASSISTANT_MICROPHONE) - -namespace chromeos { -namespace assistant { - -namespace { - -media::ChannelLayout GetChannelLayout( - const assistant_client::BufferFormat& format) { - switch (format.num_channels) { - case 1: - return media::ChannelLayout::CHANNEL_LAYOUT_MONO; - case 2: - return media::ChannelLayout::CHANNEL_LAYOUT_STEREO; - default: - NOTREACHED(); - return media::ChannelLayout::CHANNEL_LAYOUT_UNSUPPORTED; - } -} - -} // namespace - -AudioStream::AudioStream( - chromeos::libassistant::mojom::PlatformDelegate* platform_delegate, - const std::string& device_id, - bool detect_dead_stream, - assistant_client::BufferFormat buffer_format, - media::AudioCapturerSource::CaptureCallback* capture_callback) - : device_id_(device_id), - detect_dead_stream_(detect_dead_stream), - buffer_format_(buffer_format), - platform_delegate_(platform_delegate), - capture_callback_(capture_callback) { - Start(); -} - -AudioStream::~AudioStream() { - Stop(); -} - -const std::string& AudioStream::device_id() const { - return device_id_; -} - -bool AudioStream::has_dead_stream_detection() const { - return detect_dead_stream_; -} - -void AudioStream::Start() { - mojo::PendingRemote<audio::mojom::StreamFactory> audio_stream_factory; - - platform_delegate_->BindAudioStreamFactory( - audio_stream_factory.InitWithNewPipeAndPassReceiver()); - -#if BUILDFLAG(ENABLE_FAKE_ASSISTANT_MICROPHONE) - source_ = CreateFakeInputDevice(); -#else - source_ = audio::CreateInputDevice(std::move(audio_stream_factory), - device_id(), DeadStreamDetection()); -#endif // BUILDFLAG(ENABLE_FAKE_ASSISTANT_MICROPHONE) - - source_->Initialize(GetAudioParameters(), capture_callback_); - source_->Start(); -} - -void AudioStream::Stop() { - if (source_) { - source_->Stop(); - source_.reset(); - } -} - -audio::DeadStreamDetection AudioStream::DeadStreamDetection() const { - return detect_dead_stream_ ? audio::DeadStreamDetection::kEnabled - : audio::DeadStreamDetection::kDisabled; -} - -media::AudioParameters AudioStream::GetAudioParameters() const { - // Provide buffer size for 100 ms - int frames_per_buffer = buffer_format_.sample_rate / 10; - - // AUDIO_PCM_LINEAR and AUDIO_PCM_LOW_LATENCY are the same on CRAS. - auto result = - media::AudioParameters(media::AudioParameters::AUDIO_PCM_LOW_LATENCY, - GetChannelLayout(buffer_format_), - buffer_format_.sample_rate, frames_per_buffer); - - // Set the HOTWORD mask so CRAS knows the device is used for HOTWORD purpose - // and is able to conduct the tuning specifically for the scenario. Whether - // the HOTWORD is conducted by a hotword device or other devices like - // internal mic will be determined by the device_id passed to CRAS. - result.set_effects(media::AudioParameters::PlatformEffectsMask::HOTWORD); - - return result; -} - -} // namespace assistant -} // namespace chromeos
diff --git a/chromeos/services/assistant/platform/audio_stream.h b/chromeos/services/assistant/platform/audio_stream.h deleted file mode 100644 index eb81ba9..0000000 --- a/chromeos/services/assistant/platform/audio_stream.h +++ /dev/null
@@ -1,62 +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 CHROMEOS_SERVICES_ASSISTANT_PLATFORM_AUDIO_STREAM_H_ -#define CHROMEOS_SERVICES_ASSISTANT_PLATFORM_AUDIO_STREAM_H_ - -#include <string> - -#include "base/memory/scoped_refptr.h" -#include "base/memory/weak_ptr.h" -#include "chromeos/services/libassistant/public/mojom/platform_delegate.mojom-forward.h" -#include "libassistant/shared/public/platform_audio_buffer.h" -#include "media/base/audio_capturer_source.h" -#include "services/audio/public/cpp/device_factory.h" - -namespace chromeos { -namespace assistant { - -// A single audio stream. All captured packets will be sent to the given -// capture callback. -// The audio stream will be opened as soon as this class is created, and -// will be closed in the destructor. -class AudioStream { - public: - AudioStream( - chromeos::libassistant::mojom::PlatformDelegate* platform_delegate, - const std::string& device_id, - bool detect_dead_stream, - assistant_client::BufferFormat buffer_format, - media::AudioCapturerSource::CaptureCallback* capture_callback); - AudioStream(const AudioStream&) = delete; - AudioStream& operator=(const AudioStream&) = delete; - ~AudioStream(); - - const std::string& device_id() const; - - bool has_dead_stream_detection() const; - - private: - void Start(); - - void Stop(); - - audio::DeadStreamDetection DeadStreamDetection() const; - - media::AudioParameters GetAudioParameters() const; - - // Device used for recording. - std::string device_id_; - bool detect_dead_stream_; - assistant_client::BufferFormat buffer_format_; - chromeos::libassistant::mojom::PlatformDelegate* const platform_delegate_; - media::AudioCapturerSource::CaptureCallback* const capture_callback_; - scoped_refptr<media::AudioCapturerSource> source_; - base::WeakPtrFactory<AudioStream> weak_ptr_factory_{this}; -}; - -} // namespace assistant -} // namespace chromeos - -#endif // CHROMEOS_SERVICES_ASSISTANT_PLATFORM_AUDIO_STREAM_H_
diff --git a/chromeos/services/assistant/platform_api_impl.cc b/chromeos/services/assistant/platform_api_impl.cc index 3d9fa9d..43d8d43e 100644 --- a/chromeos/services/assistant/platform_api_impl.cc +++ b/chromeos/services/assistant/platform_api_impl.cc
@@ -8,16 +8,12 @@ #include <utility> #include <vector> -#include "chromeos/services/assistant/platform/audio_devices.h" #include "chromeos/services/assistant/public/cpp/features.h" -#include "chromeos/services/assistant/public/cpp/migration/audio_input_host.h" #include "chromeos/services/assistant/utils.h" #include "libassistant/shared/public/assistant_export.h" #include "libassistant/shared/public/platform_api.h" #include "libassistant/shared/public/platform_factory.h" -#include "media/audio/audio_device_description.h" -using assistant_client::AudioOutputProvider; using assistant_client::FileProvider; using assistant_client::NetworkProvider; using assistant_client::PlatformApi; @@ -30,24 +26,13 @@ //////////////////////////////////////////////////////////////////////////////// PlatformApiImpl::PlatformApiImpl( - mojo::PendingRemote<chromeos::libassistant::mojom::AudioOutputDelegate> - audio_output_delegate, chromeos::libassistant::mojom::PlatformDelegate* platform_delegate, PowerManagerClient* power_manager_client, - scoped_refptr<base::SequencedTaskRunner> main_thread_task_runner, - scoped_refptr<base::SingleThreadTaskRunner> background_task_runner) - : audio_output_provider_(std::move(audio_output_delegate), - platform_delegate, - background_task_runner, - media::AudioDeviceDescription::kDefaultDeviceId), - network_provider_(platform_delegate) {} + scoped_refptr<base::SequencedTaskRunner> main_thread_task_runner) + : network_provider_(platform_delegate) {} PlatformApiImpl::~PlatformApiImpl() = default; -AudioOutputProvider& PlatformApiImpl::GetAudioOutputProvider() { - return audio_output_provider_; -} - FileProvider& PlatformApiImpl::GetFileProvider() { return file_provider_; }
diff --git a/chromeos/services/assistant/platform_api_impl.h b/chromeos/services/assistant/platform_api_impl.h index e18b2a1..dcbc8c7 100644 --- a/chromeos/services/assistant/platform_api_impl.h +++ b/chromeos/services/assistant/platform_api_impl.h
@@ -9,12 +9,10 @@ #include <utility> #include <vector> -#include "chromeos/services/assistant/platform/audio_output_provider_impl.h" #include "chromeos/services/assistant/platform/file_provider_impl.h" #include "chromeos/services/assistant/platform/network_provider_impl.h" #include "chromeos/services/assistant/public/cpp/assistant_service.h" #include "chromeos/services/assistant/public/cpp/migration/cros_platform_api.h" -#include "chromeos/services/libassistant/public/mojom/audio_output_delegate.mojom-forward.h" #include "chromeos/services/libassistant/public/mojom/platform_delegate.mojom-forward.h" #include "libassistant/shared/public/platform_auth.h" #include "mojo/public/cpp/bindings/pending_remote.h" @@ -28,20 +26,15 @@ class PlatformApiImpl : public CrosPlatformApi { public: PlatformApiImpl( - mojo::PendingRemote<chromeos::libassistant::mojom::AudioOutputDelegate> - audio_output_delegate, chromeos::libassistant::mojom::PlatformDelegate* platform_delegate, PowerManagerClient* power_manager_client, - scoped_refptr<base::SequencedTaskRunner> main_thread_task_runner, - scoped_refptr<base::SingleThreadTaskRunner> background_task_runner); + scoped_refptr<base::SequencedTaskRunner> main_thread_task_runner); ~PlatformApiImpl() override; - assistant_client::AudioOutputProvider& GetAudioOutputProvider() override; assistant_client::FileProvider& GetFileProvider() override; assistant_client::NetworkProvider& GetNetworkProvider() override; private: - AudioOutputProviderImpl audio_output_provider_; FileProviderImpl file_provider_; NetworkProviderImpl network_provider_;
diff --git a/chromeos/services/assistant/proxy/assistant_proxy.cc b/chromeos/services/assistant/proxy/assistant_proxy.cc index e326265..23731e3 100644 --- a/chromeos/services/assistant/proxy/assistant_proxy.cc +++ b/chromeos/services/assistant/proxy/assistant_proxy.cc
@@ -80,6 +80,8 @@ pending_url_loader_factory) { mojo::PendingRemote<AudioInputControllerMojom> pending_audio_input_controller_remote; + mojo::PendingRemote<AudioOutputDelegateMojom> + pending_audio_output_delegate_remote; mojo::PendingRemote<ConversationControllerMojom> pending_conversation_controller_remote; mojo::PendingRemote<MediaDelegateMojom> pending_media_delegate_remote; @@ -90,13 +92,15 @@ pending_media_delegate_remote.InitWithNewPipeAndPassReceiver(); mojo::PendingReceiver<PlatformDelegateMojom> pending_platform_delegate = pending_platform_delegate_remote.InitWithNewPipeAndPassReceiver(); - + pending_audio_output_delegate_receiver_ = + pending_audio_output_delegate_remote.InitWithNewPipeAndPassReceiver(); libassistant_service_remote_->Bind( pending_audio_input_controller_remote.InitWithNewPipeAndPassReceiver(), pending_conversation_controller_remote.InitWithNewPipeAndPassReceiver(), display_controller_remote_.BindNewPipeAndPassReceiver(), media_controller_remote_.BindNewPipeAndPassReceiver(), pending_service_controller_remote.InitWithNewPipeAndPassReceiver(), + std::move(pending_audio_output_delegate_remote), std::move(pending_media_delegate_remote), std::move(pending_platform_delegate_remote)); @@ -128,6 +132,12 @@ return std::move(audio_input_controller_); } +mojo::PendingReceiver<chromeos::libassistant::mojom::AudioOutputDelegate> +AssistantProxy::ExtractAudioOutputDelegate() { + DCHECK(pending_audio_output_delegate_receiver_.is_valid()); + return std::move(pending_audio_output_delegate_receiver_); +} + mojo::PendingReceiver<chromeos::libassistant::mojom::MediaDelegate> AssistantProxy::ExtractMediaDelegate() { DCHECK(media_delegate_.is_valid());
diff --git a/chromeos/services/assistant/proxy/assistant_proxy.h b/chromeos/services/assistant/proxy/assistant_proxy.h index 0ff7e05..4e78971 100644 --- a/chromeos/services/assistant/proxy/assistant_proxy.h +++ b/chromeos/services/assistant/proxy/assistant_proxy.h
@@ -8,7 +8,10 @@ #include <memory> #include "base/threading/thread.h" +#include "chromeos/services/libassistant/public/mojom/audio_input_controller.mojom.h" #include "chromeos/services/libassistant/public/mojom/conversation_controller.mojom.h" +#include "chromeos/services/libassistant/public/mojom/media_controller.mojom.h" +#include "chromeos/services/libassistant/public/mojom/platform_delegate.mojom.h" #include "chromeos/services/libassistant/public/mojom/service.mojom.h" #include "mojo/public/cpp/bindings/remote.h" @@ -70,6 +73,8 @@ mojo::PendingRemote<chromeos::libassistant::mojom::AudioInputController> ExtractAudioInputController(); + mojo::PendingReceiver<chromeos::libassistant::mojom::AudioOutputDelegate> + ExtractAudioOutputDelegate(); mojo::PendingReceiver<chromeos::libassistant::mojom::MediaDelegate> ExtractMediaDelegate(); mojo::PendingReceiver<chromeos::libassistant::mojom::PlatformDelegate> @@ -79,6 +84,8 @@ using AudioInputControllerMojom = chromeos::libassistant::mojom::AudioInputController; using PlatformDelegateMojom = chromeos::libassistant::mojom::PlatformDelegate; + using AudioOutputDelegateMojom = + chromeos::libassistant::mojom::AudioOutputDelegate; using ConversationControllerMojom = chromeos::libassistant::mojom::ConversationController; using DisplayControllerMojom = @@ -116,7 +123,8 @@ mojo::PendingRemote<AudioInputControllerMojom> audio_input_controller_; mojo::PendingReceiver<MediaDelegateMojom> media_delegate_; mojo::PendingReceiver<PlatformDelegateMojom> platform_delegate_; - + mojo::PendingReceiver<AudioOutputDelegateMojom> + pending_audio_output_delegate_receiver_; // The thread on which the Libassistant service runs. // Warning: must be the last object, so it is destroyed (and flushed) first.
diff --git a/chromeos/services/assistant/proxy/conversation_controller_proxy.cc b/chromeos/services/assistant/proxy/conversation_controller_proxy.cc index e504b0ab..7eb9147 100644 --- a/chromeos/services/assistant/proxy/conversation_controller_proxy.cc +++ b/chromeos/services/assistant/proxy/conversation_controller_proxy.cc
@@ -9,35 +9,6 @@ namespace chromeos { namespace assistant { -namespace { - -// Converts |AssistantNotification| struct to the corresponding Mojom struct -// (the Mojom-generated |AssistantNotificationPtr|). -libassistant::mojom::AssistantNotificationPtr ConvertNotificationToMojomStruct( - const AssistantNotification& notification) { - auto ptr = libassistant::mojom::AssistantNotification::New(); - ptr->server_id = notification.server_id; - ptr->consistency_token = notification.consistency_token; - ptr->opaque_token = notification.opaque_token; - ptr->grouping_key = notification.grouping_key; - ptr->obfuscated_gaia_id = notification.obfuscated_gaia_id; - return ptr; -} - -// Coverts |AssistantFeedback| struct to the corresponding Mojom struct (the -// Mojom-generated |AssistantFeedbackPtr|). -libassistant::mojom::AssistantFeedbackPtr ConvertFeedbackToMojomStruct( - const AssistantFeedback& feedback) { - auto ptr = libassistant::mojom::AssistantFeedback::New(); - ptr->description = feedback.description; - ptr->assistant_debug_info_allowed = feedback.assistant_debug_info_allowed; - ptr->screenshot_png = std::vector<uint8_t>(feedback.screenshot_png.begin(), - feedback.screenshot_png.end()); - return ptr; -} - -} // namespace - ConversationControllerProxy::ConversationControllerProxy( mojo::PendingRemote<ConversationController> conversation_controller_remote) : conversation_controller_remote_( @@ -61,20 +32,18 @@ void ConversationControllerProxy::RetrieveNotification( const AssistantNotification& notification, int32_t action_index) { - conversation_controller_remote_->RetrieveNotification( - ConvertNotificationToMojomStruct(notification), action_index); + conversation_controller_remote_->RetrieveNotification(notification, + action_index); } void ConversationControllerProxy::DismissNotification( const AssistantNotification& notification) { - conversation_controller_remote_->DismissNotification( - ConvertNotificationToMojomStruct(notification)); + conversation_controller_remote_->DismissNotification(notification); } void ConversationControllerProxy::SendAssistantFeedback( const AssistantFeedback& feedback) { - conversation_controller_remote_->SendAssistantFeedback( - ConvertFeedbackToMojomStruct(feedback)); + conversation_controller_remote_->SendAssistantFeedback(feedback); } } // namespace assistant
diff --git a/chromeos/services/assistant/public/cpp/assistant_service.cc b/chromeos/services/assistant/public/cpp/assistant_service.cc index 39d96d4..c97b695 100644 --- a/chromeos/services/assistant/public/cpp/assistant_service.cc +++ b/chromeos/services/assistant/public/cpp/assistant_service.cc
@@ -13,6 +13,9 @@ } // namespace +AssistantFeedback::AssistantFeedback() = default; +AssistantFeedback::~AssistantFeedback() = default; + // static AssistantService* AssistantService::Get() { return g_instance;
diff --git a/chromeos/services/assistant/public/cpp/assistant_service.h b/chromeos/services/assistant/public/cpp/assistant_service.h index 2e6dd7e..8b6f8f27 100644 --- a/chromeos/services/assistant/public/cpp/assistant_service.h +++ b/chromeos/services/assistant/public/cpp/assistant_service.h
@@ -140,6 +140,9 @@ // Details for Assistant feedback. struct COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) AssistantFeedback { + AssistantFeedback(); + ~AssistantFeedback(); + // User input to be sent with the feedback report. std::string description; @@ -148,7 +151,7 @@ // Screenshot if allowed by user. // Raw data (non-encoded binary octets) - std::string screenshot_png; + std::vector<uint8_t> screenshot_png; }; class COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) Assistant {
diff --git a/chromeos/services/assistant/public/cpp/migration/assistant_manager_service_delegate.h b/chromeos/services/assistant/public/cpp/migration/assistant_manager_service_delegate.h index 8d17ed01..79011be 100644 --- a/chromeos/services/assistant/public/cpp/migration/assistant_manager_service_delegate.h +++ b/chromeos/services/assistant/public/cpp/migration/assistant_manager_service_delegate.h
@@ -9,7 +9,6 @@ #include "base/single_thread_task_runner.h" #include "chromeos/services/libassistant/public/mojom/audio_input_controller.mojom-forward.h" -#include "chromeos/services/libassistant/public/mojom/audio_output_delegate.mojom-forward.h" #include "chromeos/services/libassistant/public/mojom/platform_delegate.mojom-forward.h" #include "mojo/public/cpp/bindings/pending_remote.h" @@ -41,11 +40,7 @@ pending_remote) = 0; virtual std::unique_ptr<CrosPlatformApi> CreatePlatformApi( - mojo::PendingRemote<chromeos::libassistant::mojom::AudioOutputDelegate> - audio_output_delegate, - chromeos::libassistant::mojom::PlatformDelegate* platform_delegate, - scoped_refptr<base::SingleThreadTaskRunner> - background_thread_task_runner) = 0; + chromeos::libassistant::mojom::PlatformDelegate* platform_delegate) = 0; virtual std::unique_ptr<assistant_client::AssistantManager> CreateAssistantManager(assistant_client::PlatformApi* platform_api,
diff --git a/chromeos/services/assistant/public/cpp/migration/cros_platform_api.h b/chromeos/services/assistant/public/cpp/migration/cros_platform_api.h index 7d49688..d867175 100644 --- a/chromeos/services/assistant/public/cpp/migration/cros_platform_api.h +++ b/chromeos/services/assistant/public/cpp/migration/cros_platform_api.h
@@ -8,7 +8,6 @@ #include "base/macros.h" namespace assistant_client { -class AudioOutputProvider; class FileProvider; class NetworkProvider; } // namespace assistant_client @@ -25,9 +24,6 @@ CrosPlatformApi() = default; virtual ~CrosPlatformApi() = default; - // Returns the platform's audio output provider. - virtual assistant_client::AudioOutputProvider& GetAudioOutputProvider() = 0; - // Returns the file provider to be used by libassistant. virtual assistant_client::FileProvider& GetFileProvider() = 0;
diff --git a/chromeos/services/assistant/public/cpp/migration/fake_assistant_manager_service_delegate.cc b/chromeos/services/assistant/public/cpp/migration/fake_assistant_manager_service_delegate.cc index bcc33a4e5..ae97763 100644 --- a/chromeos/services/assistant/public/cpp/migration/fake_assistant_manager_service_delegate.cc +++ b/chromeos/services/assistant/public/cpp/migration/fake_assistant_manager_service_delegate.cc
@@ -51,10 +51,7 @@ std::unique_ptr<CrosPlatformApi> FakeAssistantManagerServiceDelegate::CreatePlatformApi( - mojo::PendingRemote<chromeos::libassistant::mojom::AudioOutputDelegate> - audio_output_delegate, - chromeos::libassistant::mojom::PlatformDelegate* platform_delegate, - scoped_refptr<base::SingleThreadTaskRunner> background_thread_task_runner) { + chromeos::libassistant::mojom::PlatformDelegate* platform_delegate) { return std::make_unique<FakePlatformApi>(); }
diff --git a/chromeos/services/assistant/public/cpp/migration/fake_assistant_manager_service_delegate.h b/chromeos/services/assistant/public/cpp/migration/fake_assistant_manager_service_delegate.h index 868c879..0c40c45 100644 --- a/chromeos/services/assistant/public/cpp/migration/fake_assistant_manager_service_delegate.h +++ b/chromeos/services/assistant/public/cpp/migration/fake_assistant_manager_service_delegate.h
@@ -32,10 +32,7 @@ mojo::PendingRemote<chromeos::libassistant::mojom::AudioInputController> pending_remote) override; std::unique_ptr<CrosPlatformApi> CreatePlatformApi( - mojo::PendingRemote<chromeos::libassistant::mojom::AudioOutputDelegate> - audio_output_delegate, - chromeos::libassistant::mojom::PlatformDelegate* platform_delegate, - scoped_refptr<base::SingleThreadTaskRunner> background_thread_task_runner) + chromeos::libassistant::mojom::PlatformDelegate* platform_delegate) override; std::unique_ptr<assistant_client::AssistantManager> CreateAssistantManager( assistant_client::PlatformApi* platform_api,
diff --git a/chromeos/services/assistant/public/cpp/migration/fake_platform_api.cc b/chromeos/services/assistant/public/cpp/migration/fake_platform_api.cc index 01e05f3f9..a464dd8 100644 --- a/chromeos/services/assistant/public/cpp/migration/fake_platform_api.cc +++ b/chromeos/services/assistant/public/cpp/migration/fake_platform_api.cc
@@ -6,77 +6,13 @@ #include "base/notreached.h" #include "chromeos/services/assistant//public/cpp/migration/fake_platform_api.h" -#include "libassistant/shared/public/platform_audio_output.h" namespace chromeos { namespace assistant { -namespace { - -class FakeVolumeControl : public assistant_client::VolumeControl { - public: - // assistant_client::VolumeControl implementation: - void SetAudioFocus(assistant_client::OutputStreamType) override {} - float GetSystemVolume() override { return 0.5; } - void SetSystemVolume(float new_volume, bool user_initiated) override {} - float GetAlarmVolume() override { return 0.5; } - void SetAlarmVolume(float new_volume, bool user_initiated) override {} - bool IsSystemMuted() override { return false; } - void SetSystemMuted(bool muted) override {} -}; - -class FakeAudioOutputProvider : public assistant_client::AudioOutputProvider { - public: - FakeAudioOutputProvider() = default; - FakeAudioOutputProvider(FakeAudioOutputProvider&) = delete; - FakeAudioOutputProvider& operator=(FakeAudioOutputProvider&) = delete; - ~FakeAudioOutputProvider() override = default; - - // assistant_client::AudioOutputProvider implementation: - assistant_client::AudioOutput* CreateAudioOutput( - assistant_client::OutputStreamType type, - const assistant_client::OutputStreamFormat& stream_format) override { - NOTIMPLEMENTED(); - abort(); - } - - std::vector<assistant_client::OutputStreamEncoding> - GetSupportedStreamEncodings() override { - return {}; - } - - assistant_client::AudioInput* GetReferenceInput() override { - NOTIMPLEMENTED(); - abort(); - } - - bool SupportsPlaybackTimestamp() const override { return false; } - - assistant_client::VolumeControl& GetVolumeControl() override { - return volume_control_; - } - - void RegisterAudioEmittingStateCallback( - AudioEmittingStateCallback callback) override { - NOTIMPLEMENTED(); - } - - private: - FakeVolumeControl volume_control_; -}; - -} // namespace - -FakePlatformApi::FakePlatformApi() - : audio_output_provider_(std::make_unique<FakeAudioOutputProvider>()) {} - +FakePlatformApi::FakePlatformApi() = default; FakePlatformApi::~FakePlatformApi() = default; -assistant_client::AudioOutputProvider& -FakePlatformApi::GetAudioOutputProvider() { - return *audio_output_provider_.get(); -} - assistant_client::FileProvider& FakePlatformApi::GetFileProvider() { NOTIMPLEMENTED(); abort();
diff --git a/chromeos/services/assistant/public/cpp/migration/fake_platform_api.h b/chromeos/services/assistant/public/cpp/migration/fake_platform_api.h index b22f00c..017dca4 100644 --- a/chromeos/services/assistant/public/cpp/migration/fake_platform_api.h +++ b/chromeos/services/assistant/public/cpp/migration/fake_platform_api.h
@@ -23,12 +23,8 @@ ~FakePlatformApi() override; // CrosPlatformApi implementation: - assistant_client::AudioOutputProvider& GetAudioOutputProvider() override; assistant_client::FileProvider& GetFileProvider() override; assistant_client::NetworkProvider& GetNetworkProvider() override; - - private: - std::unique_ptr<assistant_client::AudioOutputProvider> audio_output_provider_; }; } // namespace assistant
diff --git a/chromeos/services/assistant/test_support/fake_libassistant_service.cc b/chromeos/services/assistant/test_support/fake_libassistant_service.cc index d1d4dbd..99ab2f5 100644 --- a/chromeos/services/assistant/test_support/fake_libassistant_service.cc +++ b/chromeos/services/assistant/test_support/fake_libassistant_service.cc
@@ -49,6 +49,8 @@ media_controller, mojo::PendingReceiver<libassistant::mojom::ServiceController> service_controller, + mojo::PendingRemote<libassistant::mojom::AudioOutputDelegate> + audio_output_delegate, mojo::PendingRemote<libassistant::mojom::MediaDelegate> media_delegate, mojo::PendingRemote<libassistant::mojom::PlatformDelegate> platform_delegate) {
diff --git a/chromeos/services/assistant/test_support/fake_libassistant_service.h b/chromeos/services/assistant/test_support/fake_libassistant_service.h index 9d518285..b7e1aac 100644 --- a/chromeos/services/assistant/test_support/fake_libassistant_service.h +++ b/chromeos/services/assistant/test_support/fake_libassistant_service.h
@@ -47,6 +47,8 @@ media_controller, mojo::PendingReceiver<libassistant::mojom::ServiceController> service_controller, + mojo::PendingRemote<libassistant::mojom::AudioOutputDelegate> + audio_output_delegate, mojo::PendingRemote<libassistant::mojom::MediaDelegate> media_delegate, mojo::PendingRemote<libassistant::mojom::PlatformDelegate> platform_delegate) override;
diff --git a/chromeos/services/cellular_setup/esim_manager.cc b/chromeos/services/cellular_setup/esim_manager.cc index 5344923..2865096 100644 --- a/chromeos/services/cellular_setup/esim_manager.cc +++ b/chromeos/services/cellular_setup/esim_manager.cc
@@ -19,13 +19,16 @@ ESimManager::ESimManager() : ESimManager(NetworkHandler::Get()->cellular_esim_profile_handler(), - NetworkHandler::Get()->cellular_esim_uninstall_handler()) {} + NetworkHandler::Get()->cellular_esim_uninstall_handler(), + NetworkHandler::Get()->cellular_inhibitor()) {} ESimManager::ESimManager( CellularESimProfileHandler* cellular_esim_profile_handler, - CellularESimUninstallHandler* cellular_esim_uninstall_handler) + CellularESimUninstallHandler* cellular_esim_uninstall_handler, + CellularInhibitor* cellular_inhibitor) : cellular_esim_profile_handler_(cellular_esim_profile_handler), - cellular_esim_uninstall_handler_(cellular_esim_uninstall_handler) { + cellular_esim_uninstall_handler_(cellular_esim_uninstall_handler), + cellular_inhibitor_(cellular_inhibitor) { HermesManagerClient::Get()->AddObserver(this); HermesEuiccClient::Get()->AddObserver(this); cellular_esim_profile_handler_->AddObserver(this);
diff --git a/chromeos/services/cellular_setup/esim_manager.h b/chromeos/services/cellular_setup/esim_manager.h index 875452b1..3c2e7d3 100644 --- a/chromeos/services/cellular_setup/esim_manager.h +++ b/chromeos/services/cellular_setup/esim_manager.h
@@ -22,6 +22,7 @@ namespace chromeos { class CellularESimUninstallHandler; +class CellularInhibitor; namespace cellular_setup { @@ -39,7 +40,8 @@ public: ESimManager(); ESimManager(CellularESimProfileHandler* cellular_esim_profile_handler, - CellularESimUninstallHandler* cellular_esim_uninstall_handler); + CellularESimUninstallHandler* cellular_esim_uninstall_handler, + CellularInhibitor* cellular_inhibitor); ESimManager(const ESimManager&) = delete; ESimManager& operator=(const ESimManager&) = delete; ~ESimManager() override; @@ -72,6 +74,8 @@ return cellular_esim_uninstall_handler_; } + CellularInhibitor* cellular_inhibitor() { return cellular_inhibitor_; } + private: void UpdateAvailableEuiccs(); // Removes Euicc objects in |available_euiiccs_| that are not in @@ -84,6 +88,7 @@ CellularESimProfileHandler* cellular_esim_profile_handler_; CellularESimUninstallHandler* cellular_esim_uninstall_handler_; + CellularInhibitor* cellular_inhibitor_; std::vector<std::unique_ptr<Euicc>> available_euiccs_; mojo::RemoteSet<mojom::ESimManagerObserver> observers_; mojo::ReceiverSet<mojom::ESimManager> receivers_;
diff --git a/chromeos/services/cellular_setup/esim_profile.cc b/chromeos/services/cellular_setup/esim_profile.cc index 8421ebf9..7a2ff0be 100644 --- a/chromeos/services/cellular_setup/esim_profile.cc +++ b/chromeos/services/cellular_setup/esim_profile.cc
@@ -8,6 +8,7 @@ #include "chromeos/dbus/hermes/hermes_euicc_client.h" #include "chromeos/network/cellular_esim_profile.h" #include "chromeos/network/cellular_esim_uninstall_handler.h" +#include "chromeos/network/cellular_inhibitor.h" #include "chromeos/network/network_handler.h" #include "chromeos/services/cellular_setup/esim_manager.h" #include "chromeos/services/cellular_setup/esim_mojo_utils.h" @@ -48,8 +49,8 @@ } ESimProfile::~ESimProfile() { - if (uninstall_callback_) { - NET_LOG(ERROR) << "Profile destroyed with unfulfilled uninstall callback"; + if (uninstall_callback_ || set_profile_nickname_callback_) { + NET_LOG(ERROR) << "Profile destroyed with unfulfilled callbacks"; } } @@ -122,6 +123,12 @@ void ESimProfile::SetProfileNickname(const base::string16& nickname, SetProfileNicknameCallback callback) { + if (set_profile_nickname_callback_) { + NET_LOG(ERROR) << "Set Profile Nickname already in progress."; + std::move(callback).Run(mojom::ESimOperationResult::kFailure); + return; + } + if (properties_->state == mojom::ProfileState::kInstalling || properties_->state == mojom::ProfileState::kPending) { NET_LOG(ERROR) << "Set Profile Nickname failed: Profile is not installed."; @@ -129,12 +136,13 @@ return; } - HermesProfileClient::Properties* properties = - HermesProfileClient::Get()->GetProperties(path_); - properties->nick_name().Set( - base::UTF16ToUTF8(nickname), - base::BindOnce(&ESimProfile::OnProfilePropertySet, - weak_ptr_factory_.GetWeakPtr(), std::move(callback))); + set_profile_nickname_callback_ = std::move(callback); + // Pass has_already_requested_installed_profiles=false so that a + // RequestInstalledProfiles call will be made in case this ESimProfile object + // was created from cached profile data. + esim_manager_->cellular_inhibitor()->InhibitCellularScanning(base::BindOnce( + &ESimProfile::PerformSetProfileNickname, weak_ptr_factory_.GetWeakPtr(), + nickname, /*has_already_requested_installed_profiles=*/false)); } void ESimProfile::UpdateProperties( @@ -156,10 +164,19 @@ } void ESimProfile::OnProfileRemove() { + // Run pending callbacks before profile is removed. if (uninstall_callback_) { - // Run pending uninstall callback before profile is removed. + // This profile could be removed before UninstallHandler returns. Return a + // success since the profile will be removed. std::move(uninstall_callback_).Run(mojom::ESimOperationResult::kSuccess); } + if (set_profile_nickname_callback_) { + // Setting nickname could trigger a request for installed profiles. If this + // profile gets removed at that point, return pending call with failure + // result. + std::move(set_profile_nickname_callback_) + .Run(mojom::ESimOperationResult::kFailure); + } } mojo::PendingRemote<mojom::ESimProfile> ESimProfile::CreateRemote() { @@ -168,6 +185,65 @@ return esim_profile_remote; } +void ESimProfile::PerformSetProfileNickname( + const base::string16& nickname, + bool has_already_requested_installed_profiles, + std::unique_ptr<CellularInhibitor::InhibitLock> inhibit_lock) { + if (!inhibit_lock) { + NET_LOG(ERROR) << "Error inhibiting cellular device"; + std::move(set_profile_nickname_callback_) + .Run(mojom::ESimOperationResult::kFailure); + return; + } + + // If a valid profile does not exist on Hermes, then we are using cached + // profile data. Make a request for installed profiles so that the profile + // will be loaded in hermes. + if (!ProfileExistsOnEuicc()) { + if (has_already_requested_installed_profiles) { + // If the profile doesn't exists and installed profiles have already been + // requested then give up and return with error. This profile will get + // destroyed when ESimProfileHandler updates. + NET_LOG(ERROR) << "Unable to find profile in dbus. path=" + << path_.value(); + std::move(set_profile_nickname_callback_) + .Run(mojom::ESimOperationResult::kFailure); + return; + } + + HermesEuiccClient::Get()->RequestInstalledProfiles( + euicc_->path(), + base::BindOnce(&ESimProfile::OnRequestInstalledProfilesForSetNickname, + weak_ptr_factory_.GetWeakPtr(), nickname, + std::move(inhibit_lock))); + return; + } + + HermesProfileClient::Properties* properties = + HermesProfileClient::Get()->GetProperties(path_); + properties->nick_name().Set( + base::UTF16ToUTF8(nickname), + base::BindOnce(&ESimProfile::OnProfileNicknameSet, + weak_ptr_factory_.GetWeakPtr(), std::move(inhibit_lock))); +} + +void ESimProfile::OnRequestInstalledProfilesForSetNickname( + const base::string16& nickname, + std::unique_ptr<CellularInhibitor::InhibitLock> inhibit_lock, + HermesResponseStatus status) { + if (status != HermesResponseStatus::kSuccess) { + NET_LOG(ERROR) + << "Error requesting installed profiles for set nickname. status=" + << static_cast<int>(status); + std::move(set_profile_nickname_callback_) + .Run(mojom::ESimOperationResult::kFailure); + return; + } + PerformSetProfileNickname(nickname, + /*has_already_requested_intalled_profiles=*/true, + std::move(inhibit_lock)); +} + void ESimProfile::OnPendingProfileInstallResult( ProfileInstallResultCallback callback, HermesResponseStatus status) { @@ -198,13 +274,26 @@ std::move(callback).Run(OperationResultFromStatus(status)); } -void ESimProfile::OnProfilePropertySet(ESimOperationResultCallback callback, - bool success) { +void ESimProfile::OnProfileNicknameSet( + std::unique_ptr<CellularInhibitor::InhibitLock> inhibit_lock, + bool success) { if (!success) { NET_LOG(ERROR) << "ESimProfile property set error."; } - std::move(callback).Run(success ? mojom::ESimOperationResult::kSuccess - : mojom::ESimOperationResult::kFailure); + std::move(set_profile_nickname_callback_) + .Run(success ? mojom::ESimOperationResult::kSuccess + : mojom::ESimOperationResult::kFailure); + // inhibit_lock goes out of scope and will uninhibit automatically. +} + +bool ESimProfile::ProfileExistsOnEuicc() { + HermesEuiccClient::Properties* euicc_properties = + HermesEuiccClient::Get()->GetProperties(euicc_->path()); + const std::vector<dbus::ObjectPath>& installed_profile_paths = + euicc_properties->installed_carrier_profiles().value(); + auto iter = std::find(installed_profile_paths.begin(), + installed_profile_paths.end(), path_); + return iter != installed_profile_paths.end(); } } // namespace cellular_setup
diff --git a/chromeos/services/cellular_setup/esim_profile.h b/chromeos/services/cellular_setup/esim_profile.h index cf9cbd9..3ad6e18 100644 --- a/chromeos/services/cellular_setup/esim_profile.h +++ b/chromeos/services/cellular_setup/esim_profile.h
@@ -8,6 +8,7 @@ #include "base/memory/weak_ptr.h" #include "chromeos/dbus/hermes/hermes_profile_client.h" #include "chromeos/dbus/hermes/hermes_response_status.h" +#include "chromeos/network/cellular_inhibitor.h" #include "chromeos/services/cellular_setup/public/mojom/esim_manager.mojom.h" #include "mojo/public/cpp/bindings/receiver_set.h" @@ -67,22 +68,30 @@ using ESimOperationResultCallback = base::OnceCallback<void(mojom::ESimOperationResult)>; + void PerformSetProfileNickname( + const base::string16& nickname, + bool has_already_requested_installed_profiles, + std::unique_ptr<CellularInhibitor::InhibitLock> inhibit_lock); + void OnRequestInstalledProfilesForSetNickname( + const base::string16& nickname, + std::unique_ptr<CellularInhibitor::InhibitLock> inhibit_lock, + HermesResponseStatus status); void OnPendingProfileInstallResult(ProfileInstallResultCallback callback, HermesResponseStatus status); - void OnProfileInstallResult(ProfileInstallResultCallback callback, - const std::string& eid, - HermesResponseStatus status, - const dbus::ObjectPath* object_path); void OnProfileUninstallResult(bool success); void OnESimOperationResult(ESimOperationResultCallback callback, HermesResponseStatus status); - void OnProfilePropertySet(ESimOperationResultCallback callback, bool success); + void OnProfileNicknameSet( + std::unique_ptr<CellularInhibitor::InhibitLock> inhibit_lock, + bool success); + bool ProfileExistsOnEuicc(); // Reference to Euicc that owns this profile. Euicc* euicc_; // Reference to ESimManager that owns Euicc of this profile. ESimManager* esim_manager_; UninstallProfileCallback uninstall_callback_; + SetProfileNicknameCallback set_profile_nickname_callback_; mojo::ReceiverSet<mojom::ESimProfile> receiver_set_; mojom::ESimProfilePropertiesPtr properties_; dbus::ObjectPath path_;
diff --git a/chromeos/services/cellular_setup/esim_test_base.cc b/chromeos/services/cellular_setup/esim_test_base.cc index 99735b1..3f21ecb 100644 --- a/chromeos/services/cellular_setup/esim_test_base.cc +++ b/chromeos/services/cellular_setup/esim_test_base.cc
@@ -62,9 +62,9 @@ std::make_unique<TestCellularESimProfileHandler>(); cellular_esim_profile_handler_->Init(); - esim_manager_ = - std::make_unique<ESimManager>(cellular_esim_profile_handler_.get(), - cellular_esim_uninstall_handler_.get()); + esim_manager_ = std::make_unique<ESimManager>( + cellular_esim_profile_handler_.get(), + cellular_esim_uninstall_handler_.get(), cellular_inhibitor_.get()); observer_ = std::make_unique<ESimManagerTestObserver>(); esim_manager_->AddObserver(observer_->GenerateRemote()); }
diff --git a/chromeos/services/cellular_setup/euicc.cc b/chromeos/services/cellular_setup/euicc.cc index 8ffb3ad..0375ca5 100644 --- a/chromeos/services/cellular_setup/euicc.cc +++ b/chromeos/services/cellular_setup/euicc.cc
@@ -10,6 +10,7 @@ #include "base/optional.h" #include "base/strings/strcat.h" #include "chromeos/network/cellular_esim_profile.h" +#include "chromeos/network/cellular_inhibitor.h" #include "chromeos/services/cellular_setup/esim_manager.h" #include "chromeos/services/cellular_setup/esim_mojo_utils.h" #include "chromeos/services/cellular_setup/esim_profile.h" @@ -77,17 +78,16 @@ } // Try installing directly with activation code. - HermesEuiccClient::Get()->InstallProfileFromActivationCode( - path_, activation_code, confirmation_code, - base::BindOnce(&Euicc::OnProfileInstallResult, - weak_ptr_factory_.GetWeakPtr(), std::move(callback))); + esim_manager_->cellular_inhibitor()->InhibitCellularScanning( + base::BindOnce(&Euicc::PerformInstallProfileFromActivationCode, + weak_ptr_factory_.GetWeakPtr(), activation_code, + confirmation_code, std::move(callback))); } void Euicc::RequestPendingProfiles(RequestPendingProfilesCallback callback) { NET_LOG(EVENT) << "Requesting Pending profiles"; - HermesEuiccClient::Get()->RequestPendingProfiles( - path_, /*root_smds=*/std::string(), - base::BindOnce(&Euicc::OnRequestPendingEventsResult, + esim_manager_->cellular_inhibitor()->InhibitCellularScanning( + base::BindOnce(&Euicc::PerformRequestPendingProfiles, weak_ptr_factory_.GetWeakPtr(), std::move(callback))); } @@ -175,8 +175,28 @@ return nullptr; } +void Euicc::PerformInstallProfileFromActivationCode( + const std::string& activation_code, + const std::string& confirmation_code, + InstallProfileFromActivationCodeCallback callback, + std::unique_ptr<CellularInhibitor::InhibitLock> inhibit_lock) { + if (!inhibit_lock) { + NET_LOG(ERROR) << "Error inhibiting cellular device"; + std::move(callback).Run(mojom::ProfileInstallResult::kFailure, + mojo::NullRemote()); + return; + } + + HermesEuiccClient::Get()->InstallProfileFromActivationCode( + path_, activation_code, confirmation_code, + base::BindOnce(&Euicc::OnProfileInstallResult, + weak_ptr_factory_.GetWeakPtr(), std::move(callback), + std::move(inhibit_lock))); +} + void Euicc::OnProfileInstallResult( InstallProfileFromActivationCodeCallback callback, + std::unique_ptr<CellularInhibitor::InhibitLock> inhibit_lock, HermesResponseStatus status, const dbus::ObjectPath* object_path) { if (status != HermesResponseStatus::kSuccess) { @@ -198,10 +218,28 @@ } std::move(callback).Run(mojom::ProfileInstallResult::kSuccess, esim_profile->CreateRemote()); + // inhibit_lock goes out of scope and will uninhibit automatically. } -void Euicc::OnRequestPendingEventsResult( +void Euicc::PerformRequestPendingProfiles( RequestPendingProfilesCallback callback, + std::unique_ptr<CellularInhibitor::InhibitLock> inhibit_lock) { + if (!inhibit_lock) { + NET_LOG(ERROR) << "Error inhibiting cellular device"; + std::move(callback).Run(mojom::ESimOperationResult::kFailure); + return; + } + + HermesEuiccClient::Get()->RequestPendingProfiles( + path_, /*root_smds=*/std::string(), + base::BindOnce(&Euicc::OnRequestPendingProfilesResult, + weak_ptr_factory_.GetWeakPtr(), std::move(callback), + std::move(inhibit_lock))); +} + +void Euicc::OnRequestPendingProfilesResult( + RequestPendingProfilesCallback callback, + std::unique_ptr<CellularInhibitor::InhibitLock> inhibit_lock, HermesResponseStatus status) { if (status != HermesResponseStatus::kSuccess) { NET_LOG(ERROR) << "Request Pending events failed status=" @@ -210,6 +248,7 @@ std::move(callback).Run(status == HermesResponseStatus::kSuccess ? mojom::ESimOperationResult::kSuccess : mojom::ESimOperationResult::kFailure); + // inhibit_lock goes out of scope and will uninhibit automatically. } mojom::ProfileInstallResult Euicc::GetPendingProfileInfoFromActivationCode(
diff --git a/chromeos/services/cellular_setup/euicc.h b/chromeos/services/cellular_setup/euicc.h index bdc9e6d5..c429774b 100644 --- a/chromeos/services/cellular_setup/euicc.h +++ b/chromeos/services/cellular_setup/euicc.h
@@ -7,6 +7,7 @@ #include "chromeos/dbus/hermes/hermes_euicc_client.h" #include "chromeos/dbus/hermes/hermes_profile_client.h" +#include "chromeos/network/cellular_inhibitor.h" #include "chromeos/services/cellular_setup/public/mojom/esim_manager.mojom.h" #include "mojo/public/cpp/bindings/receiver_set.h" @@ -64,11 +65,23 @@ using ProfileInstallResultCallback = base::OnceCallback<void(mojom::ProfileInstallResult)>; - void OnProfileInstallResult(InstallProfileFromActivationCodeCallback callback, - HermesResponseStatus status, - const dbus::ObjectPath* object_path); - void OnRequestPendingEventsResult(RequestPendingProfilesCallback callback, - HermesResponseStatus status); + void PerformInstallProfileFromActivationCode( + const std::string& activation_code, + const std::string& confirmation_code, + InstallProfileFromActivationCodeCallback callback, + std::unique_ptr<CellularInhibitor::InhibitLock> inhibit_lock); + void OnProfileInstallResult( + InstallProfileFromActivationCodeCallback callback, + std::unique_ptr<CellularInhibitor::InhibitLock> inhibit_lock, + HermesResponseStatus status, + const dbus::ObjectPath* object_path); + void PerformRequestPendingProfiles( + RequestPendingProfilesCallback callback, + std::unique_ptr<CellularInhibitor::InhibitLock> inhibit_lock); + void OnRequestPendingProfilesResult( + RequestPendingProfilesCallback callback, + std::unique_ptr<CellularInhibitor::InhibitLock> inhibit_lock, + HermesResponseStatus status); mojom::ProfileInstallResult GetPendingProfileInfoFromActivationCode( const std::string& activation_code, ESimProfile** profile_info);
diff --git a/chromeos/services/libassistant/BUILD.gn b/chromeos/services/libassistant/BUILD.gn index 00e1ed2..19df25e 100644 --- a/chromeos/services/libassistant/BUILD.gn +++ b/chromeos/services/libassistant/BUILD.gn
@@ -34,12 +34,6 @@ sources = [ "assistant_manager_observer.h", - "audio/audio_input_impl.cc", - "audio/audio_input_impl.h", - "audio/audio_input_provider_impl.cc", - "audio/audio_input_provider_impl.h", - "audio/audio_input_stream.cc", - "audio/audio_input_stream.h", "audio_input_controller.cc", "audio_input_controller.h", "chromium_api_delegate.cc", @@ -71,8 +65,7 @@ ] deps = [ - ":buildflags", - ":fake_input_device", + ":audio", "//build/util:webkit_version", "//chromeos/assistant/internal", "//chromeos/assistant/internal:libassistant", @@ -87,8 +80,6 @@ "//libassistant/shared/internal_api/c:api_wrappers_entrypoint", "//libassistant/shared/public", "//libassistant/shared/public:export", - "//media", - "//services/audio/public/cpp", "//services/network/public/cpp", "//services/network/public/mojom", ] @@ -96,6 +87,45 @@ defines = [ "IS_LIBASSISTANT_SERVICE_IMPL" ] } +source_set("audio") { + visibility = [ ":*" ] + + sources = [ + "audio/audio_device_owner.cc", + "audio/audio_device_owner.h", + "audio/audio_input_impl.cc", + "audio/audio_input_impl.h", + "audio/audio_input_provider_impl.cc", + "audio/audio_input_provider_impl.h", + "audio/audio_input_stream.cc", + "audio/audio_input_stream.h", + "audio/audio_media_data_source.cc", + "audio/audio_media_data_source.h", + "audio/audio_output_provider_impl.cc", + "audio/audio_output_provider_impl.h", + "audio/audio_stream_handler.cc", + "audio/audio_stream_handler.h", + "audio/volume_control_impl.cc", + "audio/volume_control_impl.h", + ] + + deps = [ + ":buildflags", + ":fake_input_device", + "//ash/public/mojom", + "//base", + "//chromeos/services/assistant/public/cpp", + "//chromeos/services/libassistant/public/mojom", + "//libassistant/shared/internal_api/c:api_wrappers_entrypoint", + "//libassistant/shared/public", + "//libassistant/shared/public:export", + "//media", + "//services/audio/public/cpp", + "//services/audio/public/mojom", + "//services/media_session/public/mojom", + ] +} + source_set("fake_input_device") { visibility = [ ":*" ] @@ -130,6 +160,7 @@ source_set("unit_tests") { testonly = true sources = [ + "audio/audio_output_provider_impl_unittest.cc", "audio_input_controller_unittest.cc", "media_controller_unittest.cc", "power_manager_provider_impl_unittest.cc", @@ -139,6 +170,7 @@ ] deps = [ + ":audio", ":internal", ":libassistant", ":test_support",
diff --git a/chromeos/services/assistant/platform/audio_device_owner.cc b/chromeos/services/libassistant/audio/audio_device_owner.cc similarity index 97% rename from chromeos/services/assistant/platform/audio_device_owner.cc rename to chromeos/services/libassistant/audio/audio_device_owner.cc index 16d10eb4..f8e3a606 100644 --- a/chromeos/services/assistant/platform/audio_device_owner.cc +++ b/chromeos/services/libassistant/audio/audio_device_owner.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 "chromeos/services/assistant/platform/audio_device_owner.h" +#include "chromeos/services/libassistant/audio/audio_device_owner.h" #include <algorithm> #include <utility> @@ -13,7 +13,7 @@ #include "services/media_session/public/mojom/media_session.mojom.h" namespace chromeos { -namespace assistant { +namespace libassistant { // A macro which ensures we are running on the background thread. #define ENSURE_BACKGROUND_THREAD(method, ...) \ @@ -94,7 +94,7 @@ } void AudioDeviceOwner::StartOnMainThread( - chromeos::libassistant::mojom::AudioOutputDelegate* audio_output_delegate, + mojom::AudioOutputDelegate* audio_output_delegate, assistant_client::AudioOutput::Delegate* delegate, mojo::PendingRemote<audio::mojom::StreamFactory> stream_factory, const assistant_client::OutputStreamFormat& format) { @@ -253,5 +253,5 @@ ScheduleFillLocked(base::TimeTicks::Now()); } -} // namespace assistant +} // namespace libassistant } // namespace chromeos
diff --git a/chromeos/services/assistant/platform/audio_device_owner.h b/chromeos/services/libassistant/audio/audio_device_owner.h similarity index 89% rename from chromeos/services/assistant/platform/audio_device_owner.h rename to chromeos/services/libassistant/audio/audio_device_owner.h index 010fc3c..bda2fa1 100644 --- a/chromeos/services/assistant/platform/audio_device_owner.h +++ b/chromeos/services/libassistant/audio/audio_device_owner.h
@@ -2,14 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROMEOS_SERVICES_ASSISTANT_PLATFORM_AUDIO_DEVICE_OWNER_H_ -#define CHROMEOS_SERVICES_ASSISTANT_PLATFORM_AUDIO_DEVICE_OWNER_H_ +#ifndef CHROMEOS_SERVICES_LIBASSISTANT_AUDIO_AUDIO_DEVICE_OWNER_H_ +#define CHROMEOS_SERVICES_LIBASSISTANT_AUDIO_AUDIO_DEVICE_OWNER_H_ #include <memory> #include <string> #include <vector> -#include "base/component_export.h" #include "base/macros.h" #include "chromeos/services/libassistant/public/mojom/audio_output_delegate.mojom-forward.h" #include "libassistant/shared/public/platform_audio_output.h" @@ -22,11 +21,10 @@ #include "services/media_session/public/mojom/media_session.mojom.h" namespace chromeos { -namespace assistant { +namespace libassistant { -class COMPONENT_EXPORT(ASSISTANT_SERVICE) AudioDeviceOwner - : public media::AudioRendererSink::RenderCallback, - media_session::mojom::MediaSessionObserver { +class AudioDeviceOwner : public media::AudioRendererSink::RenderCallback, + media_session::mojom::MediaSessionObserver { public: AudioDeviceOwner( scoped_refptr<base::SequencedTaskRunner> task_runner, @@ -107,7 +105,7 @@ DISALLOW_COPY_AND_ASSIGN(AudioDeviceOwner); }; -} // namespace assistant +} // namespace libassistant } // namespace chromeos -#endif // CHROMEOS_SERVICES_ASSISTANT_PLATFORM_AUDIO_DEVICE_OWNER_H_ +#endif // CHROMEOS_SERVICES_LIBASSISTANT_AUDIO_AUDIO_DEVICE_OWNER_H_
diff --git a/chromeos/services/libassistant/audio/audio_input_impl.h b/chromeos/services/libassistant/audio/audio_input_impl.h index fca1f0b..57bed55 100644 --- a/chromeos/services/libassistant/audio/audio_input_impl.h +++ b/chromeos/services/libassistant/audio/audio_input_impl.h
@@ -9,7 +9,6 @@ #include <string> #include <vector> -#include "base/component_export.h" #include "base/macros.h" #include "base/observer_list.h" #include "base/optional.h" @@ -29,8 +28,7 @@ class AudioInputStream; class AudioCapturer; -class COMPONENT_EXPORT(LIBASSISTANT_SERVICE) AudioInputImpl - : public assistant_client::AudioInput { +class AudioInputImpl : public assistant_client::AudioInput { public: explicit AudioInputImpl(const base::Optional<std::string>& device_id); AudioInputImpl(const AudioInputImpl&) = delete;
diff --git a/chromeos/services/assistant/platform/audio_media_data_source.cc b/chromeos/services/libassistant/audio/audio_media_data_source.cc similarity index 88% rename from chromeos/services/assistant/platform/audio_media_data_source.cc rename to chromeos/services/libassistant/audio/audio_media_data_source.cc index d7c804b..0da9a19 100644 --- a/chromeos/services/assistant/platform/audio_media_data_source.cc +++ b/chromeos/services/libassistant/audio/audio_media_data_source.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 "chromeos/services/assistant/platform/audio_media_data_source.h" +#include "chromeos/services/libassistant/audio/audio_media_data_source.h" #include <algorithm> @@ -11,7 +11,7 @@ #include "base/time/time.h" namespace chromeos { -namespace assistant { +namespace libassistant { namespace { @@ -22,7 +22,7 @@ } // namespace AudioMediaDataSource::AudioMediaDataSource( - mojo::PendingReceiver<mojom::AssistantMediaDataSource> receiver, + mojo::PendingReceiver<AssistantMediaDataSource> receiver, scoped_refptr<base::SequencedTaskRunner> task_runner) : receiver_(this, std::move(receiver)), task_runner_(task_runner), @@ -37,9 +37,7 @@ } } -void AudioMediaDataSource::Read( - uint32_t size, - mojom::AssistantMediaDataSource::ReadCallback callback) { +void AudioMediaDataSource::Read(uint32_t size, ReadCallback callback) { // Note: mojom calls are sequenced, so we should not receive a second call to // Read() before we consumed the previous |read_callback_|. DCHECK(!read_callback_); @@ -74,5 +72,5 @@ std::move(read_callback_).Run(source_buffer_); } -} // namespace assistant +} // namespace libassistant } // namespace chromeos
diff --git a/chromeos/services/assistant/platform/audio_media_data_source.h b/chromeos/services/libassistant/audio/audio_media_data_source.h similarity index 69% rename from chromeos/services/assistant/platform/audio_media_data_source.h rename to chromeos/services/libassistant/audio/audio_media_data_source.h index f1a9b7254..d9b5f2b 100644 --- a/chromeos/services/assistant/platform/audio_media_data_source.h +++ b/chromeos/services/libassistant/audio/audio_media_data_source.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROMEOS_SERVICES_ASSISTANT_PLATFORM_AUDIO_MEDIA_DATA_SOURCE_H_ -#define CHROMEOS_SERVICES_ASSISTANT_PLATFORM_AUDIO_MEDIA_DATA_SOURCE_H_ +#ifndef CHROMEOS_SERVICES_LIBASSISTANT_AUDIO_AUDIO_MEDIA_DATA_SOURCE_H_ +#define CHROMEOS_SERVICES_LIBASSISTANT_AUDIO_AUDIO_MEDIA_DATA_SOURCE_H_ #include <vector> @@ -16,22 +16,23 @@ #include "mojo/public/cpp/bindings/receiver.h" namespace chromeos { -namespace assistant { +namespace libassistant { // Class to provide media data source for audio stream decoder. // Internally it will read media data from |delegate_|. -class AudioMediaDataSource : public mojom::AssistantMediaDataSource { +class AudioMediaDataSource + : public chromeos::assistant::mojom::AssistantMediaDataSource { public: AudioMediaDataSource( - mojo::PendingReceiver<mojom::AssistantMediaDataSource> receiver, + mojo::PendingReceiver< + chromeos::assistant::mojom::AssistantMediaDataSource> receiver, scoped_refptr<base::SequencedTaskRunner> task_runner); ~AudioMediaDataSource() override; - // mojom::MediaDataSource implementation. + // chromeos::assistant::mojom::MediaDataSource implementation. // Called by utility process. Must be called after |set_delegate()|. // The caller must wait for callback to finish before issuing the next read. - void Read(uint32_t size, - mojom::AssistantMediaDataSource::ReadCallback callback) override; + void Read(uint32_t size, ReadCallback callback) override; // Called by AudioStreamHandler on main thread. void set_delegate(assistant_client::AudioOutput::Delegate* delegate) { @@ -42,7 +43,7 @@ // Called on main thread. void OnFillBuffer(int bytes_filled); - mojo::Receiver<mojom::AssistantMediaDataSource> receiver_; + mojo::Receiver<AssistantMediaDataSource> receiver_; scoped_refptr<base::SequencedTaskRunner> task_runner_; @@ -50,14 +51,14 @@ std::vector<uint8_t> source_buffer_; - mojom::AssistantMediaDataSource::ReadCallback read_callback_; + ReadCallback read_callback_; base::WeakPtrFactory<AudioMediaDataSource> weak_factory_; DISALLOW_COPY_AND_ASSIGN(AudioMediaDataSource); }; -} // namespace assistant +} // namespace libassistant } // namespace chromeos -#endif // CHROMEOS_SERVICES_ASSISTANT_PLATFORM_AUDIO_MEDIA_DATA_SOURCE_H_ +#endif // CHROMEOS_SERVICES_LIBASSISTANT_AUDIO_AUDIO_MEDIA_DATA_SOURCE_H_
diff --git a/chromeos/services/assistant/platform/audio_output_provider_impl.cc b/chromeos/services/libassistant/audio/audio_output_provider_impl.cc similarity index 87% rename from chromeos/services/assistant/platform/audio_output_provider_impl.cc rename to chromeos/services/libassistant/audio/audio_output_provider_impl.cc index f6e29b5a..b75e95b 100644 --- a/chromeos/services/assistant/platform/audio_output_provider_impl.cc +++ b/chromeos/services/libassistant/audio/audio_output_provider_impl.cc
@@ -2,21 +2,21 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chromeos/services/assistant/platform/audio_output_provider_impl.h" +#include "chromeos/services/libassistant/audio/audio_output_provider_impl.h" #include <algorithm> #include <utility> #include "base/bind.h" #include "base/memory/weak_ptr.h" -#include "chromeos/services/assistant/platform/audio_stream_handler.h" #include "chromeos/services/assistant/public/mojom/assistant_audio_decoder.mojom.h" +#include "chromeos/services/libassistant/audio/audio_stream_handler.h" #include "chromeos/services/libassistant/public/mojom/platform_delegate.mojom.h" #include "libassistant/shared/public/platform_audio_buffer.h" #include "media/audio/audio_device_description.h" namespace chromeos { -namespace assistant { +namespace libassistant { namespace { @@ -33,8 +33,9 @@ mojo::PendingRemote<audio::mojom::StreamFactory> stream_factory, scoped_refptr<base::SequencedTaskRunner> task_runner, scoped_refptr<base::SequencedTaskRunner> background_task_runner, - mojom::AssistantAudioDecoderFactory* audio_decoder_factory, - chromeos::libassistant::mojom::AudioOutputDelegate* audio_output_delegate, + chromeos::assistant::mojom::AssistantAudioDecoderFactory* + audio_decoder_factory, + mojom::AudioOutputDelegate* audio_output_delegate, assistant_client::OutputStreamType type, assistant_client::OutputStreamFormat format, const std::string& device_id) @@ -86,7 +87,7 @@ // acquiring audio focus for the internal media player. if (stream_type_ == assistant_client::OutputStreamType::STREAM_MEDIA) { audio_output_delegate_->RequestAudioFocus( - chromeos::libassistant::mojom::AudioOutputStreamType::kMediaStream); + mojom::AudioOutputStreamType::kMediaStream); } if (IsEncodedFormat(format_)) { @@ -122,9 +123,9 @@ mojo::PendingRemote<audio::mojom::StreamFactory> stream_factory_; scoped_refptr<base::SequencedTaskRunner> main_task_runner_; scoped_refptr<base::SequencedTaskRunner> background_thread_task_runner_; - mojom::AssistantAudioDecoderFactory* audio_decoder_factory_; - chromeos::libassistant::mojom::AudioOutputDelegate* const - audio_output_delegate_; + chromeos::assistant::mojom::AssistantAudioDecoderFactory* + audio_decoder_factory_; + mojom::AudioOutputDelegate* const audio_output_delegate_; const assistant_client::OutputStreamType stream_type_; assistant_client::OutputStreamFormat format_; @@ -140,21 +141,26 @@ } // namespace AudioOutputProviderImpl::AudioOutputProviderImpl( - mojo::PendingRemote<chromeos::libassistant::mojom::AudioOutputDelegate> - audio_output_delegate, - chromeos::libassistant::mojom::PlatformDelegate* platform_delegate, scoped_refptr<base::SequencedTaskRunner> background_task_runner, const std::string& device_id) - : platform_delegate_(platform_delegate), - audio_output_delegate_(std::move(audio_output_delegate)), - loop_back_input_(platform_delegate_, - media::AudioDeviceDescription::kLoopbackInputDeviceId), - volume_control_impl_(audio_output_delegate_.get(), platform_delegate), + : loop_back_input_(media::AudioDeviceDescription::kLoopbackInputDeviceId), + volume_control_impl_(), main_task_runner_(base::SequencedTaskRunnerHandle::Get()), background_task_runner_(background_task_runner), - device_id_(device_id) { + device_id_(device_id) {} + +void AudioOutputProviderImpl::Bind( + mojo::PendingRemote<mojom::AudioOutputDelegate> audio_output_delegate, + mojom::PlatformDelegate* platform_delegate) { + platform_delegate_ = platform_delegate; platform_delegate_->BindAudioDecoderFactory( audio_decoder_factory_.BindNewPipeAndPassReceiver()); + + audio_output_delegate_.Bind(std::move(audio_output_delegate)); + + volume_control_impl_.Initialize(audio_output_delegate_.get(), + platform_delegate); + loop_back_input_.Initialize(platform_delegate); } AudioOutputProviderImpl::~AudioOutputProviderImpl() = default; @@ -210,5 +216,5 @@ platform_delegate_->BindAudioStreamFactory(std::move(receiver)); } -} // namespace assistant +} // namespace libassistant } // namespace chromeos
diff --git a/chromeos/services/assistant/platform/audio_output_provider_impl.h b/chromeos/services/libassistant/audio/audio_output_provider_impl.h similarity index 73% rename from chromeos/services/assistant/platform/audio_output_provider_impl.h rename to chromeos/services/libassistant/audio/audio_output_provider_impl.h index 2a8b21e..649bc7b 100644 --- a/chromeos/services/assistant/platform/audio_output_provider_impl.h +++ b/chromeos/services/libassistant/audio/audio_output_provider_impl.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROMEOS_SERVICES_ASSISTANT_PLATFORM_AUDIO_OUTPUT_PROVIDER_IMPL_H_ -#define CHROMEOS_SERVICES_ASSISTANT_PLATFORM_AUDIO_OUTPUT_PROVIDER_IMPL_H_ +#ifndef CHROMEOS_SERVICES_LIBASSISTANT_AUDIO_AUDIO_OUTPUT_PROVIDER_IMPL_H_ +#define CHROMEOS_SERVICES_LIBASSISTANT_AUDIO_AUDIO_OUTPUT_PROVIDER_IMPL_H_ #include <memory> #include <string> @@ -13,11 +13,11 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/single_thread_task_runner.h" -#include "chromeos/services/assistant/platform/audio_device_owner.h" -#include "chromeos/services/assistant/platform/audio_input_impl.h" -#include "chromeos/services/assistant/platform/volume_control_impl.h" #include "chromeos/services/assistant/public/cpp/assistant_service.h" #include "chromeos/services/assistant/public/mojom/assistant_audio_decoder.mojom.h" +#include "chromeos/services/libassistant/audio/audio_device_owner.h" +#include "chromeos/services/libassistant/audio/audio_input_impl.h" +#include "chromeos/services/libassistant/audio/volume_control_impl.h" #include "chromeos/services/libassistant/public/mojom/audio_output_delegate.mojom.h" #include "chromeos/services/libassistant/public/mojom/platform_delegate.mojom-forward.h" #include "libassistant/shared/public/platform_audio_output.h" @@ -27,18 +27,19 @@ namespace chromeos { -namespace assistant { +namespace libassistant { class AudioOutputProviderImpl : public assistant_client::AudioOutputProvider { public: AudioOutputProviderImpl( - mojo::PendingRemote<chromeos::libassistant::mojom::AudioOutputDelegate> - audio_output_delegate, - chromeos::libassistant::mojom::PlatformDelegate* platform_delegate, scoped_refptr<base::SequencedTaskRunner> background_task_runner, const std::string& device_id); ~AudioOutputProviderImpl() override; + void Bind( + mojo::PendingRemote<mojom::AudioOutputDelegate> audio_output_delegate, + mojom::PlatformDelegate* platform_delegate); + // assistant_client::AudioOutputProvider overrides: assistant_client::AudioOutput* CreateAudioOutput( assistant_client::OutputStreamType type, @@ -61,23 +62,23 @@ mojo::PendingReceiver<audio::mojom::StreamFactory> receiver); // Owned by |AssistantManagerServiceImpl|. - chromeos::libassistant::mojom::PlatformDelegate* const platform_delegate_; + mojom::PlatformDelegate* platform_delegate_ = nullptr; - mojo::Remote<chromeos::libassistant::mojom::AudioOutputDelegate> - audio_output_delegate_; + mojo::Remote<mojom::AudioOutputDelegate> audio_output_delegate_; AudioInputImpl loop_back_input_; VolumeControlImpl volume_control_impl_; scoped_refptr<base::SequencedTaskRunner> main_task_runner_; scoped_refptr<base::SequencedTaskRunner> background_task_runner_; - mojo::Remote<mojom::AssistantAudioDecoderFactory> audio_decoder_factory_; + mojo::Remote<chromeos::assistant::mojom::AssistantAudioDecoderFactory> + audio_decoder_factory_; std::string device_id_; base::WeakPtrFactory<AudioOutputProviderImpl> weak_ptr_factory_{this}; DISALLOW_COPY_AND_ASSIGN(AudioOutputProviderImpl); }; -} // namespace assistant +} // namespace libassistant } // namespace chromeos -#endif // CHROMEOS_SERVICES_ASSISTANT_PLATFORM_AUDIO_OUTPUT_PROVIDER_IMPL_H_ +#endif // CHROMEOS_SERVICES_LIBASSISTANT_AUDIO_AUDIO_OUTPUT_PROVIDER_IMPL_H_
diff --git a/chromeos/services/assistant/platform/audio_output_provider_impl_unittest.cc b/chromeos/services/libassistant/audio/audio_output_provider_impl_unittest.cc similarity index 96% rename from chromeos/services/assistant/platform/audio_output_provider_impl_unittest.cc rename to chromeos/services/libassistant/audio/audio_output_provider_impl_unittest.cc index 003ed99..91db2e4 100644 --- a/chromeos/services/assistant/platform/audio_output_provider_impl_unittest.cc +++ b/chromeos/services/libassistant/audio/audio_output_provider_impl_unittest.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 "chromeos/services/assistant/platform/audio_output_provider_impl.h" +#include "chromeos/services/libassistant/audio/audio_output_provider_impl.h" #include <memory> #include <utility> @@ -13,14 +13,13 @@ #include "base/run_loop.h" #include "base/test/task_environment.h" #include "base/threading/thread.h" -#include "chromeos/services/assistant/platform/audio_output_delegate_impl.h" #include "libassistant/shared/public/platform_audio_output.h" #include "media/base/audio_bus.h" #include "media/base/bind_to_current_loop.h" #include "testing/gtest/include/gtest/gtest.h" namespace chromeos { -namespace assistant { +namespace libassistant { class FakeAudioOutputDelegate : public assistant_client::AudioOutput::Delegate { public: @@ -149,5 +148,5 @@ EXPECT_TRUE(audio_output_delegate.end_of_stream()); } -} // namespace assistant +} // namespace libassistant } // namespace chromeos
diff --git a/chromeos/services/assistant/platform/audio_stream_handler.cc b/chromeos/services/libassistant/audio/audio_stream_handler.cc similarity index 92% rename from chromeos/services/assistant/platform/audio_stream_handler.cc rename to chromeos/services/libassistant/audio/audio_stream_handler.cc index 78e72cb..8b14058 100644 --- a/chromeos/services/assistant/platform/audio_stream_handler.cc +++ b/chromeos/services/libassistant/audio/audio_stream_handler.cc
@@ -2,15 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chromeos/services/assistant/platform/audio_stream_handler.h" +#include "chromeos/services/libassistant/audio/audio_stream_handler.h" #include "base/bind.h" -#include "chromeos/services/assistant/platform/audio_media_data_source.h" +#include "chromeos/services/libassistant/audio/audio_media_data_source.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/pending_remote.h" namespace chromeos { -namespace assistant { +namespace libassistant { AudioStreamHandler::AudioStreamHandler( scoped_refptr<base::SequencedTaskRunner> task_runner) @@ -19,13 +19,15 @@ AudioStreamHandler::~AudioStreamHandler() = default; void AudioStreamHandler::StartAudioDecoder( - mojom::AssistantAudioDecoderFactory* audio_decoder_factory, + chromeos::assistant::mojom::AssistantAudioDecoderFactory* + audio_decoder_factory, assistant_client::AudioOutput::Delegate* delegate, InitCB on_inited) { - mojo::PendingRemote<mojom::AssistantAudioDecoderClient> client; + mojo::PendingRemote<AssistantAudioDecoderClient> client; client_receiver_.Bind(client.InitWithNewPipeAndPassReceiver()); - mojo::PendingRemote<mojom::AssistantMediaDataSource> data_source; + mojo::PendingRemote<chromeos::assistant::mojom::AssistantMediaDataSource> + data_source; media_data_source_ = std::make_unique<AudioMediaDataSource>( data_source.InitWithNewPipeAndPassReceiver(), task_runner_); @@ -180,5 +182,5 @@ audio_decoder_->Decode(); } -} // namespace assistant +} // namespace libassistant } // namespace chromeos
diff --git a/chromeos/services/assistant/platform/audio_stream_handler.h b/chromeos/services/libassistant/audio/audio_stream_handler.h similarity index 82% rename from chromeos/services/assistant/platform/audio_stream_handler.h rename to chromeos/services/libassistant/audio/audio_stream_handler.h index 93c67978..df35db9 100644 --- a/chromeos/services/assistant/platform/audio_stream_handler.h +++ b/chromeos/services/libassistant/audio/audio_stream_handler.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROMEOS_SERVICES_ASSISTANT_PLATFORM_AUDIO_STREAM_HANDLER_H_ -#define CHROMEOS_SERVICES_ASSISTANT_PLATFORM_AUDIO_STREAM_HANDLER_H_ +#ifndef CHROMEOS_SERVICES_LIBASSISTANT_AUDIO_AUDIO_STREAM_HANDLER_H_ +#define CHROMEOS_SERVICES_LIBASSISTANT_AUDIO_AUDIO_STREAM_HANDLER_H_ #include "base/macros.h" #include "base/single_thread_task_runner.h" @@ -14,12 +14,13 @@ #include "mojo/public/cpp/bindings/remote.h" namespace chromeos { -namespace assistant { +namespace libassistant { class AudioMediaDataSource; -class AudioStreamHandler : public mojom::AssistantAudioDecoderClient, - public assistant_client::AudioOutput::Delegate { +class AudioStreamHandler + : public chromeos::assistant::mojom::AssistantAudioDecoderClient, + public assistant_client::AudioOutput::Delegate { public: using InitCB = base::OnceCallback<void(const assistant_client::OutputStreamFormat&)>; @@ -30,11 +31,12 @@ // Called on main thread. void StartAudioDecoder( - mojom::AssistantAudioDecoderFactory* audio_decoder_factory, + chromeos::assistant::mojom::AssistantAudioDecoderFactory* + audio_decoder_factory, assistant_client::AudioOutput::Delegate* delegate, InitCB start_device_owner_on_main_thread); - // mojom::AssistantAudioDecoderClient overrides: + // chromeos::assistant::mojom::AssistantAudioDecoderClient overrides: // Called by |audio_decoder_| on utility thread. void OnNewBuffers(const std::vector<std::vector<uint8_t>>& buffers) override; @@ -74,9 +76,10 @@ scoped_refptr<base::SequencedTaskRunner> task_runner_; assistant_client::AudioOutput::Delegate* delegate_; - mojo::Receiver<mojom::AssistantAudioDecoderClient> client_receiver_{this}; + mojo::Receiver<AssistantAudioDecoderClient> client_receiver_{this}; std::unique_ptr<AudioMediaDataSource> media_data_source_; - mojo::Remote<mojom::AssistantAudioDecoder> audio_decoder_; + mojo::Remote<chromeos::assistant::mojom::AssistantAudioDecoder> + audio_decoder_; // True when there is more decoded data. bool no_more_data_ = false; @@ -102,7 +105,7 @@ DISALLOW_COPY_AND_ASSIGN(AudioStreamHandler); }; -} // namespace assistant +} // namespace libassistant } // namespace chromeos -#endif // CHROMEOS_SERVICES_ASSISTANT_PLATFORM_AUDIO_STREAM_HANDLER_H_ +#endif // CHROMEOS_SERVICES_LIBASSISTANT_AUDIO_AUDIO_STREAM_HANDLER_H_
diff --git a/chromeos/services/assistant/platform/volume_control_impl.cc b/chromeos/services/libassistant/audio/volume_control_impl.cc similarity index 88% rename from chromeos/services/assistant/platform/volume_control_impl.cc rename to chromeos/services/libassistant/audio/volume_control_impl.cc index cb8ca7a0..3825b26 100644 --- a/chromeos/services/assistant/platform/volume_control_impl.cc +++ b/chromeos/services/libassistant/audio/volume_control_impl.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chromeos/services/assistant/platform/volume_control_impl.h" +#include "chromeos/services/libassistant/audio/volume_control_impl.h" #include <utility> @@ -34,15 +34,18 @@ }; } // namespace mojo -namespace chromeos { -namespace assistant { -VolumeControlImpl::VolumeControlImpl( - chromeos::libassistant::mojom::AudioOutputDelegate* audio_output_delegate, - chromeos::libassistant::mojom::PlatformDelegate* platform_delegate) - : audio_output_delegate_(audio_output_delegate), - main_task_runner_(base::SequencedTaskRunnerHandle::Get()), - weak_factory_(this) { +namespace chromeos { +namespace libassistant { + +VolumeControlImpl::VolumeControlImpl() + : main_task_runner_(base::SequencedTaskRunnerHandle::Get()), + weak_factory_(this) {} + +void VolumeControlImpl::Initialize( + mojom::AudioOutputDelegate* audio_output_delegate, + mojom::PlatformDelegate* platform_delegate) { + audio_output_delegate_ = audio_output_delegate; platform_delegate->BindAssistantVolumeControl( volume_control_.BindNewPipeAndPassReceiver()); mojo::PendingRemote<ash::mojom::VolumeObserver> observer; @@ -115,5 +118,5 @@ volume_control_->SetMuted(muted); } -} // namespace assistant +} // namespace libassistant } // namespace chromeos
diff --git a/chromeos/services/assistant/platform/volume_control_impl.h b/chromeos/services/libassistant/audio/volume_control_impl.h similarity index 79% rename from chromeos/services/assistant/platform/volume_control_impl.h rename to chromeos/services/libassistant/audio/volume_control_impl.h index f076486..574afa2 100644 --- a/chromeos/services/assistant/platform/volume_control_impl.h +++ b/chromeos/services/libassistant/audio/volume_control_impl.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROMEOS_SERVICES_ASSISTANT_PLATFORM_VOLUME_CONTROL_IMPL_H_ -#define CHROMEOS_SERVICES_ASSISTANT_PLATFORM_VOLUME_CONTROL_IMPL_H_ +#ifndef CHROMEOS_SERVICES_LIBASSISTANT_AUDIO_VOLUME_CONTROL_IMPL_H_ +#define CHROMEOS_SERVICES_LIBASSISTANT_AUDIO_VOLUME_CONTROL_IMPL_H_ #include "ash/public/mojom/assistant_volume_control.mojom.h" #include "base/macros.h" @@ -14,16 +14,17 @@ #include "mojo/public/cpp/bindings/remote.h" namespace chromeos { -namespace assistant { +namespace libassistant { class VolumeControlImpl : public assistant_client::VolumeControl, public ash::mojom::VolumeObserver { public: - VolumeControlImpl( - chromeos::libassistant::mojom::AudioOutputDelegate* audio_output_delegate, - chromeos::libassistant::mojom::PlatformDelegate* platform_delegate); + VolumeControlImpl(); ~VolumeControlImpl() override; + void Initialize(mojom::AudioOutputDelegate* audio_output_delegate, + mojom::PlatformDelegate* platform_delegate); + // assistant_client::VolumeControl overrides: void SetAudioFocus( assistant_client::OutputStreamType focused_stream) override; @@ -45,8 +46,7 @@ void SetSystemMutedOnMainThread(bool muted); // Owned by |AudioOutputProviderImpl|. - chromeos::libassistant::mojom::AudioOutputDelegate* const - audio_output_delegate_; + mojom::AudioOutputDelegate* audio_output_delegate_ = nullptr; mojo::Remote<ash::mojom::AssistantVolumeControl> volume_control_; mojo::Receiver<ash::mojom::VolumeObserver> receiver_{this}; scoped_refptr<base::SequencedTaskRunner> main_task_runner_; @@ -59,7 +59,7 @@ DISALLOW_COPY_AND_ASSIGN(VolumeControlImpl); }; -} // namespace assistant +} // namespace libassistant } // namespace chromeos -#endif // CHROMEOS_SERVICES_ASSISTANT_PLATFORM_VOLUME_CONTROL_IMPL_H_ +#endif // CHROMEOS_SERVICES_LIBASSISTANT_AUDIO_VOLUME_CONTROL_IMPL_H_
diff --git a/chromeos/services/libassistant/conversation_controller.cc b/chromeos/services/libassistant/conversation_controller.cc index b9e96ba2..2f10e42 100644 --- a/chromeos/services/libassistant/conversation_controller.cc +++ b/chromeos/services/libassistant/conversation_controller.cc
@@ -66,12 +66,12 @@ } void ConversationController::RetrieveNotification( - mojom::AssistantNotificationPtr notification, + const AssistantNotification& notification, int32_t action_index) { const std::string request_interaction = assistant::SerializeNotificationRequestInteraction( - notification->server_id, notification->consistency_token, - notification->opaque_token, action_index); + notification.server_id, notification.consistency_token, + notification.opaque_token, action_index); SendVoicelessInteraction(request_interaction, /*description=*/"RequestNotification", @@ -79,7 +79,7 @@ } void ConversationController::DismissNotification( - mojom::AssistantNotificationPtr notification) { + const AssistantNotification& notification) { // |assistant_manager_internal()| may not exist if we are dismissing // notifications as part of a shutdown sequence. if (!assistant_manager_internal()) @@ -87,11 +87,11 @@ const std::string dismissed_interaction = assistant::SerializeNotificationDismissedInteraction( - notification->server_id, notification->consistency_token, - notification->opaque_token, {notification->grouping_key}); + notification.server_id, notification.consistency_token, + notification.opaque_token, {notification.grouping_key}); assistant_client::VoicelessOptions options; - options.obfuscated_gaia_id = notification->obfuscated_gaia_id; + options.obfuscated_gaia_id = notification.obfuscated_gaia_id; assistant_manager_internal()->SendVoicelessInteraction( dismissed_interaction, /*description=*/"DismissNotification", options, @@ -99,11 +99,11 @@ } void ConversationController::SendAssistantFeedback( - mojom::AssistantFeedbackPtr feedback) { - std::string raw_image_data(feedback->screenshot_png.begin(), - feedback->screenshot_png.end()); + const AssistantFeedback& feedback) { + std::string raw_image_data(feedback.screenshot_png.begin(), + feedback.screenshot_png.end()); const std::string interaction = assistant::CreateSendFeedbackInteraction( - feedback->assistant_debug_info_allowed, feedback->description, + feedback.assistant_debug_info_allowed, feedback.description, raw_image_data); SendVoicelessInteraction(interaction,
diff --git a/chromeos/services/libassistant/conversation_controller.h b/chromeos/services/libassistant/conversation_controller.h index 62e738c..8c6f628 100644 --- a/chromeos/services/libassistant/conversation_controller.h +++ b/chromeos/services/libassistant/conversation_controller.h
@@ -23,6 +23,9 @@ class COMPONENT_EXPORT(LIBASSISTANT_SERVICE) ConversationController : public mojom::ConversationController { public: + using AssistantNotification = ::chromeos::assistant::AssistantNotification; + using AssistantFeedback = ::chromeos::assistant::AssistantFeedback; + explicit ConversationController(ServiceController* service_controller); ConversationController(const ConversationController&) = delete; ConversationController& operator=(const ConversationController&) = delete; @@ -36,10 +39,10 @@ bool allow_tts, const base::Optional<std::string>& conversation_id) override; void StartEditReminderInteraction(const std::string& client_id) override; - void RetrieveNotification(mojom::AssistantNotificationPtr notification, + void RetrieveNotification(const AssistantNotification& notification, int32_t action_index) override; - void DismissNotification(mojom::AssistantNotificationPtr) override; - void SendAssistantFeedback(mojom::AssistantFeedbackPtr feedback) override; + void DismissNotification(const AssistantNotification& notification) override; + void SendAssistantFeedback(const AssistantFeedback& feedback) override; private: void SendVoicelessInteraction(const std::string& interaction,
diff --git a/chromeos/services/libassistant/libassistant_service.cc b/chromeos/services/libassistant/libassistant_service.cc index 00cfa21..974960b 100644 --- a/chromeos/services/libassistant/libassistant_service.cc +++ b/chromeos/services/libassistant/libassistant_service.cc
@@ -52,7 +52,6 @@ platform_api_ ->SetAudioInputProvider( &audio_input_controller_->audio_input_provider()) - .SetAudioOutputProvider(&platform_api->GetAudioOutputProvider()) .SetAuthProvider(fake_auth_provider_.get()) .SetFileProvider(&platform_api->GetFileProvider()) .SetNetworkProvider(&platform_api->GetNetworkProvider()); @@ -77,6 +76,7 @@ mojo::PendingReceiver<mojom::DisplayController> display_controller, mojo::PendingReceiver<mojom::MediaController> media_controller, mojo::PendingReceiver<mojom::ServiceController> service_controller, + mojo::PendingRemote<mojom::AudioOutputDelegate> audio_output_delegate, mojo::PendingRemote<mojom::MediaDelegate> media_delegate, mojo::PendingRemote<mojom::PlatformDelegate> platform_delegate) { platform_delegate_.Bind(std::move(platform_delegate)); @@ -86,9 +86,9 @@ display_controller_->Bind(std::move(display_controller)); media_controller_->Bind(std::move(media_controller), std::move(media_delegate)); + platform_api_->Bind(std::move(audio_output_delegate), + platform_delegate_.get()); service_controller_->Bind(std::move(service_controller)); - - platform_api_->Initialize(platform_delegate_.get()); } void LibassistantService::SetInitializeCallback(InitializeCallback callback) {
diff --git a/chromeos/services/libassistant/libassistant_service.h b/chromeos/services/libassistant/libassistant_service.h index 71e068bd2..f615684c 100644 --- a/chromeos/services/libassistant/libassistant_service.h +++ b/chromeos/services/libassistant/libassistant_service.h
@@ -65,6 +65,7 @@ mojo::PendingReceiver<mojom::DisplayController> display_controller, mojo::PendingReceiver<mojom::MediaController> media_controller, mojo::PendingReceiver<mojom::ServiceController> service_controller, + mojo::PendingRemote<mojom::AudioOutputDelegate> audio_output_delegate, mojo::PendingRemote<mojom::MediaDelegate> media_delegate, mojo::PendingRemote<mojom::PlatformDelegate> platform_delegate) override; void AddSpeechRecognitionObserver(
diff --git a/chromeos/services/libassistant/platform_api.cc b/chromeos/services/libassistant/platform_api.cc index 51625ca..847f9ba6 100644 --- a/chromeos/services/libassistant/platform_api.cc +++ b/chromeos/services/libassistant/platform_api.cc
@@ -3,15 +3,21 @@ // found in the LICENSE file. #include "chromeos/services/libassistant/platform_api.h" + #include "base/check.h" #include "chromeos/services/assistant/public/cpp/features.h" +#include "chromeos/services/libassistant/audio/audio_output_provider_impl.h" #include "chromeos/services/libassistant/power_manager_provider_impl.h" #include "chromeos/services/libassistant/system_provider_impl.h" +#include "media/audio/audio_device_description.h" namespace chromeos { namespace libassistant { -PlatformApi::PlatformApi() { +PlatformApi::PlatformApi() + : audio_output_provider_(std::make_unique<AudioOutputProviderImpl>( + /*background_task_runner=*/base::SequencedTaskRunnerHandle::Get(), + media::AudioDeviceDescription::kDefaultDeviceId)) { // Only enable native power features if they are supported by the UI. std::unique_ptr<PowerManagerProviderImpl> provider; if (assistant::features::IsPowerManagerEnabled()) { @@ -22,9 +28,12 @@ PlatformApi::~PlatformApi() = default; -void PlatformApi::Initialize( - chromeos::libassistant::mojom::PlatformDelegate* delegate) { - system_provider_->Initialize(delegate); +void PlatformApi::Bind( + mojo::PendingRemote<mojom::AudioOutputDelegate> audio_output_delegate, + mojom::PlatformDelegate* platform_delegate) { + audio_output_provider_->Bind(std::move(audio_output_delegate), + platform_delegate); + system_provider_->Initialize(platform_delegate); } PlatformApi& PlatformApi::SetAudioInputProvider( @@ -33,12 +42,6 @@ return *this; } -PlatformApi& PlatformApi::SetAudioOutputProvider( - assistant_client::AudioOutputProvider* provider) { - audio_output_provider_ = provider; - return *this; -} - PlatformApi& PlatformApi::SetAuthProvider( assistant_client::AuthProvider* provider) { auth_provider_ = provider;
diff --git a/chromeos/services/libassistant/platform_api.h b/chromeos/services/libassistant/platform_api.h index 86a035a..a473977 100644 --- a/chromeos/services/libassistant/platform_api.h +++ b/chromeos/services/libassistant/platform_api.h
@@ -9,11 +9,14 @@ #include <memory> +#include "chromeos/services/libassistant/public/mojom/audio_output_delegate.mojom.h" #include "chromeos/services/libassistant/public/mojom/platform_delegate.mojom.h" +#include "mojo/public/cpp/bindings/pending_remote.h" namespace chromeos { namespace libassistant { +class AudioOutputProviderImpl; class SystemProviderImpl; // Implementation of the Libassistant PlatformApi. @@ -26,10 +29,11 @@ PlatformApi& operator=(const PlatformApi&) = delete; ~PlatformApi() override; - void Initialize(chromeos::libassistant::mojom::PlatformDelegate* delegate); + void Bind( + mojo::PendingRemote<mojom::AudioOutputDelegate> audio_output_delegate, + mojom::PlatformDelegate* platform_delegate); PlatformApi& SetAudioInputProvider(assistant_client::AudioInputProvider*); - PlatformApi& SetAudioOutputProvider(assistant_client::AudioOutputProvider*); PlatformApi& SetAuthProvider(assistant_client::AuthProvider*); PlatformApi& SetFileProvider(assistant_client::FileProvider*); PlatformApi& SetNetworkProvider(assistant_client::NetworkProvider*); @@ -46,11 +50,11 @@ // The below are all owned by the browser side |PlatformApiImpl|, // which outlives us. assistant_client::AudioInputProvider* audio_input_provider_ = nullptr; - assistant_client::AudioOutputProvider* audio_output_provider_ = nullptr; assistant_client::AuthProvider* auth_provider_ = nullptr; assistant_client::FileProvider* file_provider_ = nullptr; assistant_client::NetworkProvider* network_provider_ = nullptr; + std::unique_ptr<AudioOutputProviderImpl> audio_output_provider_; std::unique_ptr<SystemProviderImpl> system_provider_; };
diff --git a/chromeos/services/libassistant/public/mojom/BUILD.gn b/chromeos/services/libassistant/public/mojom/BUILD.gn index 5d9d155..88169c61 100644 --- a/chromeos/services/libassistant/public/mojom/BUILD.gn +++ b/chromeos/services/libassistant/public/mojom/BUILD.gn
@@ -41,11 +41,22 @@ mojom = "chromeos.libassistant.mojom.AndroidAppStatus" cpp = "::chromeos::assistant::AppStatus" }, + { + mojom = "chromeos.libassistant.mojom.AssistantNotification" + cpp = "::chromeos::assistant::AssistantNotification" + }, + { + mojom = "chromeos.libassistant.mojom.AssistantFeedback" + cpp = "::chromeos::assistant::AssistantFeedback" + }, ] traits_headers = [ "mojom_traits.h" ] traits_sources = [ "mojom_traits.cc" ] - traits_public_deps = [ "//chromeos/services/assistant/public/shared" ] + traits_public_deps = [ + "//chromeos/services/assistant/public/cpp", + "//chromeos/services/assistant/public/shared", + ] }, ] }
diff --git a/chromeos/services/libassistant/public/mojom/mojom_traits.cc b/chromeos/services/libassistant/public/mojom/mojom_traits.cc index 1e11da4..bad44ac 100644 --- a/chromeos/services/libassistant/public/mojom/mojom_traits.cc +++ b/chromeos/services/libassistant/public/mojom/mojom_traits.cc
@@ -9,7 +9,15 @@ using AppStatus = chromeos::assistant::AppStatus; using AndroidAppStatus = chromeos::libassistant::mojom::AndroidAppStatus; using chromeos::assistant::AndroidAppInfo; +using chromeos::assistant::AssistantFeedback; +using chromeos::assistant::AssistantNotification; using chromeos::libassistant::mojom::AndroidAppInfoDataView; +using chromeos::libassistant::mojom::AssistantFeedbackDataView; +using chromeos::libassistant::mojom::AssistantNotificationDataView; + +//////////////////////////////////////////////////////////////////////////////// +// AndroidAppStatus +//////////////////////////////////////////////////////////////////////////////// AndroidAppStatus EnumTraits<AndroidAppStatus, AppStatus>::ToMojom( AppStatus input) { @@ -49,7 +57,12 @@ return true; } -std::string StructTraits<AndroidAppInfoDataView, AndroidAppInfo>::package_name( +//////////////////////////////////////////////////////////////////////////////// +// AndroidAppInfo +//////////////////////////////////////////////////////////////////////////////// + +const std::string& +StructTraits<AndroidAppInfoDataView, AndroidAppInfo>::package_name( const AndroidAppInfo& input) { return input.package_name; } @@ -59,13 +72,13 @@ return input.version; } -std::string +const std::string& StructTraits<AndroidAppInfoDataView, AndroidAppInfo>::localized_app_name( const AndroidAppInfo& input) { return input.localized_app_name; } -std::string StructTraits<AndroidAppInfoDataView, AndroidAppInfo>::intent( +const std::string& StructTraits<AndroidAppInfoDataView, AndroidAppInfo>::intent( const AndroidAppInfo& input) { return input.intent; } @@ -76,7 +89,7 @@ return input.status; } -std::string StructTraits<AndroidAppInfoDataView, AndroidAppInfo>::action( +const std::string& StructTraits<AndroidAppInfoDataView, AndroidAppInfo>::action( const AndroidAppInfo& input) { return input.action; } @@ -98,4 +111,86 @@ return true; } +//////////////////////////////////////////////////////////////////////////////// +// AssistantNotification +//////////////////////////////////////////////////////////////////////////////// + +const std::string& +StructTraits<AssistantNotificationDataView, AssistantNotification>::server_id( + const AssistantNotification& input) { + return input.server_id; +} + +const std::string& +StructTraits<AssistantNotificationDataView, AssistantNotification>:: + consistency_token(const AssistantNotification& input) { + return input.consistency_token; +} + +const std::string& StructTraits< + AssistantNotificationDataView, + AssistantNotification>::opaque_token(const AssistantNotification& input) { + return input.opaque_token; +} + +const std::string& StructTraits< + AssistantNotificationDataView, + AssistantNotification>::grouping_key(const AssistantNotification& input) { + return input.grouping_key; +} + +const std::string& +StructTraits<AssistantNotificationDataView, AssistantNotification>:: + obfuscated_gaia_id(const AssistantNotification& input) { + return input.obfuscated_gaia_id; +} + +bool StructTraits<AssistantNotificationDataView, AssistantNotification>::Read( + chromeos::libassistant::mojom::AssistantNotificationDataView data, + AssistantNotification* output) { + if (!data.ReadServerId(&output->server_id)) + return false; + if (!data.ReadConsistencyToken(&output->consistency_token)) + return false; + if (!data.ReadOpaqueToken(&output->opaque_token)) + return false; + if (!data.ReadGroupingKey(&output->grouping_key)) + return false; + if (!data.ReadObfuscatedGaiaId(&output->obfuscated_gaia_id)) + return false; + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// AssistantFeedback +//////////////////////////////////////////////////////////////////////////////// + +const std::string& +StructTraits<AssistantFeedbackDataView, AssistantFeedback>::description( + const AssistantFeedback& input) { + return input.description; +} + +bool StructTraits<AssistantFeedbackDataView, AssistantFeedback>:: + assistant_debug_info_allowed(const AssistantFeedback& input) { + return input.assistant_debug_info_allowed; +} + +base::span<const uint8_t> +StructTraits<AssistantFeedbackDataView, AssistantFeedback>::screenshot_png( + const AssistantFeedback& input) { + return input.screenshot_png; +} + +bool StructTraits<AssistantFeedbackDataView, AssistantFeedback>::Read( + chromeos::libassistant::mojom::AssistantFeedbackDataView data, + AssistantFeedback* output) { + if (!data.ReadDescription(&output->description)) + return false; + output->assistant_debug_info_allowed = data.assistant_debug_info_allowed(); + if (!data.ReadScreenshotPng(&output->screenshot_png)) + return false; + return true; +} + } // namespace mojo
diff --git a/chromeos/services/libassistant/public/mojom/mojom_traits.h b/chromeos/services/libassistant/public/mojom/mojom_traits.h index d544d726..3bee4413 100644 --- a/chromeos/services/libassistant/public/mojom/mojom_traits.h +++ b/chromeos/services/libassistant/public/mojom/mojom_traits.h
@@ -5,8 +5,14 @@ #ifndef CHROMEOS_SERVICES_LIBASSISTANT_PUBLIC_MOJOM_MOJOM_TRAITS_H_ #define CHROMEOS_SERVICES_LIBASSISTANT_PUBLIC_MOJOM_MOJOM_TRAITS_H_ +#include <cstdint> + +#include "base/containers/span.h" +#include "chromeos/services/assistant/public/cpp/assistant_notification.h" +#include "chromeos/services/assistant/public/cpp/assistant_service.h" #include "chromeos/services/assistant/public/shared/utils.h" -#include "chromeos/services/libassistant/public/mojom/android_app_info.mojom.h" +#include "chromeos/services/libassistant/public/mojom/android_app_info.mojom-shared.h" +#include "chromeos/services/libassistant/public/mojom/conversation_controller.mojom-shared.h" namespace mojo { @@ -15,12 +21,12 @@ chromeos::assistant::AndroidAppInfo> { using AndroidAppInfo = chromeos::assistant::AndroidAppInfo; - static std::string package_name(const AndroidAppInfo& input); + static const std::string& package_name(const AndroidAppInfo& input); static int64_t version(const AndroidAppInfo& input); - static std::string localized_app_name(const AndroidAppInfo& input); - static std::string intent(const AndroidAppInfo& input); + static const std::string& localized_app_name(const AndroidAppInfo& input); + static const std::string& intent(const AndroidAppInfo& input); static chromeos::assistant::AppStatus status(const AndroidAppInfo& input); - static std::string action(const AndroidAppInfo& input); + static const std::string& action(const AndroidAppInfo& input); static bool Read(chromeos::libassistant::mojom::AndroidAppInfoDataView data, AndroidAppInfo* output); @@ -35,6 +41,40 @@ static bool FromMojom(AndroidAppStatus input, AppStatus* output); }; +template <> +struct StructTraits< + chromeos::libassistant::mojom::AssistantNotificationDataView, + chromeos::assistant::AssistantNotification> { + using AssistantNotification = chromeos::assistant::AssistantNotification; + + static const std::string& server_id(const AssistantNotification& input); + static const std::string& consistency_token( + const AssistantNotification& input); + static const std::string& opaque_token(const AssistantNotification& input); + static const std::string& grouping_key(const AssistantNotification& input); + static const std::string& obfuscated_gaia_id( + const AssistantNotification& input); + + static bool Read( + chromeos::libassistant::mojom::AssistantNotificationDataView data, + AssistantNotification* output); +}; + +template <> +struct StructTraits<chromeos::libassistant::mojom::AssistantFeedbackDataView, + chromeos::assistant::AssistantFeedback> { + using AssistantFeedback = chromeos::assistant::AssistantFeedback; + + static const std::string& description(const AssistantFeedback& input); + static bool assistant_debug_info_allowed(const AssistantFeedback& input); + static base::span<const uint8_t> screenshot_png( + const AssistantFeedback& input); + + static bool Read( + chromeos::libassistant::mojom::AssistantFeedbackDataView data, + AssistantFeedback* output); +}; + } // namespace mojo #endif // CHROMEOS_SERVICES_LIBASSISTANT_PUBLIC_MOJOM_MOJOM_TRAITS_H_
diff --git a/chromeos/services/libassistant/public/mojom/service.mojom b/chromeos/services/libassistant/public/mojom/service.mojom index c21d2da7..605dfa1 100644 --- a/chromeos/services/libassistant/public/mojom/service.mojom +++ b/chromeos/services/libassistant/public/mojom/service.mojom
@@ -6,6 +6,7 @@ import "chromeos/services/libassistant/public/mojom/audio_input_controller.mojom"; import "chromeos/services/libassistant/public/mojom/conversation_controller.mojom"; +import "chromeos/services/libassistant/public/mojom/audio_output_delegate.mojom"; import "chromeos/services/libassistant/public/mojom/display_controller.mojom"; import "chromeos/services/libassistant/public/mojom/platform_delegate.mojom"; import "chromeos/services/libassistant/public/mojom/service_controller.mojom"; @@ -27,6 +28,7 @@ pending_receiver<DisplayController> display_controller, pending_receiver<MediaController> media_controller, pending_receiver<ServiceController> service_controller, + pending_remote<AudioOutputDelegate> audio_output_delegate, pending_remote<MediaDelegate> media_delegate, pending_remote<PlatformDelegate> platform_delegate );
diff --git a/chromeos/services/libassistant/test_support/libassistant_service_tester.cc b/chromeos/services/libassistant/test_support/libassistant_service_tester.cc index 6738dab..46b4310 100644 --- a/chromeos/services/libassistant/test_support/libassistant_service_tester.cc +++ b/chromeos/services/libassistant/test_support/libassistant_service_tester.cc
@@ -36,19 +36,24 @@ } void LibassistantServiceTester::BindControllers() { - mojo::PendingRemote<mojom::PlatformDelegate> pending_platform_delegate_remote; - pending_platform_delegate_ = - pending_platform_delegate_remote.InitWithNewPipeAndPassReceiver(); - + mojo::PendingRemote<mojom::AudioOutputDelegate> + pending_audio_output_delegate_remote; mojo::PendingRemote<mojom::MediaDelegate> pending_media_delegate_remote; + mojo::PendingRemote<mojom::PlatformDelegate> pending_platform_delegate_remote; + + pending_audio_output_delegate_ = + pending_audio_output_delegate_remote.InitWithNewPipeAndPassReceiver(); pending_media_delegate_ = pending_media_delegate_remote.InitWithNewPipeAndPassReceiver(); + pending_platform_delegate_ = + pending_platform_delegate_remote.InitWithNewPipeAndPassReceiver(); service_.Bind(audio_input_controller_.BindNewPipeAndPassReceiver(), conversation_controller_.BindNewPipeAndPassReceiver(), display_controller_.BindNewPipeAndPassReceiver(), media_controller_.BindNewPipeAndPassReceiver(), service_controller_.BindNewPipeAndPassReceiver(), + std::move(pending_audio_output_delegate_remote), std::move(pending_media_delegate_remote), std::move(pending_platform_delegate_remote)); }
diff --git a/chromeos/services/libassistant/test_support/libassistant_service_tester.h b/chromeos/services/libassistant/test_support/libassistant_service_tester.h index 7d377b65..c5920ef 100644 --- a/chromeos/services/libassistant/test_support/libassistant_service_tester.h +++ b/chromeos/services/libassistant/test_support/libassistant_service_tester.h
@@ -8,6 +8,7 @@ #include "chromeos/services/assistant/public/cpp/migration/fake_assistant_manager_service_delegate.h" #include "chromeos/services/libassistant/libassistant_service.h" #include "chromeos/services/libassistant/public/mojom/audio_input_controller.mojom.h" +#include "chromeos/services/libassistant/public/mojom/audio_output_delegate.mojom-forward.h" #include "chromeos/services/libassistant/public/mojom/conversation_controller.mojom.h" #include "chromeos/services/libassistant/public/mojom/display_controller.mojom.h" #include "chromeos/services/libassistant/public/mojom/service.mojom.h" @@ -68,8 +69,10 @@ mojo::Remote<mojom::DisplayController> display_controller_; mojo::Remote<mojom::MediaController> media_controller_; mojo::Remote<mojom::ServiceController> service_controller_; - mojo::PendingReceiver<mojom::PlatformDelegate> pending_platform_delegate_; + mojo::PendingReceiver<mojom::AudioOutputDelegate> + pending_audio_output_delegate_; mojo::PendingReceiver<mojom::MediaDelegate> pending_media_delegate_; + mojo::PendingReceiver<mojom::PlatformDelegate> pending_platform_delegate_; mojo::Remote<mojom::LibassistantService> service_remote_; assistant::FakeAssistantManagerServiceDelegate
diff --git a/chromeos/services/machine_learning/public/cpp/service_connection_unittest.cc b/chromeos/services/machine_learning/public/cpp/service_connection_unittest.cc index c452224..00dcd31 100644 --- a/chromeos/services/machine_learning/public/cpp/service_connection_unittest.cc +++ b/chromeos/services/machine_learning/public/cpp/service_connection_unittest.cc
@@ -198,7 +198,12 @@ EXPECT_TRUE(model.is_bound()); } -class TestSodaClient : public mojom::SodaClient {}; +class TestSodaClient : public mojom::SodaClient { + void OnStop() override {} + void OnStart() override {} + void OnSpeechRecognizerEvent(mojom::SpeechRecognizerEventPtr event) override { + } +}; // Tests that LoadSpeechRecognizer runs OK without a crash in a basic Mojo // Environment.
diff --git a/chromeos/services/machine_learning/public/mojom/soda.mojom b/chromeos/services/machine_learning/public/mojom/soda.mojom index a1198d37..aa99605 100644 --- a/chromeos/services/machine_learning/public/mojom/soda.mojom +++ b/chromeos/services/machine_learning/public/mojom/soda.mojom
@@ -129,6 +129,14 @@ // the client, SODA then calls these as 'events' with appropriate details // when recognition occurs. interface SodaClient { + // After SODA successfully starts / stops, in case the client + // cares: + OnStart(); + OnStop(); + + // This is how the client receives actual recognized text as well as other + // conclusions from the SODA model like "speech ended". + OnSpeechRecognizerEvent(SpeechRecognizerEvent event); }; // The mojom interface for performing the recognition of handwritten text.
diff --git a/chromeos/services/network_config/cros_network_config.cc b/chromeos/services/network_config/cros_network_config.cc index fc4d1e85..e864a19f 100644 --- a/chromeos/services/network_config/cros_network_config.cc +++ b/chromeos/services/network_config/cros_network_config.cc
@@ -8,10 +8,12 @@ #include "base/optional.h" #include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" #include "chromeos/components/sync_wifi/network_eligibility_checker.h" #include "chromeos/dbus/hermes/hermes_euicc_client.h" #include "chromeos/dbus/hermes/hermes_manager_client.h" #include "chromeos/login/login_state/login_state.h" +#include "chromeos/network/cellular_esim_profile_handler.h" #include "chromeos/network/device_state.h" #include "chromeos/network/managed_network_configuration_handler.h" #include "chromeos/network/network_connection_handler.h" @@ -298,8 +300,51 @@ return result; } +base::Optional<std::string> GetESimProfileName( + CellularESimProfileHandler* cellular_esim_profile_handler, + const NetworkState* network_state) { + DCHECK(network_state); + + // CellularESimProfileHandler is not available if the relevant flag is + // disabled. + if (!cellular_esim_profile_handler) + return base::nullopt; + + // Only Cellular networks correspond to eSIM profiles. + if (network_state->type() != shill::kTypeCellular) + return base::nullopt; + + // eSIM profiles have an associated EID and ICCID. + if (network_state->eid().empty() || network_state->iccid().empty()) + return base::nullopt; + + std::vector<CellularESimProfile> profiles = + cellular_esim_profile_handler->GetESimProfiles(); + for (const auto& profile : profiles) { + if (profile.eid() != network_state->eid() || + profile.iccid() != network_state->iccid()) { + continue; + } + + // We've found a profile corresponding to the network. If possible, use the + // profile's nickname, falling back to the name or the service provider. + + if (!profile.nickname().empty()) + return base::UTF16ToUTF8(profile.nickname()); + + if (!profile.name().empty()) + return base::UTF16ToUTF8(profile.name()); + + if (!profile.service_provider().empty()) + return base::UTF16ToUTF8(profile.service_provider()); + } + + return base::nullopt; +} + mojom::NetworkStatePropertiesPtr NetworkStateToMojo( NetworkStateHandler* network_state_handler, + CellularESimProfileHandler* cellular_esim_profile_handler, const std::vector<mojom::VpnProviderPtr>& vpn_providers, const NetworkState* network) { mojom::NetworkType type = ShillTypeToMojo(network->type()); @@ -349,6 +394,11 @@ switch (type) { case mojom::NetworkType::kCellular: { + base::Optional<std::string> profile_name = + GetESimProfileName(cellular_esim_profile_handler, network); + if (profile_name) + result->name = *profile_name; + auto cellular = mojom::CellularStateProperties::New(); cellular->activation_state = network->GetMojoActivationState(); cellular->network_technology = ShillToOnc(network->network_technology(), @@ -1772,6 +1822,7 @@ : CrosNetworkConfig( NetworkHandler::Get()->network_state_handler(), NetworkHandler::Get()->network_device_handler(), + NetworkHandler::Get()->cellular_esim_profile_handler(), NetworkHandler::Get()->managed_network_configuration_handler(), NetworkHandler::Get()->network_connection_handler(), NetworkHandler::Get()->network_certificate_handler()) {} @@ -1779,11 +1830,13 @@ CrosNetworkConfig::CrosNetworkConfig( NetworkStateHandler* network_state_handler, NetworkDeviceHandler* network_device_handler, + CellularESimProfileHandler* cellular_esim_profile_handler, ManagedNetworkConfigurationHandler* network_configuration_handler, NetworkConnectionHandler* network_connection_handler, NetworkCertificateHandler* network_certificate_handler) : network_state_handler_(network_state_handler), network_device_handler_(network_device_handler), + cellular_esim_profile_handler_(cellular_esim_profile_handler), network_configuration_handler_(network_configuration_handler), network_connection_handler_(network_connection_handler), network_certificate_handler_(network_certificate_handler) { @@ -1830,8 +1883,9 @@ std::move(callback).Run(nullptr); return; } - std::move(callback).Run( - NetworkStateToMojo(network_state_handler_, vpn_providers_, network)); + std::move(callback).Run(NetworkStateToMojo(network_state_handler_, + cellular_esim_profile_handler_, + vpn_providers_, network)); } void CrosNetworkConfig::GetNetworkStateList( @@ -1869,8 +1923,9 @@ // represent a separate network service. continue; } - mojom::NetworkStatePropertiesPtr mojo_network = - NetworkStateToMojo(network_state_handler_, vpn_providers_, network); + mojom::NetworkStatePropertiesPtr mojo_network = NetworkStateToMojo( + network_state_handler_, cellular_esim_profile_handler_, vpn_providers_, + network); if (mojo_network) result.emplace_back(std::move(mojo_network)); } @@ -2664,8 +2719,9 @@ const std::vector<const NetworkState*>& active_networks) { std::vector<mojom::NetworkStatePropertiesPtr> result; for (const NetworkState* network : active_networks) { - mojom::NetworkStatePropertiesPtr mojo_network = - NetworkStateToMojo(network_state_handler_, vpn_providers_, network); + mojom::NetworkStatePropertiesPtr mojo_network = NetworkStateToMojo( + network_state_handler_, cellular_esim_profile_handler_, vpn_providers_, + network); if (mojo_network) result.emplace_back(std::move(mojo_network)); } @@ -2677,7 +2733,8 @@ if (network->type() == shill::kTypeEthernetEap) return; mojom::NetworkStatePropertiesPtr mojo_network = - NetworkStateToMojo(network_state_handler_, vpn_providers_, network); + NetworkStateToMojo(network_state_handler_, cellular_esim_profile_handler_, + vpn_providers_, network); if (!mojo_network) return; for (auto& observer : observers_)
diff --git a/chromeos/services/network_config/cros_network_config.h b/chromeos/services/network_config/cros_network_config.h index 3ffbc76..a6b3a74 100644 --- a/chromeos/services/network_config/cros_network_config.h +++ b/chromeos/services/network_config/cros_network_config.h
@@ -21,6 +21,7 @@ namespace chromeos { +class CellularESimProfileHandler; class ManagedNetworkConfigurationHandler; class NetworkConnectionHandler; class NetworkDeviceHandler; @@ -41,6 +42,7 @@ CrosNetworkConfig( NetworkStateHandler* network_state_handler, NetworkDeviceHandler* network_device_handler, + CellularESimProfileHandler* cellular_esim_profile_handler, ManagedNetworkConfigurationHandler* network_configuration_handler, NetworkConnectionHandler* network_connection_handler, NetworkCertificateHandler* network_certificate_handler); @@ -160,6 +162,7 @@ NetworkStateHandler* network_state_handler_; // Unowned NetworkDeviceHandler* network_device_handler_; // Unowned + CellularESimProfileHandler* cellular_esim_profile_handler_; // Unowned ManagedNetworkConfigurationHandler* network_configuration_handler_; // Unowned NetworkConnectionHandler* network_connection_handler_; // Unowned
diff --git a/chromeos/services/network_config/cros_network_config_unittest.cc b/chromeos/services/network_config/cros_network_config_unittest.cc index 7f223a9..c4d0264 100644 --- a/chromeos/services/network_config/cros_network_config_unittest.cc +++ b/chromeos/services/network_config/cros_network_config_unittest.cc
@@ -27,6 +27,7 @@ #include "chromeos/network/onc/onc_utils.h" #include "chromeos/network/prohibited_technologies_handler.h" #include "chromeos/network/proxy/ui_proxy_config_service.h" +#include "chromeos/network/test_cellular_esim_profile_handler.h" #include "chromeos/services/network_config/public/cpp/cros_network_config_test_observer.h" #include "chromeos/services/network_config/public/mojom/cros_network_config.mojom-shared.h" #include "components/onc/onc_constants.h" @@ -96,6 +97,9 @@ helper_.network_state_handler(), network_profile_handler_.get(), network_device_handler_.get(), network_configuration_handler_.get(), ui_proxy_config_service_.get()); + cellular_esim_profile_handler_ = + std::make_unique<TestCellularESimProfileHandler>(); + cellular_esim_profile_handler_->Init(); network_connection_handler_ = NetworkConnectionHandler::InitializeForTesting( helper_.network_state_handler(), @@ -106,6 +110,7 @@ std::make_unique<NetworkCertificateHandler>(); cros_network_config_ = std::make_unique<CrosNetworkConfig>( helper_.network_state_handler(), network_device_handler_.get(), + cellular_esim_profile_handler_.get(), managed_network_configuration_handler_.get(), network_connection_handler_.get(), network_certificate_handler_.get()); SetupPolicy(); @@ -523,6 +528,8 @@ std::unique_ptr<NetworkConfigurationHandler> network_configuration_handler_; std::unique_ptr<ManagedNetworkConfigurationHandler> managed_network_configuration_handler_; + std::unique_ptr<TestCellularESimProfileHandler> + cellular_esim_profile_handler_; std::unique_ptr<NetworkConnectionHandler> network_connection_handler_; std::unique_ptr<chromeos::UIProxyConfigService> ui_proxy_config_service_; TestingPrefServiceSimple local_state_; @@ -657,6 +664,40 @@ EXPECT_EQ("wifi3_guid", networks[2]->guid); } +TEST_F(CrosNetworkConfigTest, ESimNetworkNameComesFromHermes) { + const char kTestEuiccPath[] = "euicc_path"; + const char kTestProfileServicePath[] = "esim_service_path"; + const char kTestIccid[] = "iccid"; + + const char kTestProfileName[] = "test_profile_name"; + const char kTestNameFromShill[] = "shill_network_name"; + + // Add a fake eSIM with name kTestProfileName. + helper().hermes_manager_test()->AddEuicc(dbus::ObjectPath(kTestEuiccPath), + "eid", true); + helper().hermes_euicc_test()->AddCarrierProfile( + dbus::ObjectPath(kTestProfileServicePath), + dbus::ObjectPath(kTestEuiccPath), kTestIccid, kTestProfileName, + "service_provider", "activation_code", kTestProfileServicePath, + hermes::profile::State::kInactive, + /*service_only=*/false); + base::RunLoop().RunUntilIdle(); + + // Change the network's name in Shill. Now, Hermes and Shill have different + // names associated with the profile. + helper().SetServiceProperty(kTestProfileServicePath, shill::kNameProperty, + base::Value(kTestNameFromShill)); + base::RunLoop().RunUntilIdle(); + + // Fetch the Cellular network for the eSIM profile. + std::string esim_guid = std::string("esim_guid") + kTestIccid; + mojom::NetworkStatePropertiesPtr network = GetNetworkState(esim_guid); + + // The network's name should be the profile name (from Hermes), not the name + // from Shill. + EXPECT_EQ(kTestProfileName, network->name); +} + TEST_F(CrosNetworkConfigTest, GetDeviceStateList) { std::vector<mojom::DeviceStatePropertiesPtr> devices = GetDeviceStateList(); ASSERT_EQ(4u, devices.size());
diff --git a/chromeos/services/network_config/public/cpp/cros_network_config_test_helper.cc b/chromeos/services/network_config/public/cpp/cros_network_config_test_helper.cc index 5e2ad1fc..8b0102ca 100644 --- a/chromeos/services/network_config/public/cpp/cros_network_config_test_helper.cc +++ b/chromeos/services/network_config/public/cpp/cros_network_config_test_helper.cc
@@ -32,6 +32,7 @@ cros_network_config_impl_ = std::make_unique<CrosNetworkConfig>( network_state_helper_.network_state_handler(), network_state_helper_.network_device_handler(), + /*cellular_esim_profile_handler=*/nullptr, network_configuration_handler, /*network_connection_handler=*/nullptr, /*network_certificate_handler=*/nullptr);
diff --git a/chromeos/settings/system_settings_provider.cc b/chromeos/settings/system_settings_provider.cc index 4cd9393..127cebd 100644 --- a/chromeos/settings/system_settings_provider.cc +++ b/chromeos/settings/system_settings_provider.cc
@@ -15,7 +15,7 @@ namespace chromeos { namespace { // TODO(olsen): PerUserTimeZoneEnabled and FineGrainedTimeZoneDetectionEnabled -// are duplicated in chrome/browser/chromeos/system/timezone_util.cc, which +// are duplicated in chrome/browser/ash/system/timezone_util.cc, which // is not visible from this package. Try to re-unify these functions by moving // timezone_util to src/chromeos too (out of src/chrome/browser).
diff --git a/components/arc/arc_features.cc b/components/arc/arc_features.cc index 39f328c..24257c3 100644 --- a/components/arc/arc_features.cc +++ b/components/arc/arc_features.cc
@@ -39,6 +39,12 @@ const base::Feature kEnableUnifiedAudioFocusFeature{ "ArcEnableUnifiedAudioFocus", base::FEATURE_ENABLED_BY_DEFAULT}; +// Controls ARC Unspecialized Application Processes. +// When enabled, Android creates a pool of processes +// that will start applications so that zygote doesn't have to wake. +const base::Feature kEnableUsap{"ArcEnableUsap", + base::FEATURE_DISABLED_BY_DEFAULT}; + // Controls experimental file picker feature for ARC. const base::Feature kFilePickerExperimentFeature{ "ArcFilePickerExperiment", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/components/arc/arc_features.h b/components/arc/arc_features.h index 6c0e595..8efc6cc 100644 --- a/components/arc/arc_features.h +++ b/components/arc/arc_features.h
@@ -19,6 +19,7 @@ extern const base::Feature kEnableDocumentsProviderInFilesAppFeature; extern const base::Feature kEnableRegularToChildTransitionFeature; extern const base::Feature kEnableUnifiedAudioFocusFeature; +extern const base::Feature kEnableUsap; extern const base::Feature kFilePickerExperimentFeature; extern const base::Feature kNativeBridge64BitSupportExperimentFeature; extern const base::Feature kNativeBridgeToggleFeature;
diff --git a/components/arc/session/arc_container_client_adapter.cc b/components/arc/session/arc_container_client_adapter.cc index 99e89159..d6a3354 100644 --- a/components/arc/session/arc_container_client_adapter.cc +++ b/components/arc/session/arc_container_client_adapter.cc
@@ -119,6 +119,17 @@ request.set_disable_media_store_maintenance( params.disable_media_store_maintenance); request.set_arc_generate_pai(params.arc_generate_play_auto_install); + + switch (params.usap_profile) { + case StartParams::UsapProfile::DEFAULT: + break; + case StartParams::UsapProfile::M4G: + case StartParams::UsapProfile::M8G: + case StartParams::UsapProfile::M16G: + VLOG(1) << "USAP profile is not supported for container."; + break; + } + chromeos::SessionManagerClient::Get()->StartArcMiniContainer( request, std::move(callback)); }
diff --git a/components/arc/session/arc_session_impl.cc b/components/arc/session/arc_session_impl.cc index d26a89d..7b2981b 100644 --- a/components/arc/session/arc_session_impl.cc +++ b/components/arc/session/arc_session_impl.cc
@@ -130,6 +130,39 @@ << (mem_info.total / 1024) << "Mb device."; } +// Applies USAP profile to the ARC mini instance start params. +// Profile is determined based on enable feature and available memory on the +// device. Possible profiles 16G,8G and 4G. For low memory devices USAP +// profile is not overridden. If |memory_stat_file_for_testing| is set, +// it specifies the file to read in tests instead of /proc/meminfo in +// production. +// Note: This is only used for VM. This profile does nothing for container. +void ApplyUsapProfile( + ArcSessionImpl::SystemMemoryInfoCallback system_memory_info_callback, + StartParams* params) { + // Check if enabled. + if (!base::FeatureList::IsEnabled(arc::kEnableUsap)) { + VLOG(1) << "USAP profile is not enabled."; + return; + } + + base::SystemMemoryInfoKB mem_info; + if (!system_memory_info_callback.Run(&mem_info)) { + LOG(ERROR) << "Failed to get system memory info"; + return; + } + + if (mem_info.total >= kClassify16GbDeviceInKb) { + params->usap_profile = StartParams::UsapProfile::M16G; + } else if (mem_info.total >= kClassify8GbDeviceInKb) { + params->usap_profile = StartParams::UsapProfile::M8G; + } else if (mem_info.total >= kClassify4GbDeviceInKb) { + params->usap_profile = StartParams::UsapProfile::M4G; + } else { + params->usap_profile = StartParams::UsapProfile::DEFAULT; + } +} + // Real Delegate implementation to connect Mojo. class ArcSessionDelegateImpl : public ArcSessionImpl::Delegate { public: @@ -495,6 +528,7 @@ << ", num_cores_disabled=" << params.num_cores_disabled; ApplyDalvikMemoryProfile(system_memory_info_callback_, ¶ms); + ApplyUsapProfile(system_memory_info_callback_, ¶ms); client_->StartMiniArc(std::move(params), base::BindOnce(&ArcSessionImpl::OnMiniInstanceStarted,
diff --git a/components/arc/session/arc_start_params.h b/components/arc/session/arc_start_params.h index 0ed94c5..6b6ce19 100644 --- a/components/arc/session/arc_start_params.h +++ b/components/arc/session/arc_start_params.h
@@ -33,6 +33,17 @@ M16G, }; + enum class UsapProfile { + // Default USAP profile suitable for all devices. + DEFAULT = 0, + // USAP profile suitable for 4G devices. + M4G, + // USAP profile suitable for 8G devices. + M8G, + // USAP profile suitable for 16G devices. + M16G, + }; + StartParams(); ~StartParams(); StartParams(StartParams&& other); @@ -50,6 +61,8 @@ DalvikMemoryProfile dalvik_memory_profile = DalvikMemoryProfile::DEFAULT; + UsapProfile usap_profile = UsapProfile::DEFAULT; + // Experiment flag for ARC Custom Tabs. bool arc_custom_tabs_experiment = false;
diff --git a/components/arc/session/arc_vm_client_adapter.cc b/components/arc/session/arc_vm_client_adapter.cc index 2db771a..420277b4 100644 --- a/components/arc/session/arc_vm_client_adapter.cc +++ b/components/arc/session/arc_vm_client_adapter.cc
@@ -273,6 +273,25 @@ break; } + std::string log_profile_name; + switch (start_params.usap_profile) { + case StartParams::UsapProfile::DEFAULT: + log_profile_name = "default low-memory"; + break; + case StartParams::UsapProfile::M4G: + result.push_back("androidboot.usap_profile=4G"); + log_profile_name = "high-memory 4G"; + break; + case StartParams::UsapProfile::M8G: + result.push_back("androidboot.usap_profile=8G"); + log_profile_name = "high-memory 8G"; + break; + case StartParams::UsapProfile::M16G: + result.push_back("androidboot.usap_profile=16G"); + log_profile_name = "high-memory 16G"; + break; + } + VLOG(1) << "Applied " << log_profile_name << " USAP profile"; return result; }
diff --git a/components/arc/session/arc_vm_client_adapter_unittest.cc b/components/arc/session/arc_vm_client_adapter_unittest.cc index 2209848..77bc39a8 100644 --- a/components/arc/session/arc_vm_client_adapter_unittest.cc +++ b/components/arc/session/arc_vm_client_adapter_unittest.cc
@@ -1666,5 +1666,44 @@ } } +struct UsapProfileTestParam { + // Requested profile. + StartParams::UsapProfile profile; + // Name of profile that is expected. + const char* profile_name; +}; + +constexpr UsapProfileTestParam kUsapProfileTestCases[] = { + {StartParams::UsapProfile::DEFAULT, nullptr}, + {StartParams::UsapProfile::M4G, "4G"}, + {StartParams::UsapProfile::M8G, "8G"}, + {StartParams::UsapProfile::M16G, "16G"}}; + +class ArcVmClientAdapterUsapProfileTest + : public ArcVmClientAdapterTest, + public testing::WithParamInterface<UsapProfileTestParam> {}; + +INSTANTIATE_TEST_SUITE_P(All, + ArcVmClientAdapterUsapProfileTest, + ::testing::ValuesIn(kUsapProfileTestCases)); + +TEST_P(ArcVmClientAdapterUsapProfileTest, Profile) { + const auto& test_param = GetParam(); + StartParams start_params(GetPopulatedStartParams()); + start_params.usap_profile = test_param.profile; + SetValidUserInfo(); + StartMiniArcWithParams(true, std::move(start_params)); + auto request = GetTestConciergeClient()->start_arc_vm_request(); + if (test_param.profile_name) { + EXPECT_TRUE(base::Contains( + GetTestConciergeClient()->start_arc_vm_request().params(), + std::string("androidboot.usap_profile=") + test_param.profile_name)); + } else { + // Not expected any arc_dalvik_memory_profile. + for (const auto& param : request.params()) + EXPECT_EQ(std::string::npos, param.find("usap_profile")); + } +} + } // namespace } // namespace arc
diff --git a/components/autofill/content/browser/content_autofill_driver.cc b/components/autofill/content/browser/content_autofill_driver.cc index e13c708..5101799 100644 --- a/components/autofill/content/browser/content_autofill_driver.cc +++ b/components/autofill/content/browser/content_autofill_driver.cc
@@ -17,6 +17,7 @@ #include "components/autofill/core/browser/form_structure.h" #include "components/autofill/core/browser/payments/payments_service_url.h" #include "components/autofill/core/common/autofill_features.h" +#include "components/autofill/core/common/autofill_payments_features.h" #include "components/version_info/channel.h" #include "content/public/browser/back_forward_cache.h" #include "content/public/browser/browser_context.h" @@ -348,6 +349,8 @@ return; } + ShowOfferNotificationIfApplicable(navigation_handle); + submitted_forms_.clear(); autofill_handler_->Reset(); } @@ -459,4 +462,28 @@ autofill_manager_ = nullptr; } +void ContentAutofillDriver::ShowOfferNotificationIfApplicable( + content::NavigationHandle* navigation_handle) { + if (!navigation_handle->IsInMainFrame()) + return; + + // TODO(crbug.com/1093057): Android webview does not have |autofill_manager_|, + // so flow is not enabled in Android Webview. + if (!base::FeatureList::IsEnabled( + features::kAutofillEnableOfferNotification) || + !autofill_manager_) { + return; + } + + AutofillOfferManager* offer_manager = autofill_manager_->offer_manager(); + // Try to show offer notification when the last committed URL has the domain + // that an offer is applicable for. + GURL url = autofill_manager_->client()->GetLastCommittedURL(); + if (offer_manager->IsUrlEligible(url)) { + std::vector<GURL> domains = + offer_manager->GetEligibleDomainsForOfferForUrl(url); + autofill_manager_->client()->ShowOfferNotificationIfApplicable(domains); + } +} + } // namespace autofill
diff --git a/components/autofill/content/browser/content_autofill_driver.h b/components/autofill/content/browser/content_autofill_driver.h index 8d01a26..f659b5d 100644 --- a/components/autofill/content/browser/content_autofill_driver.h +++ b/components/autofill/content/browser/content_autofill_driver.h
@@ -189,6 +189,11 @@ // been used. bool DocumentUsedWebOTP() const; + // Show a bubble or infobar indicating that the current page has an eligible + // offer or reward, if the bubble/infobar is not currently being visible. + void ShowOfferNotificationIfApplicable( + content::NavigationHandle* navigation_handle); + // Weak ref to the RenderFrameHost the driver is associated with. Should // always be non-NULL and valid for lifetime of |this|. content::RenderFrameHost* const render_frame_host_;
diff --git a/components/autofill/core/browser/autofill_client.cc b/components/autofill/core/browser/autofill_client.cc index 94e37d0..0a95921 100644 --- a/components/autofill/core/browser/autofill_client.cc +++ b/components/autofill/core/browser/autofill_client.cc
@@ -57,6 +57,12 @@ } #endif +void AutofillClient::ShowOfferNotificationIfApplicable( + const std::vector<GURL>& domains_to_display_bubble) { + // This is overridden by platform subclasses. Currently only + // ChromeAutofillClient (Chrome Desktop and Clank) implement this. +} + LogManager* AutofillClient::GetLogManager() const { return nullptr; }
diff --git a/components/autofill/core/browser/autofill_client.h b/components/autofill/core/browser/autofill_client.h index 8b9107c2..0dd96da 100644 --- a/components/autofill/core/browser/autofill_client.h +++ b/components/autofill/core/browser/autofill_client.h
@@ -502,6 +502,16 @@ // Hide the Autofill popup if one is currently showing. virtual void HideAutofillPopup(PopupHidingReason reason) = 0; + // TODO(crbug.com/1093057): Rename all the "domain" in this flow to origin. + // The server is passing down full origin of the + // urls. "Domain" is no longer accurate. + // Will show a bubble or infobar indicating that the current web domain has an + // eligible offer or reward if no other notification bubble is currently + // visible. See bubble controller for details. The bubble is sticky over a set + // of domains given in |domains_to_display_bubble|. + virtual void ShowOfferNotificationIfApplicable( + const std::vector<GURL>& domains_to_display_bubble); + // Whether the Autocomplete feature of Autofill should be enabled. virtual bool IsAutocompleteEnabled() = 0;
diff --git a/components/autofill/core/browser/autofill_handler.cc b/components/autofill/core/browser/autofill_handler.cc index 4dacf97..a744f8c5 100644 --- a/components/autofill/core/browser/autofill_handler.cc +++ b/components/autofill/core/browser/autofill_handler.cc
@@ -4,8 +4,11 @@ #include "components/autofill/core/browser/autofill_handler.h" +#include "base/bind.h" #include "base/containers/adapters.h" #include "base/feature_list.h" +#include "base/strings/string_number_conversions.h" +#include "base/threading/thread_task_runner_handle.h" #include "components/autofill/core/browser/form_structure.h" #include "components/autofill/core/browser/logging/log_manager.h" #include "components/autofill/core/common/autofill_data_validation.h" @@ -148,6 +151,8 @@ AutofillHandler::~AutofillHandler() { translate_observation_.Reset(); + if (!query_result_delay_task_.IsCancelled()) + query_result_delay_task_.Cancel(); } void AutofillHandler::OnLanguageDetermined( @@ -520,6 +525,32 @@ LogAutofillTypePredictionsAvailable(log_manager_, queried_forms); + // TODO(crbug.com/1176816): Remove the test code after initial integration. + int delay = 0; + if (auto* cmd = base::CommandLine::ForCurrentProcess()) { + // This command line helps to simulate query result arriving after autofill + // is triggered and shall be used for manual test only. + std::string value = cmd->GetSwitchValueASCII( + "autofill-server-query-result-delay-in-seconds"); + if (!base::StringToInt(value, &delay)) + delay = 0; + } + + if (delay > 0) { + query_result_delay_task_.Reset( + base::BindOnce(&AutofillHandler::PropagateAutofillPredictionsToDriver, + base::Unretained(this))); + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, + base::BindOnce(query_result_delay_task_.callback(), queried_forms), + base::TimeDelta::FromSeconds(delay)); + } else { + PropagateAutofillPredictionsToDriver(queried_forms); + } +} + +void AutofillHandler::PropagateAutofillPredictionsToDriver( + const std::vector<FormStructure*>& queried_forms) { // Forward form structures to the password generation manager to detect // account creation forms. driver()->PropagateAutofillPredictions(queried_forms);
diff --git a/components/autofill/core/browser/autofill_handler.h b/components/autofill/core/browser/autofill_handler.h index be34dff..5357a35a 100644 --- a/components/autofill/core/browser/autofill_handler.h +++ b/components/autofill/core/browser/autofill_handler.h
@@ -10,6 +10,7 @@ #include <string> #include <vector> +#include "base/cancelable_callback.h" #include "base/compiler_specific.h" #include "base/scoped_observation.h" #include "base/time/time.h" @@ -335,6 +336,9 @@ // |form_structures|. void OnFormsParsed(const std::vector<const FormData*>& forms); + void PropagateAutofillPredictionsToDriver( + const std::vector<FormStructure*>& forms); + // Provides driver-level context to the shared code of the component. Must // outlive this object. AutofillDriver* const driver_; @@ -369,6 +373,10 @@ // Tracks whether or not rich query encoding is enabled for this client. const bool is_rich_query_enabled_ = false; + // Task to delay propagate the query result to driver for testing. + base::CancelableOnceCallback<void(const std::vector<FormStructure*>&)> + query_result_delay_task_; + // Will be not null only for |SaveCardBubbleViewsFullFormBrowserTest|. ObserverForTest* observer_for_testing_ = nullptr;
diff --git a/components/autofill/core/browser/autofill_manager.h b/components/autofill/core/browser/autofill_manager.h index 5413a7b..b018693 100644 --- a/components/autofill/core/browser/autofill_manager.h +++ b/components/autofill/core/browser/autofill_manager.h
@@ -170,6 +170,8 @@ // Returns true only if the previewed form should be cleared. bool ShouldClearPreviewedForm(); + AutofillOfferManager* offer_manager() { return offer_manager_; } + CreditCardAccessManager* credit_card_access_manager() { return credit_card_access_manager_.get(); } @@ -675,7 +677,8 @@ std::unique_ptr<CreditCardAccessManager> credit_card_access_manager_; // The autofill offer manager, used to to retrieve offers for card - // suggestions. + // suggestions. Initialized when AutofillManager is created. |offer_manager_| + // is never null. AutofillOfferManager* offer_manager_; // Collected information about the autofill form where a credit card will be
diff --git a/components/autofill/core/browser/payments/autofill_offer_manager.cc b/components/autofill/core/browser/payments/autofill_offer_manager.cc index f469370b..333a4b0 100644 --- a/components/autofill/core/browser/payments/autofill_offer_manager.cc +++ b/components/autofill/core/browser/payments/autofill_offer_manager.cc
@@ -81,6 +81,37 @@ } } +bool AutofillOfferManager::IsUrlEligible(const GURL& last_committed_url) { + GURL last_committed_url_origin = last_committed_url.GetOrigin(); + return base::ranges::count(eligible_merchant_domains_, + last_committed_url_origin); +} + +std::vector<GURL> AutofillOfferManager::GetEligibleDomainsForOfferForUrl( + const GURL& last_committed_url) { + std::vector<GURL> linked_domains; + std::vector<AutofillOfferData*> offers = + personal_data_->GetCreditCardOffers(); + + // Check which offer is eligible on current domain, then return the full set + // of domains for that offer. + for (auto* offer : offers) { + if (IsOfferEligible(*offer, last_committed_url.GetOrigin())) { + for (auto& domain : offer->merchant_domain) { + linked_domains.emplace_back(domain); + } + break; + } + } + + // Remove duplicates. + base::ranges::sort(linked_domains); + linked_domains.erase(base::ranges::unique(linked_domains), + linked_domains.end()); + + return linked_domains; +} + void AutofillOfferManager::UpdateEligibleMerchantDomains() { eligible_merchant_domains_.clear(); std::vector<AutofillOfferData*> offers =
diff --git a/components/autofill/core/browser/payments/autofill_offer_manager.h b/components/autofill/core/browser/payments/autofill_offer_manager.h index df9fceef..e017873 100644 --- a/components/autofill/core/browser/payments/autofill_offer_manager.h +++ b/components/autofill/core/browser/payments/autofill_offer_manager.h
@@ -42,7 +42,17 @@ void UpdateSuggestionsWithOffers(const GURL& last_committed_url, std::vector<Suggestion>& suggestions); + // Returns true only if the domain of |last_committed_url| has an offer. + bool IsUrlEligible(const GURL& last_committed_url); + + // Returns the set of domains linked to a specific offer that contains the + // domain of |last_committed_url|. + std::vector<GURL> GetEligibleDomainsForOfferForUrl( + const GURL& last_committed_url); + private: + FRIEND_TEST_ALL_PREFIXES(AutofillOfferManagerTest, IsUrlEligible); + // Queries |personal_data_| to reset the elements of // |eligible_merchant_domains_| void UpdateEligibleMerchantDomains();
diff --git a/components/autofill/core/browser/payments/autofill_offer_manager_unittest.cc b/components/autofill/core/browser/payments/autofill_offer_manager_unittest.cc index 964cbfa5..b4a8193 100644 --- a/components/autofill/core/browser/payments/autofill_offer_manager_unittest.cc +++ b/components/autofill/core/browser/payments/autofill_offer_manager_unittest.cc
@@ -71,7 +71,9 @@ void CreateCreditCardOfferForCard(const CreditCard& card, std::string offer_reward_amount, - bool expired = false) { + bool expired = false, + std::vector<GURL> domains = { + GURL(kTestUrl)}) { AutofillOfferData offer_data; offer_data.offer_id = 4444; offer_data.offer_reward_amount = offer_reward_amount; @@ -80,7 +82,7 @@ } else { offer_data.expiry = AutofillClock::Now() + base::TimeDelta::FromDays(2); } - offer_data.merchant_domain = {GURL(kTestUrl)}; + offer_data.merchant_domain = std::move(domains); offer_data.eligible_instrument_id = {card.instrument_id()}; personal_data_manager_.AddCreditCardOfferData(offer_data); } @@ -194,4 +196,60 @@ EXPECT_EQ(suggestions[1].backend_id, kTestGuid2); } +TEST_F(AutofillOfferManagerTest, IsUrlEligible) { + CreditCard card1 = CreateCreditCard(kTestGuid, kTestNumber, 100); + CreditCard card2 = CreateCreditCard(kTestGuid2, "4111111111111111", 101); + CreateCreditCardOfferForCard( + card1, "5%", /*expired=*/false, + {GURL("http://www.google.com"), GURL("http://www.youtube.com")}); + CreateCreditCardOfferForCard(card2, "10%", /*expired=*/false, + {GURL("http://maps.google.com")}); + autofill_offer_manager_->UpdateEligibleMerchantDomains(); + + EXPECT_TRUE( + autofill_offer_manager_->IsUrlEligible(GURL("http://www.google.com"))); + EXPECT_FALSE( + autofill_offer_manager_->IsUrlEligible(GURL("http://www.example.com"))); + EXPECT_TRUE( + autofill_offer_manager_->IsUrlEligible(GURL("http://maps.google.com"))); +} + +TEST_F(AutofillOfferManagerTest, + GetEligibleDomainsForOfferForUrl_ReturnNothingWhenFindNoMatch) { + CreditCard card1 = CreateCreditCard(kTestGuid, kTestNumber, 100); + CreateCreditCardOfferForCard( + card1, "5%", /*expired=*/false, + {GURL("http://www.google.com"), GURL("http://www.youtube.com")}); + + EXPECT_EQ( + 0U, autofill_offer_manager_ + ->GetEligibleDomainsForOfferForUrl(GURL("http://www.example.com")) + .size()); +} + +TEST_F(AutofillOfferManagerTest, + GetEligibleDomainsForOfferForUrl_ReturnCorrectSetWhenFindMatch) { + CreditCard card1 = CreateCreditCard(kTestGuid, kTestNumber, 100); + CreditCard card2 = CreateCreditCard(kTestGuid2, "4111111111111111", 101); + CreateCreditCardOfferForCard( + card1, "5%", /*expired=*/false, + /*domains=*/ + {GURL("http://www.google.com"), GURL("http://www.youtube.com")}); + CreateCreditCardOfferForCard( + card2, "5%", /*expired=*/false, + /*domains=*/ + {GURL("http://www.example.com"), GURL("http://www.example2.com")}); + + std::vector<GURL> eligible_domain = + autofill_offer_manager_->GetEligibleDomainsForOfferForUrl( + GURL("http://www.example.com")); + EXPECT_EQ(2U, eligible_domain.size()); + EXPECT_NE(eligible_domain.end(), + std::find(eligible_domain.begin(), eligible_domain.end(), + GURL("http://www.example.com"))); + EXPECT_NE(eligible_domain.end(), + std::find(eligible_domain.begin(), eligible_domain.end(), + GURL("http://www.example2.com"))); +} + } // namespace autofill
diff --git a/components/cronet/OWNERS b/components/cronet/OWNERS index fb59c70..15c012eb 100644 --- a/components/cronet/OWNERS +++ b/components/cronet/OWNERS
@@ -1 +1,2 @@ +torne@chromium.org file://net/OWNERS
diff --git a/components/cronet/android/cronet_integrated_mode_state.cc b/components/cronet/android/cronet_integrated_mode_state.cc index 6f5e1c2..9b68873 100644 --- a/components/cronet/android/cronet_integrated_mode_state.cc +++ b/components/cronet/android/cronet_integrated_mode_state.cc
@@ -15,7 +15,7 @@ void SetIntegratedModeNetworkTaskRunner( base::SingleThreadTaskRunner* network_task_runner) { - CHECK_EQ(base::subtle::Acquire_CompareAndSwap( + CHECK_EQ(base::subtle::Release_CompareAndSwap( &g_integrated_mode_network_task_runner, 0, reinterpret_cast<base::subtle::AtomicWord>(network_task_runner)), 0); @@ -23,7 +23,7 @@ base::SingleThreadTaskRunner* GetIntegratedModeNetworkTaskRunner() { base::subtle::AtomicWord task_runner = - base::subtle::Release_Load(&g_integrated_mode_network_task_runner); + base::subtle::Acquire_Load(&g_integrated_mode_network_task_runner); CHECK(task_runner); return reinterpret_cast<base::SingleThreadTaskRunner*>(task_runner); }
diff --git a/components/exo/client_controlled_shell_surface.cc b/components/exo/client_controlled_shell_surface.cc index b2457f1..e1d930fa 100644 --- a/components/exo/client_controlled_shell_surface.cc +++ b/components/exo/client_controlled_shell_surface.cc
@@ -326,7 +326,7 @@ bool can_minimize, int container, bool default_scale_cancellation) - : ShellSurfaceBase(surface, gfx::Point(), true, can_minimize, container), + : ShellSurfaceBase(surface, gfx::Point(), can_minimize, container), current_pin_(chromeos::WindowPinType::kNone), use_default_scale_cancellation_(default_scale_cancellation) { server_side_resize_ = true;
diff --git a/components/exo/display.cc b/components/exo/display.cc index df36a295..222da6fca 100644 --- a/components/exo/display.cc +++ b/components/exo/display.cc
@@ -148,7 +148,7 @@ } return std::make_unique<ShellSurface>( - surface, gfx::Point(), true /* activatable */, false /* can_minimize */, + surface, gfx::Point(), /*can_minimize=*/false, ash::desks_util::GetActiveDeskContainerId()); } @@ -162,7 +162,7 @@ } return std::make_unique<XdgShellSurface>( - surface, gfx::Point(), true /* activatable */, false /* can_minimize */, + surface, gfx::Point(), /*can_minimize=*/false, ash::desks_util::GetActiveDeskContainerId()); }
diff --git a/components/exo/pointer_unittest.cc b/components/exo/pointer_unittest.cc index daa478e..1820754 100644 --- a/components/exo/pointer_unittest.cc +++ b/components/exo/pointer_unittest.cc
@@ -547,9 +547,9 @@ gfx::Vector2d(1, 1)); std::unique_ptr<Surface> child_surface(new Surface); - std::unique_ptr<ShellSurface> child_shell_surface( - new ShellSurface(child_surface.get(), gfx::Point(9, 9), true, false, - ash::desks_util::GetActiveDeskContainerId())); + std::unique_ptr<ShellSurface> child_shell_surface(new ShellSurface( + child_surface.get(), gfx::Point(9, 9), /*can_minimize=*/false, + ash::desks_util::GetActiveDeskContainerId())); child_shell_surface->DisableMovement(); child_shell_surface->SetParent(shell_surface.get()); gfx::Size child_buffer_size(15, 15); @@ -709,7 +709,7 @@ // Create modal surface. std::unique_ptr<Surface> surface(new Surface); std::unique_ptr<ShellSurface> shell_surface( - new ShellSurface(surface.get(), gfx::Point(), true, false, + new ShellSurface(surface.get(), gfx::Point(), /*can_minimize=*/false, ash::kShellWindowId_SystemModalContainer)); shell_surface->DisableMovement(); std::unique_ptr<Buffer> buffer( @@ -768,7 +768,7 @@ // Create surface for modal window. std::unique_ptr<Surface> surface2(new Surface); std::unique_ptr<ShellSurface> shell_surface2( - new ShellSurface(surface2.get(), gfx::Point(), true, false, + new ShellSurface(surface2.get(), gfx::Point(), /*can_minimize=*/false, ash::kShellWindowId_SystemModalContainer)); shell_surface2->DisableMovement(); std::unique_ptr<Buffer> buffer2( @@ -830,7 +830,7 @@ // Create modal surface. std::unique_ptr<Surface> surface(new Surface); std::unique_ptr<ShellSurface> shell_surface( - new ShellSurface(surface.get(), gfx::Point(), true, false, + new ShellSurface(surface.get(), gfx::Point(), /*can_minimize=*/false, ash::kShellWindowId_SystemModalContainer)); shell_surface->DisableMovement(); std::unique_ptr<Buffer> buffer( @@ -881,7 +881,7 @@ // Create another surface for a non-modal window. std::unique_ptr<Surface> surface2(new Surface); std::unique_ptr<ShellSurface> shell_surface2( - new ShellSurface(surface2.get(), gfx::Point(), true, false, + new ShellSurface(surface2.get(), gfx::Point(), /*can_minimize=*/false, ash::kShellWindowId_SystemModalContainer)); shell_surface2->DisableMovement(); std::unique_ptr<Buffer> buffer2( @@ -1043,7 +1043,7 @@ gfx::Vector2d(10, 10); auto child_surface = std::make_unique<Surface>(); auto child_shell_surface = std::make_unique<ShellSurface>( - child_surface.get(), child_surface_origin, true, false, + child_surface.get(), child_surface_origin, /*can_minimize=*/false, ash::desks_util::GetActiveDeskContainerId()); child_shell_surface->DisableMovement(); child_shell_surface->SetParent(shell_surface.get()); @@ -1171,7 +1171,7 @@ auto child_surface = std::make_unique<Surface>(); auto child_shell_surface = std::make_unique<ShellSurface>( - child_surface.get(), gfx::Point(), true, false, + child_surface.get(), gfx::Point(), /*can_minimize=*/false, ash::desks_util::GetActiveDeskContainerId()); child_shell_surface->DisableMovement(); child_shell_surface->SetParent(shell_surface.get());
diff --git a/components/exo/shell_surface.cc b/components/exo/shell_surface.cc index 4031bdee..9ddb1b0 100644 --- a/components/exo/shell_surface.cc +++ b/components/exo/shell_surface.cc
@@ -92,16 +92,14 @@ ShellSurface::ShellSurface(Surface* surface, const gfx::Point& origin, - bool activatable, bool can_minimize, int container) - : ShellSurfaceBase(surface, origin, activatable, can_minimize, container) {} + : ShellSurfaceBase(surface, origin, can_minimize, container) {} ShellSurface::ShellSurface(Surface* surface) : ShellSurfaceBase(surface, gfx::Point(), - true, - true, + /*can_minimize=*/true, ash::desks_util::GetActiveDeskContainerId()) {} ShellSurface::~ShellSurface() {
diff --git a/components/exo/shell_surface.h b/components/exo/shell_surface.h index 31f12a4..45ee33b 100644 --- a/components/exo/shell_surface.h +++ b/components/exo/shell_surface.h
@@ -31,7 +31,6 @@ // specified as part of the geometry is relative to the shell surface. ShellSurface(Surface* surface, const gfx::Point& origin, - bool activatable, bool can_minimize, int container); explicit ShellSurface(Surface* surface);
diff --git a/components/exo/shell_surface_base.cc b/components/exo/shell_surface_base.cc index 0a81339c..6388012 100644 --- a/components/exo/shell_surface_base.cc +++ b/components/exo/shell_surface_base.cc
@@ -298,13 +298,11 @@ ShellSurfaceBase::ShellSurfaceBase(Surface* surface, const gfx::Point& origin, - bool activatable, bool can_minimize, int container) : SurfaceTreeHost(base::StringPrintf("ExoShellSurfaceHost-%d", shell_id)), origin_(origin), container_(container), - activatable_(activatable), can_minimize_(can_minimize) { WMHelper::GetInstance()->AddActivationObserver(this); surface->AddSurfaceObserver(this);
diff --git a/components/exo/shell_surface_base.h b/components/exo/shell_surface_base.h index 599dc82..a0a84e01 100644 --- a/components/exo/shell_surface_base.h +++ b/components/exo/shell_surface_base.h
@@ -58,7 +58,6 @@ // specified as part of the geometry is relative to the shell surface. ShellSurfaceBase(Surface* surface, const gfx::Point& origin, - bool activatable, bool can_minimize, int container); ~ShellSurfaceBase() override;
diff --git a/components/exo/test/exo_test_helper.cc b/components/exo/test/exo_test_helper.cc index d204e2b..74b1f66 100644 --- a/components/exo/test/exo_test_helper.cc +++ b/components/exo/test/exo_test_helper.cc
@@ -110,8 +110,9 @@ surface_.reset(new Surface()); int container = is_modal ? ash::kShellWindowId_SystemModalContainer : ash::desks_util::GetActiveDeskContainerId(); - shell_surface_ = std::make_unique<ShellSurface>(surface_.get(), gfx::Point(), - true, false, container); + shell_surface_ = + std::make_unique<ShellSurface>(surface_.get(), gfx::Point(), + /*can minimize=*/false, container); buffer_.reset(new Buffer(std::move(gpu_buffer))); surface_->Attach(buffer_.get());
diff --git a/components/exo/touch_unittest.cc b/components/exo/touch_unittest.cc index ccfacc5..bc348ee 100644 --- a/components/exo/touch_unittest.cc +++ b/components/exo/touch_unittest.cc
@@ -548,7 +548,7 @@ auto child_surface = std::make_unique<Surface>(); auto child_shell_surface = std::make_unique<ShellSurface>( - child_surface.get(), gfx::Point(), true, false, + child_surface.get(), gfx::Point(), /*can_minimize=*/false, ash::desks_util::GetActiveDeskContainerId()); child_shell_surface->DisableMovement(); child_shell_surface->SetParent(shell_surface.get());
diff --git a/components/exo/ui_lock_controller_unittest.cc b/components/exo/ui_lock_controller_unittest.cc index f57d70a..7c1f115 100644 --- a/components/exo/ui_lock_controller_unittest.cc +++ b/components/exo/ui_lock_controller_unittest.cc
@@ -61,7 +61,6 @@ auto surface = std::make_unique<Surface>(); auto shell_surface = std::make_unique<ShellSurface>( surface.get(), gfx::Point{0, 0}, - /*activatable=*/true, /*can_minimize=*/true, ash::desks_util::GetActiveDeskContainerId()); auto buffer = std::make_unique<Buffer>( exo_test_helper()->CreateGpuMemoryBuffer({w, h}));
diff --git a/components/exo/xdg_shell_surface.cc b/components/exo/xdg_shell_surface.cc index b6351cff..15d09c4 100644 --- a/components/exo/xdg_shell_surface.cc +++ b/components/exo/xdg_shell_surface.cc
@@ -19,10 +19,9 @@ XdgShellSurface::XdgShellSurface(Surface* surface, const gfx::Point& origin, - bool activatable, bool can_minimize, int container) - : ShellSurface(surface, origin, activatable, can_minimize, container) {} + : ShellSurface(surface, origin, can_minimize, container) {} XdgShellSurface::~XdgShellSurface() {}
diff --git a/components/exo/xdg_shell_surface.h b/components/exo/xdg_shell_surface.h index 87973a9..a84ca77 100644 --- a/components/exo/xdg_shell_surface.h +++ b/components/exo/xdg_shell_surface.h
@@ -44,11 +44,11 @@ // specified as part of the geometry is relative to the shell surface. XdgShellSurface(Surface* surface, const gfx::Point& origin, - bool activatable, bool can_minimize, int container); ~XdgShellSurface() override; + // ShellSurfaceBase:: void OverrideInitParams(views::Widget::InitParams* params) override; bool x_flipped() const { return x_flipped_; }
diff --git a/components/exo/xdg_shell_surface_unittest.cc b/components/exo/xdg_shell_surface_unittest.cc index a1ff680c..33e4c64 100644 --- a/components/exo/xdg_shell_surface_unittest.cc +++ b/components/exo/xdg_shell_surface_unittest.cc
@@ -27,7 +27,6 @@ auto surface = std::make_unique<Surface>(); auto shell_surface = std::make_unique<XdgShellSurface>( surface.get(), gfx::Point{0, 0}, - /*activatable=*/true, /*can_minimize=*/true, ash::desks_util::GetActiveDeskContainerId()); auto buffer = std::make_unique<Buffer>( exo_test_helper()->CreateGpuMemoryBuffer({w, h}));
diff --git a/components/feed/core/proto/v2/store.proto b/components/feed/core/proto/v2/store.proto index 206d9059..68224893 100644 --- a/components/feed/core/proto/v2/store.proto +++ b/components/feed/core/proto/v2/store.proto
@@ -16,6 +16,7 @@ // This data is sourced from the wire protocol, which is converted upon receipt. // This would replace both Journal and Content stores. // +// TODO(crbug/1152592): Support multiple streams. // This is the 'value' in the key/value store. // Keys are defined as: // S/<stream-id> -> stream_data
diff --git a/components/feed/core/v2/config.cc b/components/feed/core/v2/config.cc index 4ff2188..8f433fb 100644 --- a/components/feed/core/v2/config.cc +++ b/components/feed/core/v2/config.cc
@@ -34,6 +34,11 @@ kInterestFeedV2, "max_feed_query_requests_per_day", config->max_feed_query_requests_per_day); + config->max_next_page_requests_per_day = + base::GetFieldTrialParamByFeatureAsInt( + kInterestFeedV2, "max_next_page_requests_per_day", + config->max_next_page_requests_per_day); + config->max_action_upload_requests_per_day = base::GetFieldTrialParamByFeatureAsInt( kInterestFeedV2, "max_action_upload_requests_per_day",
diff --git a/components/feed/core/v2/config.h b/components/feed/core/v2/config.h index 1f375149..19b3362 100644 --- a/components/feed/core/v2/config.h +++ b/components/feed/core/v2/config.h
@@ -14,8 +14,10 @@ // The Feed configuration. Default values appear below. Always use // |GetFeedConfig()| to get the current configuration. struct Config { - // Maximum number of FeedQuery or action upload requests per day. + // Maximum number of requests per day for FeedQuery, NextPage, and + // ActionUpload. int max_feed_query_requests_per_day = 20; + int max_next_page_requests_per_day = 20; int max_action_upload_requests_per_day = 20; // We'll always attempt to refresh content older than this. base::TimeDelta stale_content_threshold = base::TimeDelta::FromHours(4);
diff --git a/components/feed/core/v2/enums.h b/components/feed/core/v2/enums.h index 596e78a00..eff9e25 100644 --- a/components/feed/core/v2/enums.h +++ b/components/feed/core/v2/enums.h
@@ -12,6 +12,7 @@ enum class NetworkRequestType : int { kFeedQuery = 0, kUploadActions = 1, + kNextPage = 2, }; // This must be kept in sync with FeedLoadStreamStatus in enums.xml.
diff --git a/components/feed/core/v2/feed_network.h b/components/feed/core/v2/feed_network.h index a5676de45..182b16ca 100644 --- a/components/feed/core/v2/feed_network.h +++ b/components/feed/core/v2/feed_network.h
@@ -8,6 +8,7 @@ #include <memory> #include "base/callback.h" +#include "components/feed/core/v2/enums.h" #include "components/feed/core/v2/public/types.h" namespace feedwire { @@ -51,6 +52,7 @@ // |callback| will be called unless the request is canceled with // |CancelRequests()|. virtual void SendQueryRequest( + NetworkRequestType request_type, const feedwire::Request& request, bool force_signed_out_request, base::OnceCallback<void(QueryRequestResult)> callback) = 0;
diff --git a/components/feed/core/v2/feed_network_impl.cc b/components/feed/core/v2/feed_network_impl.cc index 43f82af4..93d0f11 100644 --- a/components/feed/core/v2/feed_network_impl.cc +++ b/components/feed/core/v2/feed_network_impl.cc
@@ -93,10 +93,11 @@ namespace { void ParseAndForwardQueryResponse( + NetworkRequestType request_type, base::OnceCallback<void(FeedNetwork::QueryRequestResult)> result_callback, RawResponse raw_response) { MetricsReporter::NetworkRequestComplete( - NetworkRequestType::kFeedQuery, raw_response.response_info.status_code); + request_type, raw_response.response_info.status_code); FeedNetwork::QueryRequestResult result; result.response_info = raw_response.response_info; if (result.response_info.status_code == 200) { @@ -430,6 +431,7 @@ FeedNetworkImpl::~FeedNetworkImpl() = default; void FeedNetworkImpl::SendQueryRequest( + NetworkRequestType request_type, const feedwire::Request& request, bool force_signed_out_request, base::OnceCallback<void(QueryRequestResult)> callback) { @@ -469,7 +471,8 @@ url); Send(url, "GET", /*request_body=*/{}, force_signed_out_request, /*allow_bless_auth=*/host_overridden, - base::BindOnce(&ParseAndForwardQueryResponse, std::move(callback))); + base::BindOnce(&ParseAndForwardQueryResponse, request_type, + std::move(callback))); } void FeedNetworkImpl::SendActionRequest(
diff --git a/components/feed/core/v2/feed_network_impl.h b/components/feed/core/v2/feed_network_impl.h index e9e88aa..221325e 100644 --- a/components/feed/core/v2/feed_network_impl.h +++ b/components/feed/core/v2/feed_network_impl.h
@@ -48,6 +48,7 @@ // FeedNetwork. void SendQueryRequest( + NetworkRequestType request_type, const feedwire::Request& request, bool force_signed_out_request, base::OnceCallback<void(QueryRequestResult)> callback) override;
diff --git a/components/feed/core/v2/feed_network_impl_unittest.cc b/components/feed/core/v2/feed_network_impl_unittest.cc index 3f8c6a0..149bd85 100644 --- a/components/feed/core/v2/feed_network_impl_unittest.cc +++ b/components/feed/core/v2/feed_network_impl_unittest.cc
@@ -207,7 +207,8 @@ TEST_F(FeedNetworkTest, SendQueryRequestEmpty) { CallbackReceiver<QueryRequestResult> receiver; - feed_network()->SendQueryRequest(feedwire::Request(), false, receiver.Bind()); + feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery, + feedwire::Request(), false, receiver.Bind()); ASSERT_TRUE(receiver.GetResult()); const QueryRequestResult& result = *receiver.GetResult(); @@ -217,7 +218,8 @@ TEST_F(FeedNetworkTest, SendQueryRequestSendsValidRequest) { CallbackReceiver<QueryRequestResult> receiver; - feed_network()->SendQueryRequest(GetTestFeedRequest(), false, + feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery, + GetTestFeedRequest(), false, receiver.Bind()); network::ResourceRequest resource_request = RespondToQueryRequest("", net::HTTP_OK); @@ -239,7 +241,8 @@ TEST_F(FeedNetworkTest, SendQueryRequestForceSignedOut) { CallbackReceiver<QueryRequestResult> receiver; feed_network()->SendQueryRequest( - GetTestFeedRequest(), /*force_signed_out_request=*/true, receiver.Bind()); + NetworkRequestType::kFeedQuery, GetTestFeedRequest(), + /*force_signed_out_request=*/true, receiver.Bind()); network::ResourceRequest resource_request = RespondToQueryRequest("", net::HTTP_OK); @@ -252,7 +255,8 @@ TEST_F(FeedNetworkTest, SendQueryRequestInvalidResponse) { CallbackReceiver<QueryRequestResult> receiver; - feed_network()->SendQueryRequest(GetTestFeedRequest(), false, + feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery, + GetTestFeedRequest(), false, receiver.Bind()); RespondToQueryRequest("invalid", net::HTTP_OK); @@ -264,7 +268,8 @@ TEST_F(FeedNetworkTest, SendQueryRequestReceivesResponse) { CallbackReceiver<QueryRequestResult> receiver; - feed_network()->SendQueryRequest(GetTestFeedRequest(), false, + feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery, + GetTestFeedRequest(), false, receiver.Bind()); RespondToQueryRequest(GetTestFeedResponse(), net::HTTP_OK); @@ -282,7 +287,8 @@ TEST_F(FeedNetworkTest, SendQueryRequestIgnoresBodyForNon200Response) { CallbackReceiver<QueryRequestResult> receiver; - feed_network()->SendQueryRequest(GetTestFeedRequest(), false, + feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery, + GetTestFeedRequest(), false, receiver.Bind()); RespondToQueryRequest(GetTestFeedResponse(), net::HTTP_FORBIDDEN); @@ -297,7 +303,8 @@ TEST_F(FeedNetworkTest, CancelRequest) { CallbackReceiver<QueryRequestResult> receiver; - feed_network()->SendQueryRequest(GetTestFeedRequest(), false, + feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery, + GetTestFeedRequest(), false, receiver.Bind()); feed_network()->CancelRequests(); task_environment_.FastForwardUntilNoTasksRemain(); @@ -308,7 +315,8 @@ TEST_F(FeedNetworkTest, RequestTimeout) { base::HistogramTester histogram_tester; CallbackReceiver<QueryRequestResult> receiver; - feed_network()->SendQueryRequest(GetTestFeedRequest(), false, + feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery, + GetTestFeedRequest(), false, receiver.Bind()); task_environment_.FastForwardBy(TimeDelta::FromSeconds(30)); @@ -322,11 +330,13 @@ TEST_F(FeedNetworkTest, ParallelRequests) { CallbackReceiver<QueryRequestResult> receiver1, receiver2; - feed_network()->SendQueryRequest(GetTestFeedRequest(), false, + feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery, + GetTestFeedRequest(), false, receiver1.Bind()); // Make another request with a different URL so Respond() won't affect both // requests. feed_network()->SendQueryRequest( + NetworkRequestType::kFeedQuery, GetTestFeedRequest(feedwire::FeedQuery::NEXT_PAGE_SCROLL), false, receiver2.Bind()); @@ -350,7 +360,8 @@ TEST_F(FeedNetworkTest, ShouldReportResponseStatusCode) { CallbackReceiver<QueryRequestResult> receiver; base::HistogramTester histogram_tester; - feed_network()->SendQueryRequest(GetTestFeedRequest(), false, + feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery, + GetTestFeedRequest(), false, receiver.Bind()); RespondToQueryRequest(GetTestFeedResponse(), net::HTTP_FORBIDDEN); @@ -365,7 +376,8 @@ CallbackReceiver<QueryRequestResult> receiver; base::HistogramTester histogram_tester; - feed_network()->SendQueryRequest(GetTestFeedRequest(), false, + feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery, + GetTestFeedRequest(), false, receiver.Bind()); identity_env()->WaitForAccessTokenRequestIfNecessaryAndRespondWithError( GoogleServiceAuthError( @@ -391,7 +403,8 @@ TEST_F(FeedNetworkTest, ShouldIncludeAPIKeyForNoSignedInUser) { identity_env()->ClearPrimaryAccount(); CallbackReceiver<QueryRequestResult> receiver; - feed_network()->SendQueryRequest(GetTestFeedRequest(), false, + feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery, + GetTestFeedRequest(), false, receiver.Bind()); network::ResourceRequest resource_request = @@ -407,7 +420,8 @@ CallbackReceiver<QueryRequestResult> receiver; const TimeDelta kDuration = TimeDelta::FromMilliseconds(12345); - feed_network()->SendQueryRequest(GetTestFeedRequest(), false, + feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery, + GetTestFeedRequest(), false, receiver.Bind()); task_environment_.FastForwardBy(kDuration); RespondToQueryRequest(GetTestFeedResponse(), net::HTTP_OK); @@ -423,7 +437,8 @@ CallbackReceiver<QueryRequestResult> receiver; profile_prefs().SetString(feed::prefs::kHostOverrideHost, "http://www.newhost.com/"); - feed_network()->SendQueryRequest(GetTestFeedRequest(), false, + feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery, + GetTestFeedRequest(), false, receiver.Bind()); ASSERT_EQ("www.newhost.com", GetPendingRequestURL().host());
diff --git a/components/feed/core/v2/feed_stream.cc b/components/feed/core/v2/feed_stream.cc index ec4a14ac..52474d5 100644 --- a/components/feed/core/v2/feed_stream.cc +++ b/components/feed/core/v2/feed_stream.cc
@@ -163,6 +163,9 @@ return LocalActionId(id); } +FeedStream::Stream::Stream() : type(kInterestStream) {} +FeedStream::Stream::~Stream() = default; + FeedStream::FeedStream(RefreshTaskScheduler* refresh_task_scheduler, MetricsReporter* metrics_reporter, Delegate* delegate, @@ -191,9 +194,9 @@ static WireResponseTranslator default_translator; wire_response_translator_ = &default_translator; - surface_updater_ = std::make_unique<SurfaceUpdater>(metrics_reporter_); - offline_page_spy_ = std::make_unique<OfflinePageSpy>(surface_updater_.get(), - offline_page_model); + Stream& stream = GetStream(kInterestStream); + offline_page_spy_ = std::make_unique<OfflinePageSpy>( + stream.surface_updater.get(), offline_page_model); if (prefetch_service_) { offline_suggestions_provider_ = @@ -218,8 +221,36 @@ FeedStream::~FeedStream() = default; +FeedStream::Stream* FeedStream::FindStream(const StreamType& stream_type) { + auto iter = streams_.find(stream_type); + return (iter != streams_.end()) ? &iter->second : nullptr; +} + +const FeedStream::Stream* FeedStream::FindStream( + const StreamType& stream_type) const { + return const_cast<FeedStream*>(this)->FindStream(stream_type); +} + +FeedStream::Stream& FeedStream::GetStream(const StreamType& stream_type) { + auto iter = streams_.find(stream_type); + if (iter != streams_.end()) + return iter->second; + FeedStream::Stream& new_stream = streams_[stream_type]; + new_stream.type = stream_type; + new_stream.surface_updater = + std::make_unique<SurfaceUpdater>(metrics_reporter_); + return new_stream; +} + +StreamModel* FeedStream::GetModel(const StreamType& stream_type) { + Stream* stream = FindStream(stream_type); + return stream ? stream->model.get() : nullptr; +} + void FeedStream::TriggerStreamLoad() { - if (model_ || model_loading_in_progress_) + // TODO(crbug/1152592): Parameterize stream loading by stream type. + Stream& stream = GetStream(kInterestStream); + if (stream.model || stream.model_loading_in_progress) return; // If we should not load the stream, abort and send a zero-state update. @@ -229,8 +260,9 @@ return; } - model_loading_in_progress_ = true; - surface_updater_->LoadStreamStarted(); + stream.model_loading_in_progress = true; + + stream.surface_updater->LoadStreamStarted(); task_queue_.AddTask(std::make_unique<LoadStreamTask>( LoadStreamTask::LoadType::kInitialLoad, this, base::BindOnce(&FeedStream::InitialStreamLoadComplete, @@ -238,6 +270,8 @@ } void FeedStream::InitialStreamLoadComplete(LoadStreamTask::Result result) { + // TODO(crbug/1152592): Parameterize stream loading by stream type. + Stream& stream = GetStream(kInterestStream); PopulateDebugStreamData(result, *profile_prefs_); metrics_reporter_->OnLoadStream( result.load_from_store_status, result.final_status, @@ -245,9 +279,9 @@ std::move(result.latencies)); UpdateIsActivityLoggingEnabled(); - model_loading_in_progress_ = false; - - surface_updater_->LoadStreamComplete(model_ != nullptr, result.final_status); + stream.model_loading_in_progress = false; + stream.surface_updater->LoadStreamComplete(stream.model != nullptr, + result.final_status); if (result.loaded_new_content_from_network && prefetch_service_) prefetch_service_->NewSuggestionsAvailable(); @@ -268,10 +302,12 @@ } void FeedStream::UpdateIsActivityLoggingEnabled() { + Stream& stream = GetStream(kInterestStream); is_activity_logging_enabled_ = - model_ && - ((model_->signed_in() && model_->logging_enabled()) || - (!model_->signed_in() && GetFeedConfig().send_signed_out_session_logs)); + stream.model && + ((stream.model->signed_in() && stream.model->logging_enabled()) || + (!stream.model->signed_in() && + GetFeedConfig().send_signed_out_session_logs)); } std::string FeedStream::GetSessionId() const { @@ -284,54 +320,63 @@ void FeedStream::AttachSurface(SurfaceInterface* surface) { metrics_reporter_->SurfaceOpened(surface->GetSurfaceId()); - + Stream& stream = GetStream(surface->GetStreamType()); // Skip normal processing when overriding stream data from the internals page. if (forced_stream_update_for_debugging_.updated_slices_size() > 0) { - surface_updater_->SurfaceAdded(surface); + stream.surface_updater->SurfaceAdded(surface); surface->StreamUpdate(forced_stream_update_for_debugging_); return; } TriggerStreamLoad(); - surface_updater_->SurfaceAdded(surface); + stream.surface_updater->SurfaceAdded(surface); // Cancel any scheduled model unload task. - ++unload_on_detach_sequence_number_; + ++stream.unload_on_detach_sequence_number; UpdateCanUploadActionsWithNoticeCard(); } void FeedStream::DetachSurface(SurfaceInterface* surface) { + Stream& stream = GetStream(surface->GetStreamType()); metrics_reporter_->SurfaceClosed(surface->GetSurfaceId()); - surface_updater_->SurfaceRemoved(surface); + stream.surface_updater->SurfaceRemoved(surface); UpdateCanUploadActionsWithNoticeCard(); - ScheduleModelUnloadIfNoSurfacesAttached(); + ScheduleModelUnloadIfNoSurfacesAttached(surface->GetStreamType()); } -void FeedStream::ScheduleModelUnloadIfNoSurfacesAttached() { - if (surface_updater_->HasSurfaceAttached()) +void FeedStream::ScheduleModelUnloadIfNoSurfacesAttached( + const StreamType& stream_type) { + Stream& stream = GetStream(stream_type); + if (stream.surface_updater->HasSurfaceAttached()) return; base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, base::BindOnce(&FeedStream::AddUnloadModelIfNoSurfacesAttachedTask, - GetWeakPtr(), unload_on_detach_sequence_number_), + GetWeakPtr(), stream.type, + stream.unload_on_detach_sequence_number), GetFeedConfig().model_unload_timeout); } -void FeedStream::AddUnloadModelIfNoSurfacesAttachedTask(int sequence_number) { +void FeedStream::AddUnloadModelIfNoSurfacesAttachedTask( + const StreamType& stream_type, + int sequence_number) { + Stream& stream = GetStream(stream_type); // Don't continue if unload_on_detach_sequence_number_ has changed. - if (unload_on_detach_sequence_number_ != sequence_number) + if (stream.unload_on_detach_sequence_number != sequence_number) return; task_queue_.AddTask(std::make_unique<offline_pages::ClosureTask>( base::BindOnce(&FeedStream::UnloadModelIfNoSurfacesAttachedTask, - base::Unretained(this)))); + base::Unretained(this), stream_type))); } -void FeedStream::UnloadModelIfNoSurfacesAttachedTask() { - if (surface_updater_->HasSurfaceAttached()) +void FeedStream::UnloadModelIfNoSurfacesAttachedTask( + const StreamType& stream_type) { + Stream& stream = GetStream(stream_type); + if (stream.surface_updater->HasSurfaceAttached()) return; - UnloadModel(); + UnloadModel(stream_type); } bool FeedStream::IsArticlesListVisible() { @@ -346,9 +391,10 @@ return profile_prefs_->GetBoolean(prefs::kEnableSnippets); } -void FeedStream::LoadMore(SurfaceId surface_id, +void FeedStream::LoadMore(const SurfaceInterface& surface, base::OnceCallback<void(bool)> callback) { - if (!model_) { + Stream& stream = GetStream(surface.GetStreamType()); + if (!stream.model) { DLOG(ERROR) << "Ignoring LoadMore() before the model is loaded"; return std::move(callback).Run(false); } @@ -360,8 +406,8 @@ return std::move(callback).Run(false); } - metrics_reporter_->OnLoadMoreBegin(surface_id); - surface_updater_->SetLoadingMore(true); + metrics_reporter_->OnLoadMoreBegin(surface.GetSurfaceId()); + stream.surface_updater->SetLoadingMore(true); // Have at most one in-flight LoadMore() request. Send the result to all // requestors. @@ -375,8 +421,10 @@ void FeedStream::LoadMoreComplete(LoadMoreTask::Result result) { UpdateIsActivityLoggingEnabled(); + // TODO(crbug/1152592): Parameterize stream loading by stream type. + Stream& stream = GetStream(kInterestStream); metrics_reporter_->OnLoadMore(result.final_status); - surface_updater_->SetLoadingMore(false); + stream.surface_updater->SetLoadingMore(false); std::vector<base::OnceCallback<void(bool)>> moved_callbacks = std::move(load_more_complete_callbacks_); bool success = result.final_status == LoadStreamStatus::kLoadedFromNetwork; @@ -389,45 +437,55 @@ } void FeedStream::ExecuteOperations( + const StreamType& stream_type, std::vector<feedstore::DataOperation> operations) { - if (!model_) { + StreamModel* model = GetModel(stream_type); + if (!model) { DLOG(ERROR) << "Calling ExecuteOperations before the model is loaded"; return; } - return model_->ExecuteOperations(std::move(operations)); + return model->ExecuteOperations(std::move(operations)); } EphemeralChangeId FeedStream::CreateEphemeralChange( + const StreamType& stream_type, std::vector<feedstore::DataOperation> operations) { - if (!model_) { + StreamModel* model = GetModel(stream_type); + if (!model) { DLOG(ERROR) << "Calling CreateEphemeralChange before the model is loaded"; return {}; } metrics_reporter_->OtherUserAction(FeedUserActionType::kEphemeralChange); - return model_->CreateEphemeralChange(std::move(operations)); + return model->CreateEphemeralChange(std::move(operations)); } EphemeralChangeId FeedStream::CreateEphemeralChangeFromPackedData( + const StreamType& stream_type, base::StringPiece data) { feedpacking::DismissData msg; msg.ParseFromArray(data.data(), data.size()); - return CreateEphemeralChange(TranslateDismissData(base::Time::Now(), msg)); + return CreateEphemeralChange(stream_type, + TranslateDismissData(base::Time::Now(), msg)); } -bool FeedStream::CommitEphemeralChange(EphemeralChangeId id) { - if (!model_) +bool FeedStream::CommitEphemeralChange(const StreamType& stream_type, + EphemeralChangeId id) { + StreamModel* model = GetModel(stream_type); + if (!model) return false; metrics_reporter_->OtherUserAction( FeedUserActionType::kEphemeralChangeCommited); - return model_->CommitEphemeralChange(id); + return model->CommitEphemeralChange(id); } -bool FeedStream::RejectEphemeralChange(EphemeralChangeId id) { - if (!model_) +bool FeedStream::RejectEphemeralChange(const StreamType& stream_type, + EphemeralChangeId id) { + StreamModel* model = GetModel(stream_type); + if (!model) return false; metrics_reporter_->OtherUserAction( FeedUserActionType::kEphemeralChangeRejected); - return model_->RejectEphemeralChange(id); + return model->RejectEphemeralChange(id); } void FeedStream::ProcessThereAndBackAgain(base::StringPiece data) { @@ -478,18 +536,21 @@ } void FeedStream::ForceRefreshForDebuggingTask() { - UnloadModel(); + UnloadModel(kInterestStream); store_->ClearStreamData(base::DoNothing()); TriggerStreamLoad(); } std::string FeedStream::DumpStateForDebugging() { + Stream& stream = GetStream(kInterestStream); std::stringstream ss; - if (model_) { - ss << "model loaded, " << model_->GetContentList().size() << " contents, " - << "signed_in=" << model_->signed_in() - << ", logging_enabled=" << model_->logging_enabled() - << ", privacy_notice_fulfilled=" << model_->privacy_notice_fulfilled(); + if (stream.model) { + ss << "model loaded, " << stream.model->GetContentList().size() + << " contents, " + << "signed_in=" << stream.model->signed_in() + << ", logging_enabled=" << stream.model->logging_enabled() + << ", privacy_notice_fulfilled=" + << stream.model->privacy_notice_fulfilled(); } RequestSchedule schedule = prefs::GetRequestSchedule(*profile_prefs_); if (schedule.refresh_offsets.empty()) { @@ -519,7 +580,9 @@ } bool FeedStream::HasSurfaceAttached() const { - return surface_updater_->HasSurfaceAttached(); + // TODO(crbug/1152592): Make ClearAll() work with multiple streams. + const Stream* stream = FindStream(kInterestStream); + return stream && stream->surface_updater->HasSurfaceAttached(); } void FeedStream::LoadModelForTesting(std::unique_ptr<StreamModel> model) { @@ -562,7 +625,9 @@ // being loaded. Because |ShouldAttemptLoad()| is used both before and during // the load process, we need to ignore this check when |model_loading| is // true. - if (model_ || (!model_loading && model_loading_in_progress_)) + // TODO(crbug/1152592): Parameterize stream loading by stream type. + Stream& stream = GetStream(kInterestStream); + if (stream.model || (!model_loading && stream.model_loading_in_progress)) return LoadStreamStatus::kModelAlreadyLoaded; if (!IsArticlesListVisible()) @@ -588,6 +653,8 @@ LoadStreamStatus FeedStream::ShouldMakeFeedQueryRequest(bool is_load_more, bool consume_quota) { + // TODO(crbug/1152592): Parameterize stream loading by stream type. + Stream& stream = GetStream(kInterestStream); if (!is_load_more) { // Time has passed since calling |ShouldAttemptLoad()|, call it again to // confirm we should still attempt loading. @@ -598,7 +665,7 @@ } } else { // LoadMore requires a next page token. - if (!model_ || model_->GetNextPageToken().empty()) { + if (!stream.model || stream.model->GetNextPageToken().empty()) { return LoadStreamStatus::kCannotLoadMoreNoNextPageToken; } } @@ -607,8 +674,9 @@ return LoadStreamStatus::kCannotLoadFromNetworkOffline; } - if (consume_quota && - !request_throttler_.RequestQuota(NetworkRequestType::kFeedQuery)) { + if (consume_quota && !request_throttler_.RequestQuota( + !is_load_more ? NetworkRequestType::kFeedQuery + : NetworkRequestType::kNextPage)) { return LoadStreamStatus::kCannotLoadFromNetworkThrottled; } @@ -620,6 +688,9 @@ } RequestMetadata FeedStream::GetRequestMetadata(bool is_for_next_page) const { + // TODO(crbug/1152592): Parameterize stream loading by stream type. + const Stream* stream = FindStream(kInterestStream); + DCHECK(stream); RequestMetadata result; result.chrome_info = chrome_info_; result.display_metrics = delegate_->GetDisplayMetrics(); @@ -631,8 +702,8 @@ // If we are continuing an existing feed, use whatever session continuity // mechanism is currently associated with the stream: client-instance-id // for signed-in feed, session_id token for signed-out. - DCHECK(model_); - if (model_->signed_in()) { + DCHECK(stream->model); + if (stream->model->signed_in()) { result.client_instance_id = GetClientInstanceId(); } else { result.session_id = GetMetadata()->GetSessionIdToken(); @@ -655,7 +726,9 @@ } void FeedStream::OnEulaAccepted() { - if (surface_updater_->HasSurfaceAttached()) + // TODO(crbug/1152592): Parameterize stream loading by stream type. + Stream& stream = GetStream(kInterestStream); + if (stream.surface_updater->HasSurfaceAttached()) TriggerStreamLoad(); } @@ -762,12 +835,16 @@ } void FeedStream::LoadModel(std::unique_ptr<StreamModel> model) { - DCHECK(!model_); - model_ = std::move(model); - model_->SetStoreObserver(this); - surface_updater_->SetModel(model_.get()); - offline_page_spy_->SetModel(model_.get()); - ScheduleModelUnloadIfNoSurfacesAttached(); + // TODO(crbug/1152592): Parameterize stream loading by stream type. + Stream& stream = GetStream(kInterestStream); + DCHECK(!stream.model); + stream.model = std::move(model); + stream.model->SetStoreObserver(this); + stream.surface_updater->SetModel(stream.model.get()); + if (stream.type.IsInterest()) { + offline_page_spy_->SetModel(stream.model.get()); + } + ScheduleModelUnloadIfNoSurfacesAttached(stream.type); } void FeedStream::SetRequestSchedule(RequestSchedule schedule) { @@ -781,50 +858,69 @@ feed::prefs::SetRequestSchedule(schedule, *profile_prefs_); } -void FeedStream::UnloadModel() { +void FeedStream::UnloadModel(const StreamType& stream_type) { // Note: This should only be called from a running Task, as some tasks assume // the model remains loaded. - if (!model_) + Stream* stream = FindStream(stream_type); + if (!stream || !stream->model) return; - offline_page_spy_->SetModel(nullptr); - surface_updater_->SetModel(nullptr); - model_.reset(); + if (stream_type.IsInterest()) { + offline_page_spy_->SetModel(nullptr); + } + stream->surface_updater->SetModel(nullptr); + stream->model.reset(); } -void FeedStream::ReportOpenAction(const std::string& slice_id) { - int index = surface_updater_->GetSliceIndexFromSliceId(slice_id); +void FeedStream::ReportOpenAction(const StreamType& stream_type, + const std::string& slice_id) { + Stream& stream = GetStream(stream_type); + + int index = stream.surface_updater->GetSliceIndexFromSliceId(slice_id); if (index < 0) index = MetricsReporter::kUnknownCardIndex; metrics_reporter_->OpenAction(index); - notice_card_tracker_.OnOpenAction(index); + if (stream_type.IsInterest()) { + notice_card_tracker_.OnOpenAction(index); + } } void FeedStream::ReportOpenVisitComplete(base::TimeDelta visit_time) { metrics_reporter_->OpenVisitComplete(visit_time); } -void FeedStream::ReportOpenInNewTabAction(const std::string& slice_id) { - int index = surface_updater_->GetSliceIndexFromSliceId(slice_id); +void FeedStream::ReportOpenInNewTabAction(const StreamType& stream_type, + const std::string& slice_id) { + Stream& stream = GetStream(stream_type); + int index = stream.surface_updater->GetSliceIndexFromSliceId(slice_id); if (index < 0) index = MetricsReporter::kUnknownCardIndex; metrics_reporter_->OpenInNewTabAction(index); - notice_card_tracker_.OnOpenAction(index); + if (stream_type.IsInterest()) { + notice_card_tracker_.OnOpenAction(index); + } } void FeedStream::ReportSliceViewed(SurfaceId surface_id, + const StreamType& stream_type, const std::string& slice_id) { - int index = surface_updater_->GetSliceIndexFromSliceId(slice_id); + Stream& stream = GetStream(stream_type); + int index = stream.surface_updater->GetSliceIndexFromSliceId(slice_id); if (index >= 0) { - UpdateShownSlicesUploadCondition(index); - notice_card_tracker_.OnSliceViewed(index); + if (stream_type.IsInterest()) { + UpdateShownSlicesUploadCondition(index); + notice_card_tracker_.OnSliceViewed(index); + } metrics_reporter_->ContentSliceViewed(surface_id, index); } } // TODO(crbug/1147237): Rename this method and related members? bool FeedStream::CanUploadActions() const { + // TODO(crbug/1152592): Determine notice card behavior with web feeds. return can_upload_actions_with_notice_card_ || !prefs::GetLastFetchHadNoticeCard(*profile_prefs_); } void FeedStream::SetLastStreamLoadHadNoticeCard(bool value) { + // TODO(crbug/1152592): Determine notice card behavior with web feeds. prefs::SetLastFetchHadNoticeCard(*profile_prefs_, value); } bool FeedStream::HasReachedConditionsToUploadActionsWithNoticeCard() { + // TODO(crbug/1152592): Determine notice card behavior with web feeds. if (base::FeatureList::IsEnabled( feed::kInterestFeedV2ClicksAndViewsConditionalUpload)) { return prefs::GetHasReachedClickAndViewActionsUploadConditions( @@ -836,6 +932,7 @@ return true; } void FeedStream::DeclareHasReachedConditionsToUploadActionsWithNoticeCard() { + // TODO(crbug/1152592): Determine notice card behavior with web feeds. if (base::FeatureList::IsEnabled( feed::kInterestFeedV2ClicksAndViewsConditionalUpload)) { prefs::SetHasReachedClickAndViewActionsUploadConditions(*profile_prefs_, @@ -845,23 +942,32 @@ void FeedStream::UpdateShownSlicesUploadCondition(int viewed_slice_index) { constexpr int kShownSlicesThreshold = 2; - DCHECK(model_) << "Model was unloaded while handling a viewed slice"; + // TODO(crbug/1152592): Determine notice card behavior with web feeds. + Stream& stream = GetStream(kInterestStream); + if (!stream.model) { + DLOG(ERROR) << "Model was unloaded while handling a viewed slice"; + return; + } // Don't take shown slices into consideration when the upload conditions has // already been reached. - if (HasReachedConditionsToUploadActionsWithNoticeCard()) + if (HasReachedConditionsToUploadActionsWithNoticeCard()) { return; + } - if (!model_->signed_in()) + if (!stream.model->signed_in()) { return; + } if (viewed_slice_index + 1 >= kShownSlicesThreshold) DeclareHasReachedConditionsToUploadActionsWithNoticeCard(); } bool FeedStream::CanLogViews() const { + // TODO(crbug/1152592): Determine notice card behavior with web feeds. return CanUploadActions(); } void FeedStream::UpdateCanUploadActionsWithNoticeCard() { + // TODO(crbug/1152592): Determine notice card behavior with web feeds. can_upload_actions_with_notice_card_ = HasReachedConditionsToUploadActionsWithNoticeCard(); }
diff --git a/components/feed/core/v2/feed_stream.h b/components/feed/core/v2/feed_stream.h index 2b45b09..61c505c 100644 --- a/components/feed/core/v2/feed_stream.h +++ b/components/feed/core/v2/feed_stream.h
@@ -136,16 +136,21 @@ base::OnceCallback<void(NetworkResponse)> callback) override; void CancelImageFetch(ImageFetchId id) override; PersistentKeyValueStoreImpl* GetPersistentKeyValueStore() override; - void LoadMore(SurfaceId surface_id, + void LoadMore(const SurfaceInterface& surface, base::OnceCallback<void(bool)> callback) override; void ExecuteOperations( + const StreamType& stream_type, std::vector<feedstore::DataOperation> operations) override; EphemeralChangeId CreateEphemeralChange( + const StreamType& stream_type, std::vector<feedstore::DataOperation> operations) override; EphemeralChangeId CreateEphemeralChangeFromPackedData( + const StreamType& stream_type, base::StringPiece data) override; - bool CommitEphemeralChange(EphemeralChangeId id) override; - bool RejectEphemeralChange(EphemeralChangeId id) override; + bool CommitEphemeralChange(const StreamType& stream_type, + EphemeralChangeId id) override; + bool RejectEphemeralChange(const StreamType& stream_type, + EphemeralChangeId id) override; void ProcessThereAndBackAgain(base::StringPiece data) override; void ProcessViewAction(base::StringPiece data) override; DebugStreamData GetDebugStreamData() override; @@ -155,12 +160,15 @@ const feedui::StreamUpdate& stream_update) override; void ReportSliceViewed(SurfaceId surface_id, + const StreamType& stream_type, const std::string& slice_id) override; void ReportFeedViewed(SurfaceId surface_id) override; void ReportPageLoaded() override; - void ReportOpenAction(const std::string& slice_id) override; + void ReportOpenAction(const StreamType& stream_type, + const std::string& slice_id) override; void ReportOpenVisitComplete(base::TimeDelta visit_time) override; - void ReportOpenInNewTabAction(const std::string& slice_id) override; + void ReportOpenInNewTabAction(const StreamType& stream_type, + const std::string& slice_id) override; void ReportStreamScrolled(int distance_dp) override; void ReportStreamScrollStart() override; void ReportOtherUserAction(FeedUserActionType action_type) override; @@ -238,7 +246,7 @@ // Unloads the model. Surfaces are not updated, and will remain frozen until a // model load is requested. - void UnloadModel(); + void UnloadModel(const StreamType& stream_type); // Triggers a stream load. The load will be aborted if |ShouldAttemptLoad()| // is not true. @@ -249,7 +257,7 @@ void FinishClearAll(); // Returns the model if it is loaded, or null otherwise. - StreamModel* GetModel() { return model_.get(); } + StreamModel* GetModel(const StreamType& stream_type); RequestMetadata GetRequestMetadata(bool is_for_next_page) const; @@ -274,6 +282,23 @@ private: class OfflineSuggestionsProvider; + struct Stream { + Stream(); + ~Stream(); + Stream(const Stream&) = delete; + Stream& operator=(const Stream&) = delete; + StreamType type; + // Whether the model is being loaded. Used to prevent multiple simultaneous + // attempts to load the model. + bool model_loading_in_progress = false; + std::unique_ptr<SurfaceUpdater> surface_updater; + // The stream model. Null if not yet loaded. + // Internally, this should only be changed by |LoadModel()| and + // |UnloadModel()|. + std::unique_ptr<StreamModel> model; + int unload_on_detach_sequence_number = 0; + }; + base::WeakPtr<FeedStream> GetWeakPtr() { return weak_ptr_factory_.GetWeakPtr(); } @@ -289,9 +314,10 @@ // To only be called from within a |Task|. void ForceRefreshForDebuggingTask(); - void ScheduleModelUnloadIfNoSurfacesAttached(); - void AddUnloadModelIfNoSurfacesAttachedTask(int sequence_number); - void UnloadModelIfNoSurfacesAttachedTask(); + void ScheduleModelUnloadIfNoSurfacesAttached(const StreamType& stream_type); + void AddUnloadModelIfNoSurfacesAttachedTask(const StreamType& stream_type, + int sequence_number); + void UnloadModelIfNoSurfacesAttachedTask(const StreamType& stream_type); void InitialStreamLoadComplete(LoadStreamTask::Result result); void LoadMoreComplete(LoadMoreTask::Result result); @@ -311,6 +337,10 @@ void UpdateCanUploadActionsWithNoticeCard(); + Stream& GetStream(const StreamType& type); + Stream* FindStream(const StreamType& type); + const Stream* FindStream(const StreamType& type) const; + // Unowned. offline_pages::PrefetchService* prefetch_service_; @@ -327,23 +357,18 @@ ChromeInfo chrome_info_; offline_pages::TaskQueue task_queue_; - // Whether the model is being loaded. Used to prevent multiple simultaneous - // attempts to load the model. - bool model_loading_in_progress_ = false; - std::unique_ptr<SurfaceUpdater> surface_updater_; + + std::map<StreamType, Stream> streams_; + std::unique_ptr<OfflineSuggestionsProvider> offline_suggestions_provider_; std::unique_ptr<OfflinePageSpy> offline_page_spy_; - // The stream model. Null if not yet loaded. - // Internally, this should only be changed by |LoadModel()| and - // |UnloadModel()|. - std::unique_ptr<StreamModel> model_; // Mutable state. RequestThrottler request_throttler_; base::TimeTicks signed_out_refreshes_until_; std::vector<base::OnceCallback<void(bool)>> load_more_complete_callbacks_; Metadata metadata_; - int unload_on_detach_sequence_number_ = 0; + bool is_activity_logging_enabled_ = false; // Whether the feed stream can upload actions with the notice card in the // feed.
diff --git a/components/feed/core/v2/feed_stream_unittest.cc b/components/feed/core/v2/feed_stream_unittest.cc index 07d3c5e..7157842 100644 --- a/components/feed/core/v2/feed_stream_unittest.cc +++ b/components/feed/core/v2/feed_stream_unittest.cc
@@ -166,7 +166,8 @@ public: // Provide some helper functionality to attach/detach the surface. // This way we can auto-detach in the destructor. - explicit TestSurface(FeedStream* stream = nullptr) { + explicit TestSurface(FeedStream* stream = nullptr) + : FeedStream::SurfaceInterface(kInterestStream) { if (stream) Attach(stream); } @@ -305,6 +306,7 @@ public: // FeedNetwork implementation. void SendQueryRequest( + NetworkRequestType request_type, const feedwire::Request& request, bool force_signed_out_request, base::OnceCallback<void(QueryRequestResult)> callback) override { @@ -658,7 +660,7 @@ void UnloadModel() { WaitForIdleTaskQueue(); - stream_->UnloadModel(); + stream_->UnloadModel(kInterestStream); } // Dumps the state of |FeedStore| to a string for debugging. @@ -759,7 +761,7 @@ EXPECT_EQ(LoadStreamStatus::kLoadedFromNetwork, metrics_reporter_->background_refresh_status); EXPECT_TRUE(response_translator_.InjectedResponseConsumed()); - EXPECT_FALSE(stream_->GetModel()); + EXPECT_FALSE(stream_->GetModel(kInterestStream)); TestSurface surface(stream_.get()); WaitForIdleTaskQueue(); EXPECT_EQ("loading -> 2 slices", surface.DescribeUpdates()); @@ -864,12 +866,13 @@ } TestSurface surface(stream_.get()); // Remove #1, add #2. - stream_->ExecuteOperations({ - MakeOperation(MakeRemove(MakeClusterId(1))), - MakeOperation(MakeCluster(2, MakeRootId())), - MakeOperation(MakeContentNode(2, MakeClusterId(2))), - MakeOperation(MakeContent(2)), - }); + stream_->ExecuteOperations( + kInterestStream, { + MakeOperation(MakeRemove(MakeClusterId(1))), + MakeOperation(MakeCluster(2, MakeRootId())), + MakeOperation(MakeContentNode(2, MakeClusterId(2))), + MakeOperation(MakeContent(2)), + }); ASSERT_TRUE(surface.update); const feedui::StreamUpdate& initial_state = surface.initial_state.value(); const feedui::StreamUpdate& update = surface.update.value(); @@ -892,18 +895,20 @@ } TestSurface surface(stream_.get()); // Add #2. - stream_->ExecuteOperations({ - MakeOperation(MakeCluster(2, MakeRootId())), - MakeOperation(MakeContentNode(2, MakeClusterId(2))), - MakeOperation(MakeContent(2)), - }); + stream_->ExecuteOperations( + kInterestStream, { + MakeOperation(MakeCluster(2, MakeRootId())), + MakeOperation(MakeContentNode(2, MakeClusterId(2))), + MakeOperation(MakeContent(2)), + }); // Clear the last update and add #3. - stream_->ExecuteOperations({ - MakeOperation(MakeCluster(3, MakeRootId())), - MakeOperation(MakeContentNode(3, MakeClusterId(3))), - MakeOperation(MakeContent(3)), - }); + stream_->ExecuteOperations( + kInterestStream, { + MakeOperation(MakeCluster(3, MakeRootId())), + MakeOperation(MakeContentNode(3, MakeClusterId(3))), + MakeOperation(MakeContent(3)), + }); // The last update should have only one new piece of content. // This verifies the current content set is tracked properly. @@ -925,10 +930,11 @@ WaitForIdleTaskQueue(); // Remove both pieces of content. - stream_->ExecuteOperations({ - MakeOperation(MakeRemove(MakeClusterId(0))), - MakeOperation(MakeRemove(MakeClusterId(1))), - }); + stream_->ExecuteOperations(kInterestStream, + { + MakeOperation(MakeRemove(MakeClusterId(0))), + MakeOperation(MakeRemove(MakeClusterId(1))), + }); ASSERT_EQ("loading -> 2 slices -> no-cards", surface.DescribeUpdates()); } @@ -945,9 +951,10 @@ surface.Clear(); // Arbitrary stream change. Surface should not see the update. - stream_->ExecuteOperations({ - MakeOperation(MakeRemove(MakeClusterId(1))), - }); + stream_->ExecuteOperations(kInterestStream, + { + MakeOperation(MakeRemove(MakeClusterId(1))), + }); EXPECT_FALSE(surface.update); } @@ -974,8 +981,9 @@ EXPECT_EQ("loading -> 2 slices", surface.DescribeUpdates()); // Verify the model is filled correctly. - EXPECT_STRINGS_EQUAL(ModelStateFor(MakeTypicalInitialModelState()), - stream_->GetModel()->DumpStateForTesting()); + EXPECT_STRINGS_EQUAL( + ModelStateFor(MakeTypicalInitialModelState()), + stream_->GetModel(kInterestStream)->DumpStateForTesting()); // Verify the data was written to the store. EXPECT_STRINGS_EQUAL(ModelStateFor(MakeTypicalInitialModelState()), ModelStateFor(store_.get())); @@ -1059,7 +1067,7 @@ WaitForIdleTaskQueue(); ASSERT_EQ(1, network_.send_query_call_count); surface.Detach(); - stream_->UnloadModel(); + stream_->UnloadModel(surface.GetStreamType()); // Ensure a refresh is foreced only after a scheduled refresh was missed. // First, load the stream after 11 seconds. @@ -1072,7 +1080,7 @@ // Load the stream after 13 seconds. We missed the scheduled refresh at // 12 seconds. surface.Detach(); - stream_->UnloadModel(); + stream_->UnloadModel(surface.GetStreamType()); task_environment_.AdvanceClock(base::TimeDelta::FromSeconds(2)); surface.Attach(stream_.get()); WaitForIdleTaskQueue(); @@ -1280,16 +1288,16 @@ // Validate the downstream consumption of the response. EXPECT_EQ("loading -> 2 slices", surface.DescribeUpdates()); EXPECT_EQ(kSessionId, stream_->GetMetadata()->GetSessionIdToken()); - EXPECT_FALSE(stream_->GetModel()->signed_in()); + EXPECT_FALSE(stream_->GetModel(surface.GetStreamType())->signed_in()); // Advance the clock beyond the forced signed out period. task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(2)); - EXPECT_FALSE(stream_->GetModel()->signed_in()); + EXPECT_FALSE(stream_->GetModel(surface.GetStreamType())->signed_in()); // Requests for subsequent pages continue the use existing session. // Subsequent responses may omit the session id. response_translator_.InjectResponse(model_generator.MakeNextPage()); - stream_->LoadMore(surface.GetSurfaceId(), base::DoNothing()); + stream_->LoadMore(surface, base::DoNothing()); WaitForIdleTaskQueue(); // Validate that the network request was sent as signed out and @@ -1304,7 +1312,7 @@ kSessionId); // The model should still be in the signed-out state. - EXPECT_FALSE(stream_->GetModel()->signed_in()); + EXPECT_FALSE(stream_->GetModel(kInterestStream)->signed_in()); // Force a refresh of the feed by clearing the cache. The request for the // first page should revert back to signed-in. The response data will denote @@ -1319,7 +1327,7 @@ EXPECT_FALSE(network_.forced_signed_out_request); // The model should now be in the signed-in state. - EXPECT_TRUE(stream_->GetModel()->signed_in()); + EXPECT_TRUE(stream_->GetModel(kInterestStream)->signed_in()); EXPECT_TRUE(stream_->GetMetadata()->GetSessionIdToken().empty()); } @@ -1360,8 +1368,9 @@ ASSERT_EQ("loading -> 2 slices", surface.DescribeUpdates()); EXPECT_FALSE(network_.query_request_sent); // Verify the model is filled correctly. - EXPECT_STRINGS_EQUAL(ModelStateFor(MakeTypicalInitialModelState()), - stream_->GetModel()->DumpStateForTesting()); + EXPECT_STRINGS_EQUAL( + ModelStateFor(MakeTypicalInitialModelState()), + stream_->GetModel(kInterestStream)->DumpStateForTesting()); } TEST_F(FeedStreamTest, LoadingSpinnerIsSentInitially) { @@ -1412,7 +1421,7 @@ MakeOperation(MakeContentNode(2, MakeClusterId(2))), MakeOperation(MakeContent(2)), }; - stream_->ExecuteOperations(operations); + stream_->ExecuteOperations(kInterestStream, operations); WaitForIdleTaskQueue(); @@ -1437,7 +1446,7 @@ MakeOperation(MakeContentNode(3, MakeClusterId(3))), MakeOperation(MakeContent(3)), }; - stream_->ExecuteOperations(operations2); + stream_->ExecuteOperations(surface.GetStreamType(), operations2); WaitForIdleTaskQueue(); EXPECT_STRINGS_EQUAL( @@ -1452,7 +1461,7 @@ WaitForIdleTaskQueue(); stream_->ReportSliceViewed( - surface.GetSurfaceId(), + surface.GetSurfaceId(), surface.GetStreamType(), surface.initial_state->updated_slices(1).slice().slice_id()); EXPECT_EQ(1, metrics_reporter_->slice_viewed_index); } @@ -1467,7 +1476,7 @@ // Load page 2. response_translator_.InjectResponse(MakeTypicalNextPageState(2)); CallbackReceiver<bool> callback; - stream_->LoadMore(surface.GetSurfaceId(), callback.Bind()); + stream_->LoadMore(surface, callback.Bind()); // Ensure metrics reporter was informed at the start of the operation. EXPECT_EQ(surface.GetSurfaceId(), metrics_reporter_->load_more_surface_id); WaitForIdleTaskQueue(); @@ -1477,7 +1486,7 @@ // Load page 3. response_translator_.InjectResponse(MakeTypicalNextPageState(3)); - stream_->LoadMore(surface.GetSurfaceId(), callback.Bind()); + stream_->LoadMore(surface, callback.Bind()); WaitForIdleTaskQueue(); ASSERT_EQ(base::Optional<bool>(true), callback.GetResult()); @@ -1494,14 +1503,15 @@ // Load page 2. response_translator_.InjectResponse(MakeTypicalNextPageState(2)); CallbackReceiver<bool> callback; - stream_->LoadMore(surface.GetSurfaceId(), callback.Bind()); + stream_->LoadMore(surface, callback.Bind()); WaitForIdleTaskQueue(); ASSERT_EQ(base::Optional<bool>(true), callback.GetResult()); // Verify stored state is equivalent to in-memory model. - EXPECT_STRINGS_EQUAL(stream_->GetModel()->DumpStateForTesting(), - ModelStateFor(store_.get())); + EXPECT_STRINGS_EQUAL( + stream_->GetModel(kInterestStream)->DumpStateForTesting(), + ModelStateFor(store_.get())); } TEST_F(FeedStreamTest, LoadMorePersistAndLoadMore) { @@ -1515,7 +1525,7 @@ // Load page 2. response_translator_.InjectResponse(MakeTypicalNextPageState(2)); CallbackReceiver<bool> callback; - stream_->LoadMore(surface.GetSurfaceId(), callback.Bind()); + stream_->LoadMore(surface, callback.Bind()); WaitForIdleTaskQueue(); ASSERT_EQ(base::Optional<bool>(true), callback.GetResult()); @@ -1528,14 +1538,15 @@ WaitForIdleTaskQueue(); callback.Clear(); surface.Clear(); - stream_->LoadMore(surface.GetSurfaceId(), callback.Bind()); + stream_->LoadMore(surface, callback.Bind()); WaitForIdleTaskQueue(); ASSERT_EQ(base::Optional<bool>(true), callback.GetResult()); ASSERT_EQ("4 slices +spinner -> 6 slices", surface.DescribeUpdates()); // Verify stored state is equivalent to in-memory model. - EXPECT_STRINGS_EQUAL(stream_->GetModel()->DumpStateForTesting(), - ModelStateFor(store_.get())); + EXPECT_STRINGS_EQUAL( + stream_->GetModel(surface.GetStreamType())->DumpStateForTesting(), + ModelStateFor(store_.get())); } TEST_F(FeedStreamTest, LoadMoreSendsTokens) { @@ -1547,7 +1558,7 @@ stream_->GetMetadata()->SetConsistencyToken("token-1"); response_translator_.InjectResponse(MakeTypicalNextPageState(2)); CallbackReceiver<bool> callback; - stream_->LoadMore(surface.GetSurfaceId(), callback.Bind()); + stream_->LoadMore(surface, callback.Bind()); WaitForIdleTaskQueue(); ASSERT_EQ("2 slices +spinner -> 4 slices", surface.DescribeUpdates()); @@ -1563,7 +1574,7 @@ stream_->GetMetadata()->SetConsistencyToken("token-2"); response_translator_.InjectResponse(MakeTypicalNextPageState(3)); - stream_->LoadMore(surface.GetSurfaceId(), callback.Bind()); + stream_->LoadMore(surface, callback.Bind()); WaitForIdleTaskQueue(); ASSERT_EQ("4 slices +spinner -> 6 slices", surface.DescribeUpdates()); @@ -1589,7 +1600,7 @@ WaitForIdleTaskQueue(); CallbackReceiver<bool> callback; - stream_->LoadMore(surface.GetSurfaceId(), callback.Bind()); + stream_->LoadMore(surface, callback.Bind()); WaitForIdleTaskQueue(); // LoadMore fails, and does not make an additional request. @@ -1610,7 +1621,7 @@ // Don't inject another response, which results in a proto translation // failure. CallbackReceiver<bool> callback; - stream_->LoadMore(surface.GetSurfaceId(), callback.Bind()); + stream_->LoadMore(surface, callback.Bind()); WaitForIdleTaskQueue(); EXPECT_EQ(base::Optional<bool>(false), callback.GetResult()); @@ -1626,14 +1637,15 @@ // Use a different initial state (which includes a CLEAR_ALL). response_translator_.InjectResponse(MakeTypicalInitialModelState(5)); CallbackReceiver<bool> callback; - stream_->LoadMore(surface.GetSurfaceId(), callback.Bind()); + stream_->LoadMore(surface, callback.Bind()); WaitForIdleTaskQueue(); ASSERT_EQ(base::Optional<bool>(true), callback.GetResult()); // Verify stored state is equivalent to in-memory model. - EXPECT_STRINGS_EQUAL(stream_->GetModel()->DumpStateForTesting(), - ModelStateFor(store_.get())); + EXPECT_STRINGS_EQUAL( + stream_->GetModel(surface.GetStreamType())->DumpStateForTesting(), + ModelStateFor(store_.get())); // Verify the new state has been pushed to |surface|. ASSERT_EQ("2 slices +spinner -> 2 slices", surface.DescribeUpdates()); @@ -1654,7 +1666,8 @@ TEST_F(FeedStreamTest, LoadMoreBeforeLoad) { CallbackReceiver<bool> callback; - stream_->LoadMore(SurfaceId(), callback.Bind()); + TestSurface surface; + stream_->LoadMore(surface, callback.Bind()); EXPECT_EQ(base::Optional<bool>(false), callback.GetResult()); } @@ -1720,7 +1733,7 @@ TestSurface surface(stream_.get()); WaitForIdleTaskQueue(); - stream_->LoadMore(surface.GetSurfaceId(), base::DoNothing()); + stream_->LoadMore(surface, base::DoNothing()); response_translator_.InjectResponse(MakeTypicalNextPageState(2)); response_translator_.InjectResponse(MakeTypicalInitialModelState()); stream_->OnCacheDataCleared(); // triggers ClearAll(). @@ -1871,7 +1884,7 @@ // Reach conditions. stream_->ReportSliceViewed( - surface.GetSurfaceId(), + surface.GetSurfaceId(), surface.GetStreamType(), surface.initial_state->updated_slices(1).slice().slice_id()); // Verify that the view action is still dropped because we haven't @@ -1902,7 +1915,7 @@ // Reach conditions. stream_->ReportSliceViewed( - surface.GetSurfaceId(), + surface.GetSurfaceId(), surface.GetStreamType(), surface.initial_state->updated_slices(1).slice().slice_id()); // Attach a new surface to update the bit to enable uploads. @@ -1911,7 +1924,7 @@ // Trigger an upload through load more to isolate the effect of the on-attach // event on enabling uploads. response_translator_.InjectResponse(MakeTypicalNextPageState()); - stream_->LoadMore(surface.GetSurfaceId(), base::DoNothing()); + stream_->LoadMore(surface, base::DoNothing()); WaitForIdleTaskQueue(); // Verify that the ThereAndBackAgain action was uploaded. @@ -1931,7 +1944,7 @@ // Reach conditions. stream_->ReportSliceViewed( - surface.GetSurfaceId(), + surface.GetSurfaceId(), surface.GetStreamType(), surface.initial_state->updated_slices(1).slice().slice_id()); stream_->OnEnterBackground(); @@ -1975,7 +1988,7 @@ // Reach conditions. stream_->ReportSliceViewed( - surface.GetSurfaceId(), + surface.GetSurfaceId(), surface.GetStreamType(), surface.initial_state->updated_slices(1).slice().slice_id()); // Assert that uploads are not yet enabled. @@ -1996,7 +2009,7 @@ // Reach conditions. stream_->ReportSliceViewed( - surface.GetSurfaceId(), + surface.GetSurfaceId(), surface.GetStreamType(), surface.initial_state->updated_slices(1).slice().slice_id()); // Update the upload enable bits which will enable upload. @@ -2049,7 +2062,7 @@ // Try to reach conditions. stream_->ReportSliceViewed( - surface.GetSurfaceId(), + surface.GetSurfaceId(), surface.GetStreamType(), surface.initial_state->updated_slices(1).slice().slice_id()); // Try to trigger an upload through a query. @@ -2114,7 +2127,7 @@ network_.consistency_token = "token-12"; - stream_->LoadMore(surface.GetSurfaceId(), base::DoNothing()); + stream_->LoadMore(surface, base::DoNothing()); WaitForIdleTaskQueue(); EXPECT_EQ(1, network_.action_request_sent->feed_actions_size()); @@ -2144,7 +2157,7 @@ MakeTypicalNextPageState(page++, kTestTimeEpoch, signed_in, waa_on, privacy_notice_fulfilled)); CallbackReceiver<bool> callback; - stream_->LoadMore(surface.GetSurfaceId(), callback.Bind()); + stream_->LoadMore(surface, callback.Bind()); WaitForIdleTaskQueue(); EXPECT_EQ( stream_->IsActivityLoggingEnabled(), @@ -2178,7 +2191,7 @@ // effect of load more. base::HistogramTester histograms; - stream_->LoadMore(surface.GetSurfaceId(), base::DoNothing()); + stream_->LoadMore(surface, base::DoNothing()); WaitForIdleTaskQueue(); // Process a view action that should be dropped because the upload of actions @@ -2342,11 +2355,11 @@ task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(999)); WaitForIdleTaskQueue(); - EXPECT_TRUE(stream_->GetModel()); + EXPECT_TRUE(stream_->GetModel(surface.GetStreamType())); task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(2)); WaitForIdleTaskQueue(); - EXPECT_FALSE(stream_->GetModel()); + EXPECT_FALSE(stream_->GetModel(surface.GetStreamType())); } TEST_F(FeedStreamTest, ModelDoesNotUnloadIfSurfaceIsAttached) { @@ -2362,13 +2375,13 @@ task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(999)); WaitForIdleTaskQueue(); - EXPECT_TRUE(stream_->GetModel()); + EXPECT_TRUE(stream_->GetModel(surface.GetStreamType())); surface.Attach(stream_.get()); task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(2)); WaitForIdleTaskQueue(); - EXPECT_TRUE(stream_->GetModel()); + EXPECT_TRUE(stream_->GetModel(surface.GetStreamType())); } TEST_F(FeedStreamTest, ModelUnloadsAfterSecondTimeout) { @@ -2384,7 +2397,7 @@ task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(999)); WaitForIdleTaskQueue(); - EXPECT_TRUE(stream_->GetModel()); + EXPECT_TRUE(stream_->GetModel(surface.GetStreamType())); // Attaching another surface will prolong the unload time for another second. surface.Attach(stream_.get()); @@ -2392,11 +2405,11 @@ task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(999)); WaitForIdleTaskQueue(); - EXPECT_TRUE(stream_->GetModel()); + EXPECT_TRUE(stream_->GetModel(surface.GetStreamType())); task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(2)); WaitForIdleTaskQueue(); - EXPECT_FALSE(stream_->GetModel()); + EXPECT_FALSE(stream_->GetModel(surface.GetStreamType())); } TEST_F(FeedStreamTest, ProvidesPrefetchSuggestionsWhenModelLoaded) { @@ -2437,7 +2450,7 @@ callback.Bind()); WaitForIdleTaskQueue(); - ASSERT_FALSE(stream_->GetModel()); + ASSERT_FALSE(stream_->GetModel(kInterestStream)); ASSERT_TRUE(callback.GetResult()); const std::vector<offline_pages::PrefetchSuggestion>& suggestions = callback.GetResult().value(); @@ -2550,7 +2563,7 @@ TestSurface surface(stream_.get()); WaitForIdleTaskQueue(); - stream_->UnloadModel(); + stream_->UnloadModel(surface.GetStreamType()); // Offline badge no longer present. EXPECT_EQ((std::map<std::string, std::string>()), @@ -2606,7 +2619,7 @@ // LoadMore, and verify the same token is used. response_translator_.InjectResponse(MakeTypicalNextPageState(2)); - stream_->LoadMore(surface.GetSurfaceId(), base::DoNothing()); + stream_->LoadMore(surface, base::DoNothing()); WaitForIdleTaskQueue(); ASSERT_EQ(2, network_.send_query_call_count); @@ -2625,7 +2638,7 @@ stream_->OnSignedOut(); WaitForIdleTaskQueue(); - EXPECT_FALSE(stream_->GetModel()); + EXPECT_FALSE(stream_->GetModel(surface.GetStreamType())); const bool is_for_next_page = false; // No model so no first page yet. const std::string new_instance_id = stream_->GetRequestMetadata(is_for_next_page).client_instance_id; @@ -2649,14 +2662,17 @@ surface.initial_state->updated_slices(notice_card_index) .slice() .slice_id(); - stream_->ReportSliceViewed(surface.GetSurfaceId(), slice_id); - stream_->ReportSliceViewed(surface.GetSurfaceId(), slice_id); - stream_->ReportSliceViewed(surface.GetSurfaceId(), slice_id); - stream_->ReportOpenAction(slice_id); + stream_->ReportSliceViewed(surface.GetSurfaceId(), surface.GetStreamType(), + slice_id); + stream_->ReportSliceViewed(surface.GetSurfaceId(), surface.GetStreamType(), + slice_id); + stream_->ReportSliceViewed(surface.GetSurfaceId(), surface.GetStreamType(), + slice_id); + stream_->ReportOpenAction(surface.GetStreamType(), slice_id); response_translator_.InjectResponse(MakeTypicalInitialModelState()); refresh_scheduler_.Clear(); - stream_->UnloadModel(); + stream_->UnloadModel(surface.GetStreamType()); stream_->ExecuteRefreshTask(); WaitForIdleTaskQueue(); @@ -2749,7 +2765,7 @@ task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1)); response_translator_.InjectResponse(model_generator.MakeNextPage(2), kSessionToken1); - stream_->LoadMore(surface.GetSurfaceId(), base::DoNothing()); + stream_->LoadMore(surface, base::DoNothing()); WaitForIdleTaskQueue(); ASSERT_EQ(2, network_.send_query_call_count); EXPECT_TRUE(network_.query_request_sent->feed_request() @@ -2772,7 +2788,7 @@ // - the session-id's expiry time should be unchanged task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1)); response_translator_.InjectResponse(model_generator.MakeNextPage(3)); - stream_->LoadMore(surface.GetSurfaceId(), base::DoNothing()); + stream_->LoadMore(surface, base::DoNothing()); WaitForIdleTaskQueue(); ASSERT_EQ(3, network_.send_query_call_count); EXPECT_TRUE(network_.query_request_sent->feed_request() @@ -2796,7 +2812,7 @@ task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1)); response_translator_.InjectResponse(model_generator.MakeNextPage(4), kSessionToken2); - stream_->LoadMore(surface.GetSurfaceId(), base::DoNothing()); + stream_->LoadMore(surface, base::DoNothing()); WaitForIdleTaskQueue(); ASSERT_EQ(4, network_.send_query_call_count); EXPECT_TRUE(network_.query_request_sent->feed_request()
diff --git a/components/feed/core/v2/metrics_reporter.cc b/components/feed/core/v2/metrics_reporter.cc index 5ed284b..e63bab94 100644 --- a/components/feed/core/v2/metrics_reporter.cc +++ b/components/feed/core/v2/metrics_reporter.cc
@@ -425,6 +425,11 @@ "ContentSuggestions.Feed.Network.ResponseStatus.UploadActions", http_status_code); return; + case NetworkRequestType::kNextPage: + base::UmaHistogramSparse( + "ContentSuggestions.Feed.Network.ResponseStatus.NextPage", + http_status_code); + return; } }
diff --git a/components/feed/core/v2/notice_card_tracker.cc b/components/feed/core/v2/notice_card_tracker.cc index cb318c86..99d8a42 100644 --- a/components/feed/core/v2/notice_card_tracker.cc +++ b/components/feed/core/v2/notice_card_tracker.cc
@@ -69,8 +69,9 @@ } bool NoticeCardTracker::HasNoticeCardActionsCountPrerequisites(int index) { - if (!base::FeatureList::IsEnabled(feed::kInterestFeedNoticeCardAutoDismiss)) + if (!base::FeatureList::IsEnabled(feed::kInterestFeedNoticeCardAutoDismiss)) { return false; + } if (!prefs::GetLastFetchHadNoticeCard(*profile_prefs_)) { return false; @@ -94,4 +95,4 @@ prefs::IncrementNoticeCardClicksCount(*profile_prefs_); } -} // namespace feed \ No newline at end of file +} // namespace feed
diff --git a/components/feed/core/v2/public/feed_stream_api.cc b/components/feed/core/v2/public/feed_stream_api.cc index 87c23e7b..b5216278 100644 --- a/components/feed/core/v2/public/feed_stream_api.cc +++ b/components/feed/core/v2/public/feed_stream_api.cc
@@ -9,7 +9,8 @@ FeedStreamApi::FeedStreamApi() = default; FeedStreamApi::~FeedStreamApi() = default; -FeedStreamApi::SurfaceInterface::SurfaceInterface() { +FeedStreamApi::SurfaceInterface::SurfaceInterface(StreamType stream_type) + : stream_type_(stream_type) { static SurfaceId::Generator id_generator; surface_id_ = id_generator.GenerateNextId(); }
diff --git a/components/feed/core/v2/public/feed_stream_api.h b/components/feed/core/v2/public/feed_stream_api.h index 1c2c272..65a9137 100644 --- a/components/feed/core/v2/public/feed_stream_api.h +++ b/components/feed/core/v2/public/feed_stream_api.h
@@ -26,26 +26,57 @@ namespace feed { class PersistentKeyValueStore; +// Selects the stream type. +// TODO(crbug.com/1152592): Need to use StreamType in several places: +// - Stream loading/saving +// - Metrics +// Note: currently there are two options, but this leaves room for more +// parameters. +class StreamType { + public: + enum class Type { + kInterest, + kWebFeed, + }; + constexpr explicit StreamType(Type t) : type(t) {} + bool operator<(const StreamType& rhs) const { return type < rhs.type; } + bool operator==(const StreamType& rhs) const { return type == rhs.type; } + + bool IsInterest() const { return type == Type::kInterest; } + bool IsWebFeed() const { return type == Type::kWebFeed; } + + private: + Type type = Type::kInterest; +}; + +constexpr StreamType kInterestStream(StreamType::Type::kInterest); + // This is the public access point for interacting with the Feed stream // contents. class FeedStreamApi { public: class SurfaceInterface : public base::CheckedObserver { public: - SurfaceInterface(); + explicit SurfaceInterface(StreamType type); ~SurfaceInterface() override; - // Called after registering the observer to provide the full stream state. - // Also called whenever the stream changes. - virtual void StreamUpdate(const feedui::StreamUpdate&) = 0; + // Returns a unique ID for the surface. The ID will not be reused until // after the Chrome process is closed. SurfaceId GetSurfaceId() const; + // Returns the `StreamType` this `SurfaceInterface` requests. + StreamType GetStreamType() const { return stream_type_; } + + // Called after registering the observer to provide the full stream state. + // Also called whenever the stream changes. + virtual void StreamUpdate(const feedui::StreamUpdate&) = 0; + virtual void ReplaceDataStoreEntry(base::StringPiece key, base::StringPiece data) = 0; virtual void RemoveDataStoreEntry(base::StringPiece key) = 0; private: + StreamType stream_type_; SurfaceId surface_id_; }; @@ -80,7 +111,7 @@ // Calls |callback| when complete. If no content could be added, the parameter // is false, and the caller should expect |LoadMore| to fail if called // further. - virtual void LoadMore(SurfaceId surface, + virtual void LoadMore(const SurfaceInterface& surface, base::OnceCallback<void(bool)> callback) = 0; // Request to fetch and image for use in the feed. Calls |callback| @@ -99,20 +130,25 @@ // Apply |operations| to the stream model. Does nothing if the model is not // yet loaded. virtual void ExecuteOperations( + const StreamType& stream_type, std::vector<feedstore::DataOperation> operations) = 0; // Create a temporary change that may be undone or committed later. Does // nothing if the model is not yet loaded. virtual EphemeralChangeId CreateEphemeralChange( + const StreamType& stream_type, std::vector<feedstore::DataOperation> operations) = 0; // Same as |CreateEphemeralChange()|, but data is a serialized // |feedpacking::DismissData| message. virtual EphemeralChangeId CreateEphemeralChangeFromPackedData( + const StreamType& stream_type, base::StringPiece data) = 0; // Commits a change. Returns false if the change does not exist. - virtual bool CommitEphemeralChange(EphemeralChangeId id) = 0; + virtual bool CommitEphemeralChange(const StreamType& stream_type, + EphemeralChangeId id) = 0; // Rejects a change. Returns false if the change does not exist. - virtual bool RejectEphemeralChange(EphemeralChangeId id) = 0; + virtual bool RejectEphemeralChange(const StreamType& stream_type, + EphemeralChangeId id) = 0; // Sends 'ThereAndBackAgainData' back to the server. |data| is a serialized // |feedwire::ThereAndBackAgainData| message. @@ -127,6 +163,7 @@ // A slice was viewed (2/3rds of it is in the viewport). Should be called // once for each viewed slice in the stream. virtual void ReportSliceViewed(SurfaceId surface_id, + const StreamType& stream_type, const std::string& slice_id) = 0; // Some feed content has been loaded and is now available to the user on the // feed surface. Reported only once after a surface is attached. @@ -134,13 +171,15 @@ // A web page was loaded in response to opening a link from the Feed. virtual void ReportPageLoaded() = 0; // The user triggered the default open action, usually by tapping the card. - virtual void ReportOpenAction(const std::string& slice_id) = 0; + virtual void ReportOpenAction(const StreamType& stream_type, + const std::string& slice_id) = 0; // The user triggered an open action, visited a web page, and then navigated // away or backgrouded the tab. |visit_time| is a measure of how long the // visited page was foregrounded. virtual void ReportOpenVisitComplete(base::TimeDelta visit_time) = 0; // The user triggered the 'open in new tab' action. - virtual void ReportOpenInNewTabAction(const std::string& slice_id) = 0; + virtual void ReportOpenInNewTabAction(const StreamType& stream_type, + const std::string& slice_id) = 0; // The user scrolled the feed by |distance_dp| and then stopped. virtual void ReportStreamScrolled(int distance_dp) = 0; // The user started scrolling the feed. Typically followed by a call to
diff --git a/components/feed/core/v2/request_throttler.cc b/components/feed/core/v2/request_throttler.cc index cddfdc3..4c237769 100644 --- a/components/feed/core/v2/request_throttler.cc +++ b/components/feed/core/v2/request_throttler.cc
@@ -18,6 +18,8 @@ return GetFeedConfig().max_feed_query_requests_per_day; case NetworkRequestType::kUploadActions: return GetFeedConfig().max_action_upload_requests_per_day; + case NetworkRequestType::kNextPage: + return GetFeedConfig().max_next_page_requests_per_day; } }
diff --git a/components/feed/core/v2/tasks/clear_all_task.cc b/components/feed/core/v2/tasks/clear_all_task.cc index 45fb2c7..95619a4 100644 --- a/components/feed/core/v2/tasks/clear_all_task.cc +++ b/components/feed/core/v2/tasks/clear_all_task.cc
@@ -17,7 +17,8 @@ ClearAllTask::~ClearAllTask() = default; void ClearAllTask::Run() { - stream_->UnloadModel(); + // TODO(crbug/1152592): Need to unload all models here. + stream_->UnloadModel(kInterestStream); stream_->GetPersistentKeyValueStore()->ClearAll(base::DoNothing()); stream_->GetStore()->ClearAll( base::BindOnce(&ClearAllTask::StoreClearComplete, GetWeakPtr()));
diff --git a/components/feed/core/v2/tasks/get_prefetch_suggestions_task.cc b/components/feed/core/v2/tasks/get_prefetch_suggestions_task.cc index 69cf3fb4..57a076d 100644 --- a/components/feed/core/v2/tasks/get_prefetch_suggestions_task.cc +++ b/components/feed/core/v2/tasks/get_prefetch_suggestions_task.cc
@@ -50,8 +50,8 @@ GetPrefetchSuggestionsTask::~GetPrefetchSuggestionsTask() = default; void GetPrefetchSuggestionsTask::Run() { - if (stream_->GetModel()) { - PullSuggestionsFromModel(*stream_->GetModel()); + if (stream_->GetModel(kInterestStream)) { + PullSuggestionsFromModel(*stream_->GetModel(kInterestStream)); return; }
diff --git a/components/feed/core/v2/tasks/load_more_task.cc b/components/feed/core/v2/tasks/load_more_task.cc index 19509e53..8e57766 100644 --- a/components/feed/core/v2/tasks/load_more_task.cc +++ b/components/feed/core/v2/tasks/load_more_task.cc
@@ -30,7 +30,8 @@ void LoadMoreTask::Run() { // Check prerequisites. - StreamModel* model = stream_->GetModel(); + // TODO(crbug/1152592): Parameterize stream loading by stream type. + StreamModel* model = stream_->GetModel(kInterestStream); if (!model) return Done(LoadStreamStatus::kLoadMoreModelIsNotLoaded); @@ -46,7 +47,8 @@ } void LoadMoreTask::UploadActionsComplete(UploadActionsTask::Result result) { - StreamModel* model = stream_->GetModel(); + // TODO(crbug/1152592): Parameterize stream loading by stream type. + StreamModel* model = stream_->GetModel(kInterestStream); DCHECK(model) << "Model was unloaded outside of a Task"; // Determine whether the load more request should be forced signed-out @@ -65,17 +67,18 @@ // Send network request. fetch_start_time_ = base::TimeTicks::Now(); stream_->GetNetwork()->SendQueryRequest( + NetworkRequestType::kNextPage, CreateFeedQueryLoadMoreRequest( stream_->GetRequestMetadata(/*is_for_next_page=*/true), stream_->GetMetadata()->GetConsistencyToken(), - stream_->GetModel()->GetNextPageToken()), + stream_->GetModel(kInterestStream)->GetNextPageToken()), force_signed_out_request, base::BindOnce(&LoadMoreTask::QueryRequestComplete, GetWeakPtr())); } void LoadMoreTask::QueryRequestComplete( FeedNetwork::QueryRequestResult result) { - StreamModel* model = stream_->GetModel(); + StreamModel* model = stream_->GetModel(kInterestStream); DCHECK(model) << "Model was unloaded outside of a Task"; if (!result.response_body)
diff --git a/components/feed/core/v2/tasks/load_stream_task.cc b/components/feed/core/v2/tasks/load_stream_task.cc index 5eb66ed6..89802de 100644 --- a/components/feed/core/v2/tasks/load_stream_task.cc +++ b/components/feed/core/v2/tasks/load_stream_task.cc
@@ -131,6 +131,7 @@ std::make_unique<UploadActionsTask::Result>(std::move(result)); latencies_->StepComplete(LoadLatencyTimes::kUploadActions); stream_->GetNetwork()->SendQueryRequest( + NetworkRequestType::kFeedQuery, CreateFeedQueryRefreshRequest( GetRequestReason(load_type_), stream_->GetRequestMetadata(/*is_for_next_page=*/false), @@ -143,7 +144,7 @@ FeedNetwork::QueryRequestResult result) { latencies_->StepComplete(LoadLatencyTimes::kQueryRequest); - DCHECK(!stream_->GetModel()); + DCHECK(!stream_->GetModel(kInterestStream)); network_response_info_ = result.response_info;
diff --git a/components/feed/core/v2/tasks/prefetch_images_task.cc b/components/feed/core/v2/tasks/prefetch_images_task.cc index 7131229..b8b5b52 100644 --- a/components/feed/core/v2/tasks/prefetch_images_task.cc +++ b/components/feed/core/v2/tasks/prefetch_images_task.cc
@@ -38,8 +38,8 @@ PrefetchImagesTask::~PrefetchImagesTask() = default; void PrefetchImagesTask::Run() { - if (stream_->GetModel()) { - PrefetchImagesFromModel(*stream_->GetModel()); + if (stream_->GetModel(kInterestStream)) { + PrefetchImagesFromModel(*stream_->GetModel(kInterestStream)); return; }
diff --git a/components/full_restore/window_info.h b/components/full_restore/window_info.h index 86feaadc..235e241 100644 --- a/components/full_restore/window_info.h +++ b/components/full_restore/window_info.h
@@ -23,7 +23,9 @@ aura::Window* window; - // Index in MruWindowTracker to restore window stack. + // Index in MruWindowTracker to restore window stack. A larger index + // indicates a more recently used window. The index is also opposite of the + // window index in the MruWindowTracker at save time. base::Optional<int32_t> activation_index; // Virtual desk id.
diff --git a/components/messages/android/java/src/org/chromium/components/messages/MessageBannerCoordinator.java b/components/messages/android/java/src/org/chromium/components/messages/MessageBannerCoordinator.java index 853d64d..6e4f1a112 100644 --- a/components/messages/android/java/src/org/chromium/components/messages/MessageBannerCoordinator.java +++ b/components/messages/android/java/src/org/chromium/components/messages/MessageBannerCoordinator.java
@@ -64,10 +64,11 @@ /** * Hides the message banner. + * @param animate Whether to hide with an animation. * @param messageHidden The {@link Runnable} that will run once the message banner is hidden. */ - void hide(Runnable messageHidden) { - mMediator.hide(messageHidden); + void hide(boolean animate, Runnable messageHidden) { + mMediator.hide(animate, messageHidden); } void setOnTouchRunnable(Runnable runnable) {
diff --git a/components/messages/android/java/src/org/chromium/components/messages/MessageBannerMediator.java b/components/messages/android/java/src/org/chromium/components/messages/MessageBannerMediator.java index 6b607d58..5fc9cc4b 100644 --- a/components/messages/android/java/src/org/chromium/components/messages/MessageBannerMediator.java +++ b/components/messages/android/java/src/org/chromium/components/messages/MessageBannerMediator.java
@@ -116,15 +116,23 @@ /** * Hides the message banner with an animation. + * @param animate Whether to hide with an animation. * @param messageHidden The {@link Runnable} that will run once the message banner is hidden. */ - void hide(Runnable messageHidden) { + void hide(boolean animate, Runnable messageHidden) { + cancelAnyAnimations(); + + if (!animate) { + mModel.set(ALPHA, 0.f); + mModel.set(TRANSLATION_Y, -mMaxTranslationYSupplier.get()); + mCurrentState = State.HIDDEN; + } + if (mCurrentState == State.HIDDEN) { messageHidden.run(); return; } - cancelAnyAnimations(); startAnimation(true, -mMaxTranslationYSupplier.get(), false, messageHidden); }
diff --git a/components/messages/android/java/src/org/chromium/components/messages/MessageBannerMediatorUnitTest.java b/components/messages/android/java/src/org/chromium/components/messages/MessageBannerMediatorUnitTest.java index 1566b29..b08b9cac 100644 --- a/components/messages/android/java/src/org/chromium/components/messages/MessageBannerMediatorUnitTest.java +++ b/components/messages/android/java/src/org/chromium/components/messages/MessageBannerMediatorUnitTest.java
@@ -110,7 +110,7 @@ assertModelState(0, 0, 1, "fully shown."); - mMediator.hide(mHiddenRunnable); + mMediator.hide(true, mHiddenRunnable); verify(mHiddenRunnable, times(0)).run(); shadowOf(getMainLooper()).idle(); @@ -120,6 +120,19 @@ } @Test + public void testHideMessageNoAnimation() { + mMediator.show(mShownRunnable); + + shadowOf(getMainLooper()).idle(); + + assertModelState(0, 0, 1, "fully shown."); + + mMediator.hide(false, mHiddenRunnable); + assertModelState(0, -100, 0, "after hidden."); + verify(mHiddenRunnable, times(1)).run(); + } + + @Test public void testVerticalDismiss() { mMediator.show(mShownRunnable);
diff --git a/components/messages/android/java/src/org/chromium/components/messages/SingleActionMessage.java b/components/messages/android/java/src/org/chromium/components/messages/SingleActionMessage.java index 6d50135..1e5261ab 100644 --- a/components/messages/android/java/src/org/chromium/components/messages/SingleActionMessage.java +++ b/components/messages/android/java/src/org/chromium/components/messages/SingleActionMessage.java
@@ -109,11 +109,7 @@ mContainer.removeMessage(mView); if (hiddenCallback != null) hiddenCallback.run(); }; - if (animate) { - mMessageBanner.hide(hiddenRunnable); - } else { - hiddenRunnable.run(); - } + mMessageBanner.hide(animate, hiddenRunnable); } /**
diff --git a/components/messages/android/java/src/org/chromium/components/messages/SingleActionMessageTest.java b/components/messages/android/java/src/org/chromium/components/messages/SingleActionMessageTest.java index fe362e6..2d32db0 100644 --- a/components/messages/android/java/src/org/chromium/components/messages/SingleActionMessageTest.java +++ b/components/messages/android/java/src/org/chromium/components/messages/SingleActionMessageTest.java
@@ -5,6 +5,7 @@ package org.chromium.components.messages; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -77,7 +78,7 @@ message.hide(true, () -> {}); // Let's pretend the animation ended, and the mediator called the callback as a result. final ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class); - verify(messageBanner).hide(runnableCaptor.capture()); + verify(messageBanner).hide(anyBoolean(), runnableCaptor.capture()); runnableCaptor.getValue().run(); Assert.assertEquals( "Message container should not have any view after the message is hidden.", 0,
diff --git a/components/mirroring/mojom/session_observer.mojom b/components/mirroring/mojom/session_observer.mojom index 3445aab9..8d32c461 100644 --- a/components/mirroring/mojom/session_observer.mojom +++ b/components/mirroring/mojom/session_observer.mojom
@@ -24,8 +24,9 @@ CAST_TRANSPORT_ERROR, // Error occurred in cast transport. }; -// Observer interface for receiving notifications about significant lifecycle -// events. +// Observer interface for the browser process to receive notifications about +// significant lifecycle events of a mirroring session. The notifications are +// sent from the mirroring service running in a sandboxed utility process. interface SessionObserver { // Called when error occurred. The session will be stopped. OnError(SessionError error); @@ -35,6 +36,10 @@ // Called when the session stops. DidStop(); + + // Called when a message needs to be logged at INFO level by the MR logger. + LogInfoMessage(string message); + + // Called when a message needs to be logged at ERROR level by the MR logger. + LogErrorMessage(string message); }; - -
diff --git a/components/mirroring/service/session.cc b/components/mirroring/service/session.cc index ec556d46..1959896 100644 --- a/components/mirroring/service/session.cc +++ b/components/mirroring/service/session.cc
@@ -19,6 +19,7 @@ #include "base/no_destructor.h" #include "base/rand_util.h" #include "base/stl_util.h" +#include "base/strings/strcat.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/system/sys_info.h" @@ -469,6 +470,17 @@ StopSession(); } +void Session::LogInfoMessage(const std::string& message) { + if (observer_) { + observer_->LogInfoMessage(message); + } +} + +void Session::LogErrorMessage(const std::string& message) { + if (observer_) { + observer_->LogErrorMessage(message); + } +} void Session::StopStreaming() { DVLOG(2) << __func__ << " state=" << state_; if (!cast_environment_) @@ -828,6 +840,10 @@ base::CompareCase::SENSITIVE))) { QueryCapabilitiesForRemoting(); } + } else { + LogInfoMessage( + base::StrCat({"Remoting is not supported on this receiver model: ", + session_params_.receiver_model_name})); } if (initially_starting_session && observer_) @@ -835,8 +851,7 @@ } void Session::OnResponseParsingError(const std::string& error_message) { - // TODO(crbug.com/1117673): Add MR-internals logging: - // VLOG(2) << "[REJECT] " << error_message; + LogErrorMessage(base::StrCat({"MessageDispatcher error: ", error_message})); } void Session::CreateAudioStream( @@ -1007,11 +1022,14 @@ return; if (!response.valid()) { - VLOG(1) << "Bad CAPABILITIES_RESPONSE. Remoting disabled."; if (response.error()) { - VLOG(1) << " error code=" << response.error()->code - << " description=" << response.error()->description - << " details=" << response.error()->details; + LogErrorMessage(base::StringPrintf( + "Remoting is not supported. Error code: %d, description: %s, " + "details: %s", + response.error()->code, response.error()->description.c_str(), + response.error()->details.c_str())); + } else { + LogErrorMessage("Remoting is not supported. Bad CAPABILITIES_RESPONSE."); } return; } @@ -1026,8 +1044,10 @@ } if (remoting_version > kSupportedRemotingVersion) { - VLOG(1) << "Unsupported remoting version (" << remoting_version << " > " - << kSupportedRemotingVersion << ')'; + LogErrorMessage( + base::StringPrintf("Remoting is not supported. The receiver's remoting " + "version (%d) is not supported by the sender (%d).", + remoting_version, kSupportedRemotingVersion)); return; }
diff --git a/components/mirroring/service/session.h b/components/mirroring/service/session.h index 25c03dcc..1ff5dbf 100644 --- a/components/mirroring/service/session.h +++ b/components/mirroring/service/session.h
@@ -54,8 +54,10 @@ // Streaming, and the switching to/from media remoting. When constructed, it // does OFFER/ANSWER exchange with the mirroring receiver. Mirroring starts when // the exchange succeeds and stops when this class is destructed or error -// occurs. |observer| will get notified when status changes. |outbound_channel| -// is responsible for sending messages to the mirroring receiver through Cast +// occurs. Specifically, a session is torn down when (1) a new session starts, +// (2) the mirroring service note a disconnection. +// |observer| will get notified when status changes. |outbound_channel| is +// responsible for sending messages to the mirroring receiver through Cast // Channel. |inbound_channel| receives message sent from the mirroring receiver. class COMPONENT_EXPORT(MIRRORING_SERVICE) Session final : public RtpStreamClient, @@ -135,6 +137,10 @@ // Notify |observer_| that error occurred and close the session. void ReportError(mojom::SessionError error); + // Send logging messages to |observer_|. + void LogInfoMessage(const std::string& message); + void LogErrorMessage(const std::string& message); + // Callback by Audio/VideoSender to indicate encoder status change. void OnEncoderStatusChange(media::cast::OperationalStatus status);
diff --git a/components/mirroring/service/session_unittest.cc b/components/mirroring/service/session_unittest.cc index d5cdf53d8..f61003a8e 100644 --- a/components/mirroring/service/session_unittest.cc +++ b/components/mirroring/service/session_unittest.cc
@@ -111,6 +111,8 @@ MOCK_METHOD1(OnError, void(SessionError)); MOCK_METHOD0(DidStart, void()); MOCK_METHOD0(DidStop, void()); + MOCK_METHOD1(LogInfoMessage, void(const std::string&)); + MOCK_METHOD1(LogErrorMessage, void(const std::string&)); MOCK_METHOD0(OnGetVideoCaptureHost, void()); MOCK_METHOD0(OnGetNetworkContext, void());
diff --git a/components/optimization_guide/content/browser/optimization_target_model_executor_unittest.cc b/components/optimization_guide/content/browser/optimization_target_model_executor_unittest.cc index f4ff6b3..214edb8 100644 --- a/components/optimization_guide/content/browser/optimization_target_model_executor_unittest.cc +++ b/components/optimization_guide/content/browser/optimization_target_model_executor_unittest.cc
@@ -9,6 +9,7 @@ #include "components/optimization_guide/content/browser/test_optimization_guide_decider.h" #include "content/public/test/browser_task_environment.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/tflite-support/src/tensorflow_lite_support/cc/task/core/task_utils.h" namespace optimization_guide { @@ -36,26 +37,13 @@ protected: void Preprocess(const std::vector<TfLiteTensor*>& input_tensors, const std::vector<float>& input) override { - // TODO(crbug/1176459): Use PopulateTensor instead. - - float* tensor = reinterpret_cast<float*>(input_tensors[0]->data.raw); - size_t bytes = input.size() * sizeof(float); - memcpy(tensor, input.data(), bytes); + tflite::task::core::PopulateTensor<float>(input, input_tensors[0]); } std::vector<float> Postprocess( const std::vector<const TfLiteTensor*>& output_tensors) override { - // TODO(crbug/1176459): Use PopulateVector instead. - - const TfLiteTensor* tensor = output_tensors[0]; - const float* results = reinterpret_cast<const float*>(tensor->data.raw); - size_t num = tensor->bytes / sizeof(tensor->type); - std::vector<float> data; - data.reserve(num); - for (size_t i = 0; i < num; i++) { - data.emplace_back(results[i]); - } + tflite::task::core::PopulateVector<float>(output_tensors[0], &data); return data; } };
diff --git a/components/page_load_metrics/browser/BUILD.gn b/components/page_load_metrics/browser/BUILD.gn index 9815611..0308b46 100644 --- a/components/page_load_metrics/browser/BUILD.gn +++ b/components/page_load_metrics/browser/BUILD.gn
@@ -31,6 +31,8 @@ "page_load_metrics_embedder_base.h", "page_load_metrics_embedder_interface.h", "page_load_metrics_event.h", + "page_load_metrics_memory_tracker.cc", + "page_load_metrics_memory_tracker.h", "page_load_metrics_observer.cc", "page_load_metrics_observer.h", "page_load_metrics_observer_delegate.cc", @@ -49,8 +51,11 @@ deps = [ "//build:chromeos_buildflags", "//components/data_reduction_proxy/core/browser", + "//components/keyed_service/content:content", + "//components/keyed_service/core:core", "//components/page_load_metrics/common", "//components/page_load_metrics/common:page_load_metrics_mojom", + "//components/performance_manager:performance_manager", "//content/public/browser", "//content/public/common", "//net", @@ -97,6 +102,7 @@ "observers/page_load_metrics_observer_content_test_harness.h", "observers/prerender_page_load_metrics_observer_unittest.cc", "observers/use_counter_page_load_metrics_observer_unittest.cc", + "page_load_metrics_memory_tracker_unittest.cc", "page_load_metrics_util_unittest.cc", "resource_tracker_unittest.cc", ] @@ -104,8 +110,10 @@ ":browser", ":test_support", "//base/test:test_support", + "//components/keyed_service/content", "//components/page_load_metrics/common:page_load_metrics_mojom", "//components/page_load_metrics/common:test_support", + "//components/performance_manager", "//components/ukm:test_support", "//components/ukm/content", "//content/public/browser",
diff --git a/components/page_load_metrics/browser/DEPS b/components/page_load_metrics/browser/DEPS index b9b314d..28827d6 100644 --- a/components/page_load_metrics/browser/DEPS +++ b/components/page_load_metrics/browser/DEPS
@@ -3,6 +3,9 @@ "+content/public/browser", "+content/public/test", "+components/data_reduction_proxy/core/browser", + "+components/keyed_service/content", + "+components/keyed_service/core", + "+components/performance_manager/public", "+components/ukm", "+net", "+services/metrics",
diff --git a/components/page_load_metrics/browser/metrics_web_contents_observer.cc b/components/page_load_metrics/browser/metrics_web_contents_observer.cc index 9ddb0af0..d1771de4 100644 --- a/components/page_load_metrics/browser/metrics_web_contents_observer.cc +++ b/components/page_load_metrics/browser/metrics_web_contents_observer.cc
@@ -13,6 +13,7 @@ #include "base/memory/ptr_util.h" #include "base/metrics/histogram_macros.h" #include "components/page_load_metrics/browser/page_load_metrics_embedder_interface.h" +#include "components/page_load_metrics/browser/page_load_metrics_memory_tracker.h" #include "components/page_load_metrics/browser/page_load_metrics_update_dispatcher.h" #include "components/page_load_metrics/browser/page_load_metrics_util.h" #include "components/page_load_metrics/browser/page_load_tracker.h" @@ -135,6 +136,9 @@ } void MetricsWebContentsObserver::FrameDeleted(content::RenderFrameHost* rfh) { + if (auto* memory_tracker = GetMemoryTracker()) + memory_tracker->OnFrameDeleted(rfh, this); + if (committed_load_) committed_load_->FrameDeleted(rfh); } @@ -981,6 +985,18 @@ committed_load_->BroadcastEventToObservers(event); } +void MetricsWebContentsObserver::OnV8MemoryChanged( + const std::vector<MemoryUpdate>& memory_updates) { + if (committed_load_) + committed_load_->OnV8MemoryChanged(memory_updates); +} + +PageLoadMetricsMemoryTracker* MetricsWebContentsObserver::GetMemoryTracker() + const { + return embedder_interface_->GetMemoryTrackerForBrowserContext( + web_contents()->GetBrowserContext()); +} + WEB_CONTENTS_USER_DATA_KEY_IMPL(MetricsWebContentsObserver) } // namespace page_load_metrics
diff --git a/components/page_load_metrics/browser/metrics_web_contents_observer.h b/components/page_load_metrics/browser/metrics_web_contents_observer.h index ef84749..fdb2508 100644 --- a/components/page_load_metrics/browser/metrics_web_contents_observer.h +++ b/components/page_load_metrics/browser/metrics_web_contents_observer.h
@@ -39,7 +39,9 @@ namespace page_load_metrics { +struct MemoryUpdate; class PageLoadMetricsEmbedderInterface; +class PageLoadMetricsMemoryTracker; class PageLoadTracker; // MetricsWebContentsObserver tracks page loads and loading metrics @@ -49,6 +51,7 @@ : public content::WebContentsObserver, public content::WebContentsUserData<MetricsWebContentsObserver>, public content::RenderWidgetHost::InputEventObserver, + public base::SupportsWeakPtr<MetricsWebContentsObserver>, public mojom::PageLoadMetrics { public: // TestingObserver allows tests to observe MetricsWebContentsObserver state @@ -175,13 +178,25 @@ // WebContentsObserver::DidFinishNavigation methods. void BroadcastEventToObservers(PageLoadMetricsEvent event); - private: - friend class content::WebContentsUserData<MetricsWebContentsObserver>; + // Called when V8 per-frame memory usage updates are available. Virtual for + // test classes to override. + virtual void OnV8MemoryChanged( + const std::vector<MemoryUpdate>& memory_updates); + protected: + // Protected rather than private so that derived test classes can call + // constructor. MetricsWebContentsObserver( content::WebContents* web_contents, std::unique_ptr<PageLoadMetricsEmbedderInterface> embedder_interface); + private: + friend class content::WebContentsUserData<MetricsWebContentsObserver>; + + // Gets the memory tracker for the BrowserContext if it exists, or nullptr + // otherwise. The tracker measures per-frame memory usage by V8. + PageLoadMetricsMemoryTracker* GetMemoryTracker() const; + void WillStartNavigationRequestImpl( content::NavigationHandle* navigation_handle);
diff --git a/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc b/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc index 08af036..cb48f01 100644 --- a/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc +++ b/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc
@@ -864,6 +864,19 @@ CheckNoErrorEvents(); } +TEST_F(MetricsWebContentsObserverTest, FlushBufferOnAppBackground) { + mojom::PageLoadTiming timing; + PopulatePageLoadTiming(&timing); + timing.paint_timing->first_paint = base::TimeDelta::FromMilliseconds(100000); + content::NavigationSimulator::NavigateAndCommitFromBrowser( + web_contents(), GURL(kDefaultTestUrl)); + SimulateTimingUpdateWithoutFiringDispatchTimer(timing, main_rfh()); + + ASSERT_EQ(0, CountUpdatedTimingReported()); + observer()->FlushMetricsOnAppEnterBackground(); + ASSERT_EQ(1, CountUpdatedTimingReported()); +} + TEST_F(MetricsWebContentsObserverTest, FirstInputDelayMissingFirstInputTimestamp) { mojom::PageLoadTiming timing;
diff --git a/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.cc b/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.cc index cf729f28..b37301e 100644 --- a/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.cc +++ b/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.cc
@@ -26,8 +26,14 @@ #include "third_party/blink/public/mojom/mobile_metrics/mobile_friendliness.mojom.h" #include "url/gurl.h" +namespace content { +class BrowserContext; +} // namespace content + namespace page_load_metrics { +class PageLoadMetricsMemoryTracker; + namespace { class TestPageLoadMetricsEmbedderInterface @@ -57,6 +63,12 @@ bool IsExtensionUrl(const GURL& url) override { return false; } + page_load_metrics::PageLoadMetricsMemoryTracker* + GetMemoryTrackerForBrowserContext( + content::BrowserContext* browser_context) override { + return nullptr; + } + private: PageLoadMetricsObserverTester* test_; @@ -332,4 +344,15 @@ register_callback_.Run(tracker); } +void PageLoadMetricsObserverTester::SimulateMemoryUpdate( + content::RenderFrameHost* render_frame_host, + int64_t delta_bytes) { + DCHECK(render_frame_host); + if (delta_bytes != 0) { + std::vector<MemoryUpdate> update({MemoryUpdate( + render_frame_host->GetGlobalFrameRoutingId(), delta_bytes)}); + metrics_web_contents_observer_->OnV8MemoryChanged(update); + } +} + } // namespace page_load_metrics
diff --git a/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.h b/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.h index 5bde3dd8..d5295f5 100644 --- a/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.h +++ b/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.h
@@ -141,6 +141,10 @@ bool blocked_by_policy, StorageType storage_type); + // Simulate a V8 per-frame memory update. + void SimulateMemoryUpdate(content::RenderFrameHost* render_frame_host, + int64_t delta_bytes); + void SimulateMobileFriendlinessUpdate( blink::MobileFriendliness& mobile_friendliness);
diff --git a/components/page_load_metrics/browser/page_load_metrics_embedder_interface.h b/components/page_load_metrics/browser/page_load_metrics_embedder_interface.h index 419a2b3..0edef50 100644 --- a/components/page_load_metrics/browser/page_load_metrics_embedder_interface.h +++ b/components/page_load_metrics/browser/page_load_metrics_embedder_interface.h
@@ -14,11 +14,13 @@ } // namespace base namespace content { +class BrowserContext; class WebContents; } // namespace content namespace page_load_metrics { +class PageLoadMetricsMemoryTracker; class PageLoadTracker; // This class serves as a functional interface to various chrome// features. @@ -31,6 +33,11 @@ virtual std::unique_ptr<base::OneShotTimer> CreateTimer() = 0; virtual bool IsPrerender(content::WebContents* web_contents) = 0; virtual bool IsExtensionUrl(const GURL& url) = 0; + + // Returns the PageLoadMetricsMemoryTracker for the given BrowserContext if + // tracking is enabled. + virtual PageLoadMetricsMemoryTracker* GetMemoryTrackerForBrowserContext( + content::BrowserContext* browser_context) = 0; }; } // namespace page_load_metrics
diff --git a/components/page_load_metrics/browser/page_load_metrics_memory_tracker.cc b/components/page_load_metrics/browser/page_load_metrics_memory_tracker.cc new file mode 100644 index 0000000..4850195 --- /dev/null +++ b/components/page_load_metrics/browser/page_load_metrics_memory_tracker.cc
@@ -0,0 +1,179 @@ +// Copyright 2021 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 "components/page_load_metrics/browser/page_load_metrics_memory_tracker.h" + +#include <map> + +#include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "components/keyed_service/content/browser_context_keyed_service_factory.h" + +namespace features { + +// Enables or disables per-frame memory monitoring. +const base::Feature kV8PerFrameMemoryMonitoring{ + "V8PerFrameMemoryMonitoring", base::FEATURE_DISABLED_BY_DEFAULT}; + +} // namespace features + +namespace page_load_metrics { + +namespace { + +// WeakPtrs cannot be used as the key to a map without a custom comparator, so +// we use a raw pointer for the map key and bundle the WeakPtr in a struct +// to be used as the value. +struct ObserverWeakPtrAndMemoryUpdates { + base::WeakPtr<MetricsWebContentsObserver> weak_ptr; + std::vector<MemoryUpdate> updates; + ObserverWeakPtrAndMemoryUpdates( + base::WeakPtr<MetricsWebContentsObserver> wk_ptr, + MemoryUpdate update) + : weak_ptr(wk_ptr) { + updates.emplace_back(update); + } +}; + +} // namespace + +// Results of the V8PerAdFrameMemoryPollParamsStudy indicated that at the +// ~99.8th percentile, collecting at 10-second or 60-second intervals +// yields nearly equivalent results, as does using kBounded or kLazy mode. +// As there is about 10% to 20% overhead total GC time, we chose the less +// aggressive kLazy mode with a 60-second polling interval. +// For further results please see crbug.com/1116087. +PageLoadMetricsMemoryTracker::PageLoadMetricsMemoryTracker() { + if (base::FeatureList::IsEnabled(features::kV8PerFrameMemoryMonitoring)) { + memory_request_ = std::make_unique< + performance_manager::v8_memory::V8DetailedMemoryRequestAnySeq>( + base::TimeDelta::FromSeconds(60), + performance_manager::v8_memory::V8DetailedMemoryRequest:: + MeasurementMode::kLazy); + memory_request_->AddObserver(this); + } +} + +PageLoadMetricsMemoryTracker::~PageLoadMetricsMemoryTracker() = default; + +void PageLoadMetricsMemoryTracker::Shutdown() { + if (memory_request_) { + memory_request_->RemoveObserver(this); + memory_request_.reset(); + } +} + +void PageLoadMetricsMemoryTracker::OnV8MemoryMeasurementAvailable( + performance_manager::RenderProcessHostId render_process_host_id, + const performance_manager::v8_memory::V8DetailedMemoryProcessData& + process_data, + const performance_manager::v8_memory::V8DetailedMemoryObserverAnySeq:: + FrameDataMap& frame_data) { + std::map<MetricsWebContentsObserver*, ObserverWeakPtrAndMemoryUpdates> + memory_update_map; + + // Iterate through frames with available measurements. + for (const auto& map_pair : frame_data) { + content::GlobalFrameRoutingId frame_routing_id = map_pair.first; + content::RenderFrameHost* rfh = + content::RenderFrameHost::FromID(frame_routing_id); + + // We lose a small amount of data due to a RenderFrameHost + // sometimes no longer being alive by the time that a report is received. + // UMA suggests we miss about 0.078% of updates on desktop and about 0.11% + // on mobile (as measured 10/30/2020). + // See crbug.com/1116087. + if (!rfh) + continue; + + int64_t delta_bytes = + UpdateMemoryUsageAndGetDelta(rfh, map_pair.second.v8_bytes_used()); + + // Only send updates that are nontrivial. + if (delta_bytes == 0) + continue; + + // Note that at this point, we are guaranteed that the frame is alive, and + // frames cannot exist without an owning WebContents. + content::WebContents* web_contents = + content::WebContents::FromRenderFrameHost(rfh); + MetricsWebContentsObserver* observer = + MetricsWebContentsObserver::FromWebContents(web_contents); + + if (!observer) + continue; + + auto emplace_pair = memory_update_map.emplace(std::make_pair( + observer, + ObserverWeakPtrAndMemoryUpdates( + observer->AsWeakPtr(), + MemoryUpdate(rfh->GetGlobalFrameRoutingId(), delta_bytes)))); + + if (!emplace_pair.second) { + emplace_pair.first->second.updates.emplace_back( + MemoryUpdate(rfh->GetGlobalFrameRoutingId(), delta_bytes)); + } + } + + // Dispatch memory updates to each observer. Note that we store references to + // MetricsWebContentsObservers as weakptrs. This is done to ensure that if a + // WebContents was torn down synchronously as the result of a memory update + // in a different WebContents, we would not have a dangling pointer. + for (const auto& map_pair : memory_update_map) { + MetricsWebContentsObserver* observer = map_pair.second.weak_ptr.get(); + + if (!observer) + continue; + + observer->OnV8MemoryChanged(map_pair.second.updates); + } +} + +void PageLoadMetricsMemoryTracker::OnFrameDeleted( + content::RenderFrameHost* render_frame_host, + MetricsWebContentsObserver* observer) { + DCHECK(render_frame_host); + DCHECK(observer); + + auto it = per_frame_memory_usage_map_.find(render_frame_host->GetRoutingID()); + + if (it == per_frame_memory_usage_map_.end()) + return; + + // The routing id for |render_frame_host| has been found in our usage map. + // We assume that the renderer has released the frame and that its + // contents will be picked up by the next GC. So for all intents and + // purposes, the memory is freed at this point, and we remove the entry from + // our usage map and notify observers of the delta. + int64_t delta_bytes = -it->second; + per_frame_memory_usage_map_.erase(it); + + // Only send updates that are nontrivial. + if (delta_bytes == 0) + return; + + std::vector<MemoryUpdate> update({MemoryUpdate( + render_frame_host->GetGlobalFrameRoutingId(), delta_bytes)}); + observer->OnV8MemoryChanged(update); +} + +int64_t PageLoadMetricsMemoryTracker::UpdateMemoryUsageAndGetDelta( + content::RenderFrameHost* render_frame_host, + uint64_t current_bytes_used) { + DCHECK(render_frame_host); + + int64_t delta_bytes = current_bytes_used; + int routing_id = render_frame_host->GetRoutingID(); + auto it = per_frame_memory_usage_map_.find(routing_id); + + if (it != per_frame_memory_usage_map_.end()) { + delta_bytes -= it->second; + it->second = current_bytes_used; + } else { + per_frame_memory_usage_map_[routing_id] = current_bytes_used; + } + + return delta_bytes; +} + +} // namespace page_load_metrics
diff --git a/components/page_load_metrics/browser/page_load_metrics_memory_tracker.h b/components/page_load_metrics/browser/page_load_metrics_memory_tracker.h new file mode 100644 index 0000000..c6c2283 --- /dev/null +++ b/components/page_load_metrics/browser/page_load_metrics_memory_tracker.h
@@ -0,0 +1,68 @@ +// Copyright 2021 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 COMPONENTS_PAGE_LOAD_METRICS_BROWSER_PAGE_LOAD_METRICS_MEMORY_TRACKER_H_ +#define COMPONENTS_PAGE_LOAD_METRICS_BROWSER_PAGE_LOAD_METRICS_MEMORY_TRACKER_H_ + +#include "base/containers/flat_map.h" +#include "base/feature_list.h" +#include "components/keyed_service/core/keyed_service.h" +#include "components/page_load_metrics/browser/metrics_web_contents_observer.h" +#include "components/performance_manager/public/v8_memory/v8_detailed_memory.h" +#include "content/public/browser/render_frame_host.h" + +namespace features { + +extern const base::Feature kV8PerFrameMemoryMonitoring; + +} // namespace features + +namespace page_load_metrics { + +// PageLoadMetricsMemoryTracker tracks per-frame memory usage by V8 and +// forwards an individual per-frame measurement to the +// MetricsWebContentsObserver associated with the WebContents containing that +// frame. +class PageLoadMetricsMemoryTracker + : public KeyedService, + public performance_manager::v8_memory::V8DetailedMemoryObserverAnySeq { + public: + PageLoadMetricsMemoryTracker(); + ~PageLoadMetricsMemoryTracker() override; + PageLoadMetricsMemoryTracker(const PageLoadMetricsMemoryTracker&) = delete; + PageLoadMetricsMemoryTracker& operator=(const PageLoadMetricsMemoryTracker&) = + delete; + + // KeyedService: + void Shutdown() override; + + // performance_manager::v8_memory::V8DetailedMemoryObserverAnySeq: + void OnV8MemoryMeasurementAvailable( + performance_manager::RenderProcessHostId render_process_host_id, + const performance_manager::v8_memory::V8DetailedMemoryProcessData& + process_data, + const performance_manager::v8_memory::V8DetailedMemoryObserverAnySeq:: + FrameDataMap& frame_data) override; + + // Removes the entry for a deleted frame from `per_frame_memory_usage_map_`. + void OnFrameDeleted(content::RenderFrameHost* render_frame_host, + MetricsWebContentsObserver* observer); + + private: + int64_t UpdateMemoryUsageAndGetDelta( + content::RenderFrameHost* render_frame_host, + uint64_t current_bytes_used); + + // Tracks the most recent per-frame measurements by frame routing id. + base::flat_map<int, uint64_t> per_frame_memory_usage_map_; + + // Allows receipt of per-frame V8 memory measurements once instantiated + // and PageLoadMetricsMemoryTracker is added as an observer. + std::unique_ptr<performance_manager::v8_memory::V8DetailedMemoryRequestAnySeq> + memory_request_; +}; + +} // namespace page_load_metrics + +#endif // COMPONENTS_PAGE_LOAD_METRICS_BROWSER_PAGE_LOAD_METRICS_MEMORY_TRACKER_H_
diff --git a/components/page_load_metrics/browser/page_load_metrics_memory_tracker_unittest.cc b/components/page_load_metrics/browser/page_load_metrics_memory_tracker_unittest.cc new file mode 100644 index 0000000..d69f9f2 --- /dev/null +++ b/components/page_load_metrics/browser/page_load_metrics_memory_tracker_unittest.cc
@@ -0,0 +1,296 @@ +// Copyright 2021 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 "components/page_load_metrics/browser/page_load_metrics_memory_tracker.h" + +#include "base/memory/singleton.h" +#include "base/test/scoped_feature_list.h" +#include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "components/keyed_service/content/browser_context_keyed_service_factory.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_test_content_browser_client.h" +#include "components/performance_manager/public/render_process_host_id.h" +#include "components/performance_manager/public/v8_memory/v8_detailed_memory.h" +#include "content/public/browser/render_process_host.h" +#include "content/public/common/content_client.h" +#include "content/public/test/navigation_simulator.h" +#include "content/public/test/test_renderer_host.h" +#include "testing/gtest/include/gtest/gtest.h" + +using V8DetailedMemoryExecutionContextData = + performance_manager::v8_memory::V8DetailedMemoryExecutionContextData; +using FrameDataMap = base::flat_map<content::GlobalFrameRoutingId, + V8DetailedMemoryExecutionContextData>; + +const char kMainUrl[] = "https://main.com/"; +const char kSubUrl[] = "https://foo.com/"; +const char kOtherSubUrl[] = "https://bar.com/"; + +namespace page_load_metrics { + +namespace { + +class TestPageLoadMetricsEmbedder + : public page_load_metrics::PageLoadMetricsEmbedderBase { + public: + explicit TestPageLoadMetricsEmbedder(content::WebContents* web_contents) + : PageLoadMetricsEmbedderBase(web_contents) {} + TestPageLoadMetricsEmbedder(const TestPageLoadMetricsEmbedder&) = delete; + TestPageLoadMetricsEmbedder& operator=(const TestPageLoadMetricsEmbedder&) = + delete; + ~TestPageLoadMetricsEmbedder() override = default; + + // page_load_metrics::PageLoadMetricsEmbedderBase: + bool IsNewTabPageUrl(const GURL& url) override { return false; } + bool IsPrerender(content::WebContents* web_contents) override { + return false; + } + bool IsExtensionUrl(const GURL& url) override { return false; } + + page_load_metrics::PageLoadMetricsMemoryTracker* + GetMemoryTrackerForBrowserContext( + content::BrowserContext* browser_context) override { + if (!base::FeatureList::IsEnabled(features::kV8PerFrameMemoryMonitoring)) + return nullptr; + + return &memory_tracker_; + } + + protected: + // page_load_metrics::PageLoadMetricsEmbedderBase: + void RegisterEmbedderObservers( + page_load_metrics::PageLoadTracker* tracker) override {} + bool IsPrerendering() const override { return false; } + + private: + page_load_metrics::PageLoadMetricsMemoryTracker memory_tracker_; +}; + +class TestMestricsWebContentsObserver : public MetricsWebContentsObserver { + public: + TestMestricsWebContentsObserver( + content::WebContents* web_contents, + std::unique_ptr<PageLoadMetricsEmbedderInterface> embedder_interface) + : MetricsWebContentsObserver(web_contents, + std::move(embedder_interface)) {} + + int num_updates_received() const { return num_updates_received_; } + + const base::flat_map<int, int64_t>& last_memory_deltas_received() const { + return last_memory_deltas_received_; + } + + void OnV8MemoryChanged( + const std::vector<MemoryUpdate>& memory_updates) override { + for (const auto& update : memory_updates) { + num_updates_received_++; + + int routing_id = update.routing_id.frame_routing_id; + auto it = last_memory_deltas_received_.find(routing_id); + if (it == last_memory_deltas_received_.end()) + last_memory_deltas_received_[routing_id] = update.delta_bytes; + else + it->second = update.delta_bytes; + } + } + + private: + base::flat_map<int, int64_t> last_memory_deltas_received_; + int num_updates_received_ = 0; +}; + +class PageLoadMetricsMemoryTrackerTest + : public content::RenderViewHostTestHarness { + public: + PageLoadMetricsMemoryTrackerTest() = default; + ~PageLoadMetricsMemoryTrackerTest() override = default; + PageLoadMetricsMemoryTrackerTest(const PageLoadMetricsMemoryTrackerTest&) = + delete; + PageLoadMetricsMemoryTrackerTest& operator=( + const PageLoadMetricsMemoryTrackerTest&) = delete; + + void SetUp() override { + scoped_feature_list_.InitAndEnableFeature( + features::kV8PerFrameMemoryMonitoring); + + content::RenderViewHostTestHarness::SetUp(); + original_browser_client_ = + content::SetBrowserClientForTesting(&browser_client_); + + auto embedder_interface = + std::make_unique<TestPageLoadMetricsEmbedder>(web_contents()); + embedder_interface_ = embedder_interface.get(); + observer_ = new TestMestricsWebContentsObserver( + web_contents(), std::move(embedder_interface)); + web_contents()->SetUserData(TestMestricsWebContentsObserver::UserDataKey(), + base::WrapUnique(observer_)); + + tracker_ = embedder_interface_->GetMemoryTrackerForBrowserContext( + browser_context()); + } + + void TearDown() override { + content::SetBrowserClientForTesting(original_browser_client_); + tracker_->Shutdown(); + content::RenderViewHostTestHarness::TearDown(); + } + + // Returns the final RenderFrameHost after navigation commits. + content::RenderFrameHost* NavigateFrame(const std::string& url, + content::RenderFrameHost* frame) { + auto navigation_simulator = + content::NavigationSimulator::CreateRendererInitiated(GURL(url), frame); + navigation_simulator->Commit(); + return navigation_simulator->GetFinalRenderFrameHost(); + } + + // Returns the final RenderFrameHost after navigation commits. + content::RenderFrameHost* NavigateMainFrame(const std::string& url) { + return NavigateFrame(url, web_contents()->GetMainFrame()); + } + + // Returns the final RenderFrameHost after navigation commits. + content::RenderFrameHost* CreateAndNavigateSubFrame( + const std::string& url, + content::RenderFrameHost* parent) { + content::RenderFrameHost* subframe = + content::RenderFrameHostTester::For(parent)->AppendChild("frame_name"); + auto navigation_simulator = + content::NavigationSimulator::CreateRendererInitiated(GURL(url), + subframe); + navigation_simulator->Commit(); + + return navigation_simulator->GetFinalRenderFrameHost(); + } + + void SimulateMemoryMeasurementUpdate( + content::RenderFrameHost* render_frame_host, + uint64_t bytes) { + if (!render_frame_host || !render_frame_host->GetProcess()) + return; + + content::GlobalFrameRoutingId global_routing_id = + render_frame_host->GetGlobalFrameRoutingId(); + int process_id = render_frame_host->GetProcess()->GetID(); + + performance_manager::RenderProcessHostId pm_process_id = + static_cast<performance_manager::RenderProcessHostId>(process_id); + performance_manager::v8_memory::V8DetailedMemoryProcessData process_data; + V8DetailedMemoryExecutionContextData frame_data; + frame_data.set_v8_bytes_used(bytes); + + FrameDataMap frame_map; + frame_map[global_routing_id] = frame_data; + + tracker_->OnV8MemoryMeasurementAvailable(pm_process_id, process_data, + frame_map); + } + + int num_updates_received() const { return observer_->num_updates_received(); } + + const base::flat_map<int, int64_t>& last_memory_deltas_received() const { + return observer_->last_memory_deltas_received(); + } + + protected: + PageLoadMetricsMemoryTracker* tracker_; + + private: + base::test::ScopedFeatureList scoped_feature_list_; + TestMestricsWebContentsObserver* observer_; + TestPageLoadMetricsEmbedder* embedder_interface_; + PageLoadMetricsTestContentBrowserClient browser_client_; + content::ContentBrowserClient* original_browser_client_ = nullptr; +}; + +} // namespace + +TEST_F(PageLoadMetricsMemoryTrackerTest, + InitialUpdatesOnly_CorrectDeltasReceived) { + content::RenderFrameHost* main_frame = NavigateMainFrame(kMainUrl); + int main_id = main_frame->GetRoutingID(); + content::RenderFrameHost* sub_frame1 = + CreateAndNavigateSubFrame(kSubUrl, main_frame); + int sub_frame1_id = sub_frame1->GetRoutingID(); + + // Create a nested subframe with the same origin as its parent. + content::RenderFrameHost* sub_frame2 = + CreateAndNavigateSubFrame(kOtherSubUrl, sub_frame1); + int sub_frame2_id = sub_frame2->GetRoutingID(); + + SimulateMemoryMeasurementUpdate(main_frame, 100 * 1024); + SimulateMemoryMeasurementUpdate(sub_frame1, 200 * 1024); + SimulateMemoryMeasurementUpdate(sub_frame2, 300 * 1024); + + auto deltas_received = last_memory_deltas_received(); + EXPECT_EQ(3, num_updates_received()); + ASSERT_EQ(3UL, deltas_received.size()); + + EXPECT_TRUE(deltas_received.find(main_id) != deltas_received.end()); + EXPECT_EQ(100L, deltas_received[main_id] / 1024); + EXPECT_TRUE(deltas_received.find(sub_frame1_id) != deltas_received.end()); + EXPECT_EQ(200L, deltas_received[sub_frame1_id] / 1024); + EXPECT_TRUE(deltas_received.find(sub_frame2_id) != deltas_received.end()); + EXPECT_EQ(300L, deltas_received[sub_frame2_id] / 1024); +} + +TEST_F(PageLoadMetricsMemoryTrackerTest, SecondUpdates_CorrectDeltasReceived) { + content::RenderFrameHost* main_frame = NavigateMainFrame(kMainUrl); + int main_id = main_frame->GetRoutingID(); + content::RenderFrameHost* sub_frame1 = + CreateAndNavigateSubFrame(kSubUrl, main_frame); + int sub_frame1_id = sub_frame1->GetRoutingID(); + + // Create a nested subframe with the same origin as its parent. + content::RenderFrameHost* sub_frame2 = + CreateAndNavigateSubFrame(kOtherSubUrl, sub_frame1); + int sub_frame2_id = sub_frame2->GetRoutingID(); + + SimulateMemoryMeasurementUpdate(main_frame, 100 * 1024); + SimulateMemoryMeasurementUpdate(sub_frame1, 200 * 1024); + SimulateMemoryMeasurementUpdate(sub_frame2, 300 * 1024); + + // Simulate second round of updates. + SimulateMemoryMeasurementUpdate(main_frame, 50 * 1024); + SimulateMemoryMeasurementUpdate(sub_frame1, 300 * 1024); + SimulateMemoryMeasurementUpdate(sub_frame2, 100 * 1024); + + auto deltas_received = last_memory_deltas_received(); + EXPECT_EQ(6, num_updates_received()); + ASSERT_EQ(3UL, deltas_received.size()); + + EXPECT_TRUE(deltas_received.find(main_id) != deltas_received.end()); + EXPECT_EQ(-50L, deltas_received[main_id] / 1024); + EXPECT_TRUE(deltas_received.find(sub_frame1_id) != deltas_received.end()); + EXPECT_EQ(100L, deltas_received[sub_frame1_id] / 1024); + EXPECT_TRUE(deltas_received.find(sub_frame2_id) != deltas_received.end()); + EXPECT_EQ(-200L, deltas_received[sub_frame2_id] / 1024); +} + +TEST_F(PageLoadMetricsMemoryTrackerTest, FrameDeleted_CorrectDeltasReceived) { + content::RenderFrameHost* main_frame = NavigateMainFrame(kMainUrl); + int main_id = main_frame->GetRoutingID(); + content::RenderFrameHost* sub_frame = + CreateAndNavigateSubFrame(kSubUrl, main_frame); + int sub_frame_id = sub_frame->GetRoutingID(); + + SimulateMemoryMeasurementUpdate(main_frame, 100 * 1024); + SimulateMemoryMeasurementUpdate(sub_frame, 200 * 1024); + + // Delete |sub_frame| and refresh the usage map. An update should have been + // received that will make the usage corresponding to |sub_frame| zero. + content::RenderFrameHostTester::For(sub_frame)->Detach(); + + auto deltas_received = last_memory_deltas_received(); + EXPECT_EQ(3, num_updates_received()); + ASSERT_EQ(2UL, deltas_received.size()); + + EXPECT_TRUE(deltas_received.find(main_id) != deltas_received.end()); + EXPECT_EQ(100L, deltas_received[main_id] / 1024); + EXPECT_TRUE(deltas_received.find(sub_frame_id) != deltas_received.end()); + EXPECT_EQ(-200L, deltas_received[sub_frame_id] / 1024); +} + +} // namespace page_load_metrics
diff --git a/components/page_load_metrics/browser/page_load_metrics_observer.cc b/components/page_load_metrics/browser/page_load_metrics_observer.cc index 148a3b4..c2b2fe38 100644 --- a/components/page_load_metrics/browser/page_load_metrics_observer.cc +++ b/components/page_load_metrics/browser/page_load_metrics_observer.cc
@@ -8,6 +8,9 @@ namespace page_load_metrics { +MemoryUpdate::MemoryUpdate(content::GlobalFrameRoutingId id, int64_t delta) + : routing_id(id), delta_bytes(delta) {} + ExtraRequestCompleteInfo::ExtraRequestCompleteInfo( const url::Origin& origin_of_final_url, const net::IPEndPoint& remote_endpoint,
diff --git a/components/page_load_metrics/browser/page_load_metrics_observer.h b/components/page_load_metrics/browser/page_load_metrics_observer.h index 3e30bea..2c9a5ff 100644 --- a/components/page_load_metrics/browser/page_load_metrics_observer.h +++ b/components/page_load_metrics/browser/page_load_metrics_observer.h
@@ -30,6 +30,13 @@ namespace page_load_metrics { +// Struct for storing per-frame memory update data. +struct MemoryUpdate { + content::GlobalFrameRoutingId routing_id; + int64_t delta_bytes; + MemoryUpdate(content::GlobalFrameRoutingId id, int64_t delta); +}; + // Storage types reported to page load metrics observers on storage // accesses. enum class StorageType { @@ -544,6 +551,12 @@ // portal. virtual void DidActivatePortal(base::TimeTicks activation_time) {} + // Called when V8 per-frame memory usage updates are available. Each + // MemoryUpdate consists of a GlobalFrameRoutingId and a nonzero int64_t + // change in bytes used. + virtual void OnV8MemoryChanged( + const std::vector<MemoryUpdate>& memory_updates) {} + private: PageLoadMetricsObserverDelegate* delegate_ = nullptr; };
diff --git a/components/page_load_metrics/browser/page_load_tracker.cc b/components/page_load_metrics/browser/page_load_tracker.cc index 231e4ae..3f2d908 100644 --- a/components/page_load_metrics/browser/page_load_tracker.cc +++ b/components/page_load_metrics/browser/page_load_tracker.cc
@@ -15,6 +15,7 @@ #include "base/time/default_tick_clock.h" #include "base/trace_event/trace_event.h" #include "components/page_load_metrics/browser/page_load_metrics_embedder_interface.h" +#include "components/page_load_metrics/browser/page_load_metrics_memory_tracker.h" #include "components/page_load_metrics/browser/page_load_metrics_observer.h" #include "components/page_load_metrics/browser/page_load_metrics_util.h" #include "components/page_load_metrics/common/page_load_timing.h" @@ -490,6 +491,8 @@ } void PageLoadTracker::FlushMetricsOnAppEnterBackground() { + metrics_update_dispatcher()->FlushPendingTimingUpdates(); + if (!app_entered_background_) { RecordAppBackgroundPageLoadCompleted(false); app_entered_background_ = true; @@ -988,4 +991,10 @@ } } +void PageLoadTracker::OnV8MemoryChanged( + const std::vector<MemoryUpdate>& memory_updates) { + for (const auto& observer : observers_) + observer->OnV8MemoryChanged(memory_updates); +} + } // namespace page_load_metrics
diff --git a/components/page_load_metrics/browser/page_load_tracker.h b/components/page_load_metrics/browser/page_load_tracker.h index eb043f4..c48fcf0 100644 --- a/components/page_load_metrics/browser/page_load_tracker.h +++ b/components/page_load_metrics/browser/page_load_tracker.h
@@ -40,6 +40,7 @@ namespace page_load_metrics { +struct MemoryUpdate; class PageLoadMetricsEmbedderInterface; namespace internal { @@ -374,6 +375,9 @@ // portal. void DidActivatePortal(base::TimeTicks activation_time); + // Called when V8 per-frame memory usage updates are available. + void OnV8MemoryChanged(const std::vector<MemoryUpdate>& memory_updates); + private: // This function converts a TimeTicks value taken in the browser process // to navigation_start_ if:
diff --git a/components/page_load_metrics/browser/test_metrics_web_contents_observer_embedder.cc b/components/page_load_metrics/browser/test_metrics_web_contents_observer_embedder.cc index 4dfdd9ff6..26c6571 100644 --- a/components/page_load_metrics/browser/test_metrics_web_contents_observer_embedder.cc +++ b/components/page_load_metrics/browser/test_metrics_web_contents_observer_embedder.cc
@@ -179,4 +179,10 @@ return false; } +PageLoadMetricsMemoryTracker* +TestMetricsWebContentsObserverEmbedder::GetMemoryTrackerForBrowserContext( + content::BrowserContext* browser_context) { + return nullptr; +} + } // namespace page_load_metrics
diff --git a/components/page_load_metrics/browser/test_metrics_web_contents_observer_embedder.h b/components/page_load_metrics/browser/test_metrics_web_contents_observer_embedder.h index 6579c5c..ee48b812 100644 --- a/components/page_load_metrics/browser/test_metrics_web_contents_observer_embedder.h +++ b/components/page_load_metrics/browser/test_metrics_web_contents_observer_embedder.h
@@ -16,6 +16,8 @@ namespace page_load_metrics { +class PageLoadMetricsMemoryTracker; + class TestMetricsWebContentsObserverEmbedder : public PageLoadMetricsEmbedderInterface, public test::WeakMockTimerProvider { @@ -29,6 +31,8 @@ std::unique_ptr<base::OneShotTimer> CreateTimer() override; bool IsPrerender(content::WebContents* web_contents) override; bool IsExtensionUrl(const GURL& url) override; + PageLoadMetricsMemoryTracker* GetMemoryTrackerForBrowserContext( + content::BrowserContext* browser_context) override; void set_is_ntp(bool is_ntp) { is_ntp_ = is_ntp; }
diff --git a/components/password_manager/core/common/password_manager_features.cc b/components/password_manager/core/common/password_manager_features.cc index 882ad03d..d92e0378 100644 --- a/components/password_manager/core/common/password_manager_features.cc +++ b/components/password_manager/core/common/password_manager_features.cc
@@ -110,11 +110,11 @@ // dynamic form change. const base::Feature kReparseServerPredictionsFollowingFormChange = { "ReparseServerPredictionsFollowingFormChange", - base::FEATURE_DISABLED_BY_DEFAULT}; + base::FEATURE_ENABLED_BY_DEFAULT}; // Enables considering secondary server field predictions during form parsing. const base::Feature kSecondaryServerFieldPredictions = { - "SecondaryServerFieldPredictions", base::FEATURE_DISABLED_BY_DEFAULT}; + "SecondaryServerFieldPredictions", base::FEATURE_ENABLED_BY_DEFAULT}; // Enables syncing of compromised credentials. const base::Feature kSyncingCompromisedCredentials = {
diff --git a/components/performance_manager/v8_memory/v8_memory_test_helpers.cc b/components/performance_manager/v8_memory/v8_memory_test_helpers.cc index eed1019..d2708f4 100644 --- a/components/performance_manager/v8_memory/v8_memory_test_helpers.cc +++ b/components/performance_manager/v8_memory/v8_memory_test_helpers.cc
@@ -166,6 +166,7 @@ // Use MOCK_TIME so that ExpectQueryAndDelayReply can be used. base::test::TaskEnvironment::TimeSource::MOCK_TIME) { GetGraphFeaturesHelper().EnableExecutionContextRegistry(); + GetGraphFeaturesHelper().EnableV8ContextTracker(); } V8MemoryPerformanceManagerTestHarness::
diff --git a/components/performance_manager/v8_memory/web_memory_aggregator.cc b/components/performance_manager/v8_memory/web_memory_aggregator.cc index f4064ff..fc8cfa49 100644 --- a/components/performance_manager/v8_memory/web_memory_aggregator.cc +++ b/components/performance_manager/v8_memory/web_memory_aggregator.cc
@@ -28,10 +28,13 @@ // TODO(joenotcharles): If we ever need to aggregate different data for each // aggregation point, turn this into an interface and add a subclass for each // type of data to aggregate. -class WebMemoryAggregator::AggregationPointVisitor { +class AggregationPointVisitor { public: - AggregationPointVisitor(const FrameNode* aggregation_start_node, - const url::Origin& requesting_origin); + // The given |main_origin| is the origin of the main web page, which is the + // same as the origin of the top-level frames. + AggregationPointVisitor(const url::Origin& requesting_origin, + const ProcessNode* requesting_process_node, + const url::Origin& main_origin); ~AggregationPointVisitor(); @@ -42,39 +45,81 @@ mojom::WebMemoryMeasurementPtr TakeAggregationResult(); // Called on first visiting |frame_node| in a depth-first traversal. - // |aggregation_type| specificies how to treat the node in the aggregation. - void OnFrameEntered(const FrameNode* frame_node, - NodeAggregationType aggregation_type); + void OnFrameEntered(const FrameNode* frame_node); // Called after visiting |frame_node| and all its children in a depth-first // traversal. void OnFrameExited(const FrameNode* frame_node); // Called on first visiting |worker_node| in a depth-first traversal. - // |aggregation_type| specificies how to treat the node in the aggregation. - void OnWorkerEntered(const WorkerNode* worker_node, - NodeAggregationType aggregation_type); + void OnWorkerEntered(const WorkerNode* worker_node); // Called after visiting |worker_node| and all its children in a depth-first // traversal. void OnWorkerExited(const WorkerNode* worker_node); + // Called at the start of the depth-first traversal to set up the common + // root node for all frame trees. + void OnRootEntered(); + + // Called at the end of the traversal. + void OnRootExited(); + private: - const FrameNode* aggregation_start_node_; + struct Enclosing { + url::Origin origin; + mojom::WebMemoryBreakdownEntry* aggregation_point; + }; const url::Origin requesting_origin_; + const ProcessNode* requesting_process_node_; + const url::Origin main_origin_; mojom::WebMemoryMeasurementPtr aggregation_result_ = mojom::WebMemoryMeasurement::New(); - base::stack<mojom::WebMemoryBreakdownEntry*> enclosing_aggregation_points_; + mojom::WebMemoryBreakdownEntryPtr root_aggregation_point_; + base::stack<Enclosing> enclosing_; }; namespace { using AttributionScope = mojom::WebMemoryAttribution::Scope; -// Returns true if |page_node| has an opener that should be followed by the -// aggregation algorithm. -bool ShouldFollowOpenerLink(const PageNode* page_node) { - return page_node->GetOpenedType() == PageNode::OpenedType::kPopup; +// The various ways a node can be treated during the aggregation. +enum class NodeAggregationType { + // Node is same-origin to |requesting_node| and its iframe attributes are + // visible; + // will be a new aggregation point with a scope depending on the node type + // (eg. "Window" or "DedicatedWorker"). + kSameOriginAggregationPoint, + // Node is same-origin to |requesting_node| but its iframe attributes are not + // visible; + // will be a new aggregation point with a scope depending on the node type + // (eg. "Window" or "DedicatedWorker"). + kSameOriginAggregationPointWithHiddenAttributes, + // Node is cross-origin with |requesting_node| but its parent is not; will + // be a new aggregation point with scope "cross-origin-aggregated". + kCrossOriginAggregationPoint, + // Node is cross-origin with |requesting_node| and so is its parent; will + // be aggregated into its parent's aggregation point. + kCrossOriginAggregated, +}; + +NodeAggregationType GetNodeAggregationType(const url::Origin& requesting_origin, + const url::Origin& enclosing_origin, + const url::Origin& node_origin) { + bool same_origin_node = requesting_origin.IsSameOriginWith(node_origin); + bool same_origin_parent = + requesting_origin.IsSameOriginWith(enclosing_origin); + + if (same_origin_node) { + return same_origin_parent + ? NodeAggregationType::kSameOriginAggregationPoint + : NodeAggregationType:: + kSameOriginAggregationPointWithHiddenAttributes; + } else { + return same_origin_parent + ? NodeAggregationType::kCrossOriginAggregationPoint + : NodeAggregationType::kCrossOriginAggregated; + } } // Returns |frame_node|'s origin based on its current url. @@ -97,20 +142,6 @@ } #endif -// Returns the parent of |frame_node|, the opener if it has no parent, or -// nullptr if it has neither. -const FrameNode* GetParentOrOpener(const FrameNode* frame_node) { - // Only the main frame of a page should have an opener. So first check if - // there's a parent and, if not, check if there's an opener. - if (auto* parent = frame_node->GetParentFrameNode()) - return parent; - auto* page_node = frame_node->GetPageNode(); - DCHECK(page_node); - if (ShouldFollowOpenerLink(page_node)) - return page_node->GetOpenerFrameNode(); - return nullptr; -} - // Returns a mutable pointer to the WebMemoryAttribution structure in the given // |breakdown|. mojom::WebMemoryAttribution* GetAttributionFromBreakdown( @@ -162,83 +193,117 @@ aggregation_point->memory->bytes += bytes_used; } +const FrameNode* GetTopFrame(const FrameNode* frame) { + DCHECK(frame); + // Follow the parent to find the top-most frame. + auto* current = frame; + while (auto* parent = current->GetParentFrameNode()) { + current = parent; + } + + DCHECK(current); + // Make sure we didn't break out of the browsing context group. + DCHECK_EQ(current->GetBrowsingInstanceId(), frame->GetBrowsingInstanceId()); + return current; +} + +// Returns the process node of the main frame that is in the same browsing +// context group as the given frame. +const ProcessNode* GetMainProcess(const FrameNode* frame) { + // COOP guarantees that the top-most frame of the current frame tree + // and the main frame of the page have the same origin and thus have + // the same process node. + return GetTopFrame(frame)->GetProcessNode(); +} + } // anonymous namespace //////////////////////////////////////////////////////////////////////////////// // AggregationPointVisitor -WebMemoryAggregator::AggregationPointVisitor::AggregationPointVisitor( - const FrameNode* aggregation_start_node, - const url::Origin& requesting_origin) - : aggregation_start_node_(aggregation_start_node), - requesting_origin_(requesting_origin) {} +AggregationPointVisitor::AggregationPointVisitor( + const url::Origin& requesting_origin, + const ProcessNode* requesting_process_node, + const url::Origin& main_origin) + : requesting_origin_(requesting_origin), + requesting_process_node_(requesting_process_node), + main_origin_(main_origin) {} -WebMemoryAggregator::AggregationPointVisitor::~AggregationPointVisitor() = - default; +AggregationPointVisitor::~AggregationPointVisitor() { + DCHECK(enclosing_.empty()); +} mojom::WebMemoryMeasurementPtr -WebMemoryAggregator::AggregationPointVisitor::TakeAggregationResult() { +AggregationPointVisitor::TakeAggregationResult() { DCHECK(aggregation_result_); auto result = std::move(aggregation_result_); aggregation_result_ = nullptr; return result; } -void WebMemoryAggregator::AggregationPointVisitor::OnFrameEntered( - const FrameNode* frame_node, - NodeAggregationType aggregation_type) { +void AggregationPointVisitor::OnRootEntered() { + DCHECK(enclosing_.empty()); + root_aggregation_point_ = mojom::WebMemoryBreakdownEntry::New(); + root_aggregation_point_->attribution.emplace_back( + mojom::WebMemoryAttribution::New()); + enclosing_.push(Enclosing{main_origin_, root_aggregation_point_.get()}); +} + +void AggregationPointVisitor::OnRootExited() { + if (root_aggregation_point_->memory) { + aggregation_result_->breakdown.push_back( + std::move(root_aggregation_point_)); + } + enclosing_.pop(); + DCHECK(enclosing_.empty()); +} + +void AggregationPointVisitor::OnFrameEntered(const FrameNode* frame_node) { + DCHECK(!enclosing_.empty()); DCHECK(frame_node); - DCHECK_EQ(enclosing_aggregation_points_.empty(), - frame_node == aggregation_start_node_); + url::Origin node_origin = GetOrigin(frame_node); + NodeAggregationType aggregation_type = GetNodeAggregationType( + requesting_origin_, enclosing_.top().origin, node_origin); mojom::WebMemoryBreakdownEntry* aggregation_point = nullptr; switch (aggregation_type) { - case NodeAggregationType::kInvisible: - NOTREACHED(); - return; - case NodeAggregationType::kSameOriginAggregationPoint: - // Create a new aggregation point with window scope. Since this node is - // same-origin to the start node, the start node can view its current - // url. - aggregation_point = CreateBreakdownEntry(AttributionScope::kWindow, - frame_node->GetURL().spec(), - aggregation_result_.get()); - if (frame_node->IsMainFrame() || frame_node == aggregation_start_node_) { - // There should be no id or src attribute since there is no visible - // parent to take them from. Do nothing. - } else if (GetSameOriginParentOrOpener(frame_node, requesting_origin_)) { - // The parent or opener is also same-origin so the start node can view - // its attributes. Add the id and src recorded for the node in - // V8ContextTracker to the new breakdown entry. - SetBreakdownAttributionFromFrame(frame_node, aggregation_point); - } else { - // Some grandparent node is the most recent aggregation point whose - // attributes are visible to the start node, and - // |enclosing_aggregation_point| includes those attributes. Copy the - // id and src attributes from there. - CopyBreakdownAttribution(enclosing_aggregation_points_.top(), - aggregation_point); - } + aggregation_point = WebMemoryAggregator::CreateBreakdownEntry( + AttributionScope::kWindow, frame_node->GetURL().spec(), + aggregation_result_.get()); + WebMemoryAggregator::SetBreakdownAttributionFromFrame(frame_node, + aggregation_point); break; + case NodeAggregationType::kSameOriginAggregationPointWithHiddenAttributes: + aggregation_point = WebMemoryAggregator::CreateBreakdownEntry( + AttributionScope::kWindow, frame_node->GetURL().spec(), + aggregation_result_.get()); + // Some grandparent node is the most recent aggregation point whose + // attributes are visible to the start node, and + // |enclosing_aggregation_point| includes those attributes. Copy the + // id and src attributes from there. + WebMemoryAggregator::CopyBreakdownAttribution( + enclosing_.top().aggregation_point, aggregation_point); + break; case NodeAggregationType::kCrossOriginAggregationPoint: // Create a new aggregation point with cross-origin-aggregated scope. // Since this node is NOT same-origin to the start node, the start node // CANNOT view its current url. - aggregation_point = - CreateBreakdownEntry(AttributionScope::kCrossOriginAggregated, - base::nullopt, aggregation_result_.get()); + aggregation_point = WebMemoryAggregator::CreateBreakdownEntry( + AttributionScope::kCrossOriginAggregated, base::nullopt, + aggregation_result_.get()); // This is cross-origin but not being aggregated into another // aggregation point, so its parent or opener must be same-origin to the // start node, which can therefore view its attributes. Add the id and // src recorded for the node in V8ContextTracker to the new breakdown // entry. - SetBreakdownAttributionFromFrame(frame_node, aggregation_point); + WebMemoryAggregator::SetBreakdownAttributionFromFrame(frame_node, + aggregation_point); break; case NodeAggregationType::kCrossOriginAggregated: // Update the enclosing aggregation point in-place. - aggregation_point = enclosing_aggregation_points_.top(); + aggregation_point = enclosing_.top().aggregation_point; break; } @@ -246,46 +311,65 @@ DCHECK(aggregation_point); AddMemoryBytes(aggregation_point, V8DetailedMemoryExecutionContextData::ForFrameNode(frame_node), - frame_node->GetProcessNode() == - aggregation_start_node_->GetProcessNode()); + frame_node->GetProcessNode() == requesting_process_node_); - enclosing_aggregation_points_.push(aggregation_point); + enclosing_.push(Enclosing{node_origin, aggregation_point}); } -void WebMemoryAggregator::AggregationPointVisitor::OnFrameExited( - const FrameNode* frame_node) { - DCHECK(!enclosing_aggregation_points_.empty()); - enclosing_aggregation_points_.pop(); +void AggregationPointVisitor::OnFrameExited(const FrameNode* frame_node) { + enclosing_.pop(); + DCHECK(!enclosing_.empty()); } -void WebMemoryAggregator::AggregationPointVisitor::OnWorkerEntered( - const WorkerNode* worker_node, - NodeAggregationType aggregation_type) { +void AggregationPointVisitor::OnWorkerEntered(const WorkerNode* worker_node) { + DCHECK(!enclosing_.empty()); DCHECK(worker_node); - - // Aggregation starts from a frame node, so the enclosing aggregation point - // is guaranteed to exist. - DCHECK(!enclosing_aggregation_points_.empty()); + // TODO(crbug.com/1169168): Support service and shared workers. + DCHECK_EQ(worker_node->GetWorkerType(), WorkerNode::WorkerType::kDedicated); + // A dedicated worker is guaranteed to have the same origin as its parent, + // which means that a dedicated worker cannot be a cross-origin aggregation + // point. + // TODO(crbug.com/1169178): The URL of a worker node is currently not + // available without PlzDedicatedWorker, which is disabled by default. + // Until then we use the origin of the parent. + url::Origin node_origin = enclosing_.top().origin; +#if DCHECK_IS_ON() + auto client_frames = worker_node->GetClientFrames(); + DCHECK(std::all_of(client_frames.begin(), client_frames.end(), + [node_origin](const FrameNode* client) { + return node_origin.IsSameOriginWith(GetOrigin(client)); + })); + auto client_workers = worker_node->GetClientWorkers(); + DCHECK(std::all_of(client_workers.begin(), client_workers.end(), + [node_origin](const WorkerNode* client) { + // TODO(crbug.com/1169178): Remove the is_empty guard + // once worker worker URLs are available. + return client->GetURL().is_empty() || + node_origin.IsSameOriginWith(GetOrigin(client)); + })); +#endif + NodeAggregationType aggregation_type = GetNodeAggregationType( + requesting_origin_, enclosing_.top().origin, node_origin); mojom::WebMemoryBreakdownEntry* aggregation_point = nullptr; switch (aggregation_type) { case NodeAggregationType::kSameOriginAggregationPoint: + case NodeAggregationType::kSameOriginAggregationPointWithHiddenAttributes: // Create a new aggregation point with window scope. Since this node is // same-origin to the start node, the start node can view its current // url. - aggregation_point = CreateBreakdownEntry( + aggregation_point = WebMemoryAggregator::CreateBreakdownEntry( AttributionScopeFromWorkerType(worker_node->GetWorkerType()), worker_node->GetURL().spec(), aggregation_result_.get()); - CopyBreakdownAttribution(enclosing_aggregation_points_.top(), - aggregation_point); + WebMemoryAggregator::CopyBreakdownAttribution( + enclosing_.top().aggregation_point, aggregation_point); break; case NodeAggregationType::kCrossOriginAggregated: // Update the enclosing aggregation point in-place. - aggregation_point = enclosing_aggregation_points_.top(); + aggregation_point = enclosing_.top().aggregation_point; break; - case NodeAggregationType::kInvisible: case NodeAggregationType::kCrossOriginAggregationPoint: NOTREACHED(); return; @@ -296,16 +380,14 @@ AddMemoryBytes( aggregation_point, V8DetailedMemoryExecutionContextData::ForWorkerNode(worker_node), - worker_node->GetProcessNode() == - aggregation_start_node_->GetProcessNode()); + worker_node->GetProcessNode() == requesting_process_node_); - enclosing_aggregation_points_.push(aggregation_point); + enclosing_.push(Enclosing{node_origin, aggregation_point}); } -void WebMemoryAggregator::AggregationPointVisitor::OnWorkerExited( - const WorkerNode* worker_node) { - DCHECK(!enclosing_aggregation_points_.empty()); - enclosing_aggregation_points_.pop(); +void AggregationPointVisitor::OnWorkerExited(const WorkerNode* worker_node) { + enclosing_.pop(); + DCHECK(!enclosing_.empty()); } //////////////////////////////////////////////////////////////////////////////// @@ -313,23 +395,46 @@ WebMemoryAggregator::WebMemoryAggregator(const FrameNode* requesting_node) : requesting_origin_(GetOrigin(requesting_node)), - aggregation_start_node_(FindAggregationStartNode(requesting_node)) { - DCHECK(aggregation_start_node_); -} + requesting_process_node_(requesting_node->GetProcessNode()), + main_process_node_(GetMainProcess(requesting_node)), + browsing_instance_id_(requesting_node->GetBrowsingInstanceId()) {} WebMemoryAggregator::~WebMemoryAggregator() = default; mojom::WebMemoryMeasurementPtr WebMemoryAggregator::AggregateMeasureMemoryResult() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - AggregationPointVisitor ap_visitor(aggregation_start_node_, - requesting_origin_); - VisitFrame(&ap_visitor, aggregation_start_node_); + std::vector<const FrameNode*> top_frames; + main_process_node_->VisitFrameNodes(base::BindRepeating( + [](std::vector<const FrameNode*>* top_frames, + int32_t browsing_instance_id, const FrameNode* node) { + if (node->GetBrowsingInstanceId() == browsing_instance_id && + !node->GetParentFrameNode() && !GetOrigin(node).opaque()) { + top_frames->push_back(node); + } + return true; + }, + &top_frames, browsing_instance_id_)); + + CHECK(!top_frames.empty()); + url::Origin main_origin = GetOrigin(top_frames[0]); + DCHECK(std::all_of(top_frames.begin(), top_frames.end(), + [&main_origin](const FrameNode* node) { + return GetOrigin(node).IsSameOriginWith(main_origin); + })); + + AggregationPointVisitor ap_visitor(requesting_origin_, + requesting_process_node_, main_origin); + ap_visitor.OnRootEntered(); + for (const FrameNode* node : top_frames) { + VisitFrame(&ap_visitor, node); + } + ap_visitor.OnRootExited(); mojom::WebMemoryMeasurementPtr aggregation_result = ap_visitor.TakeAggregationResult(); - auto* process_data = V8DetailedMemoryProcessData::ForProcessNode( - aggregation_start_node_->GetProcessNode()); + auto* process_data = + V8DetailedMemoryProcessData::ForProcessNode(requesting_process_node_); if (process_data) { aggregation_result->detached_memory = mojom::WebMemoryUsage::New(); aggregation_result->detached_memory->bytes = @@ -338,130 +443,21 @@ aggregation_result->shared_memory->bytes = process_data->shared_v8_bytes_used(); } - return aggregation_result; } -WebMemoryAggregator::NodeAggregationType -WebMemoryAggregator::FindNodeAggregationType(const FrameNode* frame_node) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - -#if DCHECK_IS_ON() - auto* node = frame_node; - while (node && node != aggregation_start_node_) { - node = GetParentOrOpener(node); - } - // Should have broken out of the loop by reaching the start node, not nullptr. - DCHECK_EQ(node, aggregation_start_node_); -#endif - - // If |frame_node| is in a different browsing context group from |start_node| - // it should be invisible. - if (frame_node->GetBrowsingInstanceId() != - aggregation_start_node_->GetBrowsingInstanceId()) { - return NodeAggregationType::kInvisible; - } - - auto frame_origin = GetOrigin(frame_node); - - // If |frame_node| is same-origin to |start_node|, it's an aggregation point. - // (This trivially includes the |start_node| itself.) - if (requesting_origin_.IsSameOriginWith(frame_origin)) - return NodeAggregationType::kSameOriginAggregationPoint; - DCHECK_NE(frame_node, aggregation_start_node_); - - // If |frame_node| is cross-origin from |start_node|, but is a direct child of - // a same-origin node, its existence is visible to |start_node| so it's an - // aggregation point. But its current url will be hidden from |start_node|. - const FrameNode* parent_node = frame_node->GetParentFrameNode(); - - if (!parent_node) { - // A cross-origin window opened via window.open gets its own browsing - // context group due to COOP. However, while the window is being loaded it - // belongs to the old browsing context group. In that case the origin is - // opaque. - DCHECK(frame_origin.opaque()); - return NodeAggregationType::kInvisible; - } - - auto parent_origin = GetOrigin(parent_node); - if (requesting_origin_.IsSameOriginWith(parent_origin)) { - return NodeAggregationType::kCrossOriginAggregationPoint; - } - - // Otherwise |frame_node|'s memory should be aggregated into the last - // aggregation point. - return NodeAggregationType::kCrossOriginAggregated; -} - -WebMemoryAggregator::NodeAggregationType -WebMemoryAggregator::FindNodeAggregationType(const WorkerNode* worker_node, - NodeAggregationType parent_type) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - // TODO(crbug.com/1169168): Support service and shared workers. - DCHECK_EQ(worker_node->GetWorkerType(), WorkerNode::WorkerType::kDedicated); - // A dedicated worker is guaranteed to have the same origin as its parent, - // which means that a dedicated worker cannot be a cross-origin aggregation - // point. -#if DCHECK_IS_ON() - // TODO(crbug.com/1169178): The URL of a worker node is currently not - // available without PlzDedicatedWorker, which is disabled by default. Remove - // this guard once the URL is properly propagated to PM. - if (!worker_node->GetURL().is_empty()) { - auto worker_origin = GetOrigin(worker_node); - auto client_frames = worker_node->GetClientFrames(); - DCHECK(std::all_of(client_frames.begin(), client_frames.end(), - [worker_origin](const FrameNode* client) { - return worker_origin.IsSameOriginWith( - GetOrigin(client)); - })); - auto client_workers = worker_node->GetClientWorkers(); - DCHECK(std::all_of(client_workers.begin(), client_workers.end(), - [worker_origin](const WorkerNode* client) { - return worker_origin.IsSameOriginWith( - GetOrigin(client)); - })); - } -#endif - switch (parent_type) { - case NodeAggregationType::kCrossOriginAggregationPoint: - return NodeAggregationType::kCrossOriginAggregated; - case NodeAggregationType::kCrossOriginAggregated: - case NodeAggregationType::kSameOriginAggregationPoint: - return parent_type; - case NodeAggregationType::kInvisible: - // Visitation stops at an invisible node and does not enter its children. - NOTREACHED(); - return NodeAggregationType::kInvisible; - } -} - bool WebMemoryAggregator::VisitFrame(AggregationPointVisitor* ap_visitor, const FrameNode* frame_node) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(frame_node); - - // An aggregation point is a node in the graph that holds a memory breakdown - // covering itself and any descendant nodes that are aggregated into the same - // breakdown. It is represented directly by the WebMemoryBreakdownEntry - // object the describes the breakdown since there is no extra information to - // store about the aggregation point. - auto aggregation_type = FindNodeAggregationType(frame_node); - if (aggregation_type == NodeAggregationType::kInvisible) { - // Ignore this node, continue iterating its siblings. + if (frame_node->GetBrowsingInstanceId() != browsing_instance_id_) { + // Ignore frames from other browsing contexts. return true; } + ap_visitor->OnFrameEntered(frame_node); - ap_visitor->OnFrameEntered(frame_node, aggregation_type); - - // Recurse into children and opened pages. Unretained is safe because the - // Visit* functions are synchronous. - frame_node->VisitOpenedPageNodes( - base::BindRepeating(&WebMemoryAggregator::VisitOpenedPage, - base::Unretained(this), ap_visitor)); frame_node->VisitChildDedicatedWorkers(base::BindRepeating( - &WebMemoryAggregator::VisitWorker, base::Unretained(this), ap_visitor, - aggregation_type)); + &WebMemoryAggregator::VisitWorker, base::Unretained(this), ap_visitor)); frame_node->VisitChildFrameNodes(base::BindRepeating( &WebMemoryAggregator::VisitFrame, base::Unretained(this), ap_visitor)); @@ -470,85 +466,22 @@ return true; } -bool WebMemoryAggregator::VisitWorker( - AggregationPointVisitor* ap_visitor, - NodeAggregationType parent_aggregation_type, - const WorkerNode* worker_node) { +bool WebMemoryAggregator::VisitWorker(AggregationPointVisitor* ap_visitor, + const WorkerNode* worker_node) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // TODO(crbug.com/1169168): Support service and shared workers. DCHECK_EQ(worker_node->GetWorkerType(), WorkerNode::WorkerType::kDedicated); - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - NodeAggregationType aggregation_type = - FindNodeAggregationType(worker_node, parent_aggregation_type); - if (aggregation_type == NodeAggregationType::kInvisible) { - // Ignore this node, continue iterating its siblings. - return true; - } - - ap_visitor->OnWorkerEntered(worker_node, aggregation_type); + ap_visitor->OnWorkerEntered(worker_node); worker_node->VisitChildDedicatedWorkers(base::BindRepeating( - &WebMemoryAggregator::VisitWorker, base::Unretained(this), ap_visitor, - aggregation_type)); + &WebMemoryAggregator::VisitWorker, base::Unretained(this), ap_visitor)); ap_visitor->OnWorkerExited(worker_node); return true; } -bool WebMemoryAggregator::VisitOpenedPage(AggregationPointVisitor* ap_visitor, - const PageNode* page_node) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (ShouldFollowOpenerLink(page_node)) { - // Visit only the "current" main frame instead of all of the main frames - // (non-current ones are either about to die, or represent an ongoing - // navigation). - return VisitFrame(ap_visitor, page_node->GetMainFrameNode()); - } - return true; -} - -// static -const FrameNode* WebMemoryAggregator::GetSameOriginParentOrOpener( - const FrameNode* frame_node, - const url::Origin& origin) { - if (auto* parent_or_opener = GetParentOrOpener(frame_node)) { - if (origin.IsSameOriginWith(GetOrigin(parent_or_opener))) - return parent_or_opener; - } - return nullptr; -} - -// static -const FrameNode* WebMemoryAggregator::FindAggregationStartNode( - const FrameNode* requesting_node) { - DCHECK(requesting_node); - auto requesting_origin = GetOrigin(requesting_node); - DCHECK(!requesting_origin.opaque()); - - // Follow parent and opener links to find the most general same-site node to - // start the aggregation traversal from. - const FrameNode* start_node = nullptr; - for (auto* parent_or_opener = requesting_node; parent_or_opener; - parent_or_opener = - GetSameOriginParentOrOpener(parent_or_opener, requesting_origin)) { - // Only consider nodes in the same process as potential start nodes. - // (https://github.com/WICG/performance-measure-memory/issues/20). - if (parent_or_opener->GetProcessNode() == - requesting_node->GetProcessNode()) { - start_node = parent_or_opener; - } - } - - DCHECK(start_node); - DCHECK(requesting_origin.IsSameOriginWith(GetOrigin(start_node))); - - // Make sure we didn't break out of the browsing context group. - DCHECK_EQ(start_node->GetBrowsingInstanceId(), - requesting_node->GetBrowsingInstanceId()); - return start_node; -} - // static mojom::WebMemoryBreakdownEntry* WebMemoryAggregator::CreateBreakdownEntry( AttributionScope scope,
diff --git a/components/performance_manager/v8_memory/web_memory_aggregator.h b/components/performance_manager/v8_memory/web_memory_aggregator.h index 63981d40..1c93376 100644 --- a/components/performance_manager/v8_memory/web_memory_aggregator.h +++ b/components/performance_manager/v8_memory/web_memory_aggregator.h
@@ -15,11 +15,13 @@ namespace performance_manager { class FrameNode; -class PageNode; +class ProcessNode; class WorkerNode; namespace v8_memory { +class AggregationPointVisitor; + // Traverses the graph of execution contexts to find the results of the last // memory measurement and aggregates them according to the rules defined in the // performance.measureUserAgentSpecificMemory spec. @@ -32,55 +34,20 @@ // // The aggregation is performed by calling AggregateMemoryResult. The graph // traversal will not start directly from |requesting_node|, but from the - // highest node in the frame tree that is visible to it as found by - // FindAggregationStartNode. (This allows a same-origin subframe to request - // memory for the whole page it's embedded in.) + // top frame nodes. explicit WebMemoryAggregator(const FrameNode* requesting_node); ~WebMemoryAggregator(); WebMemoryAggregator(const WebMemoryAggregator& other) = delete; WebMemoryAggregator& operator=(const WebMemoryAggregator& other) = delete; - // Returns the origin of |requesting_node|. - const url::Origin& requesting_origin() const { return requesting_origin_; } - // Performs the aggregation. mojom::WebMemoryMeasurementPtr AggregateMeasureMemoryResult(); private: + friend class AggregationPointVisitor; friend class WebMemoryAggregatorTest; - class AggregationPointVisitor; - - // The various ways a node can be treated during the aggregation. - enum class NodeAggregationType { - // Node is same-origin to |requesting_node|; will be a new aggregation - // point with a scope depending on the node type (eg. "Window" or - // "DedicatedWorker"). - kSameOriginAggregationPoint, - // Node is cross-origin with |requesting_node| but its parent is not; will - // be a new aggregation point with scope - // "cross-origin-aggregated". - kCrossOriginAggregationPoint, - // Node is cross-origin with |requesting_node| and so is its parent; will - // be aggregated into its parent's aggregation point. - kCrossOriginAggregated, - // Node is in a different browsing context group; will not be added to the - // aggregation. - kInvisible, - }; - - // Returns the way that |frame_node| should be treated during the - // aggregation. |aggregation_start_node_| must be reachable from - // |frame_node| by following parent/child or opener links. This will always - // be true if |frame_node| comes from a call to VisitFrame. - NodeAggregationType FindNodeAggregationType(const FrameNode* frame_node); - // Returns the aggregation type of a dedicated worker node based on its - // parent's aggregation type. - NodeAggregationType FindNodeAggregationType( - const WorkerNode* worker_node, - NodeAggregationType parent_aggregation_type); - // FrameNodeVisitor that recursively adds |frame_node| and its children to // the aggregation using |ap_visitor|. Always returns true to continue // traversal. @@ -88,34 +55,11 @@ const FrameNode* frame_node); // WorkerNodeVisitor that recursively adds |worker_node| and its children to - // the aggregation using |ap_visitor|. |enclosing_aggregation_type| is the - // type of the aggregation point that |worker_node|'s parent is in. Always - // returns true to continue traversal. + // the aggregation using |ap_visitor|. Always returns true to continue + // traversal. bool VisitWorker(AggregationPointVisitor* ap_visitor, - NodeAggregationType enclosing_aggregation_type, const WorkerNode* worker_node); - // PageNodeVisitor that recursively adds |page_node|'s main frames and their - // children to the aggregation using |ap_visitor|. Always returns true to - // continue traversal. - bool VisitOpenedPage(AggregationPointVisitor* ap_visitor, - const PageNode* page_node); - - // Static private methods are implementation details, but can be accessed from - // friend classes for testing. - - // Returns |frame_node|'s parent or opener if the parent or opener is - // same-origin with |origin|, nullptr otherwise. - static const FrameNode* GetSameOriginParentOrOpener( - const FrameNode* frame_node, - const url::Origin& origin); - - // Walks back the chain of parents and openers from |requesting_node| to find - // the farthest ancestor that should be visible to it (all intermediate nodes - // in the chain are same-origin). - static const FrameNode* FindAggregationStartNode( - const FrameNode* requesting_node); - // Creates a new breakdown entry with the given |scope| and |url|, and adds it // to the list in |measurement|. Returns a pointer to the newly created entry. static mojom::WebMemoryBreakdownEntry* CreateBreakdownEntry( @@ -134,13 +78,14 @@ const mojom::WebMemoryBreakdownEntry* from, mojom::WebMemoryBreakdownEntry* to); - // The origin of |requesting_node|. Cached so it doesn't have to be - // recalculated in each call to VisitFrame. + // The origin of the node that requests memory measurement. const url::Origin requesting_origin_; - - // The node that the graph traversal should start from, found from - // |requesting_node| using FindAggregationStartNode. - const FrameNode* aggregation_start_node_; + // The process node of the requesting frame. + const ProcessNode* const requesting_process_node_; + // The process node of the main frame. + const ProcessNode* const main_process_node_; + // The browsing instance id of the requesting frame. + const int32_t browsing_instance_id_; SEQUENCE_CHECKER(sequence_checker_); };
diff --git a/components/performance_manager/v8_memory/web_memory_aggregator_unittest.cc b/components/performance_manager/v8_memory/web_memory_aggregator_unittest.cc index 6ce9fb3..cf917b4 100644 --- a/components/performance_manager/v8_memory/web_memory_aggregator_unittest.cc +++ b/components/performance_manager/v8_memory/web_memory_aggregator_unittest.cc
@@ -98,36 +98,8 @@ class WebMemoryAggregatorTest : public WebMemoryTestHarness { protected: - using NodeAggregationType = WebMemoryAggregator::NodeAggregationType; - // Allow individual test subclasses to access private members of // WebMemoryAggregator. - - static NodeAggregationType FindNodeAggregationType( - WebMemoryAggregator* aggregator, - const FrameNode* frame_node) { - return aggregator->FindNodeAggregationType(frame_node); - } - - static NodeAggregationType FindNodeAggregationType( - WebMemoryAggregator* aggregator, - const WorkerNode* worker_node, - NodeAggregationType parent_aggregation_type) { - return aggregator->FindNodeAggregationType(worker_node, - parent_aggregation_type); - } - - static const FrameNode* GetSameOriginParentOrOpener( - const FrameNode* frame_node, - const url::Origin& origin) { - return WebMemoryAggregator::GetSameOriginParentOrOpener(frame_node, origin); - } - - static const FrameNode* FindAggregationStartNode( - const FrameNode* requesting_node) { - return WebMemoryAggregator::FindAggregationStartNode(requesting_node); - } - static mojom::WebMemoryBreakdownEntry* CreateBreakdownEntry( mojom::WebMemoryAttribution::Scope scope, base::Optional<std::string> url, @@ -210,7 +182,6 @@ ExpectedMemoryBreakdown(10, AttributionScope::kWindow, "https://example.com/"), }); - EXPECT_EQ(FindAggregationStartNode(main_frame), main_frame); WebMemoryAggregator aggregator(main_frame); auto result = aggregator.AggregateMeasureMemoryResult(); EXPECT_EQ(MeasurementToJSON(result), MeasurementToJSON(expected_result)); @@ -219,22 +190,11 @@ TEST_F(WebMemoryAggregatorTest, AggregateSingleSiteMultiFrame) { // Example 2 from http://wicg.github.io/performance-measure-memory/#examples FrameNodeImpl* main_frame = AddFrameNode("https://example.com/", Bytes{10}); - FrameNodeImpl* child_frame = - AddFrameNode("https://example.com/iframe.html", Bytes{5}, main_frame, - "example-id", "redirect.html?target=iframe.html"); + AddFrameNode("https://example.com/iframe.html", Bytes{5}, main_frame, + "example-id", "redirect.html?target=iframe.html"); - EXPECT_EQ(FindAggregationStartNode(main_frame), main_frame); WebMemoryAggregator aggregator(main_frame); - // Test the relationships of each node in the graph. - EXPECT_EQ(FindNodeAggregationType(&aggregator, main_frame), - NodeAggregationType::kSameOriginAggregationPoint); - EXPECT_EQ(FindNodeAggregationType(&aggregator, child_frame), - NodeAggregationType::kSameOriginAggregationPoint); - EXPECT_EQ( - GetSameOriginParentOrOpener(child_frame, aggregator.requesting_origin()), - main_frame); - auto expected_result = CreateExpectedMemoryMeasurement({ ExpectedMemoryBreakdown(10, AttributionScope::kWindow, "https://example.com/"), @@ -262,44 +222,17 @@ FrameNodeImpl* child_frame = AddFrameNode("https://foo.com/iframe1", Bytes{5}, main_frame, "example-id", "https://foo.com/iframe1"); - FrameNodeImpl* grandchild1 = - AddFrameNode("https://foo.com/iframe2", Bytes{2}, child_frame, - "example-id2", "https://foo.com/iframe2"); - FrameNodeImpl* grandchild2 = - AddFrameNode("https://bar.com/iframe2", Bytes{3}, child_frame, - "example-id3", "https://bar.com/iframe2"); - // TODO(crbug.com/1085129): In the spec this is a worker, but they're not - // supported yet. - FrameNodeImpl* grandchild3 = - AddFrameNode("https://foo.com/worker.js", Bytes{4}, child_frame); + AddFrameNode("https://foo.com/iframe2", Bytes{2}, child_frame, "example-id2", + "https://foo.com/iframe2"); + AddFrameNode("https://bar.com/iframe2", Bytes{3}, child_frame, "example-id3", + "https://bar.com/iframe2"); - EXPECT_EQ(FindAggregationStartNode(main_frame), main_frame); + WorkerNodeImpl* worker = + AddWorkerNode(WorkerNode::WorkerType::kDedicated, + "https://foo.com/worker.js", Bytes{4}, child_frame); + WebMemoryAggregator aggregator(main_frame); - // Test the relationships of each node in the graph. - EXPECT_EQ(FindNodeAggregationType(&aggregator, main_frame), - NodeAggregationType::kSameOriginAggregationPoint); - EXPECT_EQ(FindNodeAggregationType(&aggregator, child_frame), - NodeAggregationType::kCrossOriginAggregationPoint); - EXPECT_EQ( - GetSameOriginParentOrOpener(child_frame, aggregator.requesting_origin()), - main_frame); - EXPECT_EQ(FindNodeAggregationType(&aggregator, grandchild1), - NodeAggregationType::kCrossOriginAggregated); - EXPECT_EQ( - GetSameOriginParentOrOpener(grandchild1, aggregator.requesting_origin()), - nullptr); - EXPECT_EQ(FindNodeAggregationType(&aggregator, grandchild2), - NodeAggregationType::kCrossOriginAggregated); - EXPECT_EQ( - GetSameOriginParentOrOpener(grandchild2, aggregator.requesting_origin()), - nullptr); - EXPECT_EQ(FindNodeAggregationType(&aggregator, grandchild3), - NodeAggregationType::kCrossOriginAggregated); - EXPECT_EQ( - GetSameOriginParentOrOpener(grandchild3, aggregator.requesting_origin()), - nullptr); - auto expected_result = CreateExpectedMemoryMeasurement({ ExpectedMemoryBreakdown(10, AttributionScope::kWindow, "https://example.com/"), @@ -309,6 +242,7 @@ }); auto result = aggregator.AggregateMeasureMemoryResult(); EXPECT_EQ(MeasurementToJSON(result), MeasurementToJSON(expected_result)); + worker->RemoveClientFrame(child_frame); } TEST_F(WebMemoryAggregatorTest, AggregateNestedCrossOrigin) { @@ -343,81 +277,26 @@ FrameNodeImpl* subframe4 = AddFrameNode("https://foo.com/iframe2", Bytes{2}, subframe3, "example-id4", "https://foo.com/iframe2"); - FrameNodeImpl* subframe5 = - AddFrameNode("https://example.com/iframe2", Bytes{1}, subframe4, - "example-id5", "https://example.com/iframe2"); - FrameNodeImpl* subframe6 = - AddFrameNode("https://example.com/iframe3", Bytes{6}, subframe3, - "example-id6", "https://example.com/iframe3"); + AddFrameNode("https://example.com/iframe2", Bytes{1}, subframe4, + "example-id5", "https://example.com/iframe2"); + AddFrameNode("https://example.com/iframe3", Bytes{6}, subframe3, + "example-id6", "https://example.com/iframe3"); // To test aggregation all the frames above are in the same process, even // though in production frames with different origins will be in different // processes whenever possible. Frames in a different process from the // requesting frame should all have 0 bytes reported. - FrameNodeImpl* cross_process_frame = - AddCrossProcessFrameNode("https://example.com/cross_process", Bytes{100}, - subframe3, "cross-process-id1"); - FrameNodeImpl* cross_process_frame2 = - AddCrossProcessFrameNode("https://foo.com/cross_process", Bytes{200}, - subframe3, "cross-process-id2"); + AddCrossProcessFrameNode("https://example.com/cross_process", Bytes{100}, + subframe3, "cross-process-id1"); + AddCrossProcessFrameNode("https://foo.com/cross_process", Bytes{200}, + subframe3, "cross-process-id2"); // A frame without a memory measurement (eg. a frame that's added to the frame // tree during the measurement) should not have a memory entry in the result. - FrameNodeImpl* empty_frame = - AddFrameNode("https://example.com/empty_frame", base::nullopt, subframe3); + AddFrameNode("https://example.com/empty_frame", base::nullopt, subframe3); - EXPECT_EQ(FindAggregationStartNode(main_frame), main_frame); WebMemoryAggregator aggregator(main_frame); - // Test the relationships of each node in the graph. - EXPECT_EQ(FindNodeAggregationType(&aggregator, main_frame), - NodeAggregationType::kSameOriginAggregationPoint); - EXPECT_EQ(FindNodeAggregationType(&aggregator, subframe), - NodeAggregationType::kCrossOriginAggregationPoint); - EXPECT_EQ( - GetSameOriginParentOrOpener(subframe, aggregator.requesting_origin()), - main_frame); - EXPECT_EQ(FindNodeAggregationType(&aggregator, subframe2), - NodeAggregationType::kCrossOriginAggregated); - EXPECT_EQ( - GetSameOriginParentOrOpener(subframe2, aggregator.requesting_origin()), - nullptr); - EXPECT_EQ(FindNodeAggregationType(&aggregator, subframe3), - NodeAggregationType::kSameOriginAggregationPoint); - EXPECT_EQ( - GetSameOriginParentOrOpener(subframe3, aggregator.requesting_origin()), - nullptr); - EXPECT_EQ(FindNodeAggregationType(&aggregator, subframe4), - NodeAggregationType::kCrossOriginAggregationPoint); - EXPECT_EQ( - GetSameOriginParentOrOpener(subframe4, aggregator.requesting_origin()), - subframe3); - EXPECT_EQ(FindNodeAggregationType(&aggregator, subframe5), - NodeAggregationType::kSameOriginAggregationPoint); - EXPECT_EQ( - GetSameOriginParentOrOpener(subframe5, aggregator.requesting_origin()), - nullptr); - EXPECT_EQ(FindNodeAggregationType(&aggregator, subframe6), - NodeAggregationType::kSameOriginAggregationPoint); - EXPECT_EQ( - GetSameOriginParentOrOpener(subframe6, aggregator.requesting_origin()), - subframe3); - EXPECT_EQ(FindNodeAggregationType(&aggregator, empty_frame), - NodeAggregationType::kSameOriginAggregationPoint); - EXPECT_EQ( - GetSameOriginParentOrOpener(empty_frame, aggregator.requesting_origin()), - subframe3); - EXPECT_EQ(FindNodeAggregationType(&aggregator, cross_process_frame), - NodeAggregationType::kSameOriginAggregationPoint); - EXPECT_EQ(GetSameOriginParentOrOpener(cross_process_frame, - aggregator.requesting_origin()), - subframe3); - EXPECT_EQ(FindNodeAggregationType(&aggregator, cross_process_frame2), - NodeAggregationType::kCrossOriginAggregationPoint); - EXPECT_EQ(GetSameOriginParentOrOpener(cross_process_frame2, - aggregator.requesting_origin()), - subframe3); - auto expected_result = CreateExpectedMemoryMeasurement({ ExpectedMemoryBreakdown(10, AttributionScope::kWindow, "https://example.com/"), @@ -457,7 +336,6 @@ "https://example.com/"), ExpectedMemoryBreakdown(20, AttributionScope::kWindow, "about:blank"), }); - EXPECT_EQ(FindAggregationStartNode(main_frame), main_frame); WebMemoryAggregator aggregator(main_frame); auto result = aggregator.AggregateMeasureMemoryResult(); EXPECT_EQ(MeasurementToJSON(result), MeasurementToJSON(expected_result)); @@ -475,86 +353,20 @@ ExpectedMemoryBreakdown(50, AttributionScope::kCrossOriginAggregated, base::nullopt), }); - EXPECT_EQ(FindAggregationStartNode(main_frame), main_frame); WebMemoryAggregator aggregator(main_frame); auto result = aggregator.AggregateMeasureMemoryResult(); EXPECT_EQ(MeasurementToJSON(result), MeasurementToJSON(expected_result)); } -TEST_F(WebMemoryAggregatorTest, FindAggregationStartNode) { - FrameNodeImpl* main_frame = AddFrameNode("https://example.com/", Bytes{10}); - FrameNodeImpl* cross_site_child = AddFrameNode( - "https://foo.com/iframe.html", Bytes{5}, main_frame, "example-id", ""); - FrameNodeImpl* same_site_child = - AddFrameNode("https://foo.com/iframe2.html", Bytes{4}, cross_site_child, - "example-id2", ""); - - // FindAggregationStartNode should return the parent foo.com frame for either - // foo.com child. It should not return the main frame since it's cross-site - // from the requesting frames. - EXPECT_EQ(FindAggregationStartNode(cross_site_child), cross_site_child); - EXPECT_EQ(FindAggregationStartNode(same_site_child), cross_site_child); - - // When aggregation starts at |cross_site_child| it should not include any - // memory from the main frame. - WebMemoryAggregator aggregator(cross_site_child); - auto expected_result = CreateExpectedMemoryMeasurement({ - ExpectedMemoryBreakdown(5, AttributionScope::kWindow, - "https://foo.com/iframe.html"), - ExpectedMemoryBreakdown(4, AttributionScope::kWindow, - "https://foo.com/iframe2.html", "example-id2", - ""), - }); - auto result = aggregator.AggregateMeasureMemoryResult(); - EXPECT_EQ(MeasurementToJSON(result), MeasurementToJSON(expected_result)); - - // When the main frame requests a measurement of the same tree it should - // aggregate the children, which are cross-site from it. - EXPECT_EQ(FindAggregationStartNode(main_frame), main_frame); - auto main_frame_expected_result = CreateExpectedMemoryMeasurement({ - ExpectedMemoryBreakdown(10, AttributionScope::kWindow, - "https://example.com/"), - ExpectedMemoryBreakdown(9, AttributionScope::kCrossOriginAggregated, - base::nullopt, "example-id", ""), - }); - WebMemoryAggregator main_frame_aggregator(main_frame); - auto main_frame_result = main_frame_aggregator.AggregateMeasureMemoryResult(); - EXPECT_EQ(MeasurementToJSON(main_frame_result), - MeasurementToJSON(main_frame_expected_result)); -} - -TEST_F(WebMemoryAggregatorTest, FindCrossProcessAggregationStartNode) { - FrameNodeImpl* main_frame = AddFrameNode("https://example.com/", Bytes{1}); - FrameNodeImpl* cross_process_child = AddCrossProcessFrameNode( - "https://example.com/cross_process.html", Bytes{2}, main_frame); - FrameNodeImpl* same_process_child = AddFrameNode( - "https://example.com/same_process.html", Bytes{3}, cross_process_child); - - auto origin = url::Origin::Create(GURL("https://example.com")); - ASSERT_EQ(GetSameOriginParentOrOpener(cross_process_child, origin), - main_frame); - ASSERT_EQ(GetSameOriginParentOrOpener(same_process_child, origin), - cross_process_child); - - // |cross_process_child| has no ancestor in the same process as it. - EXPECT_EQ(FindAggregationStartNode(cross_process_child), cross_process_child); - - // The search starting from |same_process_child| should skip over - // |cross_process_child|, which is in a different process, and find - // |main_frame| which is in the same process. - EXPECT_EQ(FindAggregationStartNode(same_process_child), main_frame); -} - TEST_F(WebMemoryAggregatorTest, AggregateWindowOpener) { FrameNodeImpl* main_frame = AddFrameNode("https://example.com/", Bytes{10}); - FrameNodeImpl* child_frame = AddFrameNode("https://example.com/iframe.html", - Bytes{5}, main_frame, "example-id"); + AddFrameNode("https://example.com/iframe.html", Bytes{5}, main_frame, + "example-id"); FrameNodeImpl* opened_frame = AddFrameNodeFromOpener( "https://example.com/window/", Bytes{4}, main_frame); - FrameNodeImpl* child_of_opened_frame = - AddFrameNode("https://example.com/window-iframe.html", Bytes{3}, - opened_frame, "example-id2"); + AddFrameNode("https://example.com/window-iframe.html", Bytes{3}, opened_frame, + "example-id2"); FrameNodeImpl* cross_site_child = AddFrameNode("https://cross-site-example.com/window-iframe.html", Bytes{2}, opened_frame, "example-id3"); @@ -563,44 +375,8 @@ FrameNodeImpl* cross_site_popup = AddCrossBrowsingInstanceFrameNodeFromOpener( "https://cross-site-example.com/", Bytes{2}, main_frame); - // FindAggregationStartNode whould return |main_frame| from any of the - // same-site frames. - for (auto* frame : - {main_frame, child_frame, opened_frame, child_of_opened_frame}) { - EXPECT_EQ(FindAggregationStartNode(frame), main_frame) << frame->url(); - } - WebMemoryAggregator aggregator(main_frame); - // Test the relationships of each node in the graph. - EXPECT_EQ(FindNodeAggregationType(&aggregator, main_frame), - NodeAggregationType::kSameOriginAggregationPoint); - EXPECT_EQ(FindNodeAggregationType(&aggregator, child_frame), - NodeAggregationType::kSameOriginAggregationPoint); - EXPECT_EQ( - GetSameOriginParentOrOpener(child_frame, aggregator.requesting_origin()), - main_frame); - EXPECT_EQ(FindNodeAggregationType(&aggregator, opened_frame), - NodeAggregationType::kSameOriginAggregationPoint); - EXPECT_EQ( - GetSameOriginParentOrOpener(opened_frame, aggregator.requesting_origin()), - main_frame); - EXPECT_EQ(FindNodeAggregationType(&aggregator, child_of_opened_frame), - NodeAggregationType::kSameOriginAggregationPoint); - EXPECT_EQ(GetSameOriginParentOrOpener(child_of_opened_frame, - aggregator.requesting_origin()), - opened_frame); - EXPECT_EQ(FindNodeAggregationType(&aggregator, cross_site_child), - NodeAggregationType::kCrossOriginAggregationPoint); - EXPECT_EQ(GetSameOriginParentOrOpener(cross_site_child, - aggregator.requesting_origin()), - opened_frame); - EXPECT_EQ(FindNodeAggregationType(&aggregator, cross_site_popup), - NodeAggregationType::kInvisible); - EXPECT_EQ(GetSameOriginParentOrOpener(cross_site_popup, - aggregator.requesting_origin()), - main_frame); - auto expected_result = CreateExpectedMemoryMeasurement({ ExpectedMemoryBreakdown(10, AttributionScope::kWindow, "https://example.com/"), @@ -617,24 +393,27 @@ auto result = aggregator.AggregateMeasureMemoryResult(); EXPECT_EQ(MeasurementToJSON(result), MeasurementToJSON(expected_result)); - // The two cross-site frames should only be able to see themselves (and their - // own children, if they had any). They have the same |bytes| so their - // expectations only vary by url. - for (auto* frame : {cross_site_child, cross_site_popup}) { - const std::string url = frame->url().spec(); - SCOPED_TRACE(url); - - const FrameNode* start_node = FindAggregationStartNode(frame); - EXPECT_EQ(start_node, frame); - - WebMemoryAggregator aggregator(start_node); - // Only check the NodeAggregationType of the single node that's iterated - // over. Parents of the start node have an undefined aggregation type. - EXPECT_EQ(FindNodeAggregationType(&aggregator, start_node), - NodeAggregationType::kSameOriginAggregationPoint); + { + WebMemoryAggregator aggregator(cross_site_child); auto expected_cross_site_result = CreateExpectedMemoryMeasurement({ - ExpectedMemoryBreakdown(2, AttributionScope::kWindow, url, + ExpectedMemoryBreakdown(22, AttributionScope::kCrossOriginAggregated), + ExpectedMemoryBreakdown( + 2, AttributionScope::kWindow, + "https://cross-site-example.com/window-iframe.html", base::nullopt, + base::nullopt), + }); + auto cross_site_result = aggregator.AggregateMeasureMemoryResult(); + EXPECT_EQ(MeasurementToJSON(cross_site_result), + MeasurementToJSON(expected_cross_site_result)); + } + + { + WebMemoryAggregator aggregator(cross_site_popup); + + auto expected_cross_site_result = CreateExpectedMemoryMeasurement({ + ExpectedMemoryBreakdown(2, AttributionScope::kWindow, + "https://cross-site-example.com/", base::nullopt, base::nullopt), }); auto cross_site_result = aggregator.AggregateMeasureMemoryResult(); @@ -649,14 +428,10 @@ // This creates an openee window with pending navigation which should be // skipped because it may get its own browsing context group once the // navigation completes. - FrameNodeImpl* pending_frame = - AddFrameNodeFromOpener(base::nullopt, Bytes{4}, main_frame); + AddFrameNodeFromOpener(base::nullopt, Bytes{4}, main_frame); WebMemoryAggregator aggregator(main_frame); - EXPECT_EQ(FindNodeAggregationType(&aggregator, pending_frame), - NodeAggregationType::kInvisible); - auto expected_result = CreateExpectedMemoryMeasurement({ ExpectedMemoryBreakdown(10, AttributionScope::kWindow, "https://example.com/"), @@ -719,6 +494,110 @@ worker1->RemoveClientFrame(child_frame); } +TEST_F(WebMemoryAggregatorTest, AggregateCrossOriginCallers) { + FrameNodeImpl* a_com = AddFrameNode("https://a.com/", Bytes{10}); + FrameNodeImpl* a_com_iframe = + AddFrameNode("https://a.com/iframe", Bytes{20}, a_com, "a_com_iframe"); + FrameNodeImpl* b_com_iframe1 = + AddFrameNode("https://b.com/iframe1", Bytes{30}, a_com, "b_com_iframe1"); + FrameNodeImpl* b_com_iframe2 = AddFrameNode( + "https://b.com/iframe2", Bytes{40}, a_com_iframe, "b_com_iframe2"); + FrameNodeImpl* c_com_iframe1 = AddFrameNode( + "https://c.com/iframe1", Bytes{50}, b_com_iframe1, "c_com_iframe1"); + FrameNodeImpl* a_com_popup1 = + AddFrameNodeFromOpener("https://a.com/popup1", Bytes{60}, c_com_iframe1); + FrameNodeImpl* b_com_iframe3 = AddFrameNode( + "https://b.com/iframe3", Bytes{70}, a_com_popup1, "b_com_iframe3"); + AddFrameNode("https://c.com/iframe2", Bytes{80}, b_com_iframe3, + "c_com_iframe2"); + AddFrameNodeFromOpener("https://a.com/popup2", Bytes{90}, b_com_iframe2); + + { + WebMemoryAggregator aggregator(a_com_popup1); + auto expected_result = CreateExpectedMemoryMeasurement({ + ExpectedMemoryBreakdown(10, AttributionScope::kWindow, + "https://a.com/"), + ExpectedMemoryBreakdown(20, AttributionScope::kWindow, + "https://a.com/iframe", "a_com_iframe"), + ExpectedMemoryBreakdown(40, AttributionScope::kCrossOriginAggregated, + base::nullopt, "b_com_iframe2"), + ExpectedMemoryBreakdown(80, AttributionScope::kCrossOriginAggregated, + base::nullopt, "b_com_iframe1"), + ExpectedMemoryBreakdown(60, AttributionScope::kWindow, + "https://a.com/popup1"), + ExpectedMemoryBreakdown(150, AttributionScope::kCrossOriginAggregated, + base::nullopt, "b_com_iframe3"), + ExpectedMemoryBreakdown(90, AttributionScope::kWindow, + "https://a.com/popup2"), + }); + auto result = aggregator.AggregateMeasureMemoryResult(); + EXPECT_EQ(MeasurementToJSON(result), MeasurementToJSON(expected_result)); + } + + { + WebMemoryAggregator aggregator(b_com_iframe3); + auto expected_result = CreateExpectedMemoryMeasurement({ + ExpectedMemoryBreakdown(180, AttributionScope::kCrossOriginAggregated, + base::nullopt), + ExpectedMemoryBreakdown(40, AttributionScope::kWindow, + "https://b.com/iframe2"), + ExpectedMemoryBreakdown(30, AttributionScope::kWindow, + "https://b.com/iframe1"), + ExpectedMemoryBreakdown(50, AttributionScope::kCrossOriginAggregated, + base::nullopt, "c_com_iframe1"), + ExpectedMemoryBreakdown(70, AttributionScope::kWindow, + "https://b.com/iframe3"), + ExpectedMemoryBreakdown(80, AttributionScope::kCrossOriginAggregated, + base::nullopt, "c_com_iframe2"), + }); + auto result = aggregator.AggregateMeasureMemoryResult(); + EXPECT_EQ(MeasurementToJSON(result), MeasurementToJSON(expected_result)); + } + + { + WebMemoryAggregator aggregator(c_com_iframe1); + auto expected_result = CreateExpectedMemoryMeasurement({ + ExpectedMemoryBreakdown(320, AttributionScope::kCrossOriginAggregated, + base::nullopt), + ExpectedMemoryBreakdown(50, AttributionScope::kWindow, + "https://c.com/iframe1"), + ExpectedMemoryBreakdown(80, AttributionScope::kWindow, + "https://c.com/iframe2"), + }); + auto result = aggregator.AggregateMeasureMemoryResult(); + EXPECT_EQ(MeasurementToJSON(result), MeasurementToJSON(expected_result)); + } +} + +TEST_F(WebMemoryAggregatorTest, AggregateCrossProcessCallers) { + FrameNodeImpl* a_com = AddFrameNode("https://a.com/", Bytes{10}); + FrameNodeImpl* b_com_iframe = AddCrossProcessFrameNode( + "https://b.com/iframe", Bytes{30}, a_com, "b_com_iframe"); + { + WebMemoryAggregator aggregator(a_com); + auto expected_result = CreateExpectedMemoryMeasurement({ + ExpectedMemoryBreakdown(10, AttributionScope::kWindow, + "https://a.com/"), + ExpectedMemoryBreakdown(0, AttributionScope::kCrossOriginAggregated, + base::nullopt, "b_com_iframe"), + }); + auto result = aggregator.AggregateMeasureMemoryResult(); + EXPECT_EQ(MeasurementToJSON(result), MeasurementToJSON(expected_result)); + } + + { + WebMemoryAggregator aggregator(b_com_iframe); + auto expected_result = CreateExpectedMemoryMeasurement({ + ExpectedMemoryBreakdown(0, AttributionScope::kCrossOriginAggregated, + base::nullopt), + ExpectedMemoryBreakdown(30, AttributionScope::kWindow, + "https://b.com/iframe"), + }); + auto result = aggregator.AggregateMeasureMemoryResult(); + EXPECT_EQ(MeasurementToJSON(result), MeasurementToJSON(expected_result)); + } +} + } // namespace v8_memory } // namespace performance_manager
diff --git a/components/performance_manager/v8_memory/web_memory_impl.cc b/components/performance_manager/v8_memory/web_memory_impl.cc index f14844a..44e3d379 100644 --- a/components/performance_manager/v8_memory/web_memory_impl.cc +++ b/components/performance_manager/v8_memory/web_memory_impl.cc
@@ -167,16 +167,6 @@ .Run("WebMeasureMemoryViaPerformanceManager feature is disabled"); return; } - // "Memory measurement allowed" predicate from - // https://wicg.github.io/performance-measure-memory/ section 3.2. - if (url::Origin::Create(frame->GetURL()) != - url::Origin::Create(frame->GetPageNode()->GetMainFrameNode()->GetURL())) { - std::move(bad_message_callback) - .Run( - "performance.measureUserAgentSpecificMemory called from " - "a cross-origin subframe"); - return; - } content::GetUIThreadTaskRunner({})->PostTask( FROM_HERE, base::BindOnce(&CheckIsCrossOriginIsolatedOnUISeq, frame->GetRenderFrameHostProxy(),
diff --git a/components/policy/core/common/cloud/cloud_policy_manager.cc b/components/policy/core/common/cloud/cloud_policy_manager.cc index 076f8ac..f7524fa 100644 --- a/components/policy/core/common/cloud/cloud_policy_manager.cc +++ b/components/policy/core/common/cloud/cloud_policy_manager.cc
@@ -42,6 +42,10 @@ CloudPolicyManager::~CloudPolicyManager() {} +bool CloudPolicyManager::IsClientRegistered() const { + return client() && client()->is_registered(); +} + void CloudPolicyManager::Init(SchemaRegistry* registry) { ConfigurationPolicyProvider::Init(registry);
diff --git a/components/policy/core/common/cloud/cloud_policy_manager.h b/components/policy/core/common/cloud/cloud_policy_manager.h index c095c37..1720f2a 100644 --- a/components/policy/core/common/cloud/cloud_policy_manager.h +++ b/components/policy/core/common/cloud/cloud_policy_manager.h
@@ -54,6 +54,10 @@ CloudPolicyCore* core() { return &core_; } const CloudPolicyCore* core() const { return &core_; } + // Returns true if the underlying CloudPolicyClient is already registered. + // Virtual for mocking. + virtual bool IsClientRegistered() const; + // ConfigurationPolicyProvider: void Init(SchemaRegistry* registry) override; void Shutdown() override;
diff --git a/components/policy/core/common/cloud/machine_level_user_cloud_policy_manager.cc b/components/policy/core/common/cloud/machine_level_user_cloud_policy_manager.cc index 6c9bc208..f97e4927 100644 --- a/components/policy/core/common/cloud/machine_level_user_cloud_policy_manager.cc +++ b/components/policy/core/common/cloud/machine_level_user_cloud_policy_manager.cc
@@ -63,10 +63,6 @@ external_data_manager_->Connect(std::move(url_loader_factory)); } -bool MachineLevelUserCloudPolicyManager::IsClientRegistered() { - return client() && client()->is_registered(); -} - void MachineLevelUserCloudPolicyManager::AddClientObserver( CloudPolicyClient::Observer* observer) { if (client())
diff --git a/components/policy/core/common/cloud/machine_level_user_cloud_policy_manager.h b/components/policy/core/common/cloud/machine_level_user_cloud_policy_manager.h index 9a36ce4..a00acfd5 100644 --- a/components/policy/core/common/cloud/machine_level_user_cloud_policy_manager.h +++ b/components/policy/core/common/cloud/machine_level_user_cloud_policy_manager.h
@@ -36,9 +36,6 @@ void Connect(PrefService* local_state, std::unique_ptr<CloudPolicyClient> client); - // Returns true if the underlying CloudPolicyClient is already registered. - bool IsClientRegistered(); - // Add or remove |observer| to/from the CloudPolicyClient embedded in |core_|. void AddClientObserver(CloudPolicyClient::Observer* observer); void RemoveClientObserver(CloudPolicyClient::Observer* observer);
diff --git a/components/policy/core/common/cloud/user_cloud_policy_manager.cc b/components/policy/core/common/cloud/user_cloud_policy_manager.cc index 6b4403e..d22bc74e 100644 --- a/components/policy/core/common/cloud/user_cloud_policy_manager.cc +++ b/components/policy/core/common/cloud/user_cloud_policy_manager.cc
@@ -103,10 +103,6 @@ SetPoliciesRequired(false); } -bool UserCloudPolicyManager::IsClientRegistered() const { - return client() && client()->is_registered(); -} - void UserCloudPolicyManager::GetChromePolicy(PolicyMap* policy_map) { CloudPolicyManager::GetChromePolicy(policy_map);
diff --git a/components/policy/core/common/cloud/user_cloud_policy_manager.h b/components/policy/core/common/cloud/user_cloud_policy_manager.h index 4c8acce..f197d2f 100644 --- a/components/policy/core/common/cloud/user_cloud_policy_manager.h +++ b/components/policy/core/common/cloud/user_cloud_policy_manager.h
@@ -68,10 +68,6 @@ // provided by this object until the next time Initialize() is invoked. void DisconnectAndRemovePolicy(); - // Returns true if the underlying CloudPolicyClient is already registered. - // Virtual for mocking. - virtual bool IsClientRegistered() const; - // Creates a CloudPolicyClient for this client. Used in situations where // callers want to create a DMToken without actually initializing the // profile's policy infrastructure (for example, during signin when we
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json index 641e2d9..c2cebe1 100644 --- a/components/policy/resources/policy_templates.json +++ b/components/policy/resources/policy_templates.json
@@ -19437,7 +19437,8 @@ 'window' ] }, - 'create_desktop_shortcut': { 'type': 'boolean' } + 'create_desktop_shortcut': { 'type': 'boolean' }, + 'fallback_app_name': { 'type': 'string' } }, 'required': ['url'] } @@ -19454,13 +19455,33 @@ }, { 'url': 'https://docs.google.com', 'default_launch_container': 'tab' + }, { + 'url': 'https://docs.google.com/editor', + 'default_launch_container': 'window', + 'fallback_app_name': 'Editor' }], 'id': 468, 'caption': '''Configure list of force-installed Web Apps''', 'tags': [], 'desc': '''Setting the policy specifies a list of web apps that install silently, without user interaction, and which users can't uninstall or turn off. - Each list item of the policy is an object with a mandatory member: <ph name="URL_LABEL">url</ph> (the URL of the web app to install) and 2 optional members: <ph name="DEFAULT_LAUNCH_CONTAINER_LABEL">default_launch_container</ph> (for how the web app opens—a new tab is the default) and <ph name="CREATE_DESKTOP_SHORTCUT_LABEL">create_desktop_shortcut</ph> (True if you want to create <ph name="LINUX_OS_NAME">Linux</ph> and Windows® desktop shortcuts). + Each list item of the policy is an object with a mandatory member: + <ph name="URL_LABEL">url</ph> (the URL of the web app to install) + + and 3 optional members: + - <ph name="DEFAULT_LAUNCH_CONTAINER_LABEL">default_launch_container</ph> + (for how the web app opens—a new tab is the default) + + - <ph name="CREATE_DESKTOP_SHORTCUT_LABEL">create_desktop_shortcut</ph> + (True if you want to create <ph name="LINUX_OS_NAME">Linux</ph> and + <ph name="MS_WIN_NAME">Microsoft® Windows®</ph> desktop shortcuts). + + - <ph name="FALLBACK_APP_NAME_LABEL">fallback_app_name</ph> + (Starting with <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> version 90, + allows you to override the app name if it is not a + Progressive Web App (PWA), or the app name that is temporarily + installed if it is a PWA but authentication is required before the + installation can be completed.) See <ph name="PINNED_LAUNCHER_APPS_POLICY_NAME">PinnedLauncherApps</ph> for pinning apps to the <ph name="PRODUCT_OS_NAME">$2<ex>Google Chrome OS</ex></ph> shelf.''', 'label': '''URLs for Web Apps to be silently installed.''',
diff --git a/components/printing/common/cloud_print_cdd_conversion.cc b/components/printing/common/cloud_print_cdd_conversion.cc index 9145586..f5c17bb 100644 --- a/components/printing/common/cloud_print_cdd_conversion.cc +++ b/components/printing/common/cloud_print_cdd_conversion.cc
@@ -18,11 +18,6 @@ #include "printing/backend/print_backend.h" #include "printing/mojom/print.mojom.h" -#if BUILDFLAG(IS_CHROMEOS_ASH) -#include "base/feature_list.h" -#include "printing/printing_features.h" -#endif // BUILDFLAG(IS_CHROMEOS_ASH) - namespace printer = cloud_devices::printer; namespace cloud_print { @@ -241,9 +236,7 @@ pin.set_value(semantic_info.pin_supported); pin.SaveTo(&description); - if (base::FeatureList::IsEnabled( - printing::features::kAdvancedPpdAttributes) && - !semantic_info.advanced_capabilities.empty()) { + if (!semantic_info.advanced_capabilities.empty()) { printer::VendorCapabilities vendor_capabilities = GetVendorCapabilities(semantic_info); vendor_capabilities.SaveTo(&description);
diff --git a/components/services/app_service/app_service_impl.cc b/components/services/app_service/app_service_impl.cc index 6395f0e..be867d0 100644 --- a/components/services/app_service/app_service_impl.cc +++ b/components/services/app_service/app_service_impl.cc
@@ -192,12 +192,13 @@ const std::string& app_id, int32_t event_flags, apps::mojom::LaunchSource launch_source, - int64_t display_id) { + apps::mojom::WindowInfoPtr window_info) { auto iter = publishers_.find(app_type); if (iter == publishers_.end()) { return; } - iter->second->Launch(app_id, event_flags, launch_source, display_id); + iter->second->Launch(app_id, event_flags, launch_source, + std::move(window_info)); } void AppServiceImpl::LaunchAppWithFiles(apps::mojom::AppType app_type, const std::string& app_id, @@ -219,13 +220,13 @@ int32_t event_flags, apps::mojom::IntentPtr intent, apps::mojom::LaunchSource launch_source, - int64_t display_id) { + apps::mojom::WindowInfoPtr window_info) { auto iter = publishers_.find(app_type); if (iter == publishers_.end()) { return; } iter->second->LaunchAppWithIntent(app_id, event_flags, std::move(intent), - launch_source, display_id); + launch_source, std::move(window_info)); } void AppServiceImpl::SetPermission(apps::mojom::AppType app_type,
diff --git a/components/services/app_service/app_service_impl.h b/components/services/app_service/app_service_impl.h index a75d357..c717a83b 100644 --- a/components/services/app_service/app_service_impl.h +++ b/components/services/app_service/app_service_impl.h
@@ -57,7 +57,7 @@ const std::string& app_id, int32_t event_flags, apps::mojom::LaunchSource launch_source, - int64_t display_id) override; + apps::mojom::WindowInfoPtr window_info) override; void LaunchAppWithFiles(apps::mojom::AppType app_type, const std::string& app_id, apps::mojom::LaunchContainer container, @@ -69,7 +69,7 @@ int32_t event_flags, apps::mojom::IntentPtr intent, apps::mojom::LaunchSource launch_source, - int64_t display_id) override; + apps::mojom::WindowInfoPtr window_info) override; void SetPermission(apps::mojom::AppType app_type, const std::string& app_id, apps::mojom::PermissionPtr permission) override;
diff --git a/components/services/app_service/app_service_impl_unittest.cc b/components/services/app_service/app_service_impl_unittest.cc index 00596f7..ed7fb8b 100644 --- a/components/services/app_service/app_service_impl_unittest.cc +++ b/components/services/app_service/app_service_impl_unittest.cc
@@ -107,7 +107,7 @@ void Launch(const std::string& app_id, int32_t event_flags, apps::mojom::LaunchSource launch_source, - int64_t display_id) override {} + apps::mojom::WindowInfoPtr window_info) override {} void CallOnApps(apps::mojom::Subscriber* subscriber, std::vector<std::string>& app_ids,
diff --git a/components/services/app_service/public/cpp/BUILD.gn b/components/services/app_service/public/cpp/BUILD.gn index d4b27ce..ba640fb 100644 --- a/components/services/app_service/public/cpp/BUILD.gn +++ b/components/services/app_service/public/cpp/BUILD.gn
@@ -191,7 +191,6 @@ ":preferred_apps", ":publisher", ":test_support", - "//chrome/test:test_support", "//content/test:test_support", "//testing/gtest", ] @@ -202,6 +201,9 @@ "instance_update_unittest.cc", ] - deps += [ ":instance_update" ] + deps += [ + ":instance_update", + "//chrome/test:test_support", + ] } }
diff --git a/components/services/app_service/public/cpp/publisher_base.cc b/components/services/app_service/public/cpp/publisher_base.cc index 69e727aa..298df6a 100644 --- a/components/services/app_service/public/cpp/publisher_base.cc +++ b/components/services/app_service/public/cpp/publisher_base.cc
@@ -105,11 +105,12 @@ NOTIMPLEMENTED(); } -void PublisherBase::LaunchAppWithIntent(const std::string& app_id, - int32_t event_flags, - apps::mojom::IntentPtr intent, - apps::mojom::LaunchSource launch_source, - int64_t display_id) { +void PublisherBase::LaunchAppWithIntent( + const std::string& app_id, + int32_t event_flags, + apps::mojom::IntentPtr intent, + apps::mojom::LaunchSource launch_source, + apps::mojom::WindowInfoPtr window_info) { NOTIMPLEMENTED(); }
diff --git a/components/services/app_service/public/cpp/publisher_base.h b/components/services/app_service/public/cpp/publisher_base.h index c9450df..6d4d4cb 100644 --- a/components/services/app_service/public/cpp/publisher_base.h +++ b/components/services/app_service/public/cpp/publisher_base.h
@@ -68,7 +68,7 @@ int32_t event_flags, apps::mojom::IntentPtr intent, apps::mojom::LaunchSource launch_source, - int64_t display_id) override; + apps::mojom::WindowInfoPtr window_info) override; void SetPermission(const std::string& app_id, apps::mojom::PermissionPtr permission) override; void Uninstall(const std::string& app_id,
diff --git a/components/services/app_service/public/mojom/app_service.mojom b/components/services/app_service/public/mojom/app_service.mojom index e19925e..a7dd445 100644 --- a/components/services/app_service/public/mojom/app_service.mojom +++ b/components/services/app_service/public/mojom/app_service.mojom
@@ -37,7 +37,7 @@ string app_id, int32 event_flags, LaunchSource launch_source, - int64 display_id); + WindowInfo? window_info); // Launches an app with |app_id| and |file_path| LaunchAppWithFiles( @@ -56,7 +56,7 @@ int32 event_flags, Intent intent, LaunchSource launch_source, - int64 display_id); + WindowInfo? window_info); SetPermission( AppType app_type, @@ -148,7 +148,7 @@ string app_id, int32 event_flags, LaunchSource launch_source, - int64 display_id); + WindowInfo? window_info); // Launches an app with |app_id| and |file_path| LaunchAppWithFiles( @@ -165,7 +165,7 @@ int32 event_flags, Intent intent, LaunchSource launch_source, - int64 display_id); + WindowInfo? window_info); SetPermission( string app_id,
diff --git a/components/services/app_service/public/mojom/types.mojom b/components/services/app_service/public/mojom/types.mojom index 7e7b650..537e3a7f 100644 --- a/components/services/app_service/public/mojom/types.mojom +++ b/components/services/app_service/public/mojom/types.mojom
@@ -416,3 +416,19 @@ // When adding new fields, also update the Merge method and other helpers in // components/services/app_service/public/cpp/access_update.* }; + +// The window bounds information. +struct Rect { + int32 x; + int32 y; + int32 width; + int32 height; +}; + +// The window information to launch an app. +struct WindowInfo { + int32 window_id = -1; + int32 state = -1; + int64 display_id = -1; + Rect? bounds; +};
diff --git a/components/startup_metric_utils/browser/startup_metric_utils.cc b/components/startup_metric_utils/browser/startup_metric_utils.cc index adc1289..1fca1d3 100644 --- a/components/startup_metric_utils/browser/startup_metric_utils.cc +++ b/components/startup_metric_utils/browser/startup_metric_utils.cc
@@ -572,23 +572,6 @@ g_application_start_ticks, ticks); } -void RecordBrowserWindowFirstPaintCompositingEnded( - const base::TimeTicks ticks) { - DCHECK(!g_application_start_ticks.is_null()); - - static bool is_first_call = true; - if (!is_first_call || ticks.is_null()) - return; - is_first_call = false; - if (!ShouldLogStartupHistogram()) - return; - - UmaHistogramWithTraceAndTemperature( - &base::UmaHistogramLongTimes100, - "Startup.BrowserWindow.FirstPaint.CompositingEnded", - g_application_start_ticks, ticks); -} - base::TimeTicks MainEntryPointTicks() { return g_chrome_main_entry_ticks; }
diff --git a/components/startup_metric_utils/browser/startup_metric_utils.h b/components/startup_metric_utils/browser/startup_metric_utils.h index d1896be6..ca65780a 100644 --- a/components/startup_metric_utils/browser/startup_metric_utils.h +++ b/components/startup_metric_utils/browser/startup_metric_utils.h
@@ -76,12 +76,6 @@ // computes time deltas based on application start time. void RecordBrowserWindowFirstPaint(base::TimeTicks ticks); -// Call this with the time when the Browser window painted its children for the -// first time and we got a CompositingEnded after that. Must be called after -// RecordApplicationStartTime(), because it computes time deltas based on -// application start time. -void RecordBrowserWindowFirstPaintCompositingEnded(base::TimeTicks ticks); - // Returns the TimeTicks corresponding to main entry as recorded by // |RecordMainEntryPointTime|. Returns a null TimeTicks if a value has not been // recorded yet. This method is expected to be called from the UI thread.
diff --git a/components/translate/content/browser/content_translate_driver.cc b/components/translate/content/browser/content_translate_driver.cc index 65678f97..73ab249 100644 --- a/components/translate/content/browser/content_translate_driver.cc +++ b/components/translate/content/browser/content_translate_driver.cc
@@ -20,6 +20,7 @@ #include "components/google/core/common/google_util.h" #include "components/language/core/browser/url_language_histogram.h" #include "components/translate/content/browser/content_record_page_language.h" +#include "components/translate/content/browser/translate_model_service.h" #include "components/translate/core/browser/translate_download_manager.h" #include "components/translate/core/browser/translate_manager.h" #include "components/translate/core/browser/translate_metrics_logger.h" @@ -57,13 +58,15 @@ ContentTranslateDriver::ContentTranslateDriver( content::NavigationController* nav_controller, - language::UrlLanguageHistogram* url_language_histogram) + language::UrlLanguageHistogram* url_language_histogram, + translate::TranslateModelService* translate_model_service) : content::WebContentsObserver(nav_controller->GetWebContents()), navigation_controller_(nav_controller), translate_manager_(nullptr), max_reload_check_attempts_(kMaxTranslateLoadCheckAttempts), next_page_seq_no_(0), - language_histogram_(url_language_histogram) { + language_histogram_(url_language_histogram), + translate_model_service_(translate_model_service) { DCHECK(navigation_controller_); } @@ -333,4 +336,22 @@ observer.OnPageTranslated(original_lang, translated_lang, error_type); } +void ContentTranslateDriver::GetLanguageDetectionModel( + GetLanguageDetectionModelCallback callback) { + if (!translate_model_service_) { + std::move(callback).Run(base::File()); + return; + } + translate_model_service_->GetLanguageDetectionModelFile( + base::BindOnce(&ContentTranslateDriver::OnLanguageDetectionModelFile, + weak_pointer_factory_.GetWeakPtr(), std::move(callback))); +} + +void ContentTranslateDriver::OnLanguageDetectionModelFile( + GetLanguageDetectionModelCallback callback, + base::File model_file) { + DCHECK(model_file.IsValid()); + std::move(callback).Run(std::move(model_file)); +} + } // namespace translate
diff --git a/components/translate/content/browser/content_translate_driver.h b/components/translate/content/browser/content_translate_driver.h index 6a3cd22..cdb7c03a 100644 --- a/components/translate/content/browser/content_translate_driver.h +++ b/components/translate/content/browser/content_translate_driver.h
@@ -34,6 +34,7 @@ struct LanguageDetectionDetails; class TranslateManager; +class TranslateModelService; // Content implementation of TranslateDriver. class ContentTranslateDriver : public TranslateDriver, @@ -55,9 +56,9 @@ } }; - ContentTranslateDriver( - content::NavigationController* nav_controller, - language::UrlLanguageHistogram* url_language_histogram); + ContentTranslateDriver(content::NavigationController* nav_controller, + language::UrlLanguageHistogram* url_language_histogram, + TranslateModelService* translate_model_service); ~ContentTranslateDriver() override; // Adds or removes observers. @@ -106,12 +107,17 @@ // Adds a receiver in |receivers_| for the passed |receiver|. void AddReceiver( mojo::PendingReceiver<translate::mojom::ContentTranslateDriver> receiver); + // Called when a page has been loaded and can be potentially translated. void RegisterPage( mojo::PendingRemote<translate::mojom::TranslateAgent> translate_agent, const translate::LanguageDetectionDetails& details, bool page_level_translation_critiera_met) override; + // translate::mojom::ContentTranslateDriver implementation: + void GetLanguageDetectionModel( + GetLanguageDetectionModelCallback callback) override; + protected: const base::ObserverList<TranslationObserver, true>& translation_observers() const { @@ -132,6 +138,11 @@ void InitiateTranslationIfReload( content::NavigationHandle* navigation_handle); + // Runs the provided callback with the loaded model file + // to pass it to the connected translate agent. + void OnLanguageDetectionModelFile(GetLanguageDetectionModelCallback callback, + base::File model_file); + // The navigation controller of the tab we are associated with. content::NavigationController* navigation_controller_; @@ -163,6 +174,10 @@ // page language is determined. base::TimeTicks finish_navigation_time_; + // The service that provides the model files needed for translate. Not owned + // but guaranteed to outlive |this|. + TranslateModelService* const translate_model_service_; + base::WeakPtrFactory<ContentTranslateDriver> weak_pointer_factory_{this}; DISALLOW_COPY_AND_ASSIGN(ContentTranslateDriver);
diff --git a/components/translate/content/browser/per_frame_content_translate_driver.cc b/components/translate/content/browser/per_frame_content_translate_driver.cc index f3d1244..f53051f 100644 --- a/components/translate/content/browser/per_frame_content_translate_driver.cc +++ b/components/translate/content/browser/per_frame_content_translate_driver.cc
@@ -130,7 +130,9 @@ PerFrameContentTranslateDriver::PerFrameContentTranslateDriver( content::NavigationController* nav_controller, language::UrlLanguageHistogram* url_language_histogram) - : ContentTranslateDriver(nav_controller, url_language_histogram) {} + : ContentTranslateDriver(nav_controller, + url_language_histogram, + /*translate_model_service=*/nullptr) {} PerFrameContentTranslateDriver::~PerFrameContentTranslateDriver() = default;
diff --git a/components/translate/content/common/translate.mojom b/components/translate/content/common/translate.mojom index 7c0ece4..10a419c 100644 --- a/components/translate/content/common/translate.mojom +++ b/components/translate/content/common/translate.mojom
@@ -4,6 +4,7 @@ module translate.mojom; +import "mojo/public/mojom/base/file.mojom"; import "mojo/public/mojom/base/time.mojom"; import "mojo/public/mojom/base/string16.mojom"; import "url/mojom/url.mojom"; @@ -78,4 +79,10 @@ // and the language for it has been determined. RegisterPage(pending_remote<TranslateAgent> translate_agent, LanguageDetectionDetails details, bool translation_critiera_met); + + // Request that the language detection model being loaded and returned + // for use by the TranslateAgent. + GetLanguageDetectionModel() + => (mojo_base.mojom.File? model_file); + };
diff --git a/components/translate/content/renderer/translate_agent.cc b/components/translate/content/renderer/translate_agent.cc index d03e20e..7e2e16e2 100644 --- a/components/translate/content/renderer/translate_agent.cc +++ b/components/translate/content/renderer/translate_agent.cc
@@ -35,6 +35,7 @@ #include "third_party/blink/public/web/web_local_frame.h" #include "third_party/blink/public/web/web_script_source.h" #include "url/gurl.h" +#include "url/url_constants.h" #include "v8/include/v8.h" using blink::WebDocument; @@ -82,6 +83,19 @@ extension_scheme_(extension_scheme) { translate_task_runner_ = this->render_frame()->GetTaskRunner( blink::TaskType::kInternalTranslation); + + if (translate::IsTFLiteLanguageDetectionEnabled()) { + translate::LanguageDetectionModel& language_detection_model = + GetLanguageDetectionModel(); + if (!language_detection_model.IsAvailable()) { + // TODO(crbug.com/1160948): Consider tracking if another agent associated + // with the same LanguageDetectionModel has already requested a model be + // provided by the translate host. + GetTranslateHandler()->GetLanguageDetectionModel( + base::BindOnce(&TranslateAgent::UpdateLanguageDetectionModel, + weak_pointer_factory_.GetWeakPtr())); + } + } } TranslateAgent::~TranslateAgent() {} @@ -99,7 +113,7 @@ // original intent of http-equiv to be an equivalent) with the former // being the language of the document and the latter being the // language of the intended audience (a distinction really only - // relevant for things like langauge textbooks). This distinction + // relevant for things like language textbooks). This distinction // shouldn't affect translation. WebLocalFrame* main_frame = render_frame()->GetWebFrame(); if (!main_frame) @@ -115,6 +129,12 @@ std::string language; if (translate::IsTFLiteLanguageDetectionEnabled()) { + if (!document.Url().ProtocolIs(url::kHttpsScheme) && + !document.Url().ProtocolIs(url::kHttpScheme)) { + // TFLite-based language detection only supports HTTP/HTTPS pages. + // Others should be ignored, for example the New Tab Page. + return; + } translate::LanguageDetectionModel& language_detection_model = GetLanguageDetectionModel(); bool is_available = language_detection_model.IsAvailable(); @@ -502,4 +522,10 @@ base::GetQuotedJSONString(target_lang) + ")"; } +void TranslateAgent::UpdateLanguageDetectionModel(base::File model_file) { + translate::LanguageDetectionModel& language_detection_model = + GetLanguageDetectionModel(); + language_detection_model.UpdateWithFile(std::move(model_file)); +} + } // namespace translate
diff --git a/components/translate/content/renderer/translate_agent.h b/components/translate/content/renderer/translate_agent.h index 162684e..0045888 100644 --- a/components/translate/content/renderer/translate_agent.h +++ b/components/translate/content/renderer/translate_agent.h
@@ -154,6 +154,10 @@ // if the page is being closed. blink::WebLocalFrame* GetMainFrame(); + // Called by the translate host when a new language detection model file + // has been loaded and is available. + void UpdateLanguageDetectionModel(base::File model_file); + // The states associated with the current translation. TranslateFrameCallback translate_callback_pending_; std::string source_lang_; @@ -184,6 +188,9 @@ // Method factory used to make calls to TranslatePageImpl. base::WeakPtrFactory<TranslateAgent> weak_method_factory_{this}; + // Weak pointer factory used to provide references to the translate host. + base::WeakPtrFactory<TranslateAgent> weak_pointer_factory_{this}; + DISALLOW_COPY_AND_ASSIGN(TranslateAgent); };
diff --git a/components/viz/common/gpu/context_lost_reason.h b/components/viz/common/gpu/context_lost_reason.h index 9a4ea393..b285d3a4 100644 --- a/components/viz/common/gpu/context_lost_reason.h +++ b/components/viz/common/gpu/context_lost_reason.h
@@ -31,9 +31,10 @@ CONTEXT_LOST_SET_DRAW_RECTANGLE_FAILED = 14, CONTEXT_LOST_DIRECT_COMPOSITION_OVERLAY_FAILED = 15, CONTEXT_LOST_SWAP_FAILED = 16, + CONTEXT_LOST_BEGIN_PAINT_FAILED = 17, // Update kMaxValue here and <enum name="ContextLostReason"> in // tools/metrics/histograms/enum.xml when adding new values. - kMaxValue = CONTEXT_LOST_SWAP_FAILED + kMaxValue = CONTEXT_LOST_BEGIN_PAINT_FAILED }; VIZ_COMMON_EXPORT ContextLostReason
diff --git a/components/viz/service/BUILD.gn b/components/viz/service/BUILD.gn index 701d66d..85a1800 100644 --- a/components/viz/service/BUILD.gn +++ b/components/viz/service/BUILD.gn
@@ -39,6 +39,12 @@ "display/display_damage_tracker.h", "display/display_resource_provider.cc", "display/display_resource_provider.h", + "display/display_resource_provider_gl.cc", + "display/display_resource_provider_gl.h", + "display/display_resource_provider_skia.cc", + "display/display_resource_provider_skia.h", + "display/display_resource_provider_software.cc", + "display/display_resource_provider_software.h", "display/display_scheduler.cc", "display/display_scheduler.h", "display/display_scheduler_base.cc", @@ -61,6 +67,8 @@ "display/gl_renderer_draw_cache.h", "display/layer_quad.cc", "display/layer_quad.h", + "display/null_renderer.cc", + "display/null_renderer.h", "display/output_surface.cc", "display/output_surface.h", "display/output_surface_client.h", @@ -513,7 +521,9 @@ "display/delegated_ink_point_pixel_test_helper.cc", "display/delegated_ink_point_pixel_test_helper.h", "display/display_damage_tracker_unittest.cc", - "display/display_resource_provider_unittest.cc", + "display/display_resource_provider_gl_unittest.cc", + "display/display_resource_provider_skia_unittest.cc", + "display/display_resource_provider_software_unittest.cc", "display/display_scheduler_unittest.cc", "display/display_unittest.cc", "display/draw_polygon_unittest.cc",
diff --git a/components/viz/service/display/display.cc b/components/viz/service/display/display.cc index 8ddbd7fc..8a000558 100644 --- a/components/viz/service/display/display.cc +++ b/components/viz/service/display/display.cc
@@ -30,8 +30,12 @@ #include "components/viz/service/display/damage_frame_annotator.h" #include "components/viz/service/display/direct_renderer.h" #include "components/viz/service/display/display_client.h" +#include "components/viz/service/display/display_resource_provider_gl.h" +#include "components/viz/service/display/display_resource_provider_skia.h" +#include "components/viz/service/display/display_resource_provider_software.h" #include "components/viz/service/display/display_scheduler.h" #include "components/viz/service/display/gl_renderer.h" +#include "components/viz/service/display/null_renderer.h" #include "components/viz/service/display/output_surface.h" #include "components/viz/service/display/renderer_utils.h" #include "components/viz/service/display/skia_output_surface.h" @@ -511,32 +515,43 @@ } void Display::InitializeRenderer(bool enable_shared_images) { - bool uses_gpu_resources = output_surface_->context_provider() || - skia_output_surface_ || - output_surface_->capabilities().skips_draw; - - resource_provider_ = std::make_unique<DisplayResourceProvider>( - uses_gpu_resources ? DisplayResourceProvider::kGpu - : DisplayResourceProvider::kSoftware, - output_surface_->context_provider(), bitmap_manager_, - enable_shared_images); if (skia_output_surface_) { + auto resource_provider = + std::make_unique<DisplayResourceProviderSkia>(bitmap_manager_); renderer_ = std::make_unique<SkiaRenderer>( &settings_, debug_settings_, output_surface_.get(), - resource_provider_.get(), overlay_processor_.get(), + resource_provider.get(), overlay_processor_.get(), skia_output_surface_); + resource_provider_ = std::move(resource_provider); } else if (output_surface_->context_provider()) { + auto resource_provider = std::make_unique<DisplayResourceProviderGL>( + output_surface_->context_provider(), bitmap_manager_, + enable_shared_images); renderer_ = std::make_unique<GLRenderer>( &settings_, debug_settings_, output_surface_.get(), - resource_provider_.get(), overlay_processor_.get(), + resource_provider.get(), overlay_processor_.get(), current_task_runner_); + resource_provider_ = std::move(resource_provider); + } else if (output_surface_->capabilities().skips_draw) { + // We use DisplayResourceProviderGL because the actual resources are gpu + // backed. + auto resource_provider = std::make_unique<DisplayResourceProviderGL>( + output_surface_->context_provider(), bitmap_manager_, + enable_shared_images); + renderer_ = std::make_unique<NullRenderer>( + &settings_, debug_settings_, output_surface_.get(), + resource_provider.get(), overlay_processor_.get()); + resource_provider_ = std::move(resource_provider); } else { + auto resource_provider = + std::make_unique<DisplayResourceProviderSoftware>(bitmap_manager_); DCHECK(!overlay_processor_->IsOverlaySupported()); auto renderer = std::make_unique<SoftwareRenderer>( &settings_, debug_settings_, output_surface_.get(), - resource_provider_.get(), overlay_processor_.get()); + resource_provider.get(), overlay_processor_.get()); software_renderer_ = renderer.get(); renderer_ = std::move(renderer); + resource_provider_ = std::move(resource_provider); } renderer_->Initialize();
diff --git a/components/viz/service/display/display_damage_tracker_unittest.cc b/components/viz/service/display/display_damage_tracker_unittest.cc index d0d0a30..a96a350 100644 --- a/components/viz/service/display/display_damage_tracker_unittest.cc +++ b/components/viz/service/display/display_damage_tracker_unittest.cc
@@ -11,7 +11,7 @@ #include "components/viz/common/quads/compositor_render_pass.h" #include "components/viz/common/surfaces/frame_sink_id.h" #include "components/viz/common/surfaces/parent_local_surface_id_allocator.h" -#include "components/viz/service/display/display_resource_provider.h" +#include "components/viz/service/display/display_resource_provider_software.h" #include "components/viz/service/display/surface_aggregator.h" #include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" #include "components/viz/service/frame_sinks/compositor_frame_sink_support.h" @@ -31,10 +31,7 @@ public: DisplayDamageTrackerTest() : manager_(&shared_bitmap_manager_), - resource_provider_(DisplayResourceProvider::kSoftware, - nullptr, - &shared_bitmap_manager_, - false), + resource_provider_(&shared_bitmap_manager_), aggregator_(manager_.surface_manager(), &resource_provider_, false, @@ -117,7 +114,7 @@ ServerSharedBitmapManager shared_bitmap_manager_; FrameSinkManagerImpl manager_; - DisplayResourceProvider resource_provider_; + DisplayResourceProviderSoftware resource_provider_; SurfaceAggregator aggregator_; Client root_client_; scoped_refptr<base::NullTaskRunner> task_runner_;
diff --git a/components/viz/service/display/display_resource_provider.h b/components/viz/service/display/display_resource_provider.h index dede041..f5d6b08 100644 --- a/components/viz/service/display/display_resource_provider.h +++ b/components/viz/service/display/display_resource_provider.h
@@ -67,12 +67,6 @@ kGpu, kSoftware, }; - // TODO(cblume, crbug.com/900973): |enable_shared_images| is a temporary - // solution that unblocks us until SharedImages are threadsafe in WebView. - DisplayResourceProvider(Mode mode, - ContextProvider* compositor_context_provider, - SharedBitmapManager* shared_bitmap_manager, - bool enable_shared_images = true); ~DisplayResourceProvider() override; DisplayResourceProvider(const DisplayResourceProvider&) = delete; @@ -360,6 +354,14 @@ // WebView it happens only when Android calls us on RenderThread. void SetAllowAccessToGPUThread(bool allow); + protected: + // TODO(cblume, crbug.com/900973): |enable_shared_images| is a temporary + // solution that unblocks us until SharedImages are threadsafe in WebView. + DisplayResourceProvider(Mode mode, + ContextProvider* compositor_context_provider, + SharedBitmapManager* shared_bitmap_manager, + bool enable_shared_images = true); + private: friend class ScopedAllowGpuAccessForDisplayResourceProvider; enum DeleteStyle {
diff --git a/components/viz/service/display/display_resource_provider_gl.cc b/components/viz/service/display/display_resource_provider_gl.cc new file mode 100644 index 0000000..d756fe0 --- /dev/null +++ b/components/viz/service/display/display_resource_provider_gl.cc
@@ -0,0 +1,18 @@ +// Copyright 2021 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 "components/viz/service/display/display_resource_provider_gl.h" + +namespace viz { + +DisplayResourceProviderGL::DisplayResourceProviderGL( + ContextProvider* compositor_context_provider, + SharedBitmapManager* shared_bitmap_manager, + bool enable_shared_images) + : DisplayResourceProvider(DisplayResourceProvider::kGpu, + compositor_context_provider, + shared_bitmap_manager, + enable_shared_images) {} + +} // namespace viz
diff --git a/components/viz/service/display/display_resource_provider_gl.h b/components/viz/service/display/display_resource_provider_gl.h new file mode 100644 index 0000000..0004ba9 --- /dev/null +++ b/components/viz/service/display/display_resource_provider_gl.h
@@ -0,0 +1,24 @@ +// Copyright 2021 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 COMPONENTS_VIZ_SERVICE_DISPLAY_DISPLAY_RESOURCE_PROVIDER_GL_H_ +#define COMPONENTS_VIZ_SERVICE_DISPLAY_DISPLAY_RESOURCE_PROVIDER_GL_H_ + +#include "components/viz/service/display/display_resource_provider.h" +#include "components/viz/service/viz_service_export.h" + +namespace viz { + +// DisplayResourceProvider implementation used with GLRenderer. +class VIZ_SERVICE_EXPORT DisplayResourceProviderGL + : public DisplayResourceProvider { + public: + DisplayResourceProviderGL(ContextProvider* compositor_context_provider, + SharedBitmapManager* shared_bitmap_manager, + bool enable_shared_images = true); +}; + +} // namespace viz + +#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_DISPLAY_RESOURCE_PROVIDER_GL_H_
diff --git a/components/viz/service/display/display_resource_provider_unittest.cc b/components/viz/service/display/display_resource_provider_gl_unittest.cc similarity index 63% rename from components/viz/service/display/display_resource_provider_unittest.cc rename to components/viz/service/display/display_resource_provider_gl_unittest.cc index d0887c6e..54cffae1 100644 --- a/components/viz/service/display/display_resource_provider_unittest.cc +++ b/components/viz/service/display/display_resource_provider_gl_unittest.cc
@@ -1,38 +1,30 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2021 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 "components/viz/service/display/display_resource_provider.h" +#include "components/viz/service/display/display_resource_provider_gl.h" #include <stddef.h> #include <stdint.h> -#include <algorithm> -#include <map> #include <memory> #include <set> #include <unordered_map> +#include <utility> #include <vector> #include "base/bind.h" #include "base/callback_helpers.h" #include "base/check.h" -#include "base/memory/read_only_shared_memory_region.h" #include "base/memory/ref_counted.h" -#include "base/memory/shared_memory_mapping.h" #include "build/build_config.h" -#include "cc/test/render_pass_test_utils.h" -#include "cc/test/resource_provider_test_utils.h" #include "components/viz/client/client_resource_provider.h" -#include "components/viz/common/resources/bitmap_allocation.h" #include "components/viz/common/resources/resource_format_utils.h" #include "components/viz/common/resources/returned_resource.h" -#include "components/viz/common/resources/shared_bitmap.h" #include "components/viz/common/resources/single_release_callback.h" #include "components/viz/service/display/shared_bitmap_manager.h" #include "components/viz/test/test_context_provider.h" #include "components/viz/test/test_gles2_interface.h" -#include "components/viz/test/test_gpu_memory_buffer_manager.h" #include "components/viz/test/test_shared_bitmap_manager.h" #include "gpu/GLES2/gl2extchromium.h" #include "testing/gmock/include/gmock/gmock.h" @@ -40,7 +32,6 @@ #include "third_party/khronos/GLES2/gl2.h" #include "third_party/khronos/GLES2/gl2ext.h" #include "ui/gfx/geometry/rect.h" -#include "ui/gfx/gpu_memory_buffer.h" using testing::_; using testing::ByMove; @@ -62,30 +53,11 @@ return other == sync_token; } -MATCHER_P(SamePtr, ptr_to_expected, "") { - return arg.get() == ptr_to_expected; -} - static void CollectResources(std::vector<ReturnedResource>* array, const std::vector<ReturnedResource>& returned) { array->insert(array->end(), returned.begin(), returned.end()); } -static SharedBitmapId CreateAndFillSharedBitmap(SharedBitmapManager* manager, - const gfx::Size& size, - ResourceFormat format, - uint32_t value) { - SharedBitmapId shared_bitmap_id = SharedBitmap::GenerateId(); - - base::MappedReadOnlyRegion shm = - bitmap_allocation::AllocateSharedBitmap(size, RGBA_8888); - manager->ChildAllocatedSharedBitmap(shm.region.Map(), shared_bitmap_id); - base::span<uint32_t> span = - shm.mapping.GetMemoryAsSpan<uint32_t>(size.GetArea()); - std::fill(span.begin(), span.end(), value); - return shared_bitmap_id; -} - class ResourceProviderGLES2Interface : public TestGLES2Interface { public: ResourceProviderGLES2Interface() = default; @@ -109,77 +81,57 @@ gpu::SyncToken last_waited_sync_token_; }; -class DisplayResourceProviderTest : public testing::TestWithParam<bool> { +class DisplayResourceProviderGLTest : public testing::Test { public: - DisplayResourceProviderTest() : use_gpu_(GetParam()) { - if (use_gpu_) { - auto gl_owned = std::make_unique<ResourceProviderGLES2Interface>(); - gl_ = gl_owned.get(); - context_provider_ = TestContextProvider::Create(std::move(gl_owned)); - context_provider_->UnboundTestContextGL() - ->set_support_texture_format_bgra8888(true); - context_provider_->BindToCurrentThread(); + DisplayResourceProviderGLTest() { + auto gl_owned = std::make_unique<ResourceProviderGLES2Interface>(); + gl_ = gl_owned.get(); + context_provider_ = TestContextProvider::Create(std::move(gl_owned)); + context_provider_->UnboundTestContextGL() + ->set_support_texture_format_bgra8888(true); + context_provider_->BindToCurrentThread(); - child_context_provider_ = TestContextProvider::Create(); - child_context_provider_->UnboundTestContextGL() - ->set_support_texture_format_bgra8888(true); - child_context_provider_->BindToCurrentThread(); - gpu_memory_buffer_manager_ = - std::make_unique<TestGpuMemoryBufferManager>(); - } + child_context_provider_ = TestContextProvider::Create(); + child_context_provider_->UnboundTestContextGL() + ->set_support_texture_format_bgra8888(true); + child_context_provider_->BindToCurrentThread(); + // SharedBitmapManager may always be present, even if gpu compositing. shared_bitmap_manager_ = std::make_unique<TestSharedBitmapManager>(); - resource_provider_ = std::make_unique<DisplayResourceProvider>( - use_gpu_ ? DisplayResourceProvider::kGpu - : DisplayResourceProvider::kSoftware, + resource_provider_ = std::make_unique<DisplayResourceProviderGL>( context_provider_.get(), shared_bitmap_manager_.get()); - MakeChildResourceProvider(); - } - - ~DisplayResourceProviderTest() { - if (child_resource_provider_) - child_resource_provider_->ShutdownAndReleaseAllResources(); - } - - bool use_gpu() const { return use_gpu_; } - - void MakeChildResourceProvider() { child_resource_provider_ = std::make_unique<ClientResourceProvider>(); } + ~DisplayResourceProviderGLTest() override { + child_resource_provider_->ShutdownAndReleaseAllResources(); + } + static ReturnCallback GetReturnCallback( std::vector<ReturnedResource>* array) { return base::BindRepeating(&CollectResources, array); } - static void SetResourceFilter(DisplayResourceProvider* resource_provider, + static void SetResourceFilter(DisplayResourceProviderGL* resource_provider, ResourceId id, GLenum filter) { - DisplayResourceProvider::ScopedSamplerGL sampler(resource_provider, id, - GL_TEXTURE_2D, filter); + DisplayResourceProviderGL::ScopedSamplerGL sampler(resource_provider, id, + GL_TEXTURE_2D, filter); } - TransferableResource CreateResource(ResourceFormat format) { constexpr gfx::Size size(64, 64); - if (use_gpu()) { - gpu::Mailbox gpu_mailbox = gpu::Mailbox::Generate(); - gpu::SyncToken sync_token = GenSyncToken(); - EXPECT_TRUE(sync_token.HasData()); + gpu::Mailbox gpu_mailbox = gpu::Mailbox::Generate(); + gpu::SyncToken sync_token = GenSyncToken(); + EXPECT_TRUE(sync_token.HasData()); - TransferableResource gl_resource = TransferableResource::MakeGL( - gpu_mailbox, GL_LINEAR, GL_TEXTURE_2D, sync_token, size, - false /* is_overlay_candidate */); - gl_resource.format = format; - return gl_resource; - } else { - SharedBitmapId shared_bitmap_id = CreateAndFillSharedBitmap( - shared_bitmap_manager_.get(), size, format, 0); - - return TransferableResource::MakeSoftware(shared_bitmap_id, size, format); - } + TransferableResource gl_resource = TransferableResource::MakeGL( + gpu_mailbox, GL_LINEAR, GL_TEXTURE_2D, sync_token, size, + false /* is_overlay_candidate */); + gl_resource.format = format; + return gl_resource; } ResourceId MakeGpuResourceAndSendToDisplay( @@ -211,224 +163,16 @@ } protected: - const bool use_gpu_; ResourceProviderGLES2Interface* gl_ = nullptr; uint64_t next_fence_sync_ = 1; scoped_refptr<TestContextProvider> context_provider_; scoped_refptr<TestContextProvider> child_context_provider_; - std::unique_ptr<TestGpuMemoryBufferManager> gpu_memory_buffer_manager_; - std::unique_ptr<DisplayResourceProvider> resource_provider_; + std::unique_ptr<DisplayResourceProviderGL> resource_provider_; std::unique_ptr<ClientResourceProvider> child_resource_provider_; std::unique_ptr<TestSharedBitmapManager> shared_bitmap_manager_; }; -INSTANTIATE_TEST_SUITE_P(DisplayResourceProviderTests, - DisplayResourceProviderTest, - ::testing::Values(false, true)); - -class MockExternalUseClient : public ExternalUseClient { - public: - MockExternalUseClient() = default; - MOCK_METHOD1(ReleaseImageContexts, - gpu::SyncToken( - std::vector<std::unique_ptr<ImageContext>> image_contexts)); - MOCK_METHOD6(CreateImageContext, - std::unique_ptr<ImageContext>( - const gpu::MailboxHolder&, - const gfx::Size&, - ResourceFormat, - bool, - const base::Optional<gpu::VulkanYCbCrInfo>& ycbcr_info, - sk_sp<SkColorSpace>)); -}; - -TEST_P(DisplayResourceProviderTest, LockForExternalUse) { - // TODO(penghuang): consider supporting SW mode. - if (!use_gpu()) - return; - - gpu::SyncToken sync_token1(gpu::CommandBufferNamespace::GPU_IO, - gpu::CommandBufferId::FromUnsafeValue(0x123), - 0x42); - auto mailbox = gpu::Mailbox::Generate(); - constexpr gfx::Size size(64, 64); - TransferableResource gl_resource = TransferableResource::MakeGL( - mailbox, GL_LINEAR, GL_TEXTURE_2D, sync_token1, size, - false /* is_overlay_candidate */); - ResourceId id1 = child_resource_provider_->ImportResource( - gl_resource, SingleReleaseCallback::Create(base::DoNothing())); - std::vector<ReturnedResource> returned_to_child; - int child_id = - resource_provider_->CreateChild(GetReturnCallback(&returned_to_child)); - - // Transfer some resources to the parent. - std::vector<TransferableResource> list; - child_resource_provider_->PrepareSendToParent( - {id1}, &list, - static_cast<RasterContextProvider*>(child_context_provider_.get())); - ASSERT_EQ(1u, list.size()); - EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1)); - - resource_provider_->ReceiveFromChild(child_id, list); - - // In DisplayResourceProvider's namespace, use the mapped resource id. - std::unordered_map<ResourceId, ResourceId> resource_map = - resource_provider_->GetChildToParentMap(child_id); - - unsigned parent_id = resource_map[list.front().id]; - - auto owned_image_context = std::make_unique<ExternalUseClient::ImageContext>( - gpu::MailboxHolder(mailbox, sync_token1, GL_TEXTURE_2D), size, RGBA_8888, - /*ycbcr_info=*/base::nullopt, /*color_space=*/nullptr); - auto* image_context = owned_image_context.get(); - - testing::StrictMock<MockExternalUseClient> client; - DisplayResourceProvider::LockSetForExternalUse lock_set( - resource_provider_.get(), &client); - gpu::MailboxHolder holder; - EXPECT_CALL(client, CreateImageContext(_, _, _, _, _, _)) - .WillOnce(DoAll(SaveArg<0>(&holder), - Return(ByMove(std::move(owned_image_context))))); - - ExternalUseClient::ImageContext* locked_image_context = lock_set.LockResource( - parent_id, /*maybe_concurrent_reads=*/true, /*is_video_plane=*/false); - EXPECT_EQ(image_context, locked_image_context); - ASSERT_EQ(holder.mailbox, mailbox); - ASSERT_TRUE(holder.sync_token.HasData()); - - // Don't release while locked. - EXPECT_CALL(client, ReleaseImageContexts(_)).Times(0); - // Return the resources back to the child. Nothing should happen because - // of the resource lock. - resource_provider_->DeclareUsedResourcesFromChild(child_id, ResourceIdSet()); - // The resource should not be returned due to the external use lock. - EXPECT_EQ(0u, returned_to_child.size()); - - gpu::SyncToken sync_token2(gpu::CommandBufferNamespace::GPU_IO, - gpu::CommandBufferId::FromUnsafeValue(0x234), - 0x456); - sync_token2.SetVerifyFlush(); - - gpu::SyncToken sync_token3(gpu::CommandBufferNamespace::GPU_IO, - gpu::CommandBufferId::FromUnsafeValue(0x234), - 0x567); - sync_token3.SetVerifyFlush(); - // We will get a second release of |parent_id| now that we've released our - // external lock. - EXPECT_CALL(client, ReleaseImageContexts( - testing::ElementsAre(SamePtr(locked_image_context)))) - .WillOnce(Return(sync_token3)); - // UnlockResources will also call DeclareUsedResourcesFromChild. - lock_set.UnlockResources(sync_token2); - // The resource should be returned after the lock is released. - EXPECT_EQ(1u, returned_to_child.size()); - EXPECT_EQ(sync_token3, returned_to_child[0].sync_token); - child_resource_provider_->ReceiveReturnsFromParent(returned_to_child); - child_resource_provider_->RemoveImportedResource(id1); -} - -TEST_P(DisplayResourceProviderTest, LockForExternalUseWebView) { - // TODO(penghuang): consider supporting SW mode. - if (!use_gpu()) - return; - - gpu::SyncToken sync_token1(gpu::CommandBufferNamespace::GPU_IO, - gpu::CommandBufferId::FromUnsafeValue(0x123), - 0x42); - auto mailbox = gpu::Mailbox::Generate(); - constexpr gfx::Size size(64, 64); - TransferableResource gl_resource = TransferableResource::MakeGL( - mailbox, GL_LINEAR, GL_TEXTURE_2D, sync_token1, size, - false /* is_overlay_candidate */); - ResourceId id1 = child_resource_provider_->ImportResource( - gl_resource, SingleReleaseCallback::Create(base::DoNothing())); - std::vector<ReturnedResource> returned_to_child; - int child_id = - resource_provider_->CreateChild(GetReturnCallback(&returned_to_child)); - - // Transfer some resources to the parent. - std::vector<TransferableResource> list; - child_resource_provider_->PrepareSendToParent( - {id1}, &list, - static_cast<RasterContextProvider*>(child_context_provider_.get())); - ASSERT_EQ(1u, list.size()); - EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1)); - - resource_provider_->ReceiveFromChild(child_id, list); - - // In DisplayResourceProvider's namespace, use the mapped resource id. - std::unordered_map<ResourceId, ResourceId> resource_map = - resource_provider_->GetChildToParentMap(child_id); - - unsigned parent_id = resource_map[list.front().id]; - - auto owned_image_context = std::make_unique<ExternalUseClient::ImageContext>( - gpu::MailboxHolder(mailbox, sync_token1, GL_TEXTURE_2D), size, RGBA_8888, - /*ycbcr_info=*/base::nullopt, /*color_space=*/nullptr); - auto* image_context = owned_image_context.get(); - - testing::StrictMock<MockExternalUseClient> client; - DisplayResourceProvider::LockSetForExternalUse lock_set( - resource_provider_.get(), &client); - gpu::MailboxHolder holder; - EXPECT_CALL(client, CreateImageContext(_, _, _, _, _, _)) - .WillOnce(DoAll(SaveArg<0>(&holder), - Return(ByMove(std::move(owned_image_context))))); - - ExternalUseClient::ImageContext* locked_image_context = lock_set.LockResource( - parent_id, /*maybe_concurrent_reads=*/true, /*is_video_plane=*/false); - EXPECT_EQ(image_context, locked_image_context); - ASSERT_EQ(holder.mailbox, mailbox); - ASSERT_TRUE(holder.sync_token.HasData()); - - // Don't release while locked. - EXPECT_CALL(client, ReleaseImageContexts(_)).Times(0); - // Return the resources back to the child. Nothing should happen because - // of the resource lock. - resource_provider_->DeclareUsedResourcesFromChild(child_id, ResourceIdSet()); - // The resource should not be returned due to the external use lock. - EXPECT_EQ(0u, returned_to_child.size()); - - // Disable access to gpu thread. - resource_provider_->SetAllowAccessToGPUThread(false); - - gpu::SyncToken sync_token2(gpu::CommandBufferNamespace::GPU_IO, - gpu::CommandBufferId::FromUnsafeValue(0x234), - 0x456); - sync_token2.SetVerifyFlush(); - - gpu::SyncToken sync_token3(gpu::CommandBufferNamespace::GPU_IO, - gpu::CommandBufferId::FromUnsafeValue(0x234), - 0x567); - sync_token3.SetVerifyFlush(); - - // Without GPU thread access no ReleaseImageContexts() should happen - EXPECT_CALL(client, ReleaseImageContexts(_)).Times(0); - // Unlock resources - lock_set.UnlockResources(sync_token2); - // Resources should not be returned because we can't unlock them on GPU - // thread. - EXPECT_EQ(0u, returned_to_child.size()); - - // We will get a second release of |parent_id| now that we've released our - // external lock and have access to GPU thread. - EXPECT_CALL(client, ReleaseImageContexts( - testing::ElementsAre(SamePtr(locked_image_context)))) - .WillOnce(Return(sync_token3)); - // Enable access to GPU Thread - resource_provider_->SetAllowAccessToGPUThread(true); - - // The resource should be returned after the lock is released. - EXPECT_EQ(1u, returned_to_child.size()); - EXPECT_EQ(sync_token3, returned_to_child[0].sync_token); - child_resource_provider_->ReceiveReturnsFromParent(returned_to_child); - child_resource_provider_->RemoveImportedResource(id1); -} - -TEST_P(DisplayResourceProviderTest, ReadLockCountStopsReturnToChildOrDelete) { - if (!use_gpu()) - return; - +TEST_F(DisplayResourceProviderGLTest, ReadLockCountStopsReturnToChildOrDelete) { MockReleaseCallback release; TransferableResource tran = CreateResource(RGBA_8888); ResourceId id1 = child_resource_provider_->ImportResource( @@ -454,8 +198,8 @@ resource_provider_->GetChildToParentMap(child_id); ResourceId mapped_resource_id = resource_map[list[0].id]; resource_provider_->WaitSyncToken(mapped_resource_id); - DisplayResourceProvider::ScopedReadLockGL lock(resource_provider_.get(), - mapped_resource_id); + DisplayResourceProviderGL::ScopedReadLockGL lock(resource_provider_.get(), + mapped_resource_id); resource_provider_->DeclareUsedResourcesFromChild(child_id, ResourceIdSet()); @@ -489,10 +233,7 @@ ~TestFence() override = default; }; -TEST_P(DisplayResourceProviderTest, ReadLockFenceStopsReturnToChildOrDelete) { - if (!use_gpu()) - return; - +TEST_F(DisplayResourceProviderGLTest, ReadLockFenceStopsReturnToChildOrDelete) { MockReleaseCallback release; TransferableResource tran1 = CreateResource(RGBA_8888); tran1.read_lock_fences_enabled = true; @@ -524,8 +265,8 @@ { unsigned parent_id = resource_map[list.front().id]; resource_provider_->WaitSyncToken(parent_id); - DisplayResourceProvider::ScopedReadLockGL lock(resource_provider_.get(), - parent_id); + DisplayResourceProviderGL::ScopedReadLockGL lock(resource_provider_.get(), + parent_id); } resource_provider_->DeclareUsedResourcesFromChild(child_id, ResourceIdSet()); EXPECT_EQ(0u, returned_to_child.size()); @@ -542,10 +283,7 @@ child_resource_provider_->RemoveImportedResource(id1); } -TEST_P(DisplayResourceProviderTest, ReadLockFenceDestroyChild) { - if (!use_gpu()) - return; - +TEST_F(DisplayResourceProviderGLTest, ReadLockFenceDestroyChild) { MockReleaseCallback release; TransferableResource tran1 = CreateResource(RGBA_8888); @@ -582,11 +320,11 @@ scoped_refptr<TestFence> fence(new TestFence); resource_provider_->SetReadLockFence(fence.get()); { - for (size_t i = 0; i < list.size(); i++) { - unsigned parent_id = resource_map[list[i].id]; + for (auto& resource : list) { + unsigned parent_id = resource_map[resource.id]; resource_provider_->WaitSyncToken(parent_id); - DisplayResourceProvider::ScopedReadLockGL lock(resource_provider_.get(), - parent_id); + DisplayResourceProviderGL::ScopedReadLockGL lock(resource_provider_.get(), + parent_id); } } EXPECT_EQ(0u, returned_to_child.size()); @@ -608,10 +346,7 @@ child_resource_provider_->RemoveImportedResource(id2); } -TEST_P(DisplayResourceProviderTest, ReadLockFenceContextLost) { - if (!use_gpu()) - return; - +TEST_F(DisplayResourceProviderGLTest, ReadLockFenceContextLost) { TransferableResource tran1 = CreateResource(RGBA_8888); tran1.read_lock_fences_enabled = true; ResourceId id1 = child_resource_provider_->ImportResource( @@ -644,11 +379,11 @@ scoped_refptr<TestFence> fence(new TestFence); resource_provider_->SetReadLockFence(fence.get()); { - for (size_t i = 0; i < list.size(); i++) { - unsigned parent_id = resource_map[list[i].id]; + for (auto& resource : list) { + unsigned parent_id = resource_map[resource.id]; resource_provider_->WaitSyncToken(parent_id); - DisplayResourceProvider::ScopedReadLockGL lock(resource_provider_.get(), - parent_id); + DisplayResourceProviderGL::ScopedReadLockGL lock(resource_provider_.get(), + parent_id); } } EXPECT_EQ(0u, returned_to_child.size()); @@ -668,10 +403,8 @@ } // Test that ScopedBatchReturnResources batching works. -TEST_P(DisplayResourceProviderTest, ScopedBatchReturnResourcesPreventsReturn) { - if (!use_gpu()) - return; - +TEST_F(DisplayResourceProviderGLTest, + ScopedBatchReturnResourcesPreventsReturn) { MockReleaseCallback release; std::vector<ReturnedResource> returned_to_child; @@ -683,9 +416,9 @@ constexpr size_t kLockedResources = 3; constexpr size_t kUsedResources = 4; ResourceId ids[kTotalResources]; - for (size_t i = 0; i < kTotalResources; i++) { + for (auto& id : ids) { TransferableResource tran = CreateResource(RGBA_8888); - ids[i] = child_resource_provider_->ImportResource( + id = child_resource_provider_->ImportResource( tran, SingleReleaseCallback::Create(base::BindOnce( &MockReleaseCallback::Released, base::Unretained(&release)))); } @@ -704,20 +437,20 @@ // In DisplayResourceProvider's namespace, use the mapped resource id. std::unordered_map<ResourceId, ResourceId> resource_map = resource_provider_->GetChildToParentMap(child_id); - std::vector<std::unique_ptr<DisplayResourceProvider::ScopedReadLockGL>> + std::vector<std::unique_ptr<DisplayResourceProviderGL::ScopedReadLockGL>> read_locks; for (size_t i = 0; i < kLockedResources; i++) { unsigned int mapped_resource_id = resource_map[ids[i]]; resource_provider_->WaitSyncToken(mapped_resource_id); read_locks.push_back( - std::make_unique<DisplayResourceProvider::ScopedReadLockGL>( + std::make_unique<DisplayResourceProviderGL::ScopedReadLockGL>( resource_provider_.get(), mapped_resource_id)); } // Mark all locked resources, and one unlocked resource as used for first // batch. { - DisplayResourceProvider::ScopedBatchReturnResources returner( + DisplayResourceProviderGL::ScopedBatchReturnResources returner( resource_provider_.get()); resource_provider_->DeclareUsedResourcesFromChild( child_id, ResourceIdSet(ids, ids + kUsedResources)); @@ -729,7 +462,7 @@ // Return all locked resources. { - DisplayResourceProvider::ScopedBatchReturnResources returner( + DisplayResourceProviderGL::ScopedBatchReturnResources returner( resource_provider_.get()); resource_provider_->DeclareUsedResourcesFromChild( child_id, ResourceIdSet(ids + kLockedResources, ids + kUsedResources)); @@ -751,7 +484,7 @@ // Returns from destroying the child is also batched. { - DisplayResourceProvider::ScopedBatchReturnResources returner( + DisplayResourceProviderGL::ScopedBatchReturnResources returner( resource_provider_.get()); resource_provider_->DestroyChild(child_id); EXPECT_EQ(0u, returned_to_child.size()); @@ -765,7 +498,7 @@ child_resource_provider_->RemoveImportedResource(id); } -TEST_P(DisplayResourceProviderTest, LostMailboxInParent) { +TEST_F(DisplayResourceProviderGLTest, LostMailboxInParent) { gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO, gpu::CommandBufferId::FromUnsafeValue(0x12), 0x34); auto tran = CreateResource(RGBA_8888); @@ -784,64 +517,7 @@ ASSERT_EQ(1u, returned_to_child.size()); // Losing an output surface only loses hardware resources. - EXPECT_EQ(returned_to_child[0].lost, use_gpu()); -} - -TEST_P(DisplayResourceProviderTest, ReadSoftwareResources) { - if (use_gpu()) - return; - - gfx::Size size(64, 64); - ResourceFormat format = RGBA_8888; - const uint32_t kBadBeef = 0xbadbeef; - SharedBitmapId shared_bitmap_id = CreateAndFillSharedBitmap( - shared_bitmap_manager_.get(), size, format, kBadBeef); - - auto resource = - TransferableResource::MakeSoftware(shared_bitmap_id, size, format); - - MockReleaseCallback release; - ResourceId resource_id = child_resource_provider_->ImportResource( - resource, - SingleReleaseCallback::Create(base::BindOnce( - &MockReleaseCallback::Released, base::Unretained(&release)))); - EXPECT_NE(0u, resource_id); - - // Transfer resources to the parent. - std::vector<TransferableResource> send_to_parent; - std::vector<ReturnedResource> returned_to_child; - int child_id = resource_provider_->CreateChild( - base::BindRepeating(&CollectResources, &returned_to_child)); - child_resource_provider_->PrepareSendToParent( - {resource_id}, &send_to_parent, - static_cast<RasterContextProvider*>(child_context_provider_.get())); - resource_provider_->ReceiveFromChild(child_id, send_to_parent); - - // In DisplayResourceProvider's namespace, use the mapped resource id. - std::unordered_map<ResourceId, ResourceId> resource_map = - resource_provider_->GetChildToParentMap(child_id); - ResourceId mapped_resource_id = resource_map[resource_id]; - - { - DisplayResourceProvider::ScopedReadLockSkImage lock( - resource_provider_.get(), mapped_resource_id); - const SkImage* sk_image = lock.sk_image(); - SkBitmap sk_bitmap; - sk_image->asLegacyBitmap(&sk_bitmap); - EXPECT_EQ(sk_image->width(), size.width()); - EXPECT_EQ(sk_image->height(), size.height()); - EXPECT_EQ(*sk_bitmap.getAddr32(16, 16), kBadBeef); - } - - EXPECT_EQ(0u, returned_to_child.size()); - // Transfer resources back from the parent to the child. Set no resources as - // being in use. - resource_provider_->DeclareUsedResourcesFromChild(child_id, ResourceIdSet()); - EXPECT_EQ(1u, returned_to_child.size()); - child_resource_provider_->ReceiveReturnsFromParent(returned_to_child); - - EXPECT_CALL(release, Released(_, false)); - child_resource_provider_->RemoveImportedResource(resource_id); + EXPECT_EQ(returned_to_child[0].lost, true); } class TextureStateTrackingGLES2Interface : public TestGLES2Interface { @@ -869,9 +545,8 @@ auto context_provider = TestContextProvider::Create(std::move(gl_owned)); context_provider->BindToCurrentThread(); - auto resource_provider = std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kGpu, context_provider.get(), - shared_bitmap_manager); + auto resource_provider = std::make_unique<DisplayResourceProviderGL>( + context_provider.get(), shared_bitmap_manager); auto child_gl_owned = std::make_unique<TextureStateTrackingGLES2Interface>(); @@ -945,7 +620,7 @@ sampler_filter)); } - DisplayResourceProvider::ScopedSamplerGL lock( + DisplayResourceProviderGL::ScopedSamplerGL lock( resource_provider.get(), mapped_resource_id, sampler_filter); testing::Mock::VerifyAndClearExpectations(gl); @@ -972,55 +647,34 @@ } }; -TEST_P(DisplayResourceProviderTest, ReceiveGLTexture2D_LinearToLinear) { - // Mailboxing is only supported for GL textures. - if (!use_gpu()) - return; - +TEST_F(DisplayResourceProviderGLTest, ReceiveGLTexture2D_LinearToLinear) { ResourceProviderTestImportedResourceGLFilters::RunTest( shared_bitmap_manager_.get(), false, GL_LINEAR); } -TEST_P(DisplayResourceProviderTest, ReceiveGLTexture2D_NearestToNearest) { - // Mailboxing is only supported for GL textures. - if (!use_gpu()) - return; - +TEST_F(DisplayResourceProviderGLTest, ReceiveGLTexture2D_NearestToNearest) { ResourceProviderTestImportedResourceGLFilters::RunTest( shared_bitmap_manager_.get(), true, GL_NEAREST); } -TEST_P(DisplayResourceProviderTest, ReceiveGLTexture2D_NearestToLinear) { - // Mailboxing is only supported for GL textures. - if (!use_gpu()) - return; - +TEST_F(DisplayResourceProviderGLTest, ReceiveGLTexture2D_NearestToLinear) { ResourceProviderTestImportedResourceGLFilters::RunTest( shared_bitmap_manager_.get(), true, GL_LINEAR); } -TEST_P(DisplayResourceProviderTest, ReceiveGLTexture2D_LinearToNearest) { - // Mailboxing is only supported for GL textures. - if (!use_gpu()) - return; - +TEST_F(DisplayResourceProviderGLTest, ReceiveGLTexture2D_LinearToNearest) { ResourceProviderTestImportedResourceGLFilters::RunTest( shared_bitmap_manager_.get(), false, GL_NEAREST); } -TEST_P(DisplayResourceProviderTest, ReceiveGLTextureExternalOES) { - // Mailboxing is only supported for GL textures. - if (!use_gpu()) - return; - +TEST_F(DisplayResourceProviderGLTest, ReceiveGLTextureExternalOES) { auto gl_owned = std::make_unique<TextureStateTrackingGLES2Interface>(); TextureStateTrackingGLES2Interface* gl = gl_owned.get(); auto context_provider = TestContextProvider::Create(std::move(gl_owned)); context_provider->BindToCurrentThread(); - auto resource_provider = std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kGpu, context_provider.get(), - shared_bitmap_manager_.get()); + auto resource_provider = std::make_unique<DisplayResourceProviderGL>( + context_provider.get(), shared_bitmap_manager_.get()); auto child_gl_owned = std::make_unique<TextureStateTrackingGLES2Interface>(); TextureStateTrackingGLES2Interface* child_gl = child_gl_owned.get(); @@ -1083,8 +737,8 @@ EXPECT_CALL(*gl, CreateAndConsumeTextureCHROMIUM(_)) .WillOnce(Return(texture_id)); - DisplayResourceProvider::ScopedReadLockGL lock(resource_provider.get(), - mapped_resource_id); + DisplayResourceProviderGL::ScopedReadLockGL lock(resource_provider.get(), + mapped_resource_id); testing::Mock::VerifyAndClearExpectations(gl); // When done with it, a sync point should be inserted, but no produce is @@ -1103,19 +757,14 @@ child_resource_provider->RemoveImportedResource(resource_id); } -TEST_P(DisplayResourceProviderTest, WaitSyncTokenIfNeeded) { - // Mailboxing is only supported for GL textures. - if (!use_gpu()) - return; - +TEST_F(DisplayResourceProviderGLTest, WaitSyncTokenIfNeeded) { auto gl_owned = std::make_unique<TextureStateTrackingGLES2Interface>(); TextureStateTrackingGLES2Interface* gl = gl_owned.get(); auto context_provider = TestContextProvider::Create(std::move(gl_owned)); context_provider->BindToCurrentThread(); - auto resource_provider = std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kGpu, context_provider.get(), - shared_bitmap_manager_.get()); + auto resource_provider = std::make_unique<DisplayResourceProviderGL>( + context_provider.get(), shared_bitmap_manager_.get()); EXPECT_CALL(*gl, BindTexture(_, _)).Times(0); EXPECT_CALL(*gl, WaitSyncTokenCHROMIUM(_)).Times(0); @@ -1147,10 +796,7 @@ } #if defined(OS_ANDROID) -TEST_P(DisplayResourceProviderTest, OverlayPromotionHint) { - if (!use_gpu()) - return; - +TEST_F(DisplayResourceProviderGLTest, OverlayPromotionHint) { gpu::Mailbox external_mailbox = gpu::Mailbox::Generate(); gpu::SyncToken external_sync_token = GenSyncToken(); EXPECT_TRUE(external_sync_token.HasData()); @@ -1196,8 +842,8 @@ EXPECT_FALSE(resource_provider_->DoAnyResourcesWantPromotionHints()); { resource_provider_->WaitSyncToken(mapped_id1); - DisplayResourceProvider::ScopedReadLockGL lock(resource_provider_.get(), - mapped_id1); + DisplayResourceProviderGL::ScopedReadLockGL lock(resource_provider_.get(), + mapped_id1); } EXPECT_EQ(1u, resource_provider_->CountPromotionHintRequestsForTesting()); EXPECT_TRUE(resource_provider_->DoAnyResourcesWantPromotionHints());
diff --git a/components/viz/service/display/display_resource_provider_skia.cc b/components/viz/service/display/display_resource_provider_skia.cc new file mode 100644 index 0000000..2528cad --- /dev/null +++ b/components/viz/service/display/display_resource_provider_skia.cc
@@ -0,0 +1,16 @@ +// Copyright 2021 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 "components/viz/service/display/display_resource_provider_skia.h" + +namespace viz { + +DisplayResourceProviderSkia::DisplayResourceProviderSkia( + SharedBitmapManager* shared_bitmap_manager) + : DisplayResourceProvider(DisplayResourceProvider::kGpu, + /*compositor_context_provider=*/nullptr, + shared_bitmap_manager, + /*enable_shared_images=*/true) {} + +} // namespace viz
diff --git a/components/viz/service/display/display_resource_provider_skia.h b/components/viz/service/display/display_resource_provider_skia.h new file mode 100644 index 0000000..6e799996 --- /dev/null +++ b/components/viz/service/display/display_resource_provider_skia.h
@@ -0,0 +1,23 @@ +// Copyright 2021 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 COMPONENTS_VIZ_SERVICE_DISPLAY_DISPLAY_RESOURCE_PROVIDER_SKIA_H_ +#define COMPONENTS_VIZ_SERVICE_DISPLAY_DISPLAY_RESOURCE_PROVIDER_SKIA_H_ + +#include "components/viz/service/display/display_resource_provider.h" +#include "components/viz/service/viz_service_export.h" + +namespace viz { + +// DisplayResourceProvider implementation used with SkiaRenderer. +class VIZ_SERVICE_EXPORT DisplayResourceProviderSkia + : public DisplayResourceProvider { + public: + explicit DisplayResourceProviderSkia( + SharedBitmapManager* shared_bitmap_manager); +}; + +} // namespace viz + +#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_DISPLAY_RESOURCE_PROVIDER_SKIA_H_
diff --git a/components/viz/service/display/display_resource_provider_skia_unittest.cc b/components/viz/service/display/display_resource_provider_skia_unittest.cc new file mode 100644 index 0000000..4041aee --- /dev/null +++ b/components/viz/service/display/display_resource_provider_skia_unittest.cc
@@ -0,0 +1,690 @@ +// Copyright 2021 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 "components/viz/service/display/display_resource_provider_skia.h" + +#include <stddef.h> +#include <stdint.h> + +#include <memory> +#include <set> +#include <unordered_map> +#include <utility> +#include <vector> + +#include "base/bind.h" +#include "base/callback_helpers.h" +#include "base/check.h" +#include "base/memory/ref_counted.h" +#include "base/optional.h" +#include "build/build_config.h" +#include "components/viz/client/client_resource_provider.h" +#include "components/viz/common/resources/returned_resource.h" +#include "components/viz/common/resources/single_release_callback.h" +#include "components/viz/service/display/shared_bitmap_manager.h" +#include "components/viz/test/test_context_provider.h" +#include "components/viz/test/test_shared_bitmap_manager.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/khronos/GLES2/gl2.h" +#include "ui/gfx/geometry/rect.h" + +using testing::_; +using testing::ByMove; +using testing::DoAll; +using testing::Return; +using testing::SaveArg; + +namespace viz { +namespace { + +class MockReleaseCallback { + public: + MOCK_METHOD2(Released, void(const gpu::SyncToken& token, bool lost)); +}; + +MATCHER_P(SamePtr, ptr_to_expected, "") { + return arg.get() == ptr_to_expected; +} + +static void CollectResources(std::vector<ReturnedResource>* array, + const std::vector<ReturnedResource>& returned) { + array->insert(array->end(), returned.begin(), returned.end()); +} + +class MockExternalUseClient : public ExternalUseClient { + public: + MockExternalUseClient() = default; + MOCK_METHOD1(ReleaseImageContexts, + gpu::SyncToken( + std::vector<std::unique_ptr<ImageContext>> image_contexts)); + MOCK_METHOD6(CreateImageContext, + std::unique_ptr<ImageContext>( + const gpu::MailboxHolder&, + const gfx::Size&, + ResourceFormat, + bool, + const base::Optional<gpu::VulkanYCbCrInfo>& ycbcr_info, + sk_sp<SkColorSpace>)); +}; + +class DisplayResourceProviderSkiaTest : public testing::Test { + public: + DisplayResourceProviderSkiaTest() { + child_context_provider_ = TestContextProvider::Create(); + child_context_provider_->BindToCurrentThread(); + + // SharedBitmapManager may always be present, even if gpu compositing. + shared_bitmap_manager_ = std::make_unique<TestSharedBitmapManager>(); + + resource_provider_ = std::make_unique<DisplayResourceProviderSkia>( + shared_bitmap_manager_.get()); + + lock_set_.emplace(resource_provider_.get(), &client_); + + child_resource_provider_ = std::make_unique<ClientResourceProvider>(); + } + + ~DisplayResourceProviderSkiaTest() override { + child_resource_provider_->ShutdownAndReleaseAllResources(); + } + + static ReturnCallback GetReturnCallback( + std::vector<ReturnedResource>* array) { + return base::BindRepeating(&CollectResources, array); + } + + TransferableResource CreateResource(ResourceFormat format) { + constexpr gfx::Size size(64, 64); + gpu::Mailbox gpu_mailbox = gpu::Mailbox::GenerateForSharedImage(); + gpu::SyncToken sync_token = GenSyncToken(); + EXPECT_TRUE(sync_token.HasData()); + + TransferableResource gl_resource = TransferableResource::MakeGL( + gpu_mailbox, GL_LINEAR, GL_TEXTURE_2D, sync_token, size, + false /* is_overlay_candidate */); + gl_resource.format = format; + return gl_resource; + } + + gpu::SyncToken GenSyncToken() { + gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO, + gpu::CommandBufferId::FromUnsafeValue(0x123), + next_fence_sync_++); + sync_token.SetVerifyFlush(); + return sync_token; + } + + protected: + uint64_t next_fence_sync_ = 1; + scoped_refptr<TestContextProvider> child_context_provider_; + std::unique_ptr<DisplayResourceProviderSkia> resource_provider_; + std::unique_ptr<ClientResourceProvider> child_resource_provider_; + std::unique_ptr<TestSharedBitmapManager> shared_bitmap_manager_; + testing::NiceMock<MockExternalUseClient> client_; + base::Optional<DisplayResourceProviderSkia::LockSetForExternalUse> lock_set_; +}; + +TEST_F(DisplayResourceProviderSkiaTest, LockForExternalUse) { + gpu::SyncToken sync_token1(gpu::CommandBufferNamespace::GPU_IO, + gpu::CommandBufferId::FromUnsafeValue(0x123), + 0x42); + auto mailbox = gpu::Mailbox::Generate(); + constexpr gfx::Size size(64, 64); + TransferableResource gl_resource = TransferableResource::MakeGL( + mailbox, GL_LINEAR, GL_TEXTURE_2D, sync_token1, size, + false /* is_overlay_candidate */); + ResourceId id1 = child_resource_provider_->ImportResource( + gl_resource, SingleReleaseCallback::Create(base::DoNothing())); + std::vector<ReturnedResource> returned_to_child; + int child_id = + resource_provider_->CreateChild(GetReturnCallback(&returned_to_child)); + + // Transfer some resources to the parent. + std::vector<TransferableResource> list; + child_resource_provider_->PrepareSendToParent( + {id1}, &list, + static_cast<RasterContextProvider*>(child_context_provider_.get())); + ASSERT_EQ(1u, list.size()); + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1)); + + resource_provider_->ReceiveFromChild(child_id, list); + + // In DisplayResourceProvider's namespace, use the mapped resource id. + std::unordered_map<ResourceId, ResourceId> resource_map = + resource_provider_->GetChildToParentMap(child_id); + + unsigned parent_id = resource_map[list.front().id]; + + auto owned_image_context = std::make_unique<ExternalUseClient::ImageContext>( + gpu::MailboxHolder(mailbox, sync_token1, GL_TEXTURE_2D), size, RGBA_8888, + /*ycbcr_info=*/base::nullopt, /*color_space=*/nullptr); + auto* image_context = owned_image_context.get(); + + gpu::MailboxHolder holder; + EXPECT_CALL(client_, CreateImageContext(_, _, _, _, _, _)) + .WillOnce(DoAll(SaveArg<0>(&holder), + Return(ByMove(std::move(owned_image_context))))); + + ExternalUseClient::ImageContext* locked_image_context = + lock_set_->LockResource(parent_id, /*maybe_concurrent_reads=*/true, + /*is_video_plane=*/false); + EXPECT_EQ(image_context, locked_image_context); + ASSERT_EQ(holder.mailbox, mailbox); + ASSERT_TRUE(holder.sync_token.HasData()); + + // Don't release while locked. + EXPECT_CALL(client_, ReleaseImageContexts(_)).Times(0); + // Return the resources back to the child. Nothing should happen because + // of the resource lock. + resource_provider_->DeclareUsedResourcesFromChild(child_id, ResourceIdSet()); + // The resource should not be returned due to the external use lock. + EXPECT_EQ(0u, returned_to_child.size()); + + gpu::SyncToken sync_token2(gpu::CommandBufferNamespace::GPU_IO, + gpu::CommandBufferId::FromUnsafeValue(0x234), + 0x456); + sync_token2.SetVerifyFlush(); + + gpu::SyncToken sync_token3(gpu::CommandBufferNamespace::GPU_IO, + gpu::CommandBufferId::FromUnsafeValue(0x234), + 0x567); + sync_token3.SetVerifyFlush(); + // We will get a second release of |parent_id| now that we've released our + // external lock. + EXPECT_CALL(client_, ReleaseImageContexts( + testing::ElementsAre(SamePtr(locked_image_context)))) + .WillOnce(Return(sync_token3)); + // UnlockResources will also call DeclareUsedResourcesFromChild. + lock_set_->UnlockResources(sync_token2); + // The resource should be returned after the lock is released. + EXPECT_EQ(1u, returned_to_child.size()); + EXPECT_EQ(sync_token3, returned_to_child[0].sync_token); + child_resource_provider_->ReceiveReturnsFromParent(returned_to_child); + child_resource_provider_->RemoveImportedResource(id1); +} + +TEST_F(DisplayResourceProviderSkiaTest, LockForExternalUseWebView) { + gpu::SyncToken sync_token1(gpu::CommandBufferNamespace::GPU_IO, + gpu::CommandBufferId::FromUnsafeValue(0x123), + 0x42); + auto mailbox = gpu::Mailbox::Generate(); + constexpr gfx::Size size(64, 64); + TransferableResource gl_resource = TransferableResource::MakeGL( + mailbox, GL_LINEAR, GL_TEXTURE_2D, sync_token1, size, + false /* is_overlay_candidate */); + ResourceId id1 = child_resource_provider_->ImportResource( + gl_resource, SingleReleaseCallback::Create(base::DoNothing())); + std::vector<ReturnedResource> returned_to_child; + int child_id = + resource_provider_->CreateChild(GetReturnCallback(&returned_to_child)); + + // Transfer some resources to the parent. + std::vector<TransferableResource> list; + child_resource_provider_->PrepareSendToParent( + {id1}, &list, + static_cast<RasterContextProvider*>(child_context_provider_.get())); + ASSERT_EQ(1u, list.size()); + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1)); + + resource_provider_->ReceiveFromChild(child_id, list); + + // In DisplayResourceProvider's namespace, use the mapped resource id. + std::unordered_map<ResourceId, ResourceId> resource_map = + resource_provider_->GetChildToParentMap(child_id); + + unsigned parent_id = resource_map[list.front().id]; + + auto owned_image_context = std::make_unique<ExternalUseClient::ImageContext>( + gpu::MailboxHolder(mailbox, sync_token1, GL_TEXTURE_2D), size, RGBA_8888, + /*ycbcr_info=*/base::nullopt, /*color_space=*/nullptr); + auto* image_context = owned_image_context.get(); + + gpu::MailboxHolder holder; + EXPECT_CALL(client_, CreateImageContext(_, _, _, _, _, _)) + .WillOnce(DoAll(SaveArg<0>(&holder), + Return(ByMove(std::move(owned_image_context))))); + + ExternalUseClient::ImageContext* locked_image_context = + lock_set_->LockResource(parent_id, /*maybe_concurrent_reads=*/true, + /*is_video_plane=*/false); + EXPECT_EQ(image_context, locked_image_context); + ASSERT_EQ(holder.mailbox, mailbox); + ASSERT_TRUE(holder.sync_token.HasData()); + + // Don't release while locked. + EXPECT_CALL(client_, ReleaseImageContexts(_)).Times(0); + // Return the resources back to the child. Nothing should happen because + // of the resource lock. + resource_provider_->DeclareUsedResourcesFromChild(child_id, ResourceIdSet()); + // The resource should not be returned due to the external use lock. + EXPECT_EQ(0u, returned_to_child.size()); + + // Disable access to gpu thread. + resource_provider_->SetAllowAccessToGPUThread(false); + + gpu::SyncToken sync_token2(gpu::CommandBufferNamespace::GPU_IO, + gpu::CommandBufferId::FromUnsafeValue(0x234), + 0x456); + sync_token2.SetVerifyFlush(); + + gpu::SyncToken sync_token3(gpu::CommandBufferNamespace::GPU_IO, + gpu::CommandBufferId::FromUnsafeValue(0x234), + 0x567); + sync_token3.SetVerifyFlush(); + + // Without GPU thread access no ReleaseImageContexts() should happen + EXPECT_CALL(client_, ReleaseImageContexts(_)).Times(0); + // Unlock resources + lock_set_->UnlockResources(sync_token2); + // Resources should not be returned because we can't unlock them on GPU + // thread. + EXPECT_EQ(0u, returned_to_child.size()); + + // We will get a second release of |parent_id| now that we've released our + // external lock and have access to GPU thread. + EXPECT_CALL(client_, ReleaseImageContexts( + testing::ElementsAre(SamePtr(locked_image_context)))) + .WillOnce(Return(sync_token3)); + // Enable access to GPU Thread + resource_provider_->SetAllowAccessToGPUThread(true); + + // The resource should be returned after the lock is released. + EXPECT_EQ(1u, returned_to_child.size()); + EXPECT_EQ(sync_token3, returned_to_child[0].sync_token); + child_resource_provider_->ReceiveReturnsFromParent(returned_to_child); + child_resource_provider_->RemoveImportedResource(id1); +} + +class TestFence : public ResourceFence { + public: + TestFence() = default; + + // ResourceFence implementation. + void Set() override {} + bool HasPassed() override { return passed; } + + bool passed = false; + + private: + ~TestFence() override = default; +}; + +TEST_F(DisplayResourceProviderSkiaTest, + ReadLockFenceStopsReturnToChildOrDelete) { + MockReleaseCallback release; + TransferableResource tran1 = CreateResource(RGBA_8888); + tran1.read_lock_fences_enabled = true; + ResourceId id1 = child_resource_provider_->ImportResource( + tran1, SingleReleaseCallback::Create(base::BindOnce( + &MockReleaseCallback::Released, base::Unretained(&release)))); + + std::vector<ReturnedResource> returned_to_child; + int child_id = + resource_provider_->CreateChild(GetReturnCallback(&returned_to_child)); + + // Transfer some resources to the parent. + std::vector<TransferableResource> list; + child_resource_provider_->PrepareSendToParent( + {id1}, &list, + static_cast<RasterContextProvider*>(child_context_provider_.get())); + ASSERT_EQ(1u, list.size()); + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1)); + EXPECT_TRUE(list[0].read_lock_fences_enabled); + + resource_provider_->ReceiveFromChild(child_id, list); + + // In DisplayResourceProvider's namespace, use the mapped resource id. + std::unordered_map<ResourceId, ResourceId> resource_map = + resource_provider_->GetChildToParentMap(child_id); + + scoped_refptr<TestFence> fence(new TestFence); + resource_provider_->SetReadLockFence(fence.get()); + { + unsigned parent_id = resource_map[list.front().id]; + lock_set_->LockResource(parent_id, /*maybe_concurrent_reads=*/true, + /*is_video_plane=*/false); + lock_set_->UnlockResources(GenSyncToken()); + } + resource_provider_->DeclareUsedResourcesFromChild(child_id, ResourceIdSet()); + EXPECT_EQ(0u, returned_to_child.size()); + + resource_provider_->DeclareUsedResourcesFromChild(child_id, ResourceIdSet()); + EXPECT_EQ(0u, returned_to_child.size()); + fence->passed = true; + + resource_provider_->DeclareUsedResourcesFromChild(child_id, ResourceIdSet()); + EXPECT_EQ(1u, returned_to_child.size()); + + child_resource_provider_->ReceiveReturnsFromParent(returned_to_child); + EXPECT_CALL(release, Released(_, _)); + child_resource_provider_->RemoveImportedResource(id1); +} + +TEST_F(DisplayResourceProviderSkiaTest, ReadLockFenceDestroyChild) { + MockReleaseCallback release; + + TransferableResource tran1 = CreateResource(RGBA_8888); + tran1.read_lock_fences_enabled = true; + ResourceId id1 = child_resource_provider_->ImportResource( + tran1, SingleReleaseCallback::Create(base::BindOnce( + &MockReleaseCallback::Released, base::Unretained(&release)))); + + TransferableResource tran2 = CreateResource(RGBA_8888); + tran2.read_lock_fences_enabled = false; + ResourceId id2 = child_resource_provider_->ImportResource( + tran2, SingleReleaseCallback::Create(base::BindOnce( + &MockReleaseCallback::Released, base::Unretained(&release)))); + + std::vector<ReturnedResource> returned_to_child; + int child_id = + resource_provider_->CreateChild(GetReturnCallback(&returned_to_child)); + + // Transfer resources to the parent. + std::vector<TransferableResource> list; + child_resource_provider_->PrepareSendToParent( + {id1, id2}, &list, + static_cast<RasterContextProvider*>(child_context_provider_.get())); + ASSERT_EQ(2u, list.size()); + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1)); + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2)); + + resource_provider_->ReceiveFromChild(child_id, list); + + // In DisplayResourceProvider's namespace, use the mapped resource id. + std::unordered_map<ResourceId, ResourceId> resource_map = + resource_provider_->GetChildToParentMap(child_id); + + scoped_refptr<TestFence> fence(new TestFence); + resource_provider_->SetReadLockFence(fence.get()); + { + for (auto& resource : list) { + unsigned parent_id = resource_map[resource.id]; + lock_set_->LockResource(parent_id, /*maybe_concurrent_reads=*/true, + /*is_video_plane=*/false); + } + lock_set_->UnlockResources(GenSyncToken()); + } + EXPECT_EQ(0u, returned_to_child.size()); + + EXPECT_EQ(2u, resource_provider_->num_resources()); + + resource_provider_->DestroyChild(child_id); + + EXPECT_EQ(0u, resource_provider_->num_resources()); + EXPECT_EQ(2u, returned_to_child.size()); + + // id1 should be lost and id2 should not. + EXPECT_EQ(returned_to_child[0].lost, returned_to_child[0].id == id1); + EXPECT_EQ(returned_to_child[1].lost, returned_to_child[1].id == id1); + + child_resource_provider_->ReceiveReturnsFromParent(returned_to_child); + EXPECT_CALL(release, Released(_, _)).Times(2); + child_resource_provider_->RemoveImportedResource(id1); + child_resource_provider_->RemoveImportedResource(id2); +} + +TEST_F(DisplayResourceProviderSkiaTest, ReadLockFenceContextLost) { + TransferableResource tran1 = CreateResource(RGBA_8888); + tran1.read_lock_fences_enabled = true; + ResourceId id1 = child_resource_provider_->ImportResource( + tran1, SingleReleaseCallback::Create(base::DoNothing())); + + TransferableResource tran2 = CreateResource(RGBA_8888); + tran2.read_lock_fences_enabled = false; + ResourceId id2 = child_resource_provider_->ImportResource( + tran2, SingleReleaseCallback::Create(base::DoNothing())); + + std::vector<ReturnedResource> returned_to_child; + int child_id = + resource_provider_->CreateChild(GetReturnCallback(&returned_to_child)); + + // Transfer resources to the parent. + std::vector<TransferableResource> list; + child_resource_provider_->PrepareSendToParent( + {id1, id2}, &list, + static_cast<RasterContextProvider*>(child_context_provider_.get())); + ASSERT_EQ(2u, list.size()); + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1)); + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2)); + + resource_provider_->ReceiveFromChild(child_id, list); + + // In DisplayResourceProvider's namespace, use the mapped resource id. + std::unordered_map<ResourceId, ResourceId> resource_map = + resource_provider_->GetChildToParentMap(child_id); + + scoped_refptr<TestFence> fence(new TestFence); + resource_provider_->SetReadLockFence(fence.get()); + { + for (auto& resource : list) { + unsigned parent_id = resource_map[resource.id]; + DisplayResourceProvider::ScopedReadLockSharedImage lock( + resource_provider_.get(), parent_id); + } + } + EXPECT_EQ(0u, returned_to_child.size()); + + EXPECT_EQ(2u, resource_provider_->num_resources()); + resource_provider_->DidLoseContextProvider(); + resource_provider_ = nullptr; + + EXPECT_EQ(2u, returned_to_child.size()); + + EXPECT_TRUE(returned_to_child[0].lost); + EXPECT_TRUE(returned_to_child[1].lost); + + child_resource_provider_->ReceiveReturnsFromParent(returned_to_child); + child_resource_provider_->RemoveImportedResource(id1); + child_resource_provider_->RemoveImportedResource(id2); +} + +// Test that ScopedBatchReturnResources batching works. +TEST_F(DisplayResourceProviderSkiaTest, + ScopedBatchReturnResourcesPreventsReturn) { + MockReleaseCallback release; + + std::vector<ReturnedResource> returned_to_child; + int child_id = + resource_provider_->CreateChild(GetReturnCallback(&returned_to_child)); + + // Transfer some resources to the parent. + constexpr size_t kTotalResources = 5; + constexpr size_t kLockedResources = 3; + constexpr size_t kUsedResources = 4; + ResourceId ids[kTotalResources]; + for (auto& id : ids) { + TransferableResource tran = CreateResource(RGBA_8888); + id = child_resource_provider_->ImportResource( + tran, SingleReleaseCallback::Create(base::BindOnce( + &MockReleaseCallback::Released, base::Unretained(&release)))); + } + std::vector<ResourceId> resource_ids_to_transfer(ids, ids + kTotalResources); + + std::vector<TransferableResource> list; + child_resource_provider_->PrepareSendToParent( + resource_ids_to_transfer, &list, + static_cast<RasterContextProvider*>(child_context_provider_.get())); + ASSERT_EQ(kTotalResources, list.size()); + for (const auto& id : ids) + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id)); + + resource_provider_->ReceiveFromChild(child_id, list); + + // In DisplayResourceProvider's namespace, use the mapped resource id. + std::unordered_map<ResourceId, ResourceId> resource_map = + resource_provider_->GetChildToParentMap(child_id); + std::vector< + std::unique_ptr<DisplayResourceProvider::ScopedReadLockSharedImage>> + read_locks; + for (size_t i = 0; i < kLockedResources; i++) { + unsigned int mapped_resource_id = resource_map[ids[i]]; + lock_set_->LockResource(mapped_resource_id, /*maybe_concurrent_reads=*/true, + /*is_video_plane=*/false); + } + + // Mark all locked resources, and one unlocked resource as used for first + // batch. + { + DisplayResourceProvider::ScopedBatchReturnResources returner( + resource_provider_.get()); + resource_provider_->DeclareUsedResourcesFromChild( + child_id, ResourceIdSet(ids, ids + kUsedResources)); + EXPECT_EQ(0u, returned_to_child.size()); + } + EXPECT_EQ(1u, returned_to_child.size()); + child_resource_provider_->ReceiveReturnsFromParent(returned_to_child); + returned_to_child.clear(); + + // Return all locked resources. + { + DisplayResourceProvider::ScopedBatchReturnResources returner( + resource_provider_.get()); + resource_provider_->DeclareUsedResourcesFromChild( + child_id, ResourceIdSet(ids + kLockedResources, ids + kUsedResources)); + // Can be called multiple times while batching is enabled. This happens in + // practice when the same surface is visited using different paths during + // surface aggregation. + resource_provider_->DeclareUsedResourcesFromChild( + child_id, ResourceIdSet(ids + kLockedResources, ids + kUsedResources)); + lock_set_->UnlockResources(GenSyncToken()); + EXPECT_EQ(0u, returned_to_child.size()); + } + EXPECT_EQ(kLockedResources, returned_to_child.size()); + // Returned resources that were locked share the same sync token. + for (const auto& resource : returned_to_child) + EXPECT_EQ(resource.sync_token, returned_to_child[0].sync_token); + + child_resource_provider_->ReceiveReturnsFromParent(returned_to_child); + returned_to_child.clear(); + + // Returns from destroying the child is also batched. + { + DisplayResourceProvider::ScopedBatchReturnResources returner( + resource_provider_.get()); + resource_provider_->DestroyChild(child_id); + EXPECT_EQ(0u, returned_to_child.size()); + } + EXPECT_EQ(1u, returned_to_child.size()); + child_resource_provider_->ReceiveReturnsFromParent(returned_to_child); + returned_to_child.clear(); + + EXPECT_CALL(release, Released(_, _)).Times(kTotalResources); + for (const auto& id : ids) + child_resource_provider_->RemoveImportedResource(id); +} // namespace + +TEST_F(DisplayResourceProviderSkiaTest, LostMailboxInParent) { + gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO, + gpu::CommandBufferId::FromUnsafeValue(0x12), 0x34); + auto tran = CreateResource(RGBA_8888); + tran.id = 11; + + std::vector<ReturnedResource> returned_to_child; + int child_id = resource_provider_->CreateChild( + base::BindRepeating(&CollectResources, &returned_to_child)); + + // Receive a resource then lose the gpu context. + resource_provider_->ReceiveFromChild(child_id, {tran}); + resource_provider_->DidLoseContextProvider(); + + // Transfer resources back from the parent to the child. + resource_provider_->DeclareUsedResourcesFromChild(child_id, {}); + ASSERT_EQ(1u, returned_to_child.size()); + + // Losing an output surface only loses hardware resources. + EXPECT_EQ(returned_to_child[0].lost, true); +} + +#if defined(OS_ANDROID) +TEST_F(DisplayResourceProviderSkiaTest, OverlayPromotionHint) { + gpu::Mailbox external_mailbox = gpu::Mailbox::GenerateForSharedImage(); + gpu::SyncToken external_sync_token = GenSyncToken(); + EXPECT_TRUE(external_sync_token.HasData()); + + TransferableResource id1_transfer = TransferableResource::MakeGL( + external_mailbox, GL_LINEAR, GL_TEXTURE_EXTERNAL_OES, external_sync_token, + gfx::Size(1, 1), true); + id1_transfer.wants_promotion_hint = true; + id1_transfer.is_backed_by_surface_texture = true; + ResourceId id1 = child_resource_provider_->ImportResource( + id1_transfer, SingleReleaseCallback::Create(base::DoNothing())); + + TransferableResource id2_transfer = TransferableResource::MakeGL( + external_mailbox, GL_LINEAR, GL_TEXTURE_EXTERNAL_OES, external_sync_token, + gfx::Size(1, 1), true); + id2_transfer.wants_promotion_hint = false; + id2_transfer.is_backed_by_surface_texture = false; + ResourceId id2 = child_resource_provider_->ImportResource( + id2_transfer, SingleReleaseCallback::Create(base::DoNothing())); + + std::vector<ReturnedResource> returned_to_child; + int child_id = + resource_provider_->CreateChild(GetReturnCallback(&returned_to_child)); + + // Transfer some resources to the parent. + std::vector<TransferableResource> list; + child_resource_provider_->PrepareSendToParent( + {id1, id2}, &list, + static_cast<RasterContextProvider*>(child_context_provider_.get())); + ASSERT_EQ(2u, list.size()); + resource_provider_->ReceiveFromChild(child_id, list); + std::unordered_map<ResourceId, ResourceId> resource_map = + resource_provider_->GetChildToParentMap(child_id); + ResourceId mapped_id1 = resource_map[list[0].id]; + ResourceId mapped_id2 = resource_map[list[1].id]; + + // The promotion hints should not be recorded until after we wait. This is + // because we can't notify them until they're synchronized, and we choose to + // ignore unwaited resources rather than send them a "no" hint. If they end + // up in the request set before we wait, then the attempt to notify them wil; + // DCHECK when we try to lock them for reading in SendPromotionHints. + EXPECT_EQ(0u, resource_provider_->CountPromotionHintRequestsForTesting()); + EXPECT_FALSE(resource_provider_->DoAnyResourcesWantPromotionHints()); + { + resource_provider_->InitializePromotionHintRequest(mapped_id1); + DisplayResourceProvider::ScopedReadLockSharedImage lock( + resource_provider_.get(), mapped_id1); + } + EXPECT_EQ(1u, resource_provider_->CountPromotionHintRequestsForTesting()); + EXPECT_TRUE(resource_provider_->DoAnyResourcesWantPromotionHints()); + + ResourceIdSet resource_ids_to_receive; + resource_ids_to_receive.insert(id1); + resource_ids_to_receive.insert(id2); + resource_provider_->DeclareUsedResourcesFromChild(child_id, + resource_ids_to_receive); + + EXPECT_EQ(2u, resource_provider_->num_resources()); + + EXPECT_NE(0u, mapped_id1); + EXPECT_NE(0u, mapped_id2); + + // Make sure that the request for a promotion hint was noticed. + EXPECT_TRUE(resource_provider_->IsOverlayCandidate(mapped_id1)); + EXPECT_TRUE(resource_provider_->IsBackedBySurfaceTexture(mapped_id1)); + EXPECT_TRUE(resource_provider_->DoesResourceWantPromotionHint(mapped_id1)); + + EXPECT_TRUE(resource_provider_->IsOverlayCandidate(mapped_id2)); + EXPECT_FALSE(resource_provider_->IsBackedBySurfaceTexture(mapped_id2)); + EXPECT_FALSE(resource_provider_->DoesResourceWantPromotionHint(mapped_id2)); + + // ResourceProvider maintains a set of promotion hint requests that should be + // cleared when resources are deleted. + resource_provider_->DeclareUsedResourcesFromChild(child_id, ResourceIdSet()); + EXPECT_EQ(2u, returned_to_child.size()); + child_resource_provider_->ReceiveReturnsFromParent(returned_to_child); + + EXPECT_EQ(0u, resource_provider_->CountPromotionHintRequestsForTesting()); + EXPECT_FALSE(resource_provider_->DoAnyResourcesWantPromotionHints()); + + resource_provider_->DestroyChild(child_id); + + child_resource_provider_->RemoveImportedResource(id2); + child_resource_provider_->RemoveImportedResource(id1); +} +#endif + +} // namespace +} // namespace viz
diff --git a/components/viz/service/display/display_resource_provider_software.cc b/components/viz/service/display/display_resource_provider_software.cc new file mode 100644 index 0000000..01147557 --- /dev/null +++ b/components/viz/service/display/display_resource_provider_software.cc
@@ -0,0 +1,16 @@ +// Copyright 2021 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 "components/viz/service/display/display_resource_provider_software.h" + +namespace viz { + +DisplayResourceProviderSoftware::DisplayResourceProviderSoftware( + SharedBitmapManager* shared_bitmap_manager) + : DisplayResourceProvider(DisplayResourceProvider::kSoftware, + /*compositor_context_provider=*/nullptr, + shared_bitmap_manager, + /*enable_shared_images=*/true) {} + +} // namespace viz
diff --git a/components/viz/service/display/display_resource_provider_software.h b/components/viz/service/display/display_resource_provider_software.h new file mode 100644 index 0000000..eb1ce88 --- /dev/null +++ b/components/viz/service/display/display_resource_provider_software.h
@@ -0,0 +1,23 @@ +// Copyright 2021 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 COMPONENTS_VIZ_SERVICE_DISPLAY_DISPLAY_RESOURCE_PROVIDER_SOFTWARE_H_ +#define COMPONENTS_VIZ_SERVICE_DISPLAY_DISPLAY_RESOURCE_PROVIDER_SOFTWARE_H_ + +#include "components/viz/service/display/display_resource_provider.h" +#include "components/viz/service/viz_service_export.h" + +namespace viz { + +// DisplayResourceProvider implementation used with SoftwareRenderer. +class VIZ_SERVICE_EXPORT DisplayResourceProviderSoftware + : public DisplayResourceProvider { + public: + explicit DisplayResourceProviderSoftware( + SharedBitmapManager* shared_bitmap_manager); +}; + +} // namespace viz + +#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_DISPLAY_RESOURCE_PROVIDER_SOFTWARE_H_
diff --git a/components/viz/service/display/display_resource_provider_software_unittest.cc b/components/viz/service/display/display_resource_provider_software_unittest.cc new file mode 100644 index 0000000..8a966ac --- /dev/null +++ b/components/viz/service/display/display_resource_provider_software_unittest.cc
@@ -0,0 +1,175 @@ +// Copyright 2021 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 "components/viz/service/display/display_resource_provider_software.h" + +#include <stddef.h> +#include <stdint.h> + +#include <memory> +#include <set> +#include <unordered_map> +#include <utility> +#include <vector> + +#include "base/bind.h" +#include "base/callback_helpers.h" +#include "base/check.h" +#include "base/memory/read_only_shared_memory_region.h" +#include "base/memory/ref_counted.h" +#include "base/memory/shared_memory_mapping.h" +#include "build/build_config.h" +#include "components/viz/client/client_resource_provider.h" +#include "components/viz/common/resources/bitmap_allocation.h" +#include "components/viz/common/resources/resource_format_utils.h" +#include "components/viz/common/resources/returned_resource.h" +#include "components/viz/common/resources/shared_bitmap.h" +#include "components/viz/common/resources/single_release_callback.h" +#include "components/viz/service/display/shared_bitmap_manager.h" +#include "components/viz/test/test_shared_bitmap_manager.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/geometry/rect.h" + +using testing::_; +using testing::ByMove; +using testing::DoAll; +using testing::Return; +using testing::SaveArg; + +namespace viz { +namespace { + +class MockReleaseCallback { + public: + MOCK_METHOD2(Released, void(const gpu::SyncToken& token, bool lost)); +}; + +static void CollectResources(std::vector<ReturnedResource>* array, + const std::vector<ReturnedResource>& returned) { + array->insert(array->end(), returned.begin(), returned.end()); +} + +static SharedBitmapId CreateAndFillSharedBitmap(SharedBitmapManager* manager, + const gfx::Size& size, + ResourceFormat format, + uint32_t value) { + SharedBitmapId shared_bitmap_id = SharedBitmap::GenerateId(); + + base::MappedReadOnlyRegion shm = + bitmap_allocation::AllocateSharedBitmap(size, RGBA_8888); + manager->ChildAllocatedSharedBitmap(shm.region.Map(), shared_bitmap_id); + base::span<uint32_t> span = + shm.mapping.GetMemoryAsSpan<uint32_t>(size.GetArea()); + std::fill(span.begin(), span.end(), value); + return shared_bitmap_id; +} + +class DisplayResourceProviderSoftwareTest : public testing::Test { + public: + DisplayResourceProviderSoftwareTest() { + shared_bitmap_manager_ = std::make_unique<TestSharedBitmapManager>(); + + resource_provider_ = std::make_unique<DisplayResourceProviderSoftware>( + shared_bitmap_manager_.get()); + + child_resource_provider_ = std::make_unique<ClientResourceProvider>(); + } + + ~DisplayResourceProviderSoftwareTest() override { + child_resource_provider_->ShutdownAndReleaseAllResources(); + } + + TransferableResource CreateResource(ResourceFormat format) { + constexpr gfx::Size size(64, 64); + SharedBitmapId shared_bitmap_id = CreateAndFillSharedBitmap( + shared_bitmap_manager_.get(), size, format, 0); + + return TransferableResource::MakeSoftware(shared_bitmap_id, size, format); + } + + protected: + std::unique_ptr<DisplayResourceProviderSoftware> resource_provider_; + std::unique_ptr<ClientResourceProvider> child_resource_provider_; + std::unique_ptr<TestSharedBitmapManager> shared_bitmap_manager_; +}; + +TEST_F(DisplayResourceProviderSoftwareTest, LostMailboxInParent) { + gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO, + gpu::CommandBufferId::FromUnsafeValue(0x12), 0x34); + auto tran = CreateResource(RGBA_8888); + tran.id = 11; + + std::vector<ReturnedResource> returned_to_child; + int child_id = resource_provider_->CreateChild( + base::BindRepeating(&CollectResources, &returned_to_child)); + + // Receive a resource then lose the gpu context. + resource_provider_->ReceiveFromChild(child_id, {tran}); + resource_provider_->DidLoseContextProvider(); + + // Transfer resources back from the parent to the child. + resource_provider_->DeclareUsedResourcesFromChild(child_id, {}); + ASSERT_EQ(1u, returned_to_child.size()); + + // Losing an output surface only loses hardware resources. + EXPECT_EQ(returned_to_child[0].lost, false); +} + +TEST_F(DisplayResourceProviderSoftwareTest, ReadSoftwareResources) { + gfx::Size size(64, 64); + ResourceFormat format = RGBA_8888; + const uint32_t kBadBeef = 0xbadbeef; + SharedBitmapId shared_bitmap_id = CreateAndFillSharedBitmap( + shared_bitmap_manager_.get(), size, format, kBadBeef); + + auto resource = + TransferableResource::MakeSoftware(shared_bitmap_id, size, format); + + MockReleaseCallback release; + ResourceId resource_id = child_resource_provider_->ImportResource( + resource, + SingleReleaseCallback::Create(base::BindOnce( + &MockReleaseCallback::Released, base::Unretained(&release)))); + EXPECT_NE(0u, resource_id); + + // Transfer resources to the parent. + std::vector<TransferableResource> send_to_parent; + std::vector<ReturnedResource> returned_to_child; + int child_id = resource_provider_->CreateChild( + base::BindRepeating(&CollectResources, &returned_to_child)); + child_resource_provider_->PrepareSendToParent( + {resource_id}, &send_to_parent, + static_cast<RasterContextProvider*>(nullptr)); + resource_provider_->ReceiveFromChild(child_id, send_to_parent); + + // In DisplayResourceProvider's namespace, use the mapped resource id. + std::unordered_map<ResourceId, ResourceId> resource_map = + resource_provider_->GetChildToParentMap(child_id); + ResourceId mapped_resource_id = resource_map[resource_id]; + + { + DisplayResourceProviderSoftware::ScopedReadLockSkImage lock( + resource_provider_.get(), mapped_resource_id); + const SkImage* sk_image = lock.sk_image(); + SkBitmap sk_bitmap; + sk_image->asLegacyBitmap(&sk_bitmap); + EXPECT_EQ(sk_image->width(), size.width()); + EXPECT_EQ(sk_image->height(), size.height()); + EXPECT_EQ(*sk_bitmap.getAddr32(16, 16), kBadBeef); + } + + EXPECT_EQ(0u, returned_to_child.size()); + // Transfer resources back from the parent to the child. Set no resources as + // being in use. + resource_provider_->DeclareUsedResourcesFromChild(child_id, ResourceIdSet()); + EXPECT_EQ(1u, returned_to_child.size()); + child_resource_provider_->ReceiveReturnsFromParent(returned_to_child); + + EXPECT_CALL(release, Released(_, false)); + child_resource_provider_->RemoveImportedResource(resource_id); +} + +} // namespace +} // namespace viz
diff --git a/components/viz/service/display/display_scheduler_unittest.cc b/components/viz/service/display/display_scheduler_unittest.cc index 4271f4c..1d18f5a 100644 --- a/components/viz/service/display/display_scheduler_unittest.cc +++ b/components/viz/service/display/display_scheduler_unittest.cc
@@ -4,6 +4,10 @@ #include "components/viz/service/display/display_scheduler.h" +#include <set> +#include <utility> +#include <vector> + #include "base/check.h" #include "base/stl_util.h" #include "base/test/null_task_runner.h" @@ -13,6 +17,7 @@ #include "components/viz/common/frame_sinks/begin_frame_args.h" #include "components/viz/common/surfaces/surface_info.h" #include "components/viz/service/display/display.h" +#include "components/viz/service/display/display_resource_provider_software.h" #include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" #include "components/viz/test/begin_frame_args_test.h" #include "components/viz/test/fake_external_begin_frame_source.h" @@ -154,10 +159,7 @@ : fake_begin_frame_source_(0.f, false), task_runner_(new base::NullTaskRunner), surface_manager_(nullptr, 4u), - resource_provider_(DisplayResourceProvider::kSoftware, - nullptr, - &shared_bitmap_manager_, - false), + resource_provider_(&shared_bitmap_manager_), aggregator_(&surface_manager_, &resource_provider_, false, false), damage_tracker_( std::make_unique<TestDisplayDamageTracker>(&surface_manager_, @@ -216,7 +218,7 @@ scoped_refptr<base::NullTaskRunner> task_runner_; SurfaceManager surface_manager_; ServerSharedBitmapManager shared_bitmap_manager_; - DisplayResourceProvider resource_provider_; + DisplayResourceProviderSoftware resource_provider_; SurfaceAggregator aggregator_; std::unique_ptr<TestDisplayDamageTracker> damage_tracker_; FakeDisplaySchedulerClient client_;
diff --git a/components/viz/service/display/gl_renderer_unittest.cc b/components/viz/service/display/gl_renderer_unittest.cc index 372bb83b..d2798eeb 100644 --- a/components/viz/service/display/gl_renderer_unittest.cc +++ b/components/viz/service/display/gl_renderer_unittest.cc
@@ -34,7 +34,7 @@ #include "components/viz/common/quads/texture_draw_quad.h" #include "components/viz/common/resources/platform_color.h" #include "components/viz/common/resources/transferable_resource.h" -#include "components/viz/service/display/display_resource_provider.h" +#include "components/viz/service/display/display_resource_provider_gl.h" #include "components/viz/test/fake_output_surface.h" #include "components/viz/test/test_gles2_interface.h" #include "components/viz/test/test_shared_bitmap_manager.h" @@ -621,7 +621,7 @@ FakeRendererGL(const RendererSettings* settings, const DebugRendererSettings* debug_settings, OutputSurface* output_surface, - DisplayResourceProvider* resource_provider) + DisplayResourceProviderGL* resource_provider) : GLRenderer(settings, debug_settings, output_surface, @@ -632,7 +632,7 @@ FakeRendererGL(const RendererSettings* settings, const DebugRendererSettings* debug_settings, OutputSurface* output_surface, - DisplayResourceProvider* resource_provider, + DisplayResourceProviderGL* resource_provider, OverlayProcessorInterface* overlay_processor) : GLRenderer(settings, debug_settings, @@ -645,7 +645,7 @@ const RendererSettings* settings, const DebugRendererSettings* debug_settings, OutputSurface* output_surface, - DisplayResourceProvider* resource_provider, + DisplayResourceProviderGL* resource_provider, OverlayProcessorInterface* overlay_processor, scoped_refptr<base::SingleThreadTaskRunner> current_task_runner) : GLRenderer(settings, @@ -668,9 +668,8 @@ output_surface_->BindToClient(&output_surface_client_); shared_bitmap_manager_ = std::make_unique<TestSharedBitmapManager>(); - resource_provider_ = std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kGpu, output_surface_->context_provider(), - shared_bitmap_manager_.get()); + resource_provider_ = std::make_unique<DisplayResourceProviderGL>( + output_surface_->context_provider(), shared_bitmap_manager_.get()); renderer_ = std::make_unique<FakeRendererGL>(&settings_, &debug_settings_, output_surface_.get(), resource_provider_.get()); @@ -684,7 +683,7 @@ cc::FakeOutputSurfaceClient output_surface_client_; std::unique_ptr<FakeOutputSurface> output_surface_; std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_; - std::unique_ptr<DisplayResourceProvider> resource_provider_; + std::unique_ptr<DisplayResourceProviderGL> resource_provider_; std::unique_ptr<FakeRendererGL> renderer_; }; @@ -700,12 +699,11 @@ output_surface_->BindToClient(&output_surface_client_); shared_bitmap_manager_ = std::make_unique<TestSharedBitmapManager>(); - resource_provider_ = std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kGpu, output_surface_->context_provider(), - shared_bitmap_manager_.get()); - renderer_.reset(new FakeRendererGL(&settings_, &debug_settings_, - output_surface_.get(), - resource_provider_.get(), nullptr)); + resource_provider_ = std::make_unique<DisplayResourceProviderGL>( + output_surface_->context_provider(), shared_bitmap_manager_.get()); + renderer_ = std::make_unique<FakeRendererGL>( + &settings_, &debug_settings_, output_surface_.get(), + resource_provider_.get(), nullptr); renderer_->Initialize(); renderer_->SetVisible(true); @@ -805,7 +803,7 @@ cc::FakeOutputSurfaceClient output_surface_client_; std::unique_ptr<FakeOutputSurface> output_surface_; std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_; - std::unique_ptr<DisplayResourceProvider> resource_provider_; + std::unique_ptr<DisplayResourceProviderGL> resource_provider_; scoped_refptr<TestContextProvider> child_context_provider_; std::unique_ptr<ClientResourceProvider> child_resource_provider_; std::unique_ptr<FakeRendererGL> renderer_; @@ -1154,10 +1152,8 @@ std::unique_ptr<SharedBitmapManager> shared_bitmap_manager = std::make_unique<TestSharedBitmapManager>(); - std::unique_ptr<DisplayResourceProvider> resource_provider = - std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kGpu, output_surface->context_provider(), - shared_bitmap_manager.get()); + auto resource_provider = std::make_unique<DisplayResourceProviderGL>( + output_surface->context_provider(), shared_bitmap_manager.get()); RendererSettings settings; FakeRendererGL renderer(&settings, &debug_settings_, output_surface.get(), @@ -1193,10 +1189,8 @@ std::unique_ptr<SharedBitmapManager> shared_bitmap_manager = std::make_unique<TestSharedBitmapManager>(); - std::unique_ptr<DisplayResourceProvider> resource_provider = - std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kGpu, output_surface->context_provider(), - shared_bitmap_manager.get()); + auto resource_provider = std::make_unique<DisplayResourceProviderGL>( + output_surface->context_provider(), shared_bitmap_manager.get()); RendererSettings settings; FakeRendererGL renderer(&settings, &debug_settings_, output_surface.get(), @@ -1230,10 +1224,8 @@ std::unique_ptr<SharedBitmapManager> shared_bitmap_manager = std::make_unique<TestSharedBitmapManager>(); - std::unique_ptr<DisplayResourceProvider> resource_provider = - std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kGpu, output_surface->context_provider(), - shared_bitmap_manager.get()); + auto resource_provider = std::make_unique<DisplayResourceProviderGL>( + output_surface->context_provider(), shared_bitmap_manager.get()); RendererSettings settings; FakeRendererGL renderer(&settings, &debug_settings_, output_surface.get(), @@ -1276,10 +1268,8 @@ std::unique_ptr<SharedBitmapManager> shared_bitmap_manager = std::make_unique<TestSharedBitmapManager>(); - std::unique_ptr<DisplayResourceProvider> resource_provider = - std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kGpu, output_surface->context_provider(), - shared_bitmap_manager.get()); + auto resource_provider = std::make_unique<DisplayResourceProviderGL>( + output_surface->context_provider(), shared_bitmap_manager.get()); RendererSettings settings; FakeRendererGL renderer(&settings, &debug_settings_, output_surface.get(), @@ -1315,10 +1305,8 @@ std::unique_ptr<SharedBitmapManager> shared_bitmap_manager = std::make_unique<TestSharedBitmapManager>(); - std::unique_ptr<DisplayResourceProvider> resource_provider = - std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kGpu, output_surface->context_provider(), - shared_bitmap_manager.get()); + auto resource_provider = std::make_unique<DisplayResourceProviderGL>( + output_surface->context_provider(), shared_bitmap_manager.get()); RendererSettings settings; FakeRendererGL renderer(&settings, &debug_settings_, output_surface.get(), @@ -1386,10 +1374,8 @@ std::unique_ptr<SharedBitmapManager> shared_bitmap_manager = std::make_unique<TestSharedBitmapManager>(); - std::unique_ptr<DisplayResourceProvider> resource_provider = - std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kGpu, output_surface->context_provider(), - shared_bitmap_manager.get()); + auto resource_provider = std::make_unique<DisplayResourceProviderGL>( + output_surface->context_provider(), shared_bitmap_manager.get()); RendererSettings settings; FakeRendererGL renderer(&settings, &debug_settings_, output_surface.get(), @@ -1509,10 +1495,8 @@ std::unique_ptr<SharedBitmapManager> shared_bitmap_manager = std::make_unique<TestSharedBitmapManager>(); - std::unique_ptr<DisplayResourceProvider> resource_provider = - std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kGpu, output_surface->context_provider(), - shared_bitmap_manager.get()); + auto resource_provider = std::make_unique<DisplayResourceProviderGL>( + output_surface->context_provider(), shared_bitmap_manager.get()); RendererSettings settings; FakeRendererGL renderer(&settings, &debug_settings_, output_surface.get(), @@ -1582,10 +1566,8 @@ std::unique_ptr<SharedBitmapManager> shared_bitmap_manager = std::make_unique<TestSharedBitmapManager>(); - std::unique_ptr<DisplayResourceProvider> resource_provider = - std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kGpu, output_surface->context_provider(), - shared_bitmap_manager.get()); + auto resource_provider = std::make_unique<DisplayResourceProviderGL>( + output_surface->context_provider(), shared_bitmap_manager.get()); RendererSettings settings; settings.should_clear_root_render_pass = false; @@ -1692,10 +1674,8 @@ std::unique_ptr<SharedBitmapManager> shared_bitmap_manager = std::make_unique<TestSharedBitmapManager>(); - std::unique_ptr<DisplayResourceProvider> resource_provider = - std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kGpu, output_surface->context_provider(), - shared_bitmap_manager.get()); + auto resource_provider = std::make_unique<DisplayResourceProviderGL>( + output_surface->context_provider(), shared_bitmap_manager.get()); RendererSettings settings; FakeRendererGL renderer(&settings, &debug_settings_, output_surface.get(), @@ -1766,10 +1746,8 @@ std::unique_ptr<SharedBitmapManager> shared_bitmap_manager = std::make_unique<TestSharedBitmapManager>(); - std::unique_ptr<DisplayResourceProvider> resource_provider = - std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kGpu, output_surface->context_provider(), - shared_bitmap_manager.get()); + auto resource_provider = std::make_unique<DisplayResourceProviderGL>( + output_surface->context_provider(), shared_bitmap_manager.get()); RendererSettings settings; settings.partial_swap_enabled = true; @@ -1980,10 +1958,8 @@ std::unique_ptr<SharedBitmapManager> shared_bitmap_manager = std::make_unique<TestSharedBitmapManager>(); - std::unique_ptr<DisplayResourceProvider> resource_provider = - std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kGpu, output_surface->context_provider(), - shared_bitmap_manager.get()); + auto resource_provider = std::make_unique<DisplayResourceProviderGL>( + output_surface->context_provider(), shared_bitmap_manager.get()); { RendererSettings settings; @@ -2028,9 +2004,8 @@ output_surface_->BindToClient(&output_surface_client_); shared_bitmap_manager_ = std::make_unique<TestSharedBitmapManager>(); - resource_provider_ = std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kGpu, output_surface_->context_provider(), - shared_bitmap_manager_.get()); + resource_provider_ = std::make_unique<DisplayResourceProviderGL>( + output_surface_->context_provider(), shared_bitmap_manager_.get()); settings_.partial_swap_enabled = true; renderer_ = std::make_unique<FakeRendererGL>(&settings_, &debug_settings_, output_surface_.get(), @@ -2062,7 +2037,7 @@ cc::FakeOutputSurfaceClient output_surface_client_; std::unique_ptr<FakeOutputSurface> output_surface_; std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_; - std::unique_ptr<DisplayResourceProvider> resource_provider_; + std::unique_ptr<DisplayResourceProviderGL> resource_provider_; std::unique_ptr<FakeRendererGL> renderer_; }; @@ -2158,10 +2133,8 @@ std::unique_ptr<SharedBitmapManager> shared_bitmap_manager = std::make_unique<TestSharedBitmapManager>(); - std::unique_ptr<DisplayResourceProvider> resource_provider = - std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kGpu, output_surface->context_provider(), - shared_bitmap_manager.get()); + auto resource_provider = std::make_unique<DisplayResourceProviderGL>( + output_surface->context_provider(), shared_bitmap_manager.get()); RendererSettings settings; FakeRendererGL renderer(&settings, &debug_settings_, output_surface.get(), @@ -2532,9 +2505,8 @@ output_surface_->BindToClient(&output_surface_client_); shared_bitmap_manager_ = std::make_unique<TestSharedBitmapManager>(); - resource_provider_ = std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kGpu, output_surface_->context_provider(), - shared_bitmap_manager_.get()); + resource_provider_ = std::make_unique<DisplayResourceProviderGL>( + output_surface_->context_provider(), shared_bitmap_manager_.get()); renderer_.reset(new FakeRendererGL(&settings_, &debug_settings_, output_surface_.get(), @@ -2585,7 +2557,7 @@ OutputSurfaceMockGLES2Interface* gl_ = nullptr; std::unique_ptr<StrictMock<MockOutputSurface>> output_surface_; std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_; - std::unique_ptr<DisplayResourceProvider> resource_provider_; + std::unique_ptr<DisplayResourceProviderGL> resource_provider_; std::unique_ptr<FakeRendererGL> renderer_; }; @@ -2765,9 +2737,8 @@ std::unique_ptr<SharedBitmapManager> shared_bitmap_manager = std::make_unique<TestSharedBitmapManager>(); - auto parent_resource_provider = std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kGpu, output_surface->context_provider(), - shared_bitmap_manager.get()); + auto parent_resource_provider = std::make_unique<DisplayResourceProviderGL>( + output_surface->context_provider(), shared_bitmap_manager.get()); auto child_context_provider = TestContextProvider::Create(); child_context_provider->BindToCurrentThread(); @@ -2975,9 +2946,8 @@ std::unique_ptr<SharedBitmapManager> shared_bitmap_manager = std::make_unique<TestSharedBitmapManager>(); - auto parent_resource_provider = std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kGpu, output_surface->context_provider(), - shared_bitmap_manager.get()); + auto parent_resource_provider = std::make_unique<DisplayResourceProviderGL>( + output_surface->context_provider(), shared_bitmap_manager.get()); auto child_context_provider = TestContextProvider::Create(); child_context_provider->BindToCurrentThread(); @@ -3096,10 +3066,9 @@ FakeOutputSurface::Create3d(std::move(provider))); cc::FakeOutputSurfaceClient output_surface_client; output_surface->BindToClient(&output_surface_client); - std::unique_ptr<DisplayResourceProvider> resource_provider = - std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kGpu, output_surface->context_provider(), - nullptr); + std::unique_ptr<DisplayResourceProviderGL> resource_provider = + std::make_unique<DisplayResourceProviderGL>( + output_surface->context_provider(), nullptr); RendererSettings settings; FakeRendererGL renderer(&settings, &debug_settings_, output_surface.get(), resource_provider.get()); @@ -3183,10 +3152,8 @@ FakeOutputSurface::Create3d(std::move(provider))); cc::FakeOutputSurfaceClient output_surface_client; output_surface->BindToClient(&output_surface_client); - std::unique_ptr<DisplayResourceProvider> resource_provider = - std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kGpu, output_surface->context_provider(), - nullptr); + auto resource_provider = std::make_unique<DisplayResourceProviderGL>( + output_surface->context_provider(), nullptr); RendererSettings settings; FakeRendererGL renderer(&settings, &debug_settings_, output_surface.get(), resource_provider.get()); @@ -3246,9 +3213,8 @@ output_surface_ = FakeOutputSurface::Create3d(std::move(provider)); output_surface_->BindToClient(&output_surface_client_); - resource_provider_ = std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kGpu, output_surface_->context_provider(), - nullptr); + resource_provider_ = std::make_unique<DisplayResourceProviderGL>( + output_surface_->context_provider(), nullptr); settings_.partial_swap_enabled = true; settings_.slow_down_compositing_scale_factor = 1; @@ -3330,7 +3296,7 @@ FastSolidColorMockGLES2Interface* gl_ = nullptr; std::unique_ptr<FakeRendererGL> fake_renderer_; std::unique_ptr<FakeOutputSurface> output_surface_; - std::unique_ptr<DisplayResourceProvider> resource_provider_; + std::unique_ptr<DisplayResourceProviderGL> resource_provider_; cc::FakeOutputSurfaceClient output_surface_client_; RendererSettings settings_; base::test::ScopedFeatureList feature_list_; @@ -3605,10 +3571,8 @@ output_surface->set_supports_dc_layers(set_draw_rectangle); output_surface->BindToClient(&output_surface_client); - std::unique_ptr<DisplayResourceProvider> resource_provider = - std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kGpu, output_surface->context_provider(), - nullptr); + auto resource_provider = std::make_unique<DisplayResourceProviderGL>( + output_surface->context_provider(), nullptr); RendererSettings settings; settings.partial_swap_enabled = partial_swap; @@ -3764,9 +3728,8 @@ output_surface->set_supports_dc_layers(true); output_surface->BindToClient(&output_surface_client); - auto parent_resource_provider = std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kGpu, output_surface->context_provider(), - nullptr); + auto parent_resource_provider = std::make_unique<DisplayResourceProviderGL>( + output_surface->context_provider(), nullptr); auto child_context_provider = TestContextProvider::Create(); child_context_provider->BindToCurrentThread(); @@ -3888,9 +3851,8 @@ gpu::ContextResult::kSuccess); output_surface_ = FakeOutputSurface::Create3d(std::move(context_provider)); output_surface_->BindToClient(&output_surface_client_); - resource_provider_ = std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kGpu, output_surface_->context_provider(), - nullptr); + resource_provider_ = std::make_unique<DisplayResourceProviderGL>( + output_surface_->context_provider(), nullptr); renderer_ = std::make_unique<GLRenderer>( &settings_, &debug_settings_, output_surface_.get(), resource_provider_.get(), nullptr, nullptr); @@ -3902,7 +3864,7 @@ cc::FakeOutputSurfaceClient output_surface_client_; MockContextSupport* context_support_ptr_; std::unique_ptr<OutputSurface> output_surface_; - std::unique_ptr<DisplayResourceProvider> resource_provider_; + std::unique_ptr<DisplayResourceProviderGL> resource_provider_; std::unique_ptr<GLRenderer> renderer_; }; @@ -4019,10 +3981,8 @@ FakeOutputSurface::Create3d(std::move(provider))); output_surface->BindToClient(&output_surface_client); - std::unique_ptr<DisplayResourceProvider> resource_provider = - std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kGpu, output_surface->context_provider(), - nullptr); + auto resource_provider = std::make_unique<DisplayResourceProviderGL>( + output_surface->context_provider(), nullptr); RendererSettings settings; auto processor = @@ -4111,9 +4071,8 @@ output_surface_ = FakeOutputSurface::Create3d(std::move(provider)); output_surface_->BindToClient(&output_surface_client); - display_resource_provider_ = std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kGpu, output_surface_->context_provider(), - nullptr); + display_resource_provider_ = std::make_unique<DisplayResourceProviderGL>( + output_surface_->context_provider(), nullptr); settings_ = std::make_unique<RendererSettings>(); // This setting is enabled to use CALayer overlays. @@ -4160,7 +4119,7 @@ private: MockCALayerGLES2Interface* gl_; std::unique_ptr<FakeOutputSurface> output_surface_; - std::unique_ptr<DisplayResourceProvider> display_resource_provider_; + std::unique_ptr<DisplayResourceProviderGL> display_resource_provider_; std::unique_ptr<RendererSettings> settings_; std::unique_ptr<OverlayProcessorInterface> overlay_processor_; std::unique_ptr<FakeRendererGL> renderer_; @@ -5018,7 +4977,7 @@ FramebufferWatchingGLRenderer(RendererSettings* settings, const DebugRendererSettings* debug_settings, OutputSurface* output_surface, - DisplayResourceProvider* resource_provider) + DisplayResourceProviderGL* resource_provider) : FakeRendererGL(settings, debug_settings, output_surface, @@ -5060,10 +5019,8 @@ auto output_surface = FakeOutputSurface::Create3d(std::move(provider)); output_surface->BindToClient(&output_surface_client); - std::unique_ptr<DisplayResourceProvider> resource_provider = - std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kGpu, output_surface->context_provider(), - nullptr); + auto resource_provider = std::make_unique<DisplayResourceProviderGL>( + output_surface->context_provider(), nullptr); for (int i = 0; i < 2; ++i) { bool use_partial_swap = i == 0; @@ -5162,9 +5119,8 @@ output_surface_ = FakeOutputSurface::Create3d(std::move(provider)); output_surface_->set_overlay_texture_id(kSurfaceOverlayTextureId); output_surface_->set_gpu_fence_id(kGpuFenceId); - resource_provider_ = std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kGpu, output_surface_->context_provider(), - nullptr); + resource_provider_ = std::make_unique<DisplayResourceProviderGL>( + output_surface_->context_provider(), nullptr); overlay_processor_ = std::make_unique<SingleOverlayOnTopProcessor>(); overlay_processor_->AllowMultipleCandidates(); renderer_ = std::make_unique<FakeRendererGL>( @@ -5210,7 +5166,7 @@ cc::FakeOutputSurfaceClient output_surface_client_; std::unique_ptr<FakeOutputSurface> output_surface_; - std::unique_ptr<DisplayResourceProvider> resource_provider_; + std::unique_ptr<DisplayResourceProviderGL> resource_provider_; scoped_refptr<TestContextProvider> child_context_provider_; std::unique_ptr<ClientResourceProvider> child_resource_provider_; RendererSettings settings_;
diff --git a/components/viz/service/display/null_renderer.cc b/components/viz/service/display/null_renderer.cc new file mode 100644 index 0000000..7534c40 --- /dev/null +++ b/components/viz/service/display/null_renderer.cc
@@ -0,0 +1,56 @@ +// Copyright 2021 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 "components/viz/service/display/null_renderer.h" + +#include "base/notreached.h" +#include "components/viz/common/frame_sinks/copy_output_request.h" +#include "components/viz/service/display/output_surface.h" + +namespace viz { + +NullRenderer::NullRenderer(const RendererSettings* settings, + const DebugRendererSettings* debug_settings, + OutputSurface* output_surface, + DisplayResourceProvider* resource_provider, + OverlayProcessorInterface* overlay_processor) + : DirectRenderer(settings, + debug_settings, + output_surface, + resource_provider, + overlay_processor) { + DCHECK(output_surface->capabilities().skips_draw); +} +NullRenderer::~NullRenderer() = default; + +void NullRenderer::SwapBuffers(SwapFrameData swap_frame_data) { + NOTREACHED(); +} +void NullRenderer::BeginDrawingFrame() { + NOTREACHED(); +} + +bool NullRenderer::CanPartialSwap() { + return false; +} + +bool NullRenderer::IsRenderPassResourceAllocated( + const AggregatedRenderPassId& render_pass_id) const { + return false; +} + +gfx::Size NullRenderer::GetRenderPassBackingPixelSize( + const AggregatedRenderPassId& render_pass_id) { + return gfx::Size(); +} + +bool NullRenderer::FlippedFramebuffer() const { + return false; +} + +void NullRenderer::CopyDrawnRenderPass( + const copy_output::RenderPassGeometry& geometry, + std::unique_ptr<CopyOutputRequest> request) {} + +} // namespace viz
diff --git a/components/viz/service/display/null_renderer.h b/components/viz/service/display/null_renderer.h new file mode 100644 index 0000000..fa291a47a --- /dev/null +++ b/components/viz/service/display/null_renderer.h
@@ -0,0 +1,61 @@ +// Copyright 2021 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 COMPONENTS_VIZ_SERVICE_DISPLAY_NULL_RENDERER_H_ +#define COMPONENTS_VIZ_SERVICE_DISPLAY_NULL_RENDERER_H_ + +#include <memory> + +#include "components/viz/service/display/direct_renderer.h" + +namespace viz { + +// Empty implementation of the DirectRenderer, used with OutputSurfaceUnified. +// Doesn't support Draw and will crash if Draw of SwapBuffers will be called. +class VIZ_SERVICE_EXPORT NullRenderer : public DirectRenderer { + public: + NullRenderer(const RendererSettings* settings, + const DebugRendererSettings* debug_settings, + OutputSurface* output_surface, + DisplayResourceProvider* resource_provider, + OverlayProcessorInterface* overlay_processor); + ~NullRenderer() override; + + private: + void SwapBuffers(SwapFrameData swap_frame_data) override; + bool CanPartialSwap() override; + void UpdateRenderPassTextures( + const AggregatedRenderPassList& render_passes_in_draw_order, + const base::flat_map<AggregatedRenderPassId, RenderPassRequirements>& + render_passes_in_frame) override {} + void AllocateRenderPassResourceIfNeeded( + const AggregatedRenderPassId& render_pass_id, + const RenderPassRequirements& requirements) override {} + bool IsRenderPassResourceAllocated( + const AggregatedRenderPassId& render_pass_id) const override; + gfx::Size GetRenderPassBackingPixelSize( + const AggregatedRenderPassId& render_pass_id) override; + void BindFramebufferToOutputSurface() override {} + void BindFramebufferToTexture( + const AggregatedRenderPassId render_pass_id) override {} + void SetScissorTestRect(const gfx::Rect& scissor_rect) override {} + void PrepareSurfaceForPass(SurfaceInitializationMode initialization_mode, + const gfx::Rect& render_pass_scissor) override {} + void DoDrawQuad(const DrawQuad* quad, + const gfx::QuadF* clip_region) override {} + void BeginDrawingFrame() override; + void FlushOverdrawFeedback(const gfx::Rect& output_rect) override {} + void FinishDrawingFrame() override {} + bool FlippedFramebuffer() const override; + void EnsureScissorTestEnabled() override {} + void EnsureScissorTestDisabled() override {} + void DidChangeVisibility() override {} + void CopyDrawnRenderPass(const copy_output::RenderPassGeometry& geometry, + std::unique_ptr<CopyOutputRequest> request) override; + void GenerateMipmap() override {} +}; + +} // namespace viz + +#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_NULL_RENDERER_H_
diff --git a/components/viz/service/display/overlay_ca_unittest.cc b/components/viz/service/display/overlay_ca_unittest.cc index 537f8f6..cdeec342 100644 --- a/components/viz/service/display/overlay_ca_unittest.cc +++ b/components/viz/service/display/overlay_ca_unittest.cc
@@ -26,7 +26,7 @@ #include "components/viz/common/quads/video_hole_draw_quad.h" #include "components/viz/common/resources/transferable_resource.h" #include "components/viz/service/display/ca_layer_overlay.h" -#include "components/viz/service/display/display_resource_provider.h" +#include "components/viz/service/display/display_resource_provider_gl.h" #include "components/viz/service/display/gl_renderer.h" #include "components/viz/service/display/output_surface.h" #include "components/viz/service/display/output_surface_client.h" @@ -219,9 +219,8 @@ output_surface_->BindToClient(&client_); shared_bitmap_manager_ = std::make_unique<TestSharedBitmapManager>(); - resource_provider_ = std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kGpu, provider_.get(), - shared_bitmap_manager_.get()); + resource_provider_ = std::make_unique<DisplayResourceProviderGL>( + provider_.get(), shared_bitmap_manager_.get()); child_provider_ = TestContextProvider::Create(); child_provider_->BindToCurrentThread(); @@ -245,7 +244,7 @@ std::unique_ptr<OverlayOutputSurface> output_surface_; cc::FakeOutputSurfaceClient client_; std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_; - std::unique_ptr<DisplayResourceProvider> resource_provider_; + std::unique_ptr<DisplayResourceProviderGL> resource_provider_; scoped_refptr<TestContextProvider> child_provider_; std::unique_ptr<ClientResourceProvider> child_resource_provider_; std::unique_ptr<CATestOverlayProcessor> overlay_processor_;
diff --git a/components/viz/service/display/overlay_dc_unittest.cc b/components/viz/service/display/overlay_dc_unittest.cc index f392032..d44d13c 100644 --- a/components/viz/service/display/overlay_dc_unittest.cc +++ b/components/viz/service/display/overlay_dc_unittest.cc
@@ -25,7 +25,7 @@ #include "components/viz/common/quads/video_hole_draw_quad.h" #include "components/viz/common/resources/transferable_resource.h" #include "components/viz/service/display/dc_layer_overlay.h" -#include "components/viz/service/display/display_resource_provider.h" +#include "components/viz/service/display/display_resource_provider_gl.h" #include "components/viz/service/display/gl_renderer.h" #include "components/viz/service/display/output_surface.h" #include "components/viz/service/display/output_surface_client.h" @@ -232,9 +232,8 @@ output_surface_->BindToClient(&client_); shared_bitmap_manager_ = std::make_unique<TestSharedBitmapManager>(); - resource_provider_ = std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kGpu, provider_.get(), - shared_bitmap_manager_.get()); + resource_provider_ = std::make_unique<DisplayResourceProviderGL>( + provider_.get(), shared_bitmap_manager_.get()); child_provider_ = TestContextProvider::Create(); child_provider_->BindToCurrentThread(); @@ -262,7 +261,7 @@ std::unique_ptr<OverlayOutputSurface> output_surface_; cc::FakeOutputSurfaceClient client_; std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_; - std::unique_ptr<DisplayResourceProvider> resource_provider_; + std::unique_ptr<DisplayResourceProviderGL> resource_provider_; scoped_refptr<TestContextProvider> child_provider_; std::unique_ptr<ClientResourceProvider> child_resource_provider_; std::unique_ptr<OverlayProcessorWin> overlay_processor_;
diff --git a/components/viz/service/display/overlay_unittest.cc b/components/viz/service/display/overlay_unittest.cc index 1e3c5c5..e4526913 100644 --- a/components/viz/service/display/overlay_unittest.cc +++ b/components/viz/service/display/overlay_unittest.cc
@@ -27,7 +27,7 @@ #include "components/viz/common/quads/video_hole_draw_quad.h" #include "components/viz/common/resources/transferable_resource.h" #include "components/viz/service/display/ca_layer_overlay.h" -#include "components/viz/service/display/display_resource_provider.h" +#include "components/viz/service/display/display_resource_provider_gl.h" #include "components/viz/service/display/gl_renderer.h" #include "components/viz/service/display/output_surface.h" #include "components/viz/service/display/output_surface_client.h" @@ -598,9 +598,8 @@ output_surface_->BindToClient(&client_); shared_bitmap_manager_ = std::make_unique<TestSharedBitmapManager>(); - resource_provider_ = std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kGpu, provider_.get(), - shared_bitmap_manager_.get()); + resource_provider_ = std::make_unique<DisplayResourceProviderGL>( + provider_.get(), shared_bitmap_manager_.get()); child_provider_ = TestContextProvider::Create(); child_provider_->BindToCurrentThread(); @@ -659,10 +658,8 @@ output_surface.BindToClient(&client); auto shared_bitmap_manager = std::make_unique<TestSharedBitmapManager>(); - std::unique_ptr<DisplayResourceProvider> resource_provider = - std::make_unique<DisplayResourceProvider>(DisplayResourceProvider::kGpu, - provider.get(), - shared_bitmap_manager.get()); + auto resource_provider = std::make_unique<DisplayResourceProviderGL>( + provider.get(), shared_bitmap_manager.get()); auto overlay_processor = std::make_unique<TestOverlayProcessor>(); EXPECT_GE(2U, overlay_processor->GetStrategyCount()); @@ -3061,7 +3058,7 @@ OverlayInfoRendererGL(const RendererSettings* settings, const DebugRendererSettings* debug_settings, OutputSurface* output_surface, - DisplayResourceProvider* resource_provider, + DisplayResourceProviderGL* resource_provider, SingleOverlayProcessor* overlay_processor) : GLRenderer(settings, debug_settings, @@ -3126,8 +3123,8 @@ provider_->BindToCurrentThread(); output_surface_ = std::make_unique<OverlayOutputSurface>(provider_); output_surface_->BindToClient(&output_surface_client_); - resource_provider_ = std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kGpu, provider_.get(), nullptr); + resource_provider_ = + std::make_unique<DisplayResourceProviderGL>(provider_.get(), nullptr); provider_->support()->SetScheduleOverlayPlaneCallback(base::BindRepeating( &MockOverlayScheduler::Schedule, base::Unretained(&scheduler_))); @@ -3174,8 +3171,8 @@ void SwapBuffersWithoutComplete() { renderer_->SwapBuffers({}); } void SwapBuffersComplete() { renderer_->SwapBuffersComplete(); } void ReturnResourceInUseQuery(ResourceId id) { - DisplayResourceProvider::ScopedReadLockGL lock(resource_provider_.get(), - id); + DisplayResourceProviderGL::ScopedReadLockGL lock(resource_provider_.get(), + id); gpu::TextureInUseResponse response; response.texture = lock.texture_id(); response.in_use = false; @@ -3212,7 +3209,7 @@ DebugRendererSettings debug_settings_; cc::FakeOutputSurfaceClient output_surface_client_; std::unique_ptr<OverlayOutputSurface> output_surface_; - std::unique_ptr<DisplayResourceProvider> resource_provider_; + std::unique_ptr<DisplayResourceProviderGL> resource_provider_; std::unique_ptr<SingleOverlayProcessor> owned_overlay_processor_; std::unique_ptr<OverlayInfoRendererGL> renderer_; scoped_refptr<TestContextProvider> provider_;
diff --git a/components/viz/service/display/software_renderer_unittest.cc b/components/viz/service/display/software_renderer_unittest.cc index 17966bc..24401d99 100644 --- a/components/viz/service/display/software_renderer_unittest.cc +++ b/components/viz/service/display/software_renderer_unittest.cc
@@ -30,7 +30,7 @@ #include "components/viz/common/quads/tile_draw_quad.h" #include "components/viz/common/resources/bitmap_allocation.h" #include "components/viz/common/resources/shared_bitmap.h" -#include "components/viz/service/display/display_resource_provider.h" +#include "components/viz/service/display/display_resource_provider_software.h" #include "components/viz/service/display/software_output_device.h" #include "components/viz/test/fake_output_surface.h" #include "components/viz/test/test_shared_bitmap_manager.h" @@ -52,8 +52,7 @@ output_surface_->BindToClient(&output_surface_client_); shared_bitmap_manager_ = std::make_unique<TestSharedBitmapManager>(); - resource_provider_ = std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kSoftware, nullptr, + resource_provider_ = std::make_unique<DisplayResourceProviderSoftware>( shared_bitmap_manager_.get()); renderer_ = std::make_unique<SoftwareRenderer>( &settings_, &debug_settings_, output_surface_.get(), @@ -70,7 +69,7 @@ child_resource_provider_ = nullptr; } - DisplayResourceProvider* resource_provider() const { + DisplayResourceProviderSoftware* resource_provider() const { return resource_provider_.get(); } @@ -133,7 +132,7 @@ cc::FakeOutputSurfaceClient output_surface_client_; std::unique_ptr<FakeOutputSurface> output_surface_; std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_; - std::unique_ptr<DisplayResourceProvider> resource_provider_; + std::unique_ptr<DisplayResourceProviderSoftware> resource_provider_; std::unique_ptr<ClientResourceProvider> child_resource_provider_; std::unique_ptr<SoftwareRenderer> renderer_; };
diff --git a/components/viz/service/display/surface_aggregator.cc b/components/viz/service/display/surface_aggregator.cc index 0683a78..f1fee4ad 100644 --- a/components/viz/service/display/surface_aggregator.cc +++ b/components/viz/service/display/surface_aggregator.cc
@@ -1541,7 +1541,8 @@ // Ref the resources in the surface, and let the provider know we've received // new resources from the compositor frame. - surface->RefResources(resource_list); + if (surface->client()) + surface->client()->RefResources(resource_list); provider_->ReceiveFromChild(child_id, resource_list); // Figure out which resources are actually used in the render pass.
diff --git a/components/viz/service/display/surface_aggregator_perftest.cc b/components/viz/service/display/surface_aggregator_perftest.cc index 35c0402..753d7474 100644 --- a/components/viz/service/display/surface_aggregator_perftest.cc +++ b/components/viz/service/display/surface_aggregator_perftest.cc
@@ -8,7 +8,7 @@ #include "components/viz/common/quads/surface_draw_quad.h" #include "components/viz/common/quads/texture_draw_quad.h" #include "components/viz/service/display/aggregated_frame.h" -#include "components/viz/service/display/display_resource_provider.h" +#include "components/viz/service/display/display_resource_provider_software.h" #include "components/viz/service/display/surface_aggregator.h" #include "components/viz/service/display/viz_perf_test.h" #include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" @@ -16,7 +16,6 @@ #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" #include "components/viz/service/surfaces/surface_manager.h" #include "components/viz/test/compositor_frame_helpers.h" -#include "components/viz/test/test_context_provider.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/perf/perf_result_reporter.h" @@ -56,11 +55,7 @@ class SurfaceAggregatorPerfTest : public VizPerfTest { public: SurfaceAggregatorPerfTest() : manager_(&shared_bitmap_manager_) { - context_provider_ = TestContextProvider::Create(); - context_provider_->BindToCurrentThread(); - - resource_provider_ = std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kSoftware, context_provider_.get(), + resource_provider_ = std::make_unique<DisplayResourceProviderSoftware>( &shared_bitmap_manager_); } @@ -198,7 +193,6 @@ protected: ServerSharedBitmapManager shared_bitmap_manager_; FrameSinkManagerImpl manager_; - scoped_refptr<TestContextProvider> context_provider_; std::unique_ptr<DisplayResourceProvider> resource_provider_; std::unique_ptr<SurfaceAggregator> aggregator_; };
diff --git a/components/viz/service/display/surface_aggregator_unittest.cc b/components/viz/service/display/surface_aggregator_unittest.cc index 2dcab904..649e347 100644 --- a/components/viz/service/display/surface_aggregator_unittest.cc +++ b/components/viz/service/display/surface_aggregator_unittest.cc
@@ -34,7 +34,7 @@ #include "components/viz/common/surfaces/parent_local_surface_id_allocator.h" #include "components/viz/common/surfaces/subtree_capture_id.h" #include "components/viz/service/display/aggregated_frame.h" -#include "components/viz/service/display/display_resource_provider.h" +#include "components/viz/service/display/display_resource_provider_software.h" #include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" #include "components/viz/service/frame_sinks/compositor_frame_sink_support.h" #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" @@ -5582,8 +5582,8 @@ SurfaceAggregatorWithResourcesTest() : manager_(&shared_bitmap_manager_) {} void SetUp() override { - resource_provider_ = std::make_unique<DisplayResourceProvider>( - DisplayResourceProvider::kSoftware, nullptr, &shared_bitmap_manager_); + resource_provider_ = std::make_unique<DisplayResourceProviderSoftware>( + &shared_bitmap_manager_); aggregator_ = std::make_unique<SurfaceAggregator>( manager_.surface_manager(), resource_provider_.get(), false, false);
diff --git a/components/viz/service/display_embedder/output_surface_unified.h b/components/viz/service/display_embedder/output_surface_unified.h index 26e07e39..1fa3e08 100644 --- a/components/viz/service/display_embedder/output_surface_unified.h +++ b/components/viz/service/display_embedder/output_surface_unified.h
@@ -15,10 +15,10 @@ // issue begin frames and doesn't need to do any drawing work. This class is // essentially a stub implementation. // -// OutputSurfaceUnified will end up with a corresponding SoftwareRenderer. While +// OutputSurfaceUnified will end up with a corresponding NullRenderer. While // Chrome OS uses GL rendering to draw it doesn't matter what renderer is // created for the unified display because it's never used to draw. Using -// SoftwareRenderer avoids the need to allocate a GL context and command buffer, +// NullRenderer avoids the need to allocate a GL context and command buffer, // which have significant memory overhead. class OutputSurfaceUnified : public OutputSurface { public:
diff --git a/components/viz/service/display_embedder/skia_output_device.cc b/components/viz/service/display_embedder/skia_output_device.cc index e8d9048..535cbd55 100644 --- a/components/viz/service/display_embedder/skia_output_device.cc +++ b/components/viz/service/display_embedder/skia_output_device.cc
@@ -47,8 +47,14 @@ } // namespace -SkiaOutputDevice::ScopedPaint::ScopedPaint(SkiaOutputDevice* device) - : device_(device), sk_surface_(device->BeginPaint(&end_semaphores_)) {} +SkiaOutputDevice::ScopedPaint::ScopedPaint( + std::vector<GrBackendSemaphore> end_semaphores, + SkiaOutputDevice* device, + SkSurface* sk_surface) + : end_semaphores_(std::move(end_semaphores)), + device_(device), + sk_surface_(sk_surface) {} + SkiaOutputDevice::ScopedPaint::~ScopedPaint() { DCHECK(end_semaphores_.empty()); device_->EndPaint(); @@ -99,6 +105,17 @@ latency_tracker_runner_->DeleteSoon(FROM_HERE, std::move(latency_tracker_)); } +std::unique_ptr<SkiaOutputDevice::ScopedPaint> +SkiaOutputDevice::BeginScopedPaint() { + std::vector<GrBackendSemaphore> end_semaphores; + SkSurface* sk_surface = BeginPaint(&end_semaphores); + if (!sk_surface) { + return nullptr; + } + return std::make_unique<SkiaOutputDevice::ScopedPaint>( + std::move(end_semaphores), this, sk_surface); +} + void SkiaOutputDevice::Submit(bool sync_cpu, base::OnceClosure callback) { gr_context_->submit(sync_cpu); std::move(callback).Run();
diff --git a/components/viz/service/display_embedder/skia_output_device.h b/components/viz/service/display_embedder/skia_output_device.h index 7fade68..7cd93285 100644 --- a/components/viz/service/display_embedder/skia_output_device.h +++ b/components/viz/service/display_embedder/skia_output_device.h
@@ -54,7 +54,9 @@ // A helper class for defining a BeginPaint() and EndPaint() scope. class ScopedPaint { public: - explicit ScopedPaint(SkiaOutputDevice* device); + ScopedPaint(std::vector<GrBackendSemaphore> end_semaphores, + SkiaOutputDevice* device, + SkSurface* sk_surface); ~ScopedPaint(); // This can be null. @@ -94,6 +96,12 @@ DidSwapBufferCompleteCallback did_swap_buffer_complete_callback); virtual ~SkiaOutputDevice(); + // Begins a paint scope. The base implementation fails when the SkSurface + // cannot be initialized, but devices that don't draw to a SkSurface (i.e + // |SkiaOutputDeviceVulkanSecondaryCB|) can override this to bypass the + // check. + virtual std::unique_ptr<SkiaOutputDevice::ScopedPaint> BeginScopedPaint(); + // Changes the size of draw surface and invalidates it's contents. virtual bool Reshape(const gfx::Size& size, float device_scale_factor,
diff --git a/components/viz/service/display_embedder/skia_output_device_vulkan_secondary_cb.cc b/components/viz/service/display_embedder/skia_output_device_vulkan_secondary_cb.cc index b70072f..d3bdfd9 100644 --- a/components/viz/service/display_embedder/skia_output_device_vulkan_secondary_cb.cc +++ b/components/viz/service/display_embedder/skia_output_device_vulkan_secondary_cb.cc
@@ -48,6 +48,14 @@ sk_color_type; } +std::unique_ptr<SkiaOutputDevice::ScopedPaint> +SkiaOutputDeviceVulkanSecondaryCB::BeginScopedPaint() { + std::vector<GrBackendSemaphore> end_semaphores; + SkSurface* sk_surface = BeginPaint(&end_semaphores); + return std::make_unique<SkiaOutputDevice::ScopedPaint>( + std::move(end_semaphores), this, sk_surface); +} + void SkiaOutputDeviceVulkanSecondaryCB::Submit(bool sync_cpu, base::OnceClosure callback) { // Submit the primary command buffer which may render passes.
diff --git a/components/viz/service/display_embedder/skia_output_device_vulkan_secondary_cb.h b/components/viz/service/display_embedder/skia_output_device_vulkan_secondary_cb.h index 8207a3b2..97fce81 100644 --- a/components/viz/service/display_embedder/skia_output_device_vulkan_secondary_cb.h +++ b/components/viz/service/display_embedder/skia_output_device_vulkan_secondary_cb.h
@@ -21,6 +21,7 @@ gpu::MemoryTracker* memory_tracker, DidSwapBufferCompleteCallback did_swap_buffer_complete_callback); + std::unique_ptr<SkiaOutputDevice::ScopedPaint> BeginScopedPaint() override; void Submit(bool sync_cpu, base::OnceClosure callback) override; bool Reshape(const gfx::Size& size, float device_scale_factor,
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc index cee5b54a..8967aa8 100644 --- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc +++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
@@ -545,8 +545,11 @@ // We do not reset scoped_output_device_paint_ after drawing the ddl until // SwapBuffers() is called, because we may need access to output_sk_surface() // for CopyOutput(). - scoped_output_device_paint_.emplace(output_device_.get()); - DCHECK(scoped_output_device_paint_); + scoped_output_device_paint_ = output_device_->BeginScopedPaint(); + if (!scoped_output_device_paint_) { + MarkContextLost(ContextLostReason::CONTEXT_LOST_BEGIN_PAINT_FAILED); + return; + } dependency_->ScheduleGrContextCleanup();
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h index e7b6f8a..aadf50d 100644 --- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h +++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
@@ -333,7 +333,7 @@ base::flat_set<ImageContextImpl*> image_contexts_with_end_access_state_; std::unique_ptr<SkiaOutputDevice> output_device_; - base::Optional<SkiaOutputDevice::ScopedPaint> scoped_output_device_paint_; + std::unique_ptr<SkiaOutputDevice::ScopedPaint> scoped_output_device_paint_; base::Optional<OverlayProcessorInterface::OutputSurfaceOverlayPlane> output_surface_plane_;
diff --git a/components/viz/service/surfaces/surface.cc b/components/viz/service/surfaces/surface.cc index 3224499..20fdb2b 100644 --- a/components/viz/service/surfaces/surface.cc +++ b/components/viz/service/surfaces/surface.cc
@@ -127,16 +127,6 @@ previous_frame_surface_id_ = surface->surface_id(); } -void Surface::RefResources(const std::vector<TransferableResource>& resources) { - if (surface_client_) - surface_client_->RefResources(resources); -} - -void Surface::UnrefResources(const std::vector<ReturnedResource>& resources) { - if (surface_client_) - surface_client_->UnrefResources(resources); -} - void Surface::UpdateSurfaceReferences() { const base::flat_set<SurfaceId>& existing_referenced_surfaces = surface_manager_->GetSurfacesReferencedByParent(surface_id());
diff --git a/components/viz/service/surfaces/surface.h b/components/viz/service/surfaces/surface.h index eedc4afa..97eb7e4 100644 --- a/components/viz/service/surfaces/surface.h +++ b/components/viz/service/surfaces/surface.h
@@ -128,12 +128,6 @@ void SetPreviousFrameSurface(Surface* surface); - // Increments the reference count on resources specified by |resources|. - void RefResources(const std::vector<TransferableResource>& resources); - - // Decrements the reference count on resources specified by |resources|. - void UnrefResources(const std::vector<ReturnedResource>& resources); - // Returns false if |frame| is invalid. // |frame_rejected_callback| will be called once if the frame will not be // displayed.
diff --git a/components/webapps/services/web_app_origin_association/BUILD.gn b/components/webapps/services/web_app_origin_association/BUILD.gn index 8f5be8b1..150c9087 100644 --- a/components/webapps/services/web_app_origin_association/BUILD.gn +++ b/components/webapps/services/web_app_origin_association/BUILD.gn
@@ -4,6 +4,8 @@ source_set("lib") { sources = [ + "web_app_origin_association_fetcher.cc", + "web_app_origin_association_fetcher.h", "web_app_origin_association_parser.cc", "web_app_origin_association_parser.h", "web_app_origin_association_parser_impl.cc", @@ -12,7 +14,12 @@ deps = [ "//base", + "//components/services/app_service/public/cpp:app_url_handling", "//mojo/public/cpp/bindings", + "//net/traffic_annotation:traffic_annotation", + "//services/network/public/cpp", + "//skia", + "//url", ] public_deps = [ @@ -37,6 +44,7 @@ source_set("unit_tests") { testonly = true sources = [ + "web_app_origin_association_fetcher_unittest.cc", "web_app_origin_association_parser_impl_unittest.cc", "web_app_origin_association_parser_unittest.cc", ] @@ -45,6 +53,13 @@ "//base", "//base/test:test_support", "//components/webapps/services/web_app_origin_association:lib", + "//content/public/browser", + "//content/test:test_support", + "//net", + "//net:test_support", + "//services/network:network_service", + "//services/network:test_support", + "//skia", "//testing/gtest", "//url", ]
diff --git a/components/webapps/services/web_app_origin_association/DEPS b/components/webapps/services/web_app_origin_association/DEPS index e841ea2..9601bfc 100644 --- a/components/webapps/services/web_app_origin_association/DEPS +++ b/components/webapps/services/web_app_origin_association/DEPS
@@ -1,4 +1,9 @@ include_rules = [ + "+components/services/app_service/public/cpp", "+content/public/browser", + "+content/public/test", "+mojo/public", + "+net", + "+services/network", + "+third_party/skia/include", ]
diff --git a/components/webapps/services/web_app_origin_association/web_app_origin_association_fetcher.cc b/components/webapps/services/web_app_origin_association/web_app_origin_association_fetcher.cc new file mode 100644 index 0000000..a636d8c6 --- /dev/null +++ b/components/webapps/services/web_app_origin_association/web_app_origin_association_fetcher.cc
@@ -0,0 +1,116 @@ +// Copyright 2021 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 "components/webapps/services/web_app_origin_association/web_app_origin_association_fetcher.h" + +#include <utility> + +#include "base/bind.h" +#include "net/traffic_annotation/network_traffic_annotation.h" +#include "services/network/public/cpp/resource_request.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" +#include "url/gurl.h" + +namespace { + +constexpr size_t kMaxJsonSize = 1000000; // 1MB max + +int g_max_retry = 3; + +network::SimpleURLLoader::RetryMode g_retry_mode = + network::SimpleURLLoader::RETRY_ON_NETWORK_CHANGE; + +constexpr net::NetworkTrafficAnnotationTag + web_app_origin_association_traffic_annotation = + net::DefineNetworkTrafficAnnotation( + "web_app_origin_association_download", + R"( + semantics { + sender: "Web App Origin Association Fetcher" + description: + "PWAs can specify URL Handlers in the Manifest. To verify the " + "handlers, we download the corresponding web app origin " + "association files." + trigger: + "A PWA that has URL Handlers declared in the Manifest is " + "installed, updated, or when DevTools displays URL Handler " + "information to users." + data: + "Nothing." + destination: WEBSITE + } + policy { + cookies_allowed: NO + setting: + "There is no setting to disable PWA installation." + policy_exception_justification: + "Not implemented, " + "considered not necessary as no user data is sent." + })"); + +constexpr char association_file_name[] = + ".well-known/web-app-origin-association"; + +std::unique_ptr<network::SimpleURLLoader> CreateRequester(const GURL& url) { + auto resource_request = std::make_unique<network::ResourceRequest>(); + resource_request->url = url; + resource_request->method = "GET"; + auto url_loader = network::SimpleURLLoader::Create( + std::move(resource_request), + web_app_origin_association_traffic_annotation); + url_loader->SetRetryOptions(g_max_retry, g_retry_mode); + url_loader->SetURLLoaderFactoryOptions( + network::mojom::kURLLoadOptionBlockAllCookies); + return url_loader; +} +} // namespace + +namespace webapps { + +WebAppOriginAssociationFetcher::WebAppOriginAssociationFetcher() = default; + +WebAppOriginAssociationFetcher::~WebAppOriginAssociationFetcher() = default; + +void WebAppOriginAssociationFetcher::SetRetryOptionsForTest( + int max_retry, + network::SimpleURLLoader::RetryMode retry_mode) { + g_max_retry = max_retry; + g_retry_mode = retry_mode; +} + +void WebAppOriginAssociationFetcher::FetchWebAppOriginAssociationFile( + const apps::UrlHandlerInfo& url_handler, + scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory, + FetchFileCallback callback) { + const GURL resource_url = + url_handler.origin.GetURL().Resolve(association_file_name); + if (!resource_url.is_valid() || resource_url.is_empty()) { + // Do not proceed if |resource_url| is not valid. + OnResponse(std::move(callback), nullptr); + return; + } + + SendRequest(resource_url, std::move(shared_url_loader_factory), + std::move(callback)); +} + +void WebAppOriginAssociationFetcher::SendRequest( + const GURL& url, + scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory, + FetchFileCallback callback) { + url_loader_ = CreateRequester(url); + url_loader_->DownloadToString( + shared_url_loader_factory.get(), + base::BindOnce(&WebAppOriginAssociationFetcher::OnResponse, + weak_ptr_factory_.GetWeakPtr(), std::move(callback)), + kMaxJsonSize); +} + +void WebAppOriginAssociationFetcher::OnResponse( + FetchFileCallback callback, + std::unique_ptr<std::string> response_body) { + std::move(callback).Run(std::move(response_body)); +} + +} // namespace webapps
diff --git a/components/webapps/services/web_app_origin_association/web_app_origin_association_fetcher.h b/components/webapps/services/web_app_origin_association/web_app_origin_association_fetcher.h new file mode 100644 index 0000000..4b5b6cef --- /dev/null +++ b/components/webapps/services/web_app_origin_association/web_app_origin_association_fetcher.h
@@ -0,0 +1,61 @@ +// Copyright 2021 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 COMPONENTS_WEBAPPS_SERVICES_WEB_APP_ORIGIN_ASSOCIATION_WEB_APP_ORIGIN_ASSOCIATION_FETCHER_H_ +#define COMPONENTS_WEBAPPS_SERVICES_WEB_APP_ORIGIN_ASSOCIATION_WEB_APP_ORIGIN_ASSOCIATION_FETCHER_H_ + +#include <memory> +#include <string> + +#include "base/callback.h" +#include "base/gtest_prod_util.h" +#include "base/memory/scoped_refptr.h" +#include "base/memory/weak_ptr.h" +#include "components/services/app_service/public/cpp/url_handler_info.h" +#include "services/network/public/cpp/simple_url_loader.h" + +class GURL; + +namespace network { +class SharedURLLoaderFactory; +} // namespace network + +namespace webapps { + +using FetchFileCallback = + base::OnceCallback<void(std::unique_ptr<std::string> file_content)>; + +// Makes network requests to fetch web app origin association files. +class WebAppOriginAssociationFetcher { + public: + WebAppOriginAssociationFetcher(); + ~WebAppOriginAssociationFetcher(); + WebAppOriginAssociationFetcher(const WebAppOriginAssociationFetcher&) = + delete; + WebAppOriginAssociationFetcher& operator=( + const WebAppOriginAssociationFetcher&) = delete; + + void FetchWebAppOriginAssociationFile( + const apps::UrlHandlerInfo& url_handler, + scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory, + FetchFileCallback callback); + + void SetRetryOptionsForTest(int max_retry, + network::SimpleURLLoader::RetryMode retry_mode); + + private: + void SendRequest( + const GURL& url, + scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory, + FetchFileCallback callback); + void OnResponse(FetchFileCallback callback, + std::unique_ptr<std::string> response_body); + + std::unique_ptr<network::SimpleURLLoader> url_loader_; + base::WeakPtrFactory<WebAppOriginAssociationFetcher> weak_ptr_factory_{this}; +}; + +} // namespace webapps + +#endif // COMPONENTS_WEBAPPS_SERVICES_WEB_APP_ORIGIN_ASSOCIATION_WEB_APP_ORIGIN_ASSOCIATION_FETCHER_H_
diff --git a/components/webapps/services/web_app_origin_association/web_app_origin_association_fetcher_unittest.cc b/components/webapps/services/web_app_origin_association/web_app_origin_association_fetcher_unittest.cc new file mode 100644 index 0000000..bef3a0c --- /dev/null +++ b/components/webapps/services/web_app_origin_association/web_app_origin_association_fetcher_unittest.cc
@@ -0,0 +1,115 @@ +// Copyright 2021 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 "components/webapps/services/web_app_origin_association/web_app_origin_association_fetcher.h" + +#include <string> +#include <utility> + +#include "base/run_loop.h" +#include "base/test/bind.h" +#include "base/test/task_environment.h" +#include "content/public/browser/network_service_instance.h" +#include "content/public/test/browser_task_environment.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/network_service.h" +#include "services/network/test/test_network_context_client.h" +#include "services/network/test/test_shared_url_loader_factory.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +constexpr char kWebAppOriginAssociationFileContent[] = + R"({\"web_apps\": [{" + " \"manifest\": \"https://foo.com/manifest.json\"," + " \"details\": {" + " \"paths\": [\"/*\"]," + " \"exclude_paths\": [\"/blog/data\"]" + " }" + "}]})"; + +} // namespace + +namespace webapps { + +class WebAppOriginAssociationFetcherTest : public testing::Test { + public: + WebAppOriginAssociationFetcherTest() + : task_environment_(content::BrowserTaskEnvironment::IO_MAINLOOP), + server_(net::EmbeddedTestServer::TYPE_HTTPS) { + // Make sure the Network Service is started before making a NetworkContext. + content::GetNetworkService(); + + shared_url_loader_factory_ = + base::MakeRefCounted<network::TestSharedURLLoaderFactory>( + network::NetworkService::GetNetworkServiceForTesting()); + + fetcher_ = std::make_unique<WebAppOriginAssociationFetcher>(); + + // Do not retry, otherwise TestSharedURLLoaderFactory.Clone() will be + // called, which is not implemented. + fetcher_->SetRetryOptionsForTest(0, network::SimpleURLLoader::RETRY_NEVER); + } + + void SetUp() override { + server_.RegisterRequestHandler( + base::BindRepeating(&WebAppOriginAssociationFetcherTest::HandleRequest, + base::Unretained(this))); + + ASSERT_TRUE(test_server_handle_ = server_.StartAndReturnHandle()); + } + + protected: + std::unique_ptr<net::test_server::HttpResponse> HandleRequest( + const net::test_server::HttpRequest& request) { + if (request.relative_url != "/.well-known/web-app-origin-association") + return nullptr; + + auto http_response = + std::make_unique<net::test_server::BasicHttpResponse>(); + http_response->set_code(net::HTTP_OK); + http_response->set_content_type("application/json"); + http_response->set_content(kWebAppOriginAssociationFileContent); + return http_response; + } + + content::BrowserTaskEnvironment task_environment_; + net::EmbeddedTestServer server_; + net::test_server::EmbeddedTestServerHandle test_server_handle_; + scoped_refptr<network::TestSharedURLLoaderFactory> shared_url_loader_factory_; + std::unique_ptr<WebAppOriginAssociationFetcher> fetcher_; +}; + +TEST_F(WebAppOriginAssociationFetcherTest, FileExists) { + base::RunLoop run_loop; + auto handler = apps::UrlHandlerInfo(); + handler.origin = url::Origin::Create(GURL(server_.base_url())); + fetcher_->FetchWebAppOriginAssociationFile( + std::move(handler), shared_url_loader_factory_.get(), + base::BindLambdaForTesting( + [&](std::unique_ptr<std::string> file_content) { + ASSERT_FALSE(!file_content); + EXPECT_EQ(*file_content, kWebAppOriginAssociationFileContent); + run_loop.Quit(); + })); + run_loop.Run(); +} + +TEST_F(WebAppOriginAssociationFetcherTest, FileDoesNotExist) { + base::RunLoop run_loop; + auto handler = apps::UrlHandlerInfo(); + handler.origin = url::Origin::Create(server_.GetURL("https://foo.com", "/")); + fetcher_->FetchWebAppOriginAssociationFile( + std::move(handler), shared_url_loader_factory_.get(), + base::BindLambdaForTesting( + [&](std::unique_ptr<std::string> file_content) { + ASSERT_TRUE(!file_content); + run_loop.Quit(); + })); + run_loop.Run(); +} + +} // namespace webapps
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index 41e70a3..d099977 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -2714,7 +2714,6 @@ "//chromeos/dbus/power:power_manager_proto", "//chromeos/network", "//chromeos/system", - "//chromeos/tpm", "//components/session_manager/core", ] }
diff --git a/content/browser/back_forward_cache_browsertest.cc b/content/browser/back_forward_cache_browsertest.cc index fd2f595..64b80367 100644 --- a/content/browser/back_forward_cache_browsertest.cc +++ b/content/browser/back_forward_cache_browsertest.cc
@@ -271,6 +271,12 @@ ExpectOutcome( BackForwardCacheMetrics::HistoryNavigationOutcome::kNotRestored, location); + ExpectNotRestoredReasons(reasons, location); + } + + void ExpectNotRestoredReasons( + std::vector<BackForwardCacheMetrics::NotRestoredReason> reasons, + base::Location location) { uint64_t not_restored_reasons_bits = 0; for (BackForwardCacheMetrics::NotRestoredReason reason : reasons) { base::HistogramBase::Sample sample = base::HistogramBase::Sample(reason); @@ -538,10 +544,10 @@ // If we restored the page, there should be no blocking reasons logged. if (outcome == BackForwardCacheMetrics::HistoryNavigationOutcome::kRestored) { + ExpectNotRestoredReasons({}, location); ExpectBlocklistedFeatures({}, FROM_HERE); ExpectDisabledWithReasons({}, FROM_HERE); ExpectBrowsingInstanceNotSwappedReasons({}, FROM_HERE); - ExpectBrowsingInstanceNotSwappedReasons({}, FROM_HERE); } if (!check_all_sites_) return;
diff --git a/content/browser/direct_sockets/direct_sockets_browsertest.cc b/content/browser/direct_sockets/direct_sockets_browsertest.cc index 2488161..437c825 100644 --- a/content/browser/direct_sockets/direct_sockets_browsertest.cc +++ b/content/browser/direct_sockets/direct_sockets_browsertest.cc
@@ -38,6 +38,7 @@ #include "services/network/test/test_network_context.h" #include "testing/gmock/include/gmock/gmock-matchers.h" #include "url/gurl.h" +#include "url/url_canon_ip.h" using testing::StartsWith; @@ -630,27 +631,6 @@ } IN_PROC_BROWSER_TEST_F(DirectSocketsBrowserTest, - OpenTcp_RestrictedByEnterprisePolicies) { - EXPECT_TRUE(NavigateToURL(shell(), GetTestPageURL())); - - base::HistogramTester histogram_tester; - histogram_tester.ExpectBucketCount( - kPermissionDeniedHistogramName, - DirectSocketsServiceImpl::FailureType::kEnterprisePolicy, 0); - - DirectSocketsServiceImpl::SetEnterpriseManagedForTesting(true); - - const std::string script = - "openTcp({remoteAddress: '127.0.0.1', remotePort: 993})"; - - EXPECT_EQ("openTcp failed: NotAllowedError: Permission denied", - EvalJs(shell(), script)); - histogram_tester.ExpectBucketCount( - kPermissionDeniedHistogramName, - DirectSocketsServiceImpl::FailureType::kEnterprisePolicy, 1); -} - -IN_PROC_BROWSER_TEST_F(DirectSocketsBrowserTest, OpenTcp_CannotConnectNonPublic) { const auto protocol = DirectSocketsServiceImpl::ProtocolType::kTcp; // Tests for the reserved IPv4 ranges. The reserved ranges are tested by @@ -880,27 +860,6 @@ } IN_PROC_BROWSER_TEST_F(DirectSocketsBrowserTest, - OpenUdp_RestrictedByEnterprisePolicies) { - EXPECT_TRUE(NavigateToURL(shell(), GetTestPageURL())); - - base::HistogramTester histogram_tester; - histogram_tester.ExpectBucketCount( - kPermissionDeniedHistogramName, - DirectSocketsServiceImpl::FailureType::kEnterprisePolicy, 0); - - DirectSocketsServiceImpl::SetEnterpriseManagedForTesting(true); - - const std::string script = - "openUdp({remoteAddress: '127.0.0.1', remotePort: 993})"; - - EXPECT_EQ("openUdp failed: NotAllowedError: Permission denied", - EvalJs(shell(), script)); - histogram_tester.ExpectBucketCount( - kPermissionDeniedHistogramName, - DirectSocketsServiceImpl::FailureType::kEnterprisePolicy, 1); -} - -IN_PROC_BROWSER_TEST_F(DirectSocketsBrowserTest, OpenUdp_CannotConnectNonPublic) { const auto protocol = DirectSocketsServiceImpl::ProtocolType::kUdp; // Tests for the reserved IPv4 ranges. The reserved ranges are tested by
diff --git a/content/browser/direct_sockets/direct_sockets_service_impl.cc b/content/browser/direct_sockets/direct_sockets_service_impl.cc index c6970c5..7ffff22 100644 --- a/content/browser/direct_sockets/direct_sockets_service_impl.cc +++ b/content/browser/direct_sockets/direct_sockets_service_impl.cc
@@ -10,7 +10,6 @@ #include "base/feature_list.h" #include "base/metrics/histogram_functions.h" #include "base/optional.h" -#include "build/build_config.h" #include "content/browser/renderer_host/frame_tree_node.h" #include "content/browser/renderer_host/render_frame_host_impl.h" #include "content/public/browser/browser_thread.h" @@ -24,18 +23,10 @@ #include "services/network/public/cpp/resolve_host_client_base.h" #include "services/network/public/mojom/network_context.mojom.h" -#if defined(OS_WIN) || defined(OS_MAC) -#include "base/enterprise_util.h" -#elif BUILDFLAG(IS_CHROMEOS_ASH) -#include "chromeos/tpm/install_attributes.h" -#endif - namespace content { namespace { -base::Optional<bool> g_is_enterprise_managed_for_testing; - constexpr int32_t kMaxBufferSize = 32 * 1024 * 1024; constexpr char kPermissionDeniedHistogramName[] = @@ -82,23 +73,6 @@ return false; } -// TODO(crbug.com/1119662): Now only check for the device, maybe there are some -// methods that can be applied to check for the user profile. -bool IsEnterpriseManaged() { - // Return the value of the testing flag if it's set. - if (g_is_enterprise_managed_for_testing.has_value()) - return g_is_enterprise_managed_for_testing.value(); - -#if defined(OS_WIN) || defined(OS_MAC) - return base::IsMachineExternallyManaged(); -#elif BUILDFLAG(IS_CHROMEOS_ASH) - return chromeos::InstallAttributes::IsInitialized() && - chromeos::InstallAttributes::Get()->IsEnterpriseManaged(); -#else - return false; -#endif -} - } // namespace DirectSocketsServiceImpl::DirectSocketsServiceImpl(RenderFrameHost& frame_host) @@ -333,12 +307,6 @@ } // static -void DirectSocketsServiceImpl::SetEnterpriseManagedForTesting( - bool enterprise_managed) { - g_is_enterprise_managed_for_testing = enterprise_managed; -} - -// static void DirectSocketsServiceImpl::SetPermissionCallbackForTesting( PermissionCallback callback) { GetPermissionCallbackForTesting() = std::move(callback); @@ -395,14 +363,7 @@ if (options.send_buffer_size < 0 || options.receive_buffer_size < 0) return net::ERR_INVALID_ARGUMENT; - // By default, we will restrict use of the API when enterprise software - // policies are in effect. - if (IsEnterpriseManaged()) { - base::UmaHistogramEnumeration(kPermissionDeniedHistogramName, - FailureType::kEnterprisePolicy); - return net::ERR_NETWORK_ACCESS_DENIED; - } - + // TODO(crbug.com/1119662): Check for enterprise software policies. // TODO(crbug.com/1119659): Check permissions policy. // TODO(crbug.com/1119600): Implement rate limiting.
diff --git a/content/browser/direct_sockets/direct_sockets_service_impl.h b/content/browser/direct_sockets/direct_sockets_service_impl.h index dc37332..1ffa586 100644 --- a/content/browser/direct_sockets/direct_sockets_service_impl.h +++ b/content/browser/direct_sockets/direct_sockets_service_impl.h
@@ -74,8 +74,6 @@ void RenderFrameDeleted(RenderFrameHost* render_frame_host) override; void WebContentsDestroyed() override; - static void SetEnterpriseManagedForTesting(bool enterprise_managed); - static void SetPermissionCallbackForTesting(PermissionCallback callback); static void SetNetworkContextForTesting(network::mojom::NetworkContext*);
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc index a15a6e1..01d39c6 100644 --- a/content/browser/gpu/gpu_process_host.cc +++ b/content/browser/gpu/gpu_process_host.cc
@@ -277,6 +277,7 @@ #endif #if defined(OS_MAC) sandbox::policy::switches::kEnableSandboxLogging, + sandbox::policy::switches::kDisableMetalShaderCache, switches::kDisableAVFoundationOverlays, switches::kDisableMacOverlays, switches::kDisableMetalTestShaders,
diff --git a/content/browser/indexed_db/indexed_db_internals_ui.cc b/content/browser/indexed_db/indexed_db_internals_ui.cc index 1ab49fc3..93c89f7 100644 --- a/content/browser/indexed_db/indexed_db_internals_ui.cc +++ b/content/browser/indexed_db/indexed_db_internals_ui.cc
@@ -38,17 +38,7 @@ IndexedDBInternalsUI::IndexedDBInternalsUI(WebUI* web_ui) : WebUIController(web_ui) { - web_ui->RegisterMessageCallback( - "getAllOrigins", base::BindRepeating(&IndexedDBInternalsUI::GetAllOrigins, - base::Unretained(this))); - - web_ui->RegisterMessageCallback( - "downloadOriginData", - base::BindRepeating(&IndexedDBInternalsUI::DownloadOriginData, - base::Unretained(this))); - web_ui->RegisterMessageCallback( - "forceClose", base::BindRepeating(&IndexedDBInternalsUI::ForceCloseOrigin, - base::Unretained(this))); + web_ui->AddMessageHandler(std::make_unique<IndexedDBInternalsHandler>()); WebUIDataSource* source = WebUIDataSource::Create(kChromeUIIndexedDBInternalsHost); source->OverrideContentSecurityPolicy( @@ -69,42 +59,66 @@ WebUIDataSource::Add(browser_context, source); } -IndexedDBInternalsUI::~IndexedDBInternalsUI() {} +IndexedDBInternalsUI::~IndexedDBInternalsUI() = default; -void IndexedDBInternalsUI::GetAllOrigins(const base::ListValue* args) { +IndexedDBInternalsHandler::IndexedDBInternalsHandler() = default; + +IndexedDBInternalsHandler::~IndexedDBInternalsHandler() = default; + +void IndexedDBInternalsHandler::RegisterMessages() { + web_ui()->RegisterMessageCallback( + "getAllOrigins", + base::BindRepeating(&IndexedDBInternalsHandler::GetAllOrigins, + base::Unretained(this))); + + web_ui()->RegisterMessageCallback( + "downloadOriginData", + base::BindRepeating(&IndexedDBInternalsHandler::DownloadOriginData, + base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "forceClose", + base::BindRepeating(&IndexedDBInternalsHandler::ForceCloseOrigin, + base::Unretained(this))); +} + +void IndexedDBInternalsHandler::OnJavascriptDisallowed() { + weak_factory_.InvalidateWeakPtrs(); +} + +void IndexedDBInternalsHandler::GetAllOrigins(const base::ListValue* args) { DCHECK_CURRENTLY_ON(BrowserThread::UI); + AllowJavascript(); BrowserContext* browser_context = web_ui()->GetWebContents()->GetBrowserContext(); BrowserContext::ForEachStoragePartition( browser_context, base::BindRepeating( - [](base::WeakPtr<IndexedDBInternalsUI> ui, + [](base::WeakPtr<IndexedDBInternalsHandler> handler, StoragePartition* partition) { - if (!ui) + if (!handler) return; auto& control = partition->GetIndexedDBControl(); control.GetAllOriginsDetails(base::BindOnce( - [](base::WeakPtr<IndexedDBInternalsUI> ui, + [](base::WeakPtr<IndexedDBInternalsHandler> handler, base::FilePath partition_path, bool incognito, base::Value info_list) { - if (!ui) + if (!handler) return; - ui->OnOriginsReady( + handler->OnOriginsReady( info_list, incognito ? base::FilePath() : partition_path); }, - ui, partition->GetPath())); + handler, partition->GetPath())); }, weak_factory_.GetWeakPtr())); } -void IndexedDBInternalsUI::OnOriginsReady(const base::Value& origins, - const base::FilePath& path) { +void IndexedDBInternalsHandler::OnOriginsReady(const base::Value& origins, + const base::FilePath& path) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - web_ui()->CallJavascriptFunctionUnsafe("indexeddb.onOriginsReady", origins, - base::Value(path.AsUTF8Unsafe())); + FireWebUIListener("origins-ready", origins, base::Value(path.AsUTF8Unsafe())); } static void FindControl(const base::FilePath& partition_path, @@ -117,18 +131,25 @@ } } -bool IndexedDBInternalsUI::GetOriginData( +bool IndexedDBInternalsHandler::GetOriginData( const base::ListValue* args, + std::string* callback_id, base::FilePath* partition_path, Origin* origin, storage::mojom::IndexedDBControl** control) { + std::string callback_string; + if (!args->GetString(0, &callback_string)) { + return false; + } + *callback_id = callback_string; + std::string path_string; - if (!args->GetString(0, &path_string)) + if (!args->GetString(1, &path_string)) return false; *partition_path = base::FilePath::FromUTF8Unsafe(path_string); std::string url_string; - if (!args->GetString(1, &url_string)) + if (!args->GetString(2, &url_string)) return false; *origin = Origin::Create(GURL(url_string)); @@ -136,7 +157,7 @@ return GetOriginControl(*partition_path, *origin, control); } -bool IndexedDBInternalsUI::GetOriginControl( +bool IndexedDBInternalsHandler::GetOriginControl( const base::FilePath& path, const Origin& origin, storage::mojom::IndexedDBControl** control) { @@ -156,88 +177,92 @@ return true; } -void IndexedDBInternalsUI::DownloadOriginData(const base::ListValue* args) { +void IndexedDBInternalsHandler::DownloadOriginData( + const base::ListValue* args) { DCHECK_CURRENTLY_ON(BrowserThread::UI); + std::string callback_id; base::FilePath partition_path; Origin origin; storage::mojom::IndexedDBControl* control; - if (!GetOriginData(args, &partition_path, &origin, &control)) + if (!GetOriginData(args, &callback_id, &partition_path, &origin, &control)) return; + AllowJavascript(); DCHECK(control); control->ForceClose( origin, storage::mojom::ForceCloseReason::FORCE_CLOSE_INTERNALS_PAGE, base::BindOnce( - [](base::WeakPtr<IndexedDBInternalsUI> ui, Origin origin, - base::FilePath partition_path, - storage::mojom::IndexedDBControl* control) { + [](base::WeakPtr<IndexedDBInternalsHandler> handler, Origin origin, + storage::mojom::IndexedDBControl* control, + const std::string& callback_id) { // Is the connection count always zero after closing, // such that this can be simplified? control->GetConnectionCount( origin, base::BindOnce( - [](base::WeakPtr<IndexedDBInternalsUI> ui, Origin origin, - base::FilePath partition_path, - storage::mojom::IndexedDBControl* control, + [](base::WeakPtr<IndexedDBInternalsHandler> handler, + Origin origin, storage::mojom::IndexedDBControl* control, + const std::string& callback_id, uint64_t connection_count) { - if (!ui) + if (!handler) return; control->DownloadOriginData( origin, base::BindOnce( - &IndexedDBInternalsUI::OnDownloadDataReady, ui, - partition_path, origin, connection_count)); + &IndexedDBInternalsHandler::OnDownloadDataReady, + handler, callback_id, connection_count)); }, - ui, origin, partition_path, control)); + handler, origin, control, callback_id)); }, - weak_factory_.GetWeakPtr(), origin, partition_path, control)); + weak_factory_.GetWeakPtr(), origin, control, callback_id)); } -void IndexedDBInternalsUI::ForceCloseOrigin(const base::ListValue* args) { +void IndexedDBInternalsHandler::ForceCloseOrigin(const base::ListValue* args) { DCHECK_CURRENTLY_ON(BrowserThread::UI); + std::string callback_id; base::FilePath partition_path; Origin origin; storage::mojom::IndexedDBControl* control; - if (!GetOriginData(args, &partition_path, &origin, &control)) + if (!GetOriginData(args, &callback_id, &partition_path, &origin, &control)) return; + AllowJavascript(); control->ForceClose( origin, storage::mojom::ForceCloseReason::FORCE_CLOSE_INTERNALS_PAGE, base::BindOnce( - [](base::WeakPtr<IndexedDBInternalsUI> ui, - base::FilePath partition_path, Origin origin, - storage::mojom::IndexedDBControl* control) { - if (!ui) + [](base::WeakPtr<IndexedDBInternalsHandler> handler, Origin origin, + storage::mojom::IndexedDBControl* control, + const std::string& callback_id) { + if (!handler) return; control->GetConnectionCount( - origin, base::BindOnce(&IndexedDBInternalsUI::OnForcedClose, ui, - partition_path, origin)); + origin, + base::BindOnce(&IndexedDBInternalsHandler::OnForcedClose, + handler, callback_id)); }, - weak_factory_.GetWeakPtr(), partition_path, origin, control)); + weak_factory_.GetWeakPtr(), origin, control, callback_id)); } -void IndexedDBInternalsUI::OnForcedClose(const base::FilePath& partition_path, - const Origin& origin, - uint64_t connection_count) { - web_ui()->CallJavascriptFunctionUnsafe( - "indexeddb.onForcedClose", base::Value(partition_path.AsUTF8Unsafe()), - base::Value(origin.Serialize()), - base::Value(static_cast<double>(connection_count))); +void IndexedDBInternalsHandler::OnForcedClose(const std::string& callback_id, + uint64_t connection_count) { + ResolveJavascriptCallback(base::Value(callback_id), + base::Value(static_cast<double>(connection_count))); } -void IndexedDBInternalsUI::OnDownloadDataReady( - const base::FilePath& partition_path, - const Origin& origin, +void IndexedDBInternalsHandler::OnDownloadDataReady( + const std::string& callback_id, uint64_t connection_count, bool success, const base::FilePath& temp_path, const base::FilePath& zip_path) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - if (!success) + if (!success) { + RejectJavascriptCallback(base::Value(callback_id), base::Value()); return; + } const GURL url = GURL("file://" + zip_path.AsUTF8Unsafe()); WebContents* web_contents = web_ui()->GetWebContents(); @@ -275,8 +300,8 @@ // to start, then attach a download::DownloadItem::Observer to observe the // state change to the finished state. dl_params->set_callback(base::BindOnce( - &IndexedDBInternalsUI::OnDownloadStarted, base::Unretained(this), - partition_path, origin, temp_path, connection_count)); + &IndexedDBInternalsHandler::OnDownloadStarted, base::Unretained(this), + temp_path, callback_id, connection_count)); BrowserContext* context = web_contents->GetBrowserContext(); BrowserContext::GetDownloadManager(context)->DownloadUrl( @@ -326,25 +351,22 @@ std::move(temp_dir_))); } -void IndexedDBInternalsUI::OnDownloadStarted( - const base::FilePath& partition_path, - const Origin& origin, +void IndexedDBInternalsHandler::OnDownloadStarted( const base::FilePath& temp_path, + const std::string& callback_id, size_t connection_count, download::DownloadItem* item, download::DownloadInterruptReason interrupt_reason) { if (interrupt_reason != download::DOWNLOAD_INTERRUPT_REASON_NONE) { LOG(ERROR) << "Error downloading database dump: " << DownloadInterruptReasonToString(interrupt_reason); + RejectJavascriptCallback(base::Value(callback_id), base::Value()); return; } item->AddObserver(new FileDeleter(temp_path)); - web_ui()->CallJavascriptFunctionUnsafe( - "indexeddb.onOriginDownloadReady", - base::Value(partition_path.AsUTF8Unsafe()), - base::Value(origin.Serialize()), - base::Value(static_cast<double>(connection_count))); + ResolveJavascriptCallback(base::Value(callback_id), + base::Value(static_cast<double>(connection_count))); } } // namespace content
diff --git a/content/browser/indexed_db/indexed_db_internals_ui.h b/content/browser/indexed_db/indexed_db_internals_ui.h index 22b9bf3..4c38d1c 100644 --- a/content/browser/indexed_db/indexed_db_internals_ui.h +++ b/content/browser/indexed_db/indexed_db_internals_ui.h
@@ -15,6 +15,7 @@ #include "components/download/public/common/download_interrupt_reasons.h" #include "components/services/storage/public/mojom/indexed_db_control.mojom.h" #include "content/public/browser/web_ui_controller.h" +#include "content/public/browser/web_ui_message_handler.h" namespace base { class ListValue; @@ -37,38 +38,49 @@ ~IndexedDBInternalsUI() override; private: + base::WeakPtrFactory<IndexedDBInternalsUI> weak_factory_{this}; + DISALLOW_COPY_AND_ASSIGN(IndexedDBInternalsUI); +}; + +class IndexedDBInternalsHandler : public WebUIMessageHandler { + public: + IndexedDBInternalsHandler(); + ~IndexedDBInternalsHandler() override; + + // WebUIMessageHandler implementation. + void RegisterMessages() override; + void OnJavascriptDisallowed() override; + + private: void GetAllOrigins(const base::ListValue* args); void OnOriginsReady(const base::Value& origins, const base::FilePath& path); void DownloadOriginData(const base::ListValue* args); - void OnDownloadDataReady(const base::FilePath& partition_path, - const url::Origin& origin, + void OnDownloadDataReady(const std::string& callback_id, uint64_t connection_count, bool success, const base::FilePath& temp_path, const base::FilePath& zip_path); - void OnDownloadStarted(const base::FilePath& partition_path, - const url::Origin& origin, - const base::FilePath& temp_path, + void OnDownloadStarted(const base::FilePath& temp_path, + const std::string& callback_id, size_t connection_count, download::DownloadItem* item, download::DownloadInterruptReason interrupt_reason); void ForceCloseOrigin(const base::ListValue* args); - void OnForcedClose(const base::FilePath& partition_path, - const url::Origin& origin, - uint64_t connection_count); + void OnForcedClose(const std::string& callback_id, uint64_t connection_count); bool GetOriginControl(const base::FilePath& path, const url::Origin& origin, storage::mojom::IndexedDBControl** control); bool GetOriginData(const base::ListValue* args, + std::string* callback_id, base::FilePath* path, url::Origin* origin, storage::mojom::IndexedDBControl** control); - base::WeakPtrFactory<IndexedDBInternalsUI> weak_factory_{this}; - DISALLOW_COPY_AND_ASSIGN(IndexedDBInternalsUI); + base::WeakPtrFactory<IndexedDBInternalsHandler> weak_factory_{this}; + DISALLOW_COPY_AND_ASSIGN(IndexedDBInternalsHandler); }; } // namespace content
diff --git a/content/browser/media/session/media_session_controller_unittest.cc b/content/browser/media/session/media_session_controller_unittest.cc index b4a7e1a..674239b 100644 --- a/content/browser/media/session/media_session_controller_unittest.cc +++ b/content/browser/media/session/media_session_controller_unittest.cc
@@ -178,7 +178,7 @@ } IPC::TestSink& test_sink() { - return main_test_rfh()->agent_scheduling_group().sink(); + return main_test_rfh()->GetAgentSchedulingGroup().sink(); } void Suspend() {
diff --git a/content/browser/navigation_browsertest.cc b/content/browser/navigation_browsertest.cc index 2073dfb..199fb60 100644 --- a/content/browser/navigation_browsertest.cc +++ b/content/browser/navigation_browsertest.cc
@@ -22,6 +22,7 @@ #include "components/network_session_configurator/common/network_switches.h" #include "content/browser/browser_url_handler_impl.h" #include "content/browser/child_process_security_policy_impl.h" +#include "content/browser/network_service_instance_impl.h" #include "content/browser/renderer_host/navigation_request.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/common/content_navigation_policy.h" @@ -42,6 +43,7 @@ #include "content/public/common/content_client.h" #include "content/public/common/content_features.h" #include "content/public/common/content_switches.h" +#include "content/public/common/network_service_util.h" #include "content/public/common/url_constants.h" #include "content/public/test/browser_test.h" #include "content/public/test/browser_test_utils.h" @@ -61,6 +63,7 @@ #include "content/test/content_browser_test_utils_internal.h" #include "content/test/did_commit_navigation_interceptor.h" #include "content/test/fake_network_url_loader_factory.h" +#include "content/test/task_runner_deferring_throttle.h" #include "content/test/test_content_browser_client.h" #include "content/test/test_render_frame_host_factory.h" #include "ipc/ipc_security_test_util.h" @@ -4150,6 +4153,109 @@ current_frame_host()->GetLastCommittedOrigin().CanBeDerivedFrom(url)); } +IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, + ProcessShutdownDuringDeferredNavigationThrottle) { + GURL url = embedded_test_server()->GetURL("a.com", "/empty.html"); + EXPECT_TRUE(NavigateToURL(shell(), url)); + + class ShutdownThrottle : public TaskRunnerDeferringThrottle, + WebContentsObserver { + public: + explicit ShutdownThrottle(WebContents* web_contents, + NavigationHandle* handle) + : TaskRunnerDeferringThrottle(base::ThreadTaskRunnerHandle::Get(), + /*defer_start=*/false, + /*defer_redirect=*/false, + /*defer_response=*/true, + handle), + web_contents_(web_contents) { + WebContentsObserver::Observe(web_contents_); + } + + void AsyncResume() override { + // Shutdown the renderer and delay Resume() until then. + web_contents_->GetMainFrame()->GetProcess()->Shutdown(1); + } + + void RenderFrameDeleted(RenderFrameHost* frame_host) override { + TaskRunnerDeferringThrottle::AsyncResume(); + } + + private: + WebContents* web_contents_; + }; + + auto inserter = std::make_unique<TestNavigationThrottleInserter>( + shell()->web_contents(), + base::BindLambdaForTesting( + [&](NavigationHandle* handle) -> std::unique_ptr<NavigationThrottle> { + return std::make_unique<ShutdownThrottle>(shell()->web_contents(), + handle); + })); + + class DoesNotReadyToCommitObserver : public WebContentsObserver { + public: + explicit DoesNotReadyToCommitObserver(WebContents* contents) + : WebContentsObserver(contents) {} + + // WebContentsObserver overrides. + void ReadyToCommitNavigation(NavigationHandle* handle) override { + // This method should not happen. Since the process is destroyed before + // we become ready to commit, we can not ever reach + // ReadyToCommitNavigation. Doing so would fail because the renderer is + // gone. + ADD_FAILURE() << "ReadyToCommitNavigation but renderer has crashed. " + "IsRenderFrameLive: " + << handle->GetRenderFrameHost()->IsRenderFrameLive(); + navigation_was_ready_to_commit_ = true; + } + + void DidFinishNavigation(NavigationHandle* handle) override { + navigation_finished_ = true; + navigation_committed_ = handle->HasCommitted(); + } + + bool navigation_was_ready_to_commit() { + return navigation_was_ready_to_commit_; + } + bool navigation_finished() { return navigation_finished_; } + bool navigation_committed() { return navigation_committed_; } + + private: + bool navigation_was_ready_to_commit_ = false; + bool navigation_finished_ = false; + bool navigation_committed_ = false; + }; + + // Watch that ReadyToCommitNavigation() will not happen when the renderer is + // gone. + DoesNotReadyToCommitObserver no_commit_obs(shell()->web_contents()); + + // We will shutdown the renderer during this navigation. + ScopedAllowRendererCrashes scoped_allow_renderer_crashes; + + // Important: This is a browser-initiated navigation, so the NavigationRequest + // does not have an open connection (NavigationClient) to the renderer that it + // is listening to for termination while running NavigationThrottles. + // + // Expect this navigation to be aborted, so we stop waiting after the + // uncommitted navigation is done. + GURL url2 = embedded_test_server()->GetURL("a.com", "/title1.html"); + NavigateToURLBlockUntilNavigationsComplete( + shell(), url2, /*number_of_navigations=*/1, + /*ignore_uncommitted_navigations=*/false); + + // The renderer was shutdown mid-navigation. + EXPECT_FALSE(shell()->web_contents()->GetMainFrame()->IsRenderFrameLive()); + + // The navigation was aborted, which means it finished but did not commit, and + // _importantly_ it never reported "ReadyToCommitNavigation" without a live + // renderer. + EXPECT_TRUE(no_commit_obs.navigation_finished()); + EXPECT_FALSE(no_commit_obs.navigation_was_ready_to_commit()); + EXPECT_FALSE(no_commit_obs.navigation_committed()); +} + // Do sandbox flags apply to error page in sandboxed iframes? // Apparently yes. // TODO(https://crbug.com/1158370): Reconsider this. @@ -4326,6 +4432,47 @@ console_observer.Wait(); } +namespace { + +void VerifyResultsOfAboutBlankNavigation(RenderFrameHostImpl* target_frame, + RenderFrameHostImpl* initiator_frame) { + // Verify that `target_frame` has been navigated to "about:blank". + EXPECT_EQ(GURL(url::kAboutBlankURL), target_frame->GetLastCommittedURL()); + + // Verify that "about:blank" committed with the expected origin, and in the + // expected SiteInstance. + EXPECT_EQ(target_frame->GetLastCommittedOrigin(), + initiator_frame->GetLastCommittedOrigin()); + EXPECT_EQ(target_frame->GetSiteInstance(), + initiator_frame->GetSiteInstance()); + + // Start monitoring NetworkService for crashes. + // + // TODO(https://crbug.com/1169431): This should be part of BrowserTestBase. + // (with optional opt-out for things like NetworkServiceRestartBrowserTest). + bool did_network_service_crash = false; + base::CallbackListSubscription crash_monitoring_subscription = + RegisterNetworkServiceCrashHandler(base::BindLambdaForTesting( + [&]() { did_network_service_crash = true; })); + // Ask for cookies in the `target_frame`. One implicit verification here + // is whether this step will hit any `cookie_url`-related NOTREACHED or DwoC + // in RestrictedCookieManager::ValidateAccessToCookiesAt. This verification + // is non-racey, because `document.cookie` must have heard back from the + // RestrictedCookieManager before returning the value of cookies (this ignores + // possible Blink-side caching, but this is the first time the renderer needs + // the cookies and so this is okay for this test). + EXPECT_EQ("", EvalJs(target_frame, "document.cookie")); + // |network_context| might receive an error notification, but it's not + // guaranteed to have arrived at this point. Flush the remote to make sure + // the notification has been received. + // TODO(https://crbug.com/1169431): This should be part of BrowserTestBase. + if (!IsInProcessNetworkService()) + target_frame->FlushNetworkAndNavigationInterfacesForTesting(); + EXPECT_FALSE(did_network_service_crash); +} + +} // namespace + // The test below verifies that an "about:blank" navigation commits with the // right origin, even when the initiator of the navigation is not the parent or // opener of the frame targeted by the navigation. In the @@ -4372,10 +4519,7 @@ shell()->web_contents()->GetMainFrame()); child_frame = main_frame->child_at(0)->current_frame_host(); grandchild_frame = child_frame->child_at(0)->current_frame_host(); - EXPECT_EQ(main_frame->GetLastCommittedOrigin(), - grandchild_frame->GetLastCommittedOrigin()); - EXPECT_EQ(GURL(url::kAboutBlankURL), grandchild_frame->GetLastCommittedURL()); - EXPECT_EQ(main_frame->GetSiteInstance(), grandchild_frame->GetSiteInstance()); + VerifyResultsOfAboutBlankNavigation(grandchild_frame, main_frame); } // The test below verifies that an "about:blank" navigation commits with the @@ -4425,10 +4569,7 @@ shell()->web_contents()->GetMainFrame()); child_frame = main_frame->child_at(0)->current_frame_host(); grandchild_frame = child_frame->child_at(0)->current_frame_host(); - EXPECT_EQ(main_frame->GetLastCommittedOrigin(), - grandchild_frame->GetLastCommittedOrigin()); - EXPECT_EQ(GURL(url::kAboutBlankURL), grandchild_frame->GetLastCommittedURL()); - EXPECT_EQ(main_frame->GetSiteInstance(), grandchild_frame->GetSiteInstance()); + VerifyResultsOfAboutBlankNavigation(grandchild_frame, main_frame); } // The test below verifies that an "about:blank" navigation commits with the @@ -4479,10 +4620,7 @@ shell()->web_contents()->GetMainFrame()); child_frame = main_frame->child_at(0)->current_frame_host(); grandchild_frame = child_frame->child_at(0)->current_frame_host(); - EXPECT_EQ(main_frame->GetLastCommittedOrigin(), - grandchild_frame->GetLastCommittedOrigin()); - EXPECT_EQ(GURL(url::kAboutBlankURL), grandchild_frame->GetLastCommittedURL()); - EXPECT_EQ(main_frame->GetSiteInstance(), grandchild_frame->GetSiteInstance()); + VerifyResultsOfAboutBlankNavigation(grandchild_frame, main_frame); } // The test below verifies that an "about:blank" navigation commits with the @@ -4570,10 +4708,7 @@ shell()->web_contents()->GetMainFrame()); child_frame1 = main_frame->child_at(0)->current_frame_host(); child_frame2 = main_frame->child_at(1)->current_frame_host(); - EXPECT_EQ(GURL(url::kAboutBlankURL), child_frame2->GetLastCommittedURL()); - EXPECT_EQ(child_frame1->GetLastCommittedOrigin(), - child_frame2->GetLastCommittedOrigin()); - EXPECT_EQ(child_frame1->GetSiteInstance(), child_frame2->GetSiteInstance()); + VerifyResultsOfAboutBlankNavigation(child_frame2, child_frame1); } } // namespace content
diff --git a/content/browser/process_internals/process_internals_handler_impl.cc b/content/browser/process_internals/process_internals_handler_impl.cc index 5eed173..c0aa1121 100644 --- a/content/browser/process_internals/process_internals_handler_impl.cc +++ b/content/browser/process_internals/process_internals_handler_impl.cc
@@ -34,7 +34,7 @@ frame_info->routing_id = frame->GetRoutingID(); frame_info->agent_scheduling_group_id = - frame->agent_scheduling_group().id_for_debugging(); + frame->GetAgentSchedulingGroup().id_for_debugging(); frame_info->process_id = frame->GetProcess()->GetID(); frame_info->last_committed_url = frame->GetLastCommittedURL().is_valid()
diff --git a/content/browser/renderer_host/frame_tree_browsertest.cc b/content/browser/renderer_host/frame_tree_browsertest.cc index b514bf9..845fe61 100644 --- a/content/browser/renderer_host/frame_tree_browsertest.cc +++ b/content/browser/renderer_host/frame_tree_browsertest.cc
@@ -383,9 +383,11 @@ " resolve(frames[0].self.origin);" " }, 16);" "});"); + // Since we used document.write(), the URL of the frame document changes to + // match the document that called it. + EXPECT_EQ(initiator->current_url(), target->current_url()); + EXPECT_EQ(url::kHttpScheme, target->current_url().scheme()); EXPECT_EQ(target->current_origin(), about_blank_origin); - EXPECT_EQ(GURL(url::kAboutBlankURL), target->current_url()); - EXPECT_EQ(url::kAboutScheme, target->current_url().scheme()); EXPECT_FALSE(target->current_origin().opaque()); EXPECT_EQ("b.com", target->current_origin().host()); EXPECT_EQ(url::kHttpScheme, target->current_origin().scheme());
diff --git a/content/browser/renderer_host/navigation_controller_impl_browsertest.cc b/content/browser/renderer_host/navigation_controller_impl_browsertest.cc index 13c995a..8f453562 100644 --- a/content/browser/renderer_host/navigation_controller_impl_browsertest.cc +++ b/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
@@ -1602,6 +1602,9 @@ EXPECT_EQ(blank_url, new_root->current_url()); // Make a new iframe in it using document.write from the opener. + // Call document.open() outside LoadCommittedCapturer as it implicitly does a + // same-document navigation. + EXPECT_TRUE(ExecJs(root->current_frame_host(), "w.document.open()")); { LoadCommittedCapturer capturer(new_shell->web_contents()); std::string html = "<iframe src='" + url1.spec() + "'></iframe>"; @@ -1613,7 +1616,9 @@ capturer.Wait(); } ASSERT_EQ(1U, new_root->child_count()); - EXPECT_EQ(blank_url, new_root->current_url()); + // Since we did a document.open(), the new root's URL is the same as the + // outer URL. + EXPECT_EQ(url1, new_root->current_url()); EXPECT_EQ(url1, new_root->child_at(0)->current_url()); // Navigate the subframe. @@ -1625,7 +1630,7 @@ EXPECT_TRUE(ExecJs(new_root->child_at(0), script)); capturer.Wait(); } - EXPECT_EQ(blank_url, new_root->current_url()); + EXPECT_EQ(url1, new_root->current_url()); EXPECT_EQ(url2, new_root->child_at(0)->current_url()); EXPECT_EQ(2, new_shell->web_contents()->GetController().GetEntryCount()); @@ -1660,6 +1665,96 @@ EXPECT_TRUE(new_root->current_frame_host()->IsRenderFrameLive()); } +// Test that a frame's url is correctly updated after a document.open() from +// an about:blank frame. +IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest, + DocumentOpenFromAboutBlank) { + GURL url1 = embedded_test_server()->GetURL( + "/navigation_controller/page_with_iframe_simple.html"); + EXPECT_TRUE(NavigateToURL(shell(), url1)); + FrameTreeNode* root = contents()->GetFrameTree()->root(); + + // Make a new iframe that will document.open() its sibling. + { + LoadCommittedCapturer capturer(contents()); + EXPECT_EQ("done", EvalJs(root->current_frame_host(), R"( + new Promise(async resolve => { + const blank_iframe = document.createElement('iframe'); + await new Promise(resolve => { + blank_iframe.onload = resolve; + document.body.appendChild(blank_iframe); + }); + + let script = document.createElement('script'); + script.text = ` + const sibling = parent.document.getElementById("frame") + sibling.contentDocument.open(); + `; + blank_iframe.contentDocument.body.appendChild(script); + resolve("done"); + }) + )")); + capturer.Wait(); + } + ASSERT_EQ(2U, root->child_count()); + EXPECT_EQ(GURL(url::kAboutBlankURL), root->child_at(0)->current_url()); + EXPECT_EQ(GURL(url::kAboutBlankURL), root->child_at(1)->current_url()); +} + +// Test that a frame's url is correctly updated after a document.open() from +// an about:srcdoc frame. +IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest, + DocumentOpenFromSrcdoc) { + GURL url1 = embedded_test_server()->GetURL( + "/navigation_controller/page_with_iframe_simple.html"); + EXPECT_TRUE(NavigateToURL(shell(), url1)); + FrameTreeNode* root = contents()->GetFrameTree()->root(); + + // Make a new iframe that will document.open() its sibling. + { + LoadCommittedCapturer capturer(contents()); + std::string html = "<iframe src='" + url1.spec() + "'></iframe>"; + std::string script = + "let origin = document.createElement('iframe');" + "origin.srcdoc = '<script>parent.document.getElementById(\"frame\")" + ".contentDocument.open();</s' + 'cript>';" + "document.body.appendChild(origin);"; + EXPECT_TRUE(ExecJs(root->current_frame_host(), script)); + capturer.Wait(); + } + ASSERT_EQ(2U, root->child_count()); + EXPECT_EQ("about:srcdoc", root->child_at(0)->current_url()); + EXPECT_EQ("about:srcdoc", root->child_at(1)->current_url()); +} + +// Test that a frame's url is correctly updated after a document.open() from +// a blob: url +IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest, + DocumentOpenFromBloblIframe) { + GURL url1 = embedded_test_server()->GetURL( + "/navigation_controller/page_with_iframe_simple.html"); + EXPECT_TRUE(NavigateToURL(shell(), url1)); + FrameTreeNode* root = contents()->GetFrameTree()->root(); + + // Make a new iframe that will document.open() its sibling. + { + LoadCommittedCapturer capturer(contents()); + std::string html = "<iframe src='" + url1.spec() + "'></iframe>"; + std::string script = + "let origin = document.createElement('iframe');" + "let blob = new Blob(['<script>" + "parent.document.getElementById(\"frame\").contentDocument.open();" + "</s' + 'cript>'], { type: 'text/html' });" + "origin.src = URL.createObjectURL(blob);" + "document.body.appendChild(origin);"; + EXPECT_TRUE(ExecJs(root->current_frame_host(), script)); + capturer.Wait(); + } + ASSERT_EQ(2U, root->child_count()); + EXPECT_TRUE(root->child_at(0)->current_url().SchemeIsBlob()); + EXPECT_TRUE(root->child_at(1)->current_url().SchemeIsBlob()); +} + IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest, ErrorPageReplacement) { NavigationController& controller = shell()->web_contents()->GetController(); GURL error_url = embedded_test_server()->GetURL("/close-socket"); @@ -4153,7 +4248,7 @@ ASSERT_EQ(1U, root->child_at(0)->child_count()); ASSERT_EQ(0U, root->child_at(0)->child_at(0)->child_count()); EXPECT_EQ(main_url, root->current_url()); - EXPECT_EQ(blank_url, root->child_at(0)->current_url()); + EXPECT_EQ(main_url, root->child_at(0)->current_url()); EXPECT_EQ(inner_url, root->child_at(0)->child_at(0)->current_url()); EXPECT_EQ(1, controller.GetEntryCount()); @@ -4162,7 +4257,7 @@ // The entry should have FrameNavigationEntries for the subframes. ASSERT_EQ(1U, entry->root_node()->children.size()); - EXPECT_EQ(blank_url, entry->root_node()->children[0]->frame_entry->url()); + EXPECT_EQ(main_url, entry->root_node()->children[0]->frame_entry->url()); EXPECT_EQ(inner_url, entry->root_node()->children[0]->children[0]->frame_entry->url()); @@ -4188,7 +4283,7 @@ } ASSERT_EQ(1U, root->child_count()); EXPECT_EQ(main_url, root->current_url()); - EXPECT_EQ(blank_url, root->child_at(0)->current_url()); + EXPECT_EQ(main_url, root->child_at(0)->current_url()); // Verify that the inner iframe went to the correct URL. EXPECT_EQ(inner_url, root->child_at(0)->child_at(0)->current_url()); @@ -4204,7 +4299,7 @@ ASSERT_EQ(1U, entry->root_node()->children.size()); // The entry should have FrameNavigationEntries for the subframes. - EXPECT_EQ(blank_url, entry->root_node()->children[0]->frame_entry->url()); + EXPECT_EQ(main_url, entry->root_node()->children[0]->frame_entry->url()); EXPECT_EQ(inner_url, entry->root_node()->children[0]->children[0]->frame_entry->url()); @@ -6039,9 +6134,13 @@ // The original request URL will be the first entry of redirect chain, // which is the URL that initiated the client redirect. However due to the // bug above this will actually result in a blank URL. - // TODO(https://crbug.com/1171210): Fix this. Also, figure out why this also - // happens when we didn't enter the "about:blank#blocked" part above? - EXPECT_EQ(entry->GetOriginalRequestURL(), GURL()); + // TODO(https://crbug.com/1171210): Fix this. + if (AreAllSitesIsolatedForTesting() || + CanCrossSiteNavigationsProactivelySwapBrowsingInstances()) { + EXPECT_EQ(entry->GetOriginalRequestURL(), GURL()); + } else { + EXPECT_EQ(entry->GetRedirectChain()[0], start_url); + } } { @@ -7683,13 +7782,15 @@ ASSERT_NE(nullptr, frame); EXPECT_EQ(blank_url, frame->current_url()); - // Do a document.write in the subframe to create a link to click. + // Do a document.write() in the subframe to create a link to click. This sets + // the URL to be the same as the frame that called document.write(). std::string document_write_script = "var iframe = document.getElementById('frame');" "iframe.contentWindow.document.write(" " \"<a id='fraglink' href='#frag'>fragment link</a>\");" "iframe.contentWindow.document.close();"; EXPECT_TRUE(ExecJs(root->current_frame_host(), document_write_script)); + EXPECT_EQ(links_url, frame->current_url()); // Click the link to do a same document navigation. Due to the // document.write, the new URL matches the parent frame's URL. @@ -7716,7 +7817,10 @@ EXPECT_TRUE(ExecJs(root->current_frame_host(), "true;")); EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive()); - EXPECT_EQ(blank_url, frame->current_url()); + // When we go back in history, the history entry URL should be used. However, + // since we did a .write which set the history entry's URL, we go back to the + // main page URL. + EXPECT_EQ(links_url, frame->current_url()); } // Test for same document navigation kills when going back to about:blank in an @@ -7767,12 +7871,14 @@ "iframe.contentWindow.document.close();", html); EXPECT_TRUE(ExecJs(root, document_write_script)); + EXPECT_EQ(data_url, frame->current_url()); EXPECT_EQ(opaque_origin, root->current_origin()); EXPECT_EQ(opaque_origin, frame->current_origin()); - // Click the link to do a same document navigation. Due to the + // Click the link to do a same document navigation. Due to the // document.write, the new URL matches the parent frame's URL, but the - // opaque origin is preserved. + // opaque origin is preserved. Not only that, the history entry's URL is + // changed to match the parent frame's URL. GURL frame_url_2("data:text/html,Top level page#frag"); std::string link_script = "document.getElementById('fraglink').click()"; EXPECT_TRUE(ExecJs(frame, link_script)); @@ -7802,7 +7908,10 @@ EXPECT_EQ("ping", EvalJs(root, "'ping'")); EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive()); - EXPECT_EQ(blank_url, frame->current_url()); + // When we go back in history, the history entry URL should be used. However, + // since we did a .write which set the history entry's URL, we go back to the + // main page URL. + EXPECT_EQ(data_url, frame->current_url()); EXPECT_EQ(opaque_origin, frame->current_origin()); }
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc index f7fd3404..7bd4202 100644 --- a/content/browser/renderer_host/navigation_request.cc +++ b/content/browser/renderer_host/navigation_request.cc
@@ -4671,6 +4671,18 @@ void NavigationRequest::ReadyToCommitNavigation(bool is_error) { EnterChildTraceEvent("ReadyToCommitNavigation", this); + // We may come back to here asynchronously, and the renderer may be destroyed + // in the meantime. Renderer-initiated navigations listen to mojo + // disconnection from the renderer NavigationClient; but browser-initiated + // navigations do not, so we must look explicitly. We should not proceed and + // claim "ReadyToCommitNavigation" to the delegate if the renderer is gone. + if (!render_frame_host_->IsRenderFrameLive()) { + OnRendererAbortedNavigation(); + // DO NOT ADD CODE AFTER THIS, as the NavigationHandle has been deleted + // by the previous call. + return; + } + SetState(READY_TO_COMMIT); ready_to_commit_time_ = base::TimeTicks::Now(); RestartCommitTimeout();
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc index b820fbf20..6a91a4f 100644 --- a/content/browser/renderer_host/render_frame_host_impl.cc +++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -1057,7 +1057,7 @@ // Only main frames have `waiting_for_init_` set. DCHECK(!waiting_for_init_ || !parent_); - agent_scheduling_group().AddRoute(routing_id_, this); + GetAgentSchedulingGroup().AddRoute(routing_id_, this); g_routing_id_frame_map.Get().emplace( GlobalFrameRoutingId(GetProcess()->GetID(), routing_id_), this); g_token_frame_map.Get().insert(std::make_pair(frame_token_, this)); @@ -1274,7 +1274,7 @@ if (was_created && render_view_host_->GetMainFrame() != this) CHECK(IsPendingDeletion() || IsInBackForwardCache()); - agent_scheduling_group().RemoveRoute(routing_id_); + GetAgentSchedulingGroup().RemoveRoute(routing_id_); g_routing_id_frame_map.Get().erase( GlobalFrameRoutingId(GetProcess()->GetID(), routing_id_)); @@ -1516,7 +1516,7 @@ return agent_scheduling_group_.GetProcess(); } -AgentSchedulingGroupHost& RenderFrameHostImpl::agent_scheduling_group() { +AgentSchedulingGroupHost& RenderFrameHostImpl::GetAgentSchedulingGroup() { return agent_scheduling_group_; } @@ -1860,8 +1860,8 @@ if (!remote_associated_interfaces_) { mojo::AssociatedRemote<blink::mojom::AssociatedInterfaceProvider> remote_interfaces; - if (agent_scheduling_group().GetChannel()) { - agent_scheduling_group().GetRemoteRouteProvider()->GetRoute( + if (GetAgentSchedulingGroup().GetChannel()) { + GetAgentSchedulingGroup().GetRemoteRouteProvider()->GetRoute( GetRoutingID(), remote_interfaces.BindNewEndpointAndPassReceiver()); } else { // The channel may not be initialized in some tests environments. In this @@ -1903,7 +1903,7 @@ } bool RenderFrameHostImpl::Send(IPC::Message* message) { - return agent_scheduling_group().Send(message); + return GetAgentSchedulingGroup().Send(message); } bool RenderFrameHostImpl::OnMessageReceived(const IPC::Message& msg) { @@ -2277,7 +2277,7 @@ // initialized it) or may not (we have our own process or the old process // crashed) have been initialized. Calling Init() multiple times will be // ignored, so this is safe. - if (!agent_scheduling_group().Init()) + if (!GetAgentSchedulingGroup().Init()) return false; DCHECK(GetProcess()->IsInitializedAndNotDead()); @@ -2376,7 +2376,7 @@ // be able to insert the new frame in the frame tree. DCHECK(params->previous_routing_id != MSG_ROUTING_NONE || params->parent_routing_id != MSG_ROUTING_NONE); - agent_scheduling_group().CreateFrame(std::move(params)); + GetAgentSchedulingGroup().CreateFrame(std::move(params)); if (previous_routing_id != MSG_ROUTING_NONE) { RenderFrameProxyHost* proxy = RenderFrameProxyHost::FromID(
diff --git a/content/browser/renderer_host/render_frame_host_impl.h b/content/browser/renderer_host/render_frame_host_impl.h index 5e42a6fb..f76b88c 100644 --- a/content/browser/renderer_host/render_frame_host_impl.h +++ b/content/browser/renderer_host/render_frame_host_impl.h
@@ -561,7 +561,6 @@ NavigationRequest* navigation_request, bool did_create_new_document); - virtual AgentSchedulingGroupHost& agent_scheduling_group(); RenderViewHostImpl* render_view_host() { return render_view_host_.get(); } RenderFrameHostDelegate* delegate() { return delegate_; } FrameTree* frame_tree() const { return frame_tree_; } @@ -1013,6 +1012,10 @@ const mojo::AssociatedRemote<blink::mojom::LocalFrame>& GetAssociatedLocalFrame(); + // Returns the AgentSchedulingGroupHost associated with this + // RenderFrameHostImpl. + virtual AgentSchedulingGroupHost& GetAgentSchedulingGroup(); + // Returns associated remote for the blink::mojom::LocalMainFrame Mojo // interface. May be overridden by subclasses, e.g. tests which wish to // intercept outgoing local main frame messages.
diff --git a/content/browser/renderer_host/render_frame_host_manager.cc b/content/browser/renderer_host/render_frame_host_manager.cc index b8ace6d..8c15970f 100644 --- a/content/browser/renderer_host/render_frame_host_manager.cc +++ b/content/browser/renderer_host/render_frame_host_manager.cc
@@ -2988,6 +2988,14 @@ TRACE_EVENT1("navigation", "RenderFrameHostManager::CommitPending", "FrameTreeNode id", frame_tree_node_->frame_tree_node_id()); CHECK(pending_rfh); + // We either come here with a `pending_rfh` that is + // 1) a speculative RenderFrameHost, which would have been deleted + // immediately upon renderer process exit, so it must still have a live + // connection to its renderer frame. + // 2) a current RenderFrameHost which has just received a commit IPC from the + // renderer, so it must have a live connection to its renderer frame in + // order to receive the IPC. + DCHECK(pending_rfh->IsRenderFrameCreated()); // We should never have a pending bfcache entry if bfcache is disabled. DCHECK(!pending_bfcache_entry || IsBackForwardCacheEnabled()); @@ -3009,6 +3017,7 @@ // Remember if the page was focused so we can focus the new renderer in // that case. bool focus_render_view = + old_view && old_view->HasFocus() && render_frame_host_->GetMainFrame()->GetRenderWidgetHost()->is_focused(); // Remove the current frame and its descendants from the set of fullscreen @@ -3103,8 +3112,13 @@ } RenderWidgetHostView* new_view = render_frame_host_->GetView(); + // Since the committing renderer frame is live, the RenderWidgetHostView must + // also exist. For a local root frame, they share lifetimes exactly. For + // another child frame, the RenderWidgetHostView comes from a parent, but if + // this renderer frame is live its ancestors must be as well. + DCHECK(new_view); - if (focus_render_view && new_view) { + if (focus_render_view) { if (is_main_frame) { new_view->Focus(); } else { @@ -3134,7 +3148,7 @@ // Make the new view show the contents of old view until it has something // useful to show. - if (is_main_frame && old_view && new_view && old_view != new_view) + if (is_main_frame && old_view && old_view != new_view) new_view->TakeFallbackContentFrom(old_view); // The RenderViewHost keeps track of the main RenderFrameHost routing id. @@ -3213,7 +3227,7 @@ if (proxy_to_parent) proxy_to_parent->SetChildRWHView(new_view, old_size ? &*old_size : nullptr); - if (render_frame_host_->is_local_root() && new_view) { + if (render_frame_host_->is_local_root()) { // RenderFrames are created with a hidden RenderWidgetHost. When navigation // finishes, we show it if the delegate is shown. if (!frame_tree_node_->frame_tree()->IsHidden()) @@ -3223,17 +3237,6 @@ // The process will no longer try to exit, so we can decrement the count. render_frame_host_->GetProcess()->RemovePendingView(); - // If there's no RenderWidgetHostView on this frame's local root (or itself - // if it is a local root), then this RenderViewHost died while it was hidden. - // We ignored the RenderProcessGone call at the time, so we should send it now - // to make sure the sad tab shows up, etc. - if (!new_view) { - DCHECK(!render_frame_host_->IsRenderFrameLive()); - DCHECK(!new_rvh->IsRenderViewLive()); - render_frame_host_->ResetLoadingState(); - delegate_->RenderProcessGoneFromRenderManager(new_rvh); - } - // After all is done, there must never be a proxy in the list which has the // same SiteInstance as the current RenderFrameHost. CHECK(!GetRenderFrameProxyHost(render_frame_host_->GetSiteInstance()));
diff --git a/content/browser/renderer_host/render_frame_host_manager.h b/content/browser/renderer_host/render_frame_host_manager.h index 15a9549..22d9aeea 100644 --- a/content/browser/renderer_host/render_frame_host_manager.h +++ b/content/browser/renderer_host/render_frame_host_manager.h
@@ -133,8 +133,6 @@ bool proceed, const base::TimeTicks& proceed_time, bool* proceed_to_fire_unload) = 0; - virtual void RenderProcessGoneFromRenderManager( - RenderViewHost* render_view_host) = 0; virtual void CancelModalDialogsForRenderManager() = 0; virtual void NotifySwappedFromRenderManager(RenderFrameHost* old_frame, RenderFrameHost* new_frame,
diff --git a/content/browser/renderer_host/render_frame_host_manager_browsertest.cc b/content/browser/renderer_host/render_frame_host_manager_browsertest.cc index 2310739..ee37618 100644 --- a/content/browser/renderer_host/render_frame_host_manager_browsertest.cc +++ b/content/browser/renderer_host/render_frame_host_manager_browsertest.cc
@@ -4049,10 +4049,12 @@ kExpectedSiteURL.spec(), DepictFrameTree(*root)); - EXPECT_EQ(GURL(url::kAboutBlankURL), - root->child_at(0)->child_at(0)->current_url()); + EXPECT_EQ(url, root->child_at(0)->child_at(0)->current_url()); - EXPECT_FALSE(root->child_at(0)->child_at(0)->has_committed_real_load()); + // This is true because of the document.open() call, which makes the frame to + // be considered to have had committed a real load. The FrameTreeVisualizer + // test should be enough to ensure that the childmost frame is not loaded. + EXPECT_TRUE(root->child_at(0)->child_at(0)->has_committed_real_load()); } // Ensure that navigating a subframe to the same URL as its parent twice in a
diff --git a/content/browser/renderer_host/render_frame_host_manager_unittest.cc b/content/browser/renderer_host/render_frame_host_manager_unittest.cc index 68aed23..02eace6 100644 --- a/content/browser/renderer_host/render_frame_host_manager_unittest.cc +++ b/content/browser/renderer_host/render_frame_host_manager_unittest.cc
@@ -2514,6 +2514,8 @@ DidNavigateFrame(child, hostB); // Ensure that the main page is focused. + main_test_rfh()->GetView()->Focus(); + EXPECT_TRUE(main_test_rfh()->GetView()->HasFocus()); main_test_rfh()->GetRenderWidgetHost()->SetPageFocus(true); EXPECT_TRUE(main_test_rfh()->GetRenderWidgetHost()->is_focused());
diff --git a/content/browser/resources/histograms/BUILD.gn b/content/browser/resources/histograms/BUILD.gn index cc4ce92..b5fab5c 100644 --- a/content/browser/resources/histograms/BUILD.gn +++ b/content/browser/resources/histograms/BUILD.gn
@@ -5,12 +5,13 @@ import("//third_party/closure_compiler/compile_js.gni") js_type_check("closure_compile") { + uses_js_modules = true deps = [ ":histograms_internals" ] } js_library("histograms_internals") { deps = [ - "//ui/webui/resources/js:cr", - "//ui/webui/resources/js:util", + "//ui/webui/resources/js:cr.m", + "//ui/webui/resources/js:util.m", ] }
diff --git a/content/browser/resources/histograms/histograms_internals.html b/content/browser/resources/histograms/histograms_internals.html index 480bf33..e725fb7 100644 --- a/content/browser/resources/histograms/histograms_internals.html +++ b/content/browser/resources/histograms/histograms_internals.html
@@ -5,11 +5,7 @@ <html dir="ltr" lang="en"> <head> <meta charset="utf-8"> - <script src="chrome://resources/js/cr.js"></script> - <script src="chrome://resources/js/assert.js"></script> - <script src="chrome://resources/js/promise_resolver.js"></script> - <script src="chrome://resources/js/util.js"></script> - <script src="histograms_internals.js"></script> + <script type="module" src="histograms_internals.js"></script> <title>Histograms</title> </head> <h1>Histograms</h1>
diff --git a/content/browser/resources/histograms/histograms_internals.js b/content/browser/resources/histograms/histograms_internals.js index 00d71ea..5d4786a 100644 --- a/content/browser/resources/histograms/histograms_internals.js +++ b/content/browser/resources/histograms/histograms_internals.js
@@ -2,6 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import {sendWithPromise} from 'chrome://resources/js/cr.m.js'; +import {$} from 'chrome://resources/js/util.m.js'; + /** * Initiates the request for histograms. */ @@ -10,7 +13,7 @@ if (document.location.pathname) { query = document.location.pathname.substring(1); } - cr.sendWithPromise('requestHistograms', query).then(addHistograms); + sendWithPromise('requestHistograms', query).then(addHistograms); } /** @@ -29,6 +32,7 @@ clone.querySelector('p').textContent = body; $('histograms').appendChild(clone); } + $('histograms').dispatchEvent(new CustomEvent('histograms-updated-for-test')); } /**
diff --git a/content/browser/resources/indexed_db/indexeddb_internals.html b/content/browser/resources/indexed_db/indexeddb_internals.html index c8aef91..aad8e87 100644 --- a/content/browser/resources/indexed_db/indexeddb_internals.html +++ b/content/browser/resources/indexed_db/indexeddb_internals.html
@@ -166,10 +166,6 @@ <div class="content"> <div id="indexeddb-list"> </div> - <script src="chrome://resources/js/assert.js"></script> - <script src="chrome://resources/js/util.js"></script> - <script src="chrome://resources/js/cr.js"></script> - <script src="indexeddb_internals.js"></script> - <script src="chrome://resources/js/jstemplate_compiled.js"></script> + <script type="module" src="indexeddb_internals.js"></script> </body> </html>
diff --git a/content/browser/resources/indexed_db/indexeddb_internals.js b/content/browser/resources/indexed_db/indexeddb_internals.js index 8e63c36..843963d 100644 --- a/content/browser/resources/indexed_db/indexeddb_internals.js +++ b/content/browser/resources/indexed_db/indexeddb_internals.js
@@ -2,12 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -cr.define('indexeddb', function() { - 'use strict'; +import 'chrome://resources/js/jstemplate_compiled.js'; - function initialize() { - chrome.send('getAllOrigins'); - } +import {addWebUIListener, sendWithPromise} from 'chrome://resources/js/cr.m.js'; +import {$} from 'chrome://resources/js/util.m.js'; + +function initialize() { + addWebUIListener('origins-ready', onOriginsReady); + + chrome.send('getAllOrigins'); +} function progressNodeFor(link) { return link.parentNode.querySelector('.download-status'); @@ -16,15 +20,22 @@ function downloadOriginData(event) { const link = event.target; progressNodeFor(link).style.display = 'inline'; - chrome.send( - 'downloadOriginData', [link.idb_partition_path, link.idb_origin_url]); + const path = link.idb_partition_path; + const origin = link.idb_origin_url; + sendWithPromise('downloadOriginData', path, origin) + .then(count => onOriginDownloadReady(path, origin, count), () => { + console.error('Error downloading data for origin ' + origin); + }); return false; } function forceClose(event) { const link = event.target; progressNodeFor(link).style.display = 'inline'; - chrome.send('forceClose', [link.idb_partition_path, link.idb_origin_url]); + const path = link.idb_partition_path; + const origin = link.idb_origin_url; + sendWithPromise('forceClose', path, origin) + .then(count => onForcedClose(path, origin, count)); return false; } @@ -78,12 +89,4 @@ } } - return { - initialize: initialize, - onForcedClose: onForcedClose, - onOriginDownloadReady: onOriginDownloadReady, - onOriginsReady: onOriginsReady, - }; -}); - -document.addEventListener('DOMContentLoaded', indexeddb.initialize); + document.addEventListener('DOMContentLoaded', initialize);
diff --git a/content/browser/sandbox_parameters_mac.mm b/content/browser/sandbox_parameters_mac.mm index f7c7fe3e5..50aa05f 100644 --- a/content/browser/sandbox_parameters_mac.mm +++ b/content/browser/sandbox_parameters_mac.mm
@@ -39,8 +39,12 @@ namespace { -// Set by SetNetworkTestCertsDirectoryForTesting(). -base::NoDestructor<base::Optional<base::FilePath>> g_network_test_certs_dir; +base::Optional<base::FilePath>& GetNetworkTestCertsDirectory() { + // Set by SetNetworkTestCertsDirectoryForTesting(). + static base::NoDestructor<base::Optional<base::FilePath>> + network_test_certs_dir; + return *network_test_certs_dir; +} // Produce the OS version as an integer "1010", etc. and pass that to the // profile. The profile converts the string back to a number and can do @@ -160,10 +164,10 @@ CHECK(client->SetParameter(param_name, path.value())) << param_name; } - if (g_network_test_certs_dir->has_value()) { + if (GetNetworkTestCertsDirectory().has_value()) { CHECK(client->SetParameter("NETWORK_SERVICE_TEST_CERTS_DIR", sandbox::policy::SandboxMac::GetCanonicalPath( - **g_network_test_certs_dir) + *GetNetworkTestCertsDirectory()) .value())); } } @@ -212,6 +216,25 @@ SetupCommonSandboxParameters(client); } +void SetupGpuSandboxParameters(sandbox::SeatbeltExecClient* client, + const base::CommandLine& command_line) { + SetupCommonSandboxParameters(client); + AddDarwinDirs(client); + CHECK(client->SetBooleanParameter( + sandbox::policy::SandboxMac::kSandboxDisableMetalShaderCache, + command_line.HasSwitch( + sandbox::policy::switches::kDisableMetalShaderCache))); + + // Temporary for https://crbug.com/1126350. + CHECK(client->SetParameter("PARENT_DIR", + sandbox::policy::SandboxMac::GetCanonicalPath( + base::mac::OuterBundlePath().DirName()) + .value())); + base::FilePath pwd; + CHECK(base::GetCurrentDirectory(&pwd)); + CHECK(client->SetParameter("PWD", pwd.value())); +} + } // namespace void SetupSandboxParameters(sandbox::policy::SandboxType sandbox_type, @@ -225,16 +248,7 @@ SetupCommonSandboxParameters(client); break; case sandbox::policy::SandboxType::kGpu: { - SetupCommonSandboxParameters(client); - // Temporary for https://crbug.com/1126350. - CHECK(client->SetParameter("PARENT_DIR", - sandbox::policy::SandboxMac::GetCanonicalPath( - base::mac::OuterBundlePath().DirName()) - .value())); - base::FilePath pwd; - CHECK(base::GetCurrentDirectory(&pwd)); - CHECK(client->SetParameter("PWD", pwd.value())); - AddDarwinDirs(client); + SetupGpuSandboxParameters(client, command_line); break; } case sandbox::policy::SandboxType::kCdm: @@ -265,7 +279,7 @@ } void SetNetworkTestCertsDirectoryForTesting(const base::FilePath& path) { - g_network_test_certs_dir->emplace(path); + GetNetworkTestCertsDirectory().emplace(path); } } // namespace content
diff --git a/content/browser/service_worker/fake_service_worker.cc b/content/browser/service_worker/fake_service_worker.cc index 989df20..16380df 100644 --- a/content/browser/service_worker/fake_service_worker.cc +++ b/content/browser/service_worker/fake_service_worker.cc
@@ -53,23 +53,18 @@ // Enable callers to use these endpoints without us actually binding them // to an implementation. - mojo::AssociateWithDisconnectedPipe(registration_info->receiver.PassHandle()); + registration_info->receiver.EnableUnassociatedUsage(); if (registration_info->installing) { - mojo::AssociateWithDisconnectedPipe( - registration_info->installing->receiver.PassHandle()); + registration_info->installing->receiver.EnableUnassociatedUsage(); } if (registration_info->waiting) { - mojo::AssociateWithDisconnectedPipe( - registration_info->waiting->receiver.PassHandle()); + registration_info->waiting->receiver.EnableUnassociatedUsage(); } if (registration_info->active) { - mojo::AssociateWithDisconnectedPipe( - registration_info->active->receiver.PassHandle()); + registration_info->active->receiver.EnableUnassociatedUsage(); } - if (service_worker_info) { - mojo::AssociateWithDisconnectedPipe( - service_worker_info->receiver.PassHandle()); + service_worker_info->receiver.EnableUnassociatedUsage(); } registration_info_ = std::move(registration_info);
diff --git a/content/browser/service_worker/service_worker_registration_unittest.cc b/content/browser/service_worker/service_worker_registration_unittest.cc index d4d6b76..f650216 100644 --- a/content/browser/service_worker/service_worker_registration_unittest.cc +++ b/content/browser/service_worker/service_worker_registration_unittest.cc
@@ -318,7 +318,7 @@ // no need to pass |object_info_->receiver| through a message pipe endpoint. blink::mojom::ServiceWorkerRegistrationObjectInfoPtr object_info = registration_object_host->CreateObjectInfo(); - mojo::AssociateWithDisconnectedPipe(object_info->receiver.PassHandle()); + object_info->receiver.EnableUnassociatedUsage(); registration->NotifyRegistrationFailed(); // Don't crash when |registration_object_host| gets destructed.
diff --git a/content/browser/speech/tts_win.cc b/content/browser/speech/tts_win.cc index e41cab82..c5e2988 100644 --- a/content/browser/speech/tts_win.cc +++ b/content/browser/speech/tts_win.cc
@@ -530,8 +530,8 @@ bool TtsPlatformImplWin::StopSpeaking() { DCHECK(BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - worker_.Post(FROM_HERE, &TtsPlatformImplBackgroundWorker::StopSpeaking, - paused_); + worker_.AsyncCall(&TtsPlatformImplBackgroundWorker::StopSpeaking) + .WithArgs(paused_); paused_ = false; is_speaking_ = false; @@ -546,7 +546,7 @@ if (paused_ || !is_speaking_) return; - worker_.Post(FROM_HERE, &TtsPlatformImplBackgroundWorker::Pause); + worker_.AsyncCall(&TtsPlatformImplBackgroundWorker::Pause); paused_ = true; } @@ -557,7 +557,7 @@ if (!paused_) return; - worker_.Post(FROM_HERE, &TtsPlatformImplBackgroundWorker::Resume); + worker_.AsyncCall(&TtsPlatformImplBackgroundWorker::Resume); paused_ = false; } @@ -576,7 +576,7 @@ void TtsPlatformImplWin::Shutdown() { // This is required to ensures the object is released before the COM is // uninitialized. Otherwise, this is causing shutdown hangs. - worker_.Post(FROM_HERE, &TtsPlatformImplBackgroundWorker::Shutdown); + worker_.AsyncCall(&TtsPlatformImplBackgroundWorker::Shutdown); } void TtsPlatformImplWin::OnInitializeComplete(bool success, @@ -622,9 +622,9 @@ const std::string& parsed_utterance) { DCHECK(BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - worker_.Post(FROM_HERE, &TtsPlatformImplBackgroundWorker::ProcessSpeech, - utterance_id, lang, voice, params, std::move(on_speak_finished), - parsed_utterance); + worker_.AsyncCall(&TtsPlatformImplBackgroundWorker::ProcessSpeech) + .WithArgs(utterance_id, lang, voice, params, std::move(on_speak_finished), + parsed_utterance); } TtsPlatformImplWin::TtsPlatformImplWin() @@ -632,7 +632,7 @@ base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()})), worker_(worker_task_runner_, worker_task_runner_) { DCHECK(BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - worker_.Post(FROM_HERE, &TtsPlatformImplBackgroundWorker::Initialize); + worker_.AsyncCall(&TtsPlatformImplBackgroundWorker::Initialize); } // static
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index fdb2220..2e461e4a 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc
@@ -830,8 +830,8 @@ node_(this), frame_tree_(browser_context, this, this, this, this, this, this, this), is_load_to_different_document_(false), - crashed_status_(base::TERMINATION_STATUS_STILL_RUNNING), - crashed_error_code_(0), + main_frame_process_status_(base::TERMINATION_STATUS_STILL_RUNNING), + main_frame_process_error_code_(0), waiting_for_response_(false), load_state_(net::LOAD_STATE_IDLE, base::string16()), upload_size_(0), @@ -1919,7 +1919,7 @@ } bool WebContentsImpl::IsCrashed() { - switch (crashed_status_) { + switch (main_frame_process_status_) { case base::TERMINATION_STATUS_PROCESS_CRASHED: case base::TERMINATION_STATUS_ABNORMAL_TERMINATION: case base::TERMINATION_STATUS_PROCESS_WAS_KILLED: @@ -1947,25 +1947,25 @@ return false; } -void WebContentsImpl::SetIsCrashed(base::TerminationStatus status, - int error_code) { - OPTIONAL_TRACE_EVENT2("content", "WebContentsImpl::SetIsCrashed", "status", - static_cast<int>(status), "old_status", - static_cast<int>(crashed_status_)); - if (status == crashed_status_) +void WebContentsImpl::SetMainFrameProcessStatus(base::TerminationStatus status, + int error_code) { + OPTIONAL_TRACE_EVENT2("content", "WebContentsImpl::SetMainFrameProcessStatus", + "status", static_cast<int>(status), "old_status", + static_cast<int>(main_frame_process_status_)); + if (status == main_frame_process_status_) return; - crashed_status_ = status; - crashed_error_code_ = error_code; + main_frame_process_status_ = status; + main_frame_process_error_code_ = error_code; NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB); } base::TerminationStatus WebContentsImpl::GetCrashedStatus() { - return crashed_status_; + return main_frame_process_status_; } int WebContentsImpl::GetCrashedErrorCode() { - return crashed_error_code_; + return main_frame_process_error_code_; } bool WebContentsImpl::IsBeingDestroyed() { @@ -6298,6 +6298,23 @@ void WebContentsImpl::RenderFrameCreated(RenderFrameHost* render_frame_host) { TRACE_EVENT1("content", "WebContentsImpl::RenderFrameCreated", "render_frame_host", static_cast<void*>(render_frame_host)); + // The WebContents tracks the process state for the main frame's renderer. + // TODO(crbug.com/1164280): Under MPArch, with multiple frame trees in a + // WebContents, this is intended to just track the main frame of the root + // page. + if (!render_frame_host->GetParent()) { + bool was_crashed = IsCrashed(); + SetMainFrameProcessStatus(base::TERMINATION_STATUS_STILL_RUNNING, 0); + + // Restore the focus to the tab (otherwise the focus will be on the top + // window). + if (was_crashed && !FocusLocationBarByDefault()) { + if (!delegate_ || delegate_->ShouldFocusPageAfterCrash()) { + view_->Focus(); + } + } + } + observers_.NotifyObservers(&WebContentsObserver::RenderFrameCreated, render_frame_host); UpdateAccessibilityModeOnFrame(render_frame_host); @@ -6798,16 +6815,6 @@ notify_disconnection_ = true; - bool was_crashed = IsCrashed(); - SetIsCrashed(base::TERMINATION_STATUS_STILL_RUNNING, 0); - - // Restore the focus to the tab (otherwise the focus will be on the top - // window). - if (was_crashed && !FocusLocationBarByDefault() && - (!delegate_ || delegate_->ShouldFocusPageAfterCrash())) { - view_->Focus(); - } - observers_.NotifyObservers(&WebContentsObserver::RenderViewReady); view_->RenderViewReady(); } @@ -6855,15 +6862,14 @@ // probably will need to more granularly reset the state here. ResetLoadProgressState(); NotifyDisconnected(); - SetIsCrashed(status, error_code); + SetMainFrameProcessStatus(status, error_code); TRACE_EVENT0("content", "Dispatching WebContentsObserver::RenderViewTerminated"); // Some observers might destroy WebContents in RenderViewTerminated. base::WeakPtr<WebContentsImpl> weak_ptr = weak_factory_.GetWeakPtr(); - auto crashed_status = GetCrashedStatus(); for (auto& observer : observers_.observer_list()) { - observer.RenderProcessGone(crashed_status); + observer.RenderProcessGone(status); if (!weak_ptr) return; } @@ -7531,12 +7537,6 @@ // Note: |this| might be deleted at this point. } -void WebContentsImpl::RenderProcessGoneFromRenderManager( - RenderViewHost* render_view_host) { - DCHECK(crashed_status_ != base::TERMINATION_STATUS_STILL_RUNNING); - RenderViewTerminated(render_view_host, crashed_status_, crashed_error_code_); -} - void WebContentsImpl::CancelModalDialogsForRenderManager() { OPTIONAL_TRACE_EVENT0("content", "WebContentsImpl::CancelModalDialogsForRenderManager");
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h index 4355a23e9..a861fc3 100644 --- a/content/browser/web_contents/web_contents_impl.h +++ b/content/browser/web_contents/web_contents_impl.h
@@ -402,7 +402,6 @@ bool HasFileSystemAccessHandles() override; bool HasPictureInPictureVideo() override; bool IsCrashed() override; - void SetIsCrashed(base::TerminationStatus status, int error_code) override; base::TerminationStatus GetCrashedStatus() override; int GetCrashedErrorCode() override; bool IsBeingDestroyed() override; @@ -428,7 +427,6 @@ WebContentsImpl* GetResponsibleWebContents() override; void DidChangeVisibleSecurityState() override; void SyncRendererPrefs() override; - void Stop() override; void SetPageFrozen(bool frozen) override; std::unique_ptr<WebContents> Clone() override; @@ -540,7 +538,6 @@ gfx::Size GetSize() override; void UpdateWindowControlsOverlay(const gfx::Rect& bounding_rect, const gfx::Insets& insets) override; - #if defined(OS_ANDROID) base::android::ScopedJavaLocalRef<jobject> GetJavaWebContents() override; WebContentsAndroid* GetWebContentsAndroid(); @@ -549,7 +546,6 @@ void RequestFindMatchRects(int current_version) override; service_manager::InterfaceProvider* GetJavaInterfaces() override; #endif - bool HasRecentInteractiveInputEvent() override; void SetIgnoreInputEvents(bool ignore_input_events) override; @@ -972,8 +968,6 @@ bool proceed, const base::TimeTicks& proceed_time, bool* proceed_to_fire_unload) override; - void RenderProcessGoneFromRenderManager( - RenderViewHost* render_view_host) override; void CancelModalDialogsForRenderManager() override; void NotifySwappedFromRenderManager(RenderFrameHost* old_frame, RenderFrameHost* new_frame, @@ -1451,6 +1445,11 @@ void AddObserver(WebContentsObserver* observer); void RemoveObserver(WebContentsObserver* observer); + // Indicates whether this tab should be considered crashed. The setter will + // also notify the delegate when the flag is changed. + void SetMainFrameProcessStatus(base::TerminationStatus status, + int error_code); + // Clears a pending contents that has been closed before being shown. void OnWebContentsDestroyed(WebContentsImpl* web_contents); @@ -1764,9 +1763,15 @@ // TODO(pbos): Check navigation requests and handles instead of caching this. bool is_load_to_different_document_; - // Indicates if the tab is considered crashed. - base::TerminationStatus crashed_status_; - int crashed_error_code_; + // Indicates the process state of the primary main frame's renderer process. + // If the process is not live due to a crash, this will be reflected by + // IsCrashed(), though it's possible to not be live while not indicating a + // crash occurred. + // TODO(crbug.com/1164280): Under MPArch, with multiple frame trees in a + // WebContents, this just tracks the renderer process of the main frame of the + // root page. It should be named appropriately. + base::TerminationStatus main_frame_process_status_; + int main_frame_process_error_code_; // Whether this WebContents is waiting for a first-response for the // main resource of the page. This controls whether the throbber state is
diff --git a/content/browser/web_package/link_web_bundle_browsertest.cc b/content/browser/web_package/link_web_bundle_browsertest.cc index dd4e8d8..f8b8ef0 100644 --- a/content/browser/web_package/link_web_bundle_browsertest.cc +++ b/content/browser/web_package/link_web_bundle_browsertest.cc
@@ -2,10 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/files/file_path.h" +#include "base/files/file_util.h" #include "base/optional.h" +#include "base/path_service.h" #include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" #include "base/test/scoped_feature_list.h" +#include "base/threading/thread_restrictions.h" #include "content/public/browser/content_browser_client.h" #include "content/public/browser/navigation_handle.h" #include "content/public/common/content_client.h" @@ -76,6 +80,16 @@ base::Optional<net::Error> error_code_; }; +int64_t GetTestDataFileSize(const base::FilePath::CharType* file_path) { + int64_t file_size; + base::ScopedAllowBlockingForTesting allow_blocking; + base::FilePath test_data_dir; + CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir)); + CHECK(base::GetFileSize(test_data_dir.Append(base::FilePath(file_path)), + &file_size)); + return file_size; +} + } // namespace class LinkWebBundleBrowserTest : public ContentBrowserTest { @@ -123,6 +137,7 @@ }; IN_PROC_BROWSER_TEST_F(LinkWebBundleBrowserTest, SubframeLoad) { + base::HistogramTester histogram_tester; GURL url(embedded_test_server()->GetURL("/web_bundle/link_web_bundle.html")); EXPECT_TRUE(NavigateToURL(shell(), url)); @@ -137,6 +152,15 @@ "document.body.appendChild(iframe);"); run_loop.Run(); EXPECT_EQ(net::OK, *finish_navigation_observer.error_code()); + + // Check the metrics recorded in the network process. + FetchHistogramsFromChildProcesses(); + int64_t web_bundle_size = GetTestDataFileSize( + FILE_PATH_LITERAL("content/test/data/web_bundle/urn-uuid.wbn")); + histogram_tester.ExpectUniqueSample("SubresourceWebBundles.ReceivedSize", + web_bundle_size, 1); + histogram_tester.ExpectUniqueSample("SubresourceWebBundles.ContentLength", + web_bundle_size, 1); } IN_PROC_BROWSER_TEST_F(LinkWebBundleBrowserTest, FollowLink) {
diff --git a/content/public/android/java/src/org/chromium/content/browser/BrowserStartupControllerImpl.java b/content/public/android/java/src/org/chromium/content/browser/BrowserStartupControllerImpl.java index 43656db..8389943 100644 --- a/content/public/android/java/src/org/chromium/content/browser/BrowserStartupControllerImpl.java +++ b/content/public/android/java/src/org/chromium/content/browser/BrowserStartupControllerImpl.java
@@ -27,7 +27,6 @@ import org.chromium.content.browser.ServicificationStartupUma.ServicificationStartup; import org.chromium.content_public.browser.BrowserStartupController; import org.chromium.content_public.browser.UiThreadTaskTraits; -import org.chromium.ui.resources.ResourceExtractor; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -59,10 +58,6 @@ private static boolean sShouldStartGpuProcessOnBrowserStartup; - private static void setShouldStartGpuProcessOnBrowserStartup(boolean enable) { - sShouldStartGpuProcessOnBrowserStartup = enable; - } - @VisibleForTesting @CalledByNative static void browserStartupComplete(int result) { @@ -97,8 +92,8 @@ // Whether the async startup of the browser process has started. private boolean mHasStartedInitializingBrowserProcess; - // Whether tasks that occur after resource extraction have been completed. - private boolean mPostResourceExtractionTasksCompleted; + // Ensures prepareToStartBrowserProcess() logic happens only once. + private boolean mPrepareToStartCompleted; private boolean mHasCalledContentStart; @@ -208,23 +203,17 @@ // This is the first time we have been asked to start the browser process. We set the // flag that indicates that we have kicked off starting the browser process. mHasStartedInitializingBrowserProcess = true; + sShouldStartGpuProcessOnBrowserStartup = startGpuProcess; + prepareToStartBrowserProcess(false); - setShouldStartGpuProcessOnBrowserStartup(startGpuProcess); - - prepareToStartBrowserProcess(false, new Runnable() { - @Override - public void run() { - ThreadUtils.assertOnUiThread(); - if (mHasCalledContentStart) return; - mCurrentBrowserStartType = startMinimalBrowser - ? BrowserStartType.MINIMAL_BROWSER - : BrowserStartType.FULL_BROWSER; - if (contentStart() > 0) { - // Failed. The callbacks may not have run, so run them. - enqueueCallbackExecution(STARTUP_FAILURE); - } + if (!mHasCalledContentStart) { + mCurrentBrowserStartType = startMinimalBrowser ? BrowserStartType.MINIMAL_BROWSER + : BrowserStartType.FULL_BROWSER; + if (contentStart() > 0) { + // Failed. The callbacks may not have run, so run them. + enqueueCallbackExecution(STARTUP_FAILURE); } - }); + } } else if (mMinimalBrowserStarted && mLaunchFullBrowserAfterMinimalBrowserStart) { // If we missed the minimalBrowserStarted() call, launch the full browser now if needed. // Otherwise, minimalBrowserStarted() will handle the full browser launch. @@ -243,12 +232,7 @@ // If already started skip to checking the result if (!mFullBrowserStartupDone) { - if (!mHasStartedInitializingBrowserProcess || !mPostResourceExtractionTasksCompleted) { - try (ScopedSysTraceEvent e2 = ScopedSysTraceEvent.scoped( - "BrowserStartupController.prepareToStartBrowserProcess")) { - prepareToStartBrowserProcess(singleProcess, null); - } - } + prepareToStartBrowserProcess(singleProcess); boolean startedSuccessfully = true; if (!mHasCalledContentStart) { @@ -438,46 +422,31 @@ } @VisibleForTesting - void prepareToStartBrowserProcess( - final boolean singleProcess, final Runnable completionCallback) { - Log.d(TAG, "Initializing chromium process, singleProcess=%b", singleProcess); - - // This strictmode exception is to cover the case where the browser process is being started - // asynchronously but not in the main browser flow. The main browser flow will trigger - // library loading earlier and this will be a no-op, but in the other cases this will need - // to block on loading libraries. - // This applies to tests and ManageSpaceActivity, which can be launched from Settings. - StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads(); - try { - // Normally Main.java will have already loaded the library asynchronously, we only need - // to load it here if we arrived via another flow, e.g. bookmark access & sync setup. - LibraryLoader.getInstance().ensureInitialized(); - } finally { - StrictMode.setThreadPolicy(oldPolicy); + void prepareToStartBrowserProcess(final boolean singleProcess) { + if (mPrepareToStartCompleted) { + return; } - - Runnable postResourceExtraction = new Runnable() { - @Override - public void run() { - if (!mPostResourceExtractionTasksCompleted) { - // TODO(yfriedman): Remove dependency on a command line flag for this. - DeviceUtilsImpl.addDeviceSpecificUserAgentSwitch(); - BrowserStartupControllerImplJni.get().setCommandLineFlags(singleProcess); - mPostResourceExtractionTasksCompleted = true; - } - - if (completionCallback != null) completionCallback.run(); + Log.d(TAG, "Initializing chromium process, singleProcess=%b", singleProcess); + mPrepareToStartCompleted = true; + try (ScopedSysTraceEvent e = ScopedSysTraceEvent.scoped("prepareToStartBrowserProcess")) { + // This strictmode exception is to cover the case where the browser process is being + // started asynchronously but not in the main browser flow. The main browser flow will + // trigger library loading earlier and this will be a no-op, but in the other cases this + // will need to block on loading libraries. This applies to tests and + // ManageSpaceActivity, which can be launched from Settings. + StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads(); + try { + // Normally Main.java will have already loaded the library asynchronously, we only + // need to load it here if we arrived via another flow, e.g. bookmark access & sync + // setup. + LibraryLoader.getInstance().ensureInitialized(); + } finally { + StrictMode.setThreadPolicy(oldPolicy); } - }; - ResourceExtractor.get().setResultTraits(UiThreadTaskTraits.BOOTSTRAP); - if (completionCallback == null) { - // If no continuation callback is specified, then force the resource extraction - // to complete. - ResourceExtractor.get().waitForCompletion(); - postResourceExtraction.run(); - } else { - ResourceExtractor.get().addCompletionCallback(postResourceExtraction); + // TODO(yfriedman): Remove dependency on a command line flag for this. + DeviceUtilsImpl.addDeviceSpecificUserAgentSwitch(); + BrowserStartupControllerImplJni.get().setCommandLineFlags(singleProcess); } }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/BrowserStartupControllerTest.java b/content/public/android/javatests/src/org/chromium/content/browser/BrowserStartupControllerTest.java index 070eb291..381a62a 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/BrowserStartupControllerTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/BrowserStartupControllerTest.java
@@ -37,11 +37,9 @@ private boolean mMinimalBrowserStarted; @Override - void prepareToStartBrowserProcess(boolean singleProcess, Runnable completionCallback) { + void prepareToStartBrowserProcess(boolean singleProcess) { if (!mLibraryLoadSucceeds) { throw new ProcessInitException(LoaderErrors.NATIVE_LIBRARY_LOAD_FAILED); - } else if (completionCallback != null) { - completionCallback.run(); } }
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h index 05b19394..8a913c6a 100644 --- a/content/public/browser/web_contents.h +++ b/content/public/browser/web_contents.h
@@ -590,10 +590,10 @@ // Indicates whether a video is in Picture-in-Picture for |this|. virtual bool HasPictureInPictureVideo() = 0; - // Indicates whether this tab should be considered crashed. The setter will - // also notify the delegate when the flag is changed. + // Indicates whether this tab should be considered crashed. This becomes false + // again when the renderer process is recreated after a crash in order to + // recreate the main frame. virtual bool IsCrashed() = 0; - virtual void SetIsCrashed(base::TerminationStatus status, int error_code) = 0; virtual base::TerminationStatus GetCrashedStatus() = 0; virtual int GetCrashedErrorCode() = 0;
diff --git a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/NativeLibraryTestUtils.java b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/NativeLibraryTestUtils.java index 640d01f..a9630ea 100644 --- a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/NativeLibraryTestUtils.java +++ b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/NativeLibraryTestUtils.java
@@ -8,8 +8,6 @@ import org.chromium.base.library_loader.LibraryLoader; import org.chromium.base.library_loader.LibraryProcessType; import org.chromium.content_public.browser.BrowserStartupController; -import org.chromium.content_public.browser.UiThreadTaskTraits; -import org.chromium.ui.resources.ResourceExtractor; /** * Provides test support for loading and dealing with native libraries. @@ -40,12 +38,6 @@ private static void nativeInitialization(boolean initBrowserProcess) { LibraryLoader.getInstance().setLibraryProcessType(LibraryProcessType.PROCESS_BROWSER); if (initBrowserProcess) { - // Extract compressed resource paks. - ResourceExtractor resourceExtractor = ResourceExtractor.get(); - resourceExtractor.setResultTraits(UiThreadTaskTraits.BOOTSTRAP); - resourceExtractor.startExtractingResources("en"); - resourceExtractor.waitForCompletion(); - BrowserStartupController.getInstance().startBrowserProcessesSync( LibraryProcessType.PROCESS_BROWSER, false); } else {
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc index d4abda4..3ce7b43 100644 --- a/content/public/test/browser_test_utils.cc +++ b/content/public/test/browser_test_utils.cc
@@ -641,12 +641,17 @@ return ExecuteScriptWithoutUserGesture(web_contents, script); } -void NavigateToURLBlockUntilNavigationsComplete(WebContents* web_contents, - const GURL& url, - int number_of_navigations) { +void NavigateToURLBlockUntilNavigationsComplete( + WebContents* web_contents, + const GURL& url, + int number_of_navigations, + bool ignore_uncommitted_navigations) { // Prepare for the navigation. WaitForLoadStop(web_contents); - TestNavigationObserver same_tab_observer(web_contents, number_of_navigations); + TestNavigationObserver same_tab_observer( + web_contents, number_of_navigations, + MessageLoopRunner::QuitMode::IMMEDIATE, + /*ignore_uncommitted_navigations=*/ignore_uncommitted_navigations); // This mimics behavior of Shell::LoadURL... NavigationController::LoadURLParams params(url);
diff --git a/content/public/test/browser_test_utils.h b/content/public/test/browser_test_utils.h index db86181..fc6bacc 100644 --- a/content/public/test/browser_test_utils.h +++ b/content/public/test/browser_test_utils.h
@@ -136,10 +136,13 @@ const GURL& expected_commit_url); // Navigates |web_contents| to |url|, blocking until the given number of -// navigations finishes. -void NavigateToURLBlockUntilNavigationsComplete(WebContents* web_contents, - const GURL& url, - int number_of_navigations); +// navigations finishes. If |ignore_uncommitted_navigations| is true, then an +// aborted navigation also counts toward |number_of_navigations| being complete. +void NavigateToURLBlockUntilNavigationsComplete( + WebContents* web_contents, + const GURL& url, + int number_of_navigations, + bool ignore_uncommitted_navigations = true); // Perform a renderer-initiated navigation of |window| to |url|, blocking // until the navigation finishes. The navigation is done by assigning
diff --git a/content/public/test/content_browser_test_utils.cc b/content/public/test/content_browser_test_utils.cc index 41158af..557cf206 100644 --- a/content/public/test/content_browser_test_utils.cc +++ b/content/public/test/content_browser_test_utils.cc
@@ -54,11 +54,14 @@ return net::FilePathToFileURL(GetTestFilePath(dir, file)); } -void NavigateToURLBlockUntilNavigationsComplete(Shell* window, - const GURL& url, - int number_of_navigations) { +void NavigateToURLBlockUntilNavigationsComplete( + Shell* window, + const GURL& url, + int number_of_navigations, + bool ignore_uncommitted_navigations) { NavigateToURLBlockUntilNavigationsComplete(window->web_contents(), url, - number_of_navigations); + number_of_navigations, + ignore_uncommitted_navigations); } void ReloadBlockUntilNavigationsComplete(Shell* window, @@ -95,7 +98,7 @@ bool NavigateToURLAndExpectNoCommit(Shell* window, const GURL& url) { NavigationEntry* old_entry = window->web_contents()->GetController().GetLastCommittedEntry(); - NavigateToURLBlockUntilNavigationsComplete(window, url, 1); + NavigateToURLBlockUntilNavigationsComplete(window->web_contents(), url, 1); NavigationEntry* new_entry = window->web_contents()->GetController().GetLastCommittedEntry(); return old_entry == new_entry;
diff --git a/content/public/test/content_browser_test_utils.h b/content/public/test/content_browser_test_utils.h index 6e6e095..f472121 100644 --- a/content/public/test/content_browser_test_utils.h +++ b/content/public/test/content_browser_test_utils.h
@@ -87,10 +87,13 @@ const GURL& expected_commit_url); // Navigates |window| to |url|, blocking until the given number of navigations -// finishes. -void NavigateToURLBlockUntilNavigationsComplete(Shell* window, - const GURL& url, - int number_of_navigations); +// finishes. If |ignore_uncommitted_navigations| is true, then an aborted +// navigation also counts toward |number_of_navigations| being complete. +void NavigateToURLBlockUntilNavigationsComplete( + Shell* window, + const GURL& url, + int number_of_navigations, + bool ignore_uncommitted_navigations = true); // Navigates |window| to |url|, blocks until the navigation finishes, and // checks that the navigation did not commit (e.g., due to a crash or
diff --git a/content/public/test/web_contents_tester.h b/content/public/test/web_contents_tester.h index e1c890bf..95885c0 100644 --- a/content/public/test/web_contents_tester.h +++ b/content/public/test/web_contents_tester.h
@@ -96,6 +96,9 @@ // main frame of |opener|. virtual void SetOpener(WebContents* opener) = 0; + // Sets the process state for the primary main frame renderer. + virtual void SetIsCrashed(base::TerminationStatus status, int error_code) = 0; + // Returns headers that were passed in the previous SaveFrameWithHeaders(...) // call. virtual const std::string& GetSaveFrameHeaders() = 0;
diff --git a/content/test/data/accessibility/aria/aria-owns-included-in-tree-expected-blink.txt b/content/test/data/accessibility/aria/aria-owns-included-in-tree-expected-blink.txt index c025fd2..4d18bbe 100644 --- a/content/test/data/accessibility/aria/aria-owns-included-in-tree-expected-blink.txt +++ b/content/test/data/accessibility/aria/aria-owns-included-in-tree-expected-blink.txt
@@ -3,10 +3,11 @@ ++++genericContainer ignored ++++++splitter horizontal name='Control: elements that are not in tree' ++++++layoutTable -++++++++layoutTableRow -++++++++++layoutTableCell -++++++++++++textField -++++++++++++++genericContainer +++++++++genericContainer ignored +++++++++++layoutTableRow +++++++++++++layoutTableCell +++++++++++++++textField +++++++++++++++++genericContainer ++++++splitter horizontal name='An aria-owned element is always in tree' ++++++group ++++++++genericContainer ignored
diff --git a/content/test/data/accessibility/css/table-display-expected-blink.txt b/content/test/data/accessibility/css/table-display-expected-blink.txt index 7e735bb..e27a7782 100644 --- a/content/test/data/accessibility/css/table-display-expected-blink.txt +++ b/content/test/data/accessibility/css/table-display-expected-blink.txt
@@ -2,16 +2,17 @@ ++genericContainer ignored ++++genericContainer ignored ++++++layoutTable -++++++++layoutTableRow -++++++++++layoutTableCell name='Cats' -++++++++++++staticText name='Cats' -++++++++++++++inlineTextBox name='Cats' -++++++++++layoutTableCell name='Dogs' -++++++++++++staticText name='Dogs' -++++++++++++++inlineTextBox name='Dogs' -++++++++++layoutTableCell name='Iguanas' -++++++++++++staticText name='Iguanas' -++++++++++++++inlineTextBox name='Iguanas' -++++++++++layoutTableCell name='Fish' -++++++++++++staticText name='Fish' -++++++++++++++inlineTextBox name='Fish' +++++++++genericContainer ignored +++++++++++layoutTableRow +++++++++++++layoutTableCell name='Cats' +++++++++++++++staticText name='Cats' +++++++++++++++++inlineTextBox name='Cats' +++++++++++++layoutTableCell name='Dogs' +++++++++++++++staticText name='Dogs' +++++++++++++++++inlineTextBox name='Dogs' +++++++++++++layoutTableCell name='Iguanas' +++++++++++++++staticText name='Iguanas' +++++++++++++++++inlineTextBox name='Iguanas' +++++++++++++layoutTableCell name='Fish' +++++++++++++++staticText name='Fish' +++++++++++++++++inlineTextBox name='Fish'
diff --git a/content/test/data/accessibility/css/table-display-other-expected-blink.txt b/content/test/data/accessibility/css/table-display-other-expected-blink.txt index 05a4fcf..fdf06d7 100644 --- a/content/test/data/accessibility/css/table-display-other-expected-blink.txt +++ b/content/test/data/accessibility/css/table-display-other-expected-blink.txt
@@ -2,7 +2,8 @@ ++genericContainer ignored ++++genericContainer ignored ++++++layoutTable -++++++++layoutTableRow -++++++++++layoutTableCell name='cat' -++++++++++++staticText name='cat' -++++++++++++++inlineTextBox name='cat' +++++++++genericContainer ignored +++++++++++layoutTableRow +++++++++++++layoutTableCell name='cat' +++++++++++++++staticText name='cat' +++++++++++++++++inlineTextBox name='cat'
diff --git a/content/test/data/accessibility/html/table-layout-expected-blink.txt b/content/test/data/accessibility/html/table-layout-expected-blink.txt index 9ccee06d..bd0bece 100644 --- a/content/test/data/accessibility/html/table-layout-expected-blink.txt +++ b/content/test/data/accessibility/html/table-layout-expected-blink.txt
@@ -2,33 +2,34 @@ ++genericContainer ignored ++++genericContainer ignored ++++++layoutTable -++++++++layoutTableRow -++++++++++layoutTableCell name='1' -++++++++++++staticText name='1' -++++++++++++++inlineTextBox name='1' -++++++++++layoutTableCell name='2' -++++++++++++staticText name='2' -++++++++++++++inlineTextBox name='2' -++++++++++layoutTableCell name='3' -++++++++++++staticText name='3' -++++++++++++++inlineTextBox name='3' -++++++++layoutTableRow -++++++++++layoutTableCell name='4' -++++++++++++staticText name='4' -++++++++++++++inlineTextBox name='4' -++++++++++layoutTableCell name='5' -++++++++++++staticText name='5' -++++++++++++++inlineTextBox name='5' -++++++++++layoutTableCell name='6' -++++++++++++staticText name='6' -++++++++++++++inlineTextBox name='6' -++++++++layoutTableRow -++++++++++layoutTableCell name='7' -++++++++++++staticText name='7' -++++++++++++++inlineTextBox name='7' -++++++++++layoutTableCell name='8' -++++++++++++staticText name='8' -++++++++++++++inlineTextBox name='8' -++++++++++layoutTableCell name='9' -++++++++++++staticText name='9' -++++++++++++++inlineTextBox name='9' +++++++++genericContainer ignored +++++++++++layoutTableRow +++++++++++++layoutTableCell name='1' +++++++++++++++staticText name='1' +++++++++++++++++inlineTextBox name='1' +++++++++++++layoutTableCell name='2' +++++++++++++++staticText name='2' +++++++++++++++++inlineTextBox name='2' +++++++++++++layoutTableCell name='3' +++++++++++++++staticText name='3' +++++++++++++++++inlineTextBox name='3' +++++++++++layoutTableRow +++++++++++++layoutTableCell name='4' +++++++++++++++staticText name='4' +++++++++++++++++inlineTextBox name='4' +++++++++++++layoutTableCell name='5' +++++++++++++++staticText name='5' +++++++++++++++++inlineTextBox name='5' +++++++++++++layoutTableCell name='6' +++++++++++++++staticText name='6' +++++++++++++++++inlineTextBox name='6' +++++++++++layoutTableRow +++++++++++++layoutTableCell name='7' +++++++++++++++staticText name='7' +++++++++++++++++inlineTextBox name='7' +++++++++++++layoutTableCell name='8' +++++++++++++++staticText name='8' +++++++++++++++++inlineTextBox name='8' +++++++++++++layoutTableCell name='9' +++++++++++++++staticText name='9' +++++++++++++++++inlineTextBox name='9'
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt index 7ca77c6..789636dc7 100644 --- a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
@@ -940,6 +940,7 @@ crbug.com/1165751 [ android-lollipop ] conformance/glsl/bugs/vector-matrix-constructor-scalarization.html [ Failure ] crbug.com/1165751 [ android-marshmallow ] conformance/glsl/bugs/vector-matrix-constructor-scalarization.html [ Failure ] crbug.com/1165751 [ android-nougat ] conformance/glsl/bugs/vector-matrix-constructor-scalarization.html [ Failure ] +crbug.com/1165751 [ android-pie ] conformance/glsl/bugs/vector-matrix-constructor-scalarization.html [ Failure ] # Video tests are flaky. Sometimes the video is black. crbug.com/948894 [ android ] conformance/textures/video/* [ RetryOnFailure ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt index 240d335..3249c5df 100644 --- a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
@@ -174,6 +174,8 @@ crbug.com/1146483 [ fuchsia fuchsia-board-astro ] conformance/textures/misc/texture-video-transparent.html [ Skip ] crbug.com/1146483 [ fuchsia fuchsia-board-astro ] conformance/textures/image_bitmap_from_video/tex-2d-alpha-alpha-unsigned_byte.html [ Skip ] crbug.com/1146483 [ fuchsia fuchsia-board-astro ] conformance/textures/video/tex-2d-alpha-alpha-unsigned_byte.html [ Skip ] +# Need to adjust tolerances of this test. +crbug.com/1165751 [ fuchsia fuchsia-board-astro ] conformance/glsl/bugs/vector-matrix-constructor-scalarization.html [ Failure ] # Flaky on Fuchsia hardware devices [ fuchsia fuchsia-board-astro ] WebglExtension_EXT_float_blend [ Skip ] @@ -259,6 +261,7 @@ crbug.com/angleproject/4922 [ win intel angle-vulkan passthrough ] conformance/context/context-attributes-alpha-depth-stencil-antialias.html [ Failure ] # Need to adjust tolerances of this test. crbug.com/1165751 [ win intel angle-vulkan passthrough ] conformance/glsl/bugs/vector-matrix-constructor-scalarization.html [ Failure ] +crbug.com/1165751 [ win nvidia angle-vulkan passthrough ] conformance/glsl/bugs/vector-matrix-constructor-scalarization.html [ Failure ] #################### # Fuchsia failures # @@ -742,6 +745,8 @@ # Flaky renderer hangs suspected due to some driver issue on Kevin devices. crbug.com/1091562 [ chromeos-board-kevin ] * [ RetryOnFailure ] +crbug.com/1165751 [ chromeos chromeos-board-kevin ] conformance/glsl/bugs/vector-matrix-constructor-scalarization.html [ Failure ] + ######################## # SwiftShader failures # ########################
diff --git a/content/test/task_runner_deferring_throttle.cc b/content/test/task_runner_deferring_throttle.cc index c57f8e6..19476bb 100644 --- a/content/test/task_runner_deferring_throttle.cc +++ b/content/test/task_runner_deferring_throttle.cc
@@ -57,14 +57,18 @@ return "TaskRunnerDeferringThrottle"; } +void TaskRunnerDeferringThrottle::AsyncResume() { + Resume(); +} + NavigationThrottle::ThrottleCheckResult TaskRunnerDeferringThrottle::DeferToPostTask() { task_runner_->PostTaskAndReply( FROM_HERE, base::DoNothing(), - base::BindOnce(&TaskRunnerDeferringThrottle::Resume, + base::BindOnce(&TaskRunnerDeferringThrottle::AsyncResume, weak_factory_.GetWeakPtr())); return NavigationThrottle::DEFER; } -} // namespace content \ No newline at end of file +} // namespace content
diff --git a/content/test/task_runner_deferring_throttle.h b/content/test/task_runner_deferring_throttle.h index a887a5f..68ba355 100644 --- a/content/test/task_runner_deferring_throttle.h +++ b/content/test/task_runner_deferring_throttle.h
@@ -34,6 +34,10 @@ ThrottleCheckResult WillProcessResponse() override; const char* GetNameForLogging() override; + protected: + // Tests may override this to change how/when Resume() is called. + virtual void AsyncResume(); + private: ThrottleCheckResult DeferToPostTask(); @@ -47,4 +51,4 @@ } // namespace content -#endif // CONTENT_TEST_TASK_RUNNER_DEFERRING_THROTTLE_H_ \ No newline at end of file +#endif // CONTENT_TEST_TASK_RUNNER_DEFERRING_THROTTLE_H_
diff --git a/content/test/test_render_frame_host.cc b/content/test/test_render_frame_host.cc index d8056fe0..a8eb508b 100644 --- a/content/test/test_render_frame_host.cc +++ b/content/test/test_render_frame_host.cc
@@ -93,9 +93,9 @@ return static_cast<MockRenderProcessHost*>(RenderFrameHostImpl::GetProcess()); } -MockAgentSchedulingGroupHost& TestRenderFrameHost::agent_scheduling_group() { +MockAgentSchedulingGroupHost& TestRenderFrameHost::GetAgentSchedulingGroup() { return static_cast<MockAgentSchedulingGroupHost&>( - RenderFrameHostImpl::agent_scheduling_group()); + RenderFrameHostImpl::GetAgentSchedulingGroup()); } TestRenderWidgetHost* TestRenderFrameHost::GetRenderWidgetHost() {
diff --git a/content/test/test_render_frame_host.h b/content/test/test_render_frame_host.h index 2127fa1..6a75c3a 100644 --- a/content/test/test_render_frame_host.h +++ b/content/test/test_render_frame_host.h
@@ -66,7 +66,7 @@ // RenderFrameHostImpl overrides (same values, but in Test*/Mock* types) TestRenderViewHost* GetRenderViewHost() override; MockRenderProcessHost* GetProcess() override; - MockAgentSchedulingGroupHost& agent_scheduling_group() override; + MockAgentSchedulingGroupHost& GetAgentSchedulingGroup() override; TestRenderWidgetHost* GetRenderWidgetHost() override; void AddMessageToConsole(blink::mojom::ConsoleMessageLevel level, const std::string& message) override;
diff --git a/content/test/test_web_contents.cc b/content/test/test_web_contents.cc index 9cd9fba..35ee654 100644 --- a/content/test/test_web_contents.cc +++ b/content/test/test_web_contents.cc
@@ -302,6 +302,11 @@ static_cast<WebContentsImpl*>(opener)->GetFrameTree()->root()); } +void TestWebContents::SetIsCrashed(base::TerminationStatus status, + int error_code) { + SetMainFrameProcessStatus(status, error_code); +} + void TestWebContents::AddPendingContents( std::unique_ptr<WebContentsImpl> contents, const GURL& target_url) {
diff --git a/content/test/test_web_contents.h b/content/test/test_web_contents.h index 20bff22..715d1b4 100644 --- a/content/test/test_web_contents.h +++ b/content/test/test_web_contents.h
@@ -75,6 +75,7 @@ void NavigateAndFail(const GURL& url, int error_code) override; void TestSetIsLoading(bool value) override; void SetOpener(WebContents* opener) override; + void SetIsCrashed(base::TerminationStatus status, int error_code) override; const std::string& GetSaveFrameHeaders() override; const base::string16& GetSuggestedFileName() override; bool HasPendingDownloadImage(const GURL& url) override;
diff --git a/content/test/web_contents_observer_consistency_checker.cc b/content/test/web_contents_observer_consistency_checker.cc index 6eda72d..520587a7 100644 --- a/content/test/web_contents_observer_consistency_checker.cc +++ b/content/test/web_contents_observer_consistency_checker.cc
@@ -213,9 +213,9 @@ CHECK(NavigationIsOngoing(navigation_handle)); CHECK(!navigation_handle->HasCommitted()); - CHECK(navigation_handle->GetRenderFrameHost()); CHECK_EQ(navigation_handle->GetWebContents(), web_contents()); - CHECK(navigation_handle->GetRenderFrameHost() != nullptr); + CHECK(navigation_handle->GetRenderFrameHost()); + CHECK(navigation_handle->GetRenderFrameHost()->IsRenderFrameLive()); ready_to_commit_hosts_.insert( std::make_pair(navigation_handle->GetNavigationId(), @@ -232,10 +232,11 @@ CHECK_EQ(navigation_handle->GetWebContents(), web_contents()); CHECK(!navigation_handle->HasCommitted() || - navigation_handle->GetRenderFrameHost() != nullptr); - + navigation_handle->GetRenderFrameHost()); CHECK(!navigation_handle->HasCommitted() || navigation_handle->GetRenderFrameHost()->IsCurrent()); + CHECK(!navigation_handle->HasCommitted() || + navigation_handle->GetRenderFrameHost()->IsRenderFrameLive()); // If ReadyToCommitNavigation was dispatched, verify that the // |navigation_handle| has the same RenderFrameHost at this time as the one
diff --git a/device/vr/android/arcore/arcore.cc b/device/vr/android/arcore/arcore.cc index 8fe97945..0128839 100644 --- a/device/vr/android/arcore/arcore.cc +++ b/device/vr/android/arcore/arcore.cc
@@ -25,6 +25,18 @@ gfx::Transform(1, 0, 0, -1, 0, 1); } +gfx::Transform ArCore::GetDepthUvFromScreenUvTransform() const { + // + // Observe how kInputCoordinatesForTransform are transformed by ArCore & + // compute a matrix based on that. This is different than the camera UV + // transform in that it does not perform the Y-flip - the depth buffer's + // coordinate system is defined the same way as ArCore's + // AR_COORDINATES_2D_TEXTURE_NORMALIZED. + // + return MatrixFromTransformedPoints( + TransformDisplayUvCoords(kInputCoordinatesForTransform)); +} + ArCore::InitializeResult::InitializeResult( const std::unordered_set<device::mojom::XRSessionFeature>& enabled_features, base::Optional<device::mojom::XRDepthConfig> depth_configuration)
diff --git a/device/vr/android/arcore/arcore.h b/device/vr/android/arcore/arcore.h index 61b08b8..cfd4d479 100644 --- a/device/vr/android/arcore/arcore.h +++ b/device/vr/android/arcore/arcore.h
@@ -89,6 +89,7 @@ virtual void SetCameraTexture(uint32_t camera_texture_id) = 0; gfx::Transform GetCameraUvFromScreenUvTransform() const; + gfx::Transform GetDepthUvFromScreenUvTransform() const; virtual gfx::Transform GetProjectionMatrix(float near, float far) = 0;
diff --git a/device/vr/android/arcore/arcore_impl.cc b/device/vr/android/arcore/arcore_impl.cc index 5eed8a89..8f2089d 100644 --- a/device/vr/android/arcore/arcore_impl.cc +++ b/device/vr/android/arcore/arcore_impl.cc
@@ -1860,7 +1860,7 @@ result->pixel_data = std::move(pixels); // Transform needed to consume the data: - result->norm_texture_from_norm_view = GetCameraUvFromScreenUvTransform(); + result->norm_texture_from_norm_view = GetDepthUvFromScreenUvTransform(); result->size = gfx::Size(width, height); result->raw_value_to_meters = 1.0 / 1000.0; // DepthInMillimeters * 1/1000 = DepthInMeters
diff --git a/docs/README.md b/docs/README.md index 237ef16..0836b43 100644 --- a/docs/README.md +++ b/docs/README.md
@@ -305,6 +305,7 @@ * [Kiosk mode and public sessions](enterprise/kiosk_public_session.md) * [Debugging UI in OOBE/login/lock](login/ui_debugging.md) * [Chrome Logging on Chrome OS](chrome_os_logging.md) +* [Debugging tips](testing/chromeos_debugging_tips.md) ### Misc WebUI-Specific Docs * [Creating WebUI Interfaces in components/](webui_in_components.md) How to
diff --git a/docs/speed/perf_lab_platforms.md b/docs/speed/perf_lab_platforms.md index 6d563af..808b0fb 100644 --- a/docs/speed/perf_lab_platforms.md +++ b/docs/speed/perf_lab_platforms.md
@@ -20,8 +20,8 @@ ## Linux - * [linux-perf](https://ci.chromium.org/p/chrome/builders/ci/linux-perf): Ubuntu-14.04, 8 core, NVIDIA Quadro P400. - * [linux-perf-rel](https://ci.chromium.org/p/chrome/builders/ci/linux-perf-rel): Ubuntu-14.04, 8 core, NVIDIA Quadro P400. + * [linux-perf](https://ci.chromium.org/p/chrome/builders/ci/linux-perf): Ubuntu-18.04, 8 core, NVIDIA Quadro P400. + * [linux-perf-rel](https://ci.chromium.org/p/chrome/builders/ci/linux-perf-rel): Ubuntu-18.04, 8 core, NVIDIA Quadro P400. ## Mac
diff --git a/docs/ui/android/bytecode_rewriting.md b/docs/ui/android/bytecode_rewriting.md index 0c0a13a5..d5742eb 100644 --- a/docs/ui/android/bytecode_rewriting.md +++ b/docs/ui/android/bytecode_rewriting.md
@@ -53,6 +53,14 @@ [compile_java.py](https://source.chromium.org/chromium/chromium/src/+/master:build/android/gyp/compile_java.py), and print a message pointing users here, which is likely why you're reading this :) +If you need to apply FragmentActivityReplacer to a given target then add … + +``` +bytecode_rewriter_target = "//build/android/bytecode:fragment_activity_replacer" +``` + +… to the build configuration for that target. + ## How does this affect my code? The goal is for these changes to be as transparent as possible; most code shouldn't run into issues.
diff --git a/extensions/browser/BUILD.gn b/extensions/browser/BUILD.gn index 05bf58c0..1ce66fa 100644 --- a/extensions/browser/BUILD.gn +++ b/extensions/browser/BUILD.gn
@@ -103,10 +103,6 @@ "content_verify_job.h", "crx_file_info.cc", "crx_file_info.h", - "declarative_user_script_manager.cc", - "declarative_user_script_manager.h", - "declarative_user_script_manager_factory.cc", - "declarative_user_script_manager_factory.h", "declarative_user_script_set.cc", "declarative_user_script_set.h", "deferred_start_render_host.h", @@ -197,8 +193,6 @@ "extension_system_provider.h", "extension_user_script_loader.cc", "extension_user_script_loader.h", - "extension_user_script_manager.cc", - "extension_user_script_manager.h", "extension_util.cc", "extension_util.h", "extension_web_contents_observer.cc", @@ -365,6 +359,8 @@ "url_request_util.h", "user_script_loader.cc", "user_script_loader.h", + "user_script_manager.cc", + "user_script_manager.h", "verified_contents.cc", "verified_contents.h", "view_type_utils.cc",
diff --git a/extensions/browser/api/execute_code_function.cc b/extensions/browser/api/execute_code_function.cc index b2f05a7..27b0aa5 100644 --- a/extensions/browser/api/execute_code_function.cc +++ b/extensions/browser/api/execute_code_function.cc
@@ -113,14 +113,14 @@ } CHECK_NE(UserScript::UNDEFINED, run_at); - CSSOrigin css_origin = CSS_ORIGIN_AUTHOR; + CSSOrigin css_origin = CSSOrigin::kAuthor; switch (details_->css_origin) { case api::extension_types::CSS_ORIGIN_NONE: case api::extension_types::CSS_ORIGIN_AUTHOR: - css_origin = CSS_ORIGIN_AUTHOR; + css_origin = CSSOrigin::kAuthor; break; case api::extension_types::CSS_ORIGIN_USER: - css_origin = CSS_ORIGIN_USER; + css_origin = CSSOrigin::kUser; break; }
diff --git a/extensions/browser/browser_context_keyed_service_factories.cc b/extensions/browser/browser_context_keyed_service_factories.cc index f9d0281d..143abcf 100644 --- a/extensions/browser/browser_context_keyed_service_factories.cc +++ b/extensions/browser/browser_context_keyed_service_factories.cc
@@ -35,7 +35,6 @@ #include "extensions/browser/api/web_request/web_request_api.h" #include "extensions/browser/app_window/app_window_geometry_cache.h" #include "extensions/browser/app_window/app_window_registry.h" -#include "extensions/browser/declarative_user_script_manager_factory.h" #include "extensions/browser/event_router_factory.h" #include "extensions/browser/extension_message_filter.h" #include "extensions/browser/extension_prefs_factory.h" @@ -76,7 +75,6 @@ api::TCPSocketEventDispatcher::GetFactoryInstance(); api::UDPSocketEventDispatcher::GetFactoryInstance(); declarative_net_request::RulesMonitorService::GetFactoryInstance(); - DeclarativeUserScriptManagerFactory::GetInstance(); EnsureExtensionURLLoaderFactoryShutdownNotifierFactoryBuilt(); EventRouterFactory::GetInstance(); ExtensionMessageFilter::EnsureShutdownNotifierFactoryBuilt();
diff --git a/extensions/browser/declarative_user_script_manager.cc b/extensions/browser/declarative_user_script_manager.cc deleted file mode 100644 index e4709f74..0000000 --- a/extensions/browser/declarative_user_script_manager.cc +++ /dev/null
@@ -1,62 +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. - -#include "extensions/browser/declarative_user_script_manager.h" - -#include "content/public/browser/browser_context.h" -#include "extensions/browser/declarative_user_script_manager_factory.h" -#include "extensions/browser/declarative_user_script_set.h" - -namespace extensions { - -DeclarativeUserScriptManager::DeclarativeUserScriptManager( - content::BrowserContext* browser_context) - : browser_context_(browser_context) { - extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context)); -} - -DeclarativeUserScriptManager::~DeclarativeUserScriptManager() { -} - -// static -DeclarativeUserScriptManager* DeclarativeUserScriptManager::Get( - content::BrowserContext* browser_context) { - return DeclarativeUserScriptManagerFactory::GetForBrowserContext( - browser_context); -} - -DeclarativeUserScriptSet* -DeclarativeUserScriptManager::GetDeclarativeUserScriptSetByID( - const HostID& host_id) { - auto it = declarative_user_script_sets_.find(host_id); - - if (it != declarative_user_script_sets_.end()) - return it->second.get(); - - return CreateDeclarativeUserScriptSet(host_id); -} - -DeclarativeUserScriptSet* -DeclarativeUserScriptManager::CreateDeclarativeUserScriptSet( - const HostID& host_id) { - // Inserts a new DeclarativeUserScriptManager and returns a ptr to it. - return declarative_user_script_sets_ - .insert( - std::make_pair(host_id, std::make_unique<DeclarativeUserScriptSet>( - browser_context_, host_id))) - .first->second.get(); -} - -void DeclarativeUserScriptManager::OnExtensionUnloaded( - content::BrowserContext* browser_context, - const Extension* extension, - UnloadedExtensionReason reason) { - for (const auto& val : declarative_user_script_sets_) { - DeclarativeUserScriptSet* set = val.second.get(); - if (set->host_id().id() == extension->id()) - set->ClearScripts(); - } -} - -} // namespace extensions
diff --git a/extensions/browser/declarative_user_script_manager.h b/extensions/browser/declarative_user_script_manager.h deleted file mode 100644 index cbac791..0000000 --- a/extensions/browser/declarative_user_script_manager.h +++ /dev/null
@@ -1,68 +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. - -#ifndef EXTENSIONS_BROWSER_DECLARATIVE_USER_SCRIPT_MANAGER_H_ -#define EXTENSIONS_BROWSER_DECLARATIVE_USER_SCRIPT_MANAGER_H_ - -#include <map> - -#include "base/macros.h" -#include "base/scoped_observer.h" -#include "components/keyed_service/core/keyed_service.h" -#include "extensions/browser/extension_registry.h" -#include "extensions/browser/extension_registry_observer.h" -#include "extensions/common/host_id.h" - -namespace content { -class BrowserContext; -} - -namespace extensions { -class DeclarativeUserScriptSet; - -// Manages a set of DeclarativeUserScriptSet objects for script injections. -class DeclarativeUserScriptManager : public KeyedService, - public ExtensionRegistryObserver { - public: - explicit DeclarativeUserScriptManager( - content::BrowserContext* browser_context); - ~DeclarativeUserScriptManager() override; - - // Convenience method to return the DeclarativeUserScriptManager for a given - // |context|. - static DeclarativeUserScriptManager* Get(content::BrowserContext* context); - - // Gets the user script set for declarative scripts by the given HostId. - // If one does not exist, a new object will be created. - DeclarativeUserScriptSet* GetDeclarativeUserScriptSetByID( - const HostID& host_id); - - private: - using UserScriptSetMap = - std::map<HostID, std::unique_ptr<DeclarativeUserScriptSet>>; - - // ExtensionRegistryObserver: - void OnExtensionUnloaded(content::BrowserContext* browser_context, - const Extension* extension, - UnloadedExtensionReason reason) override; - - // Creates a DeclarativeUserScriptSet object. - DeclarativeUserScriptSet* CreateDeclarativeUserScriptSet( - const HostID& host_id); - - // A map of DeclarativeUserScriptSets for each host; each set is lazily - // initialized. - UserScriptSetMap declarative_user_script_sets_; - - content::BrowserContext* browser_context_; - - ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver> - extension_registry_observer_{this}; - - DISALLOW_COPY_AND_ASSIGN(DeclarativeUserScriptManager); -}; - -} // namespace extensions - -#endif // EXTENSIONS_BROWSER_DECLARATIVE_USER_SCRIPT_MANAGER_H_
diff --git a/extensions/browser/declarative_user_script_manager_factory.cc b/extensions/browser/declarative_user_script_manager_factory.cc deleted file mode 100644 index cff2c69..0000000 --- a/extensions/browser/declarative_user_script_manager_factory.cc +++ /dev/null
@@ -1,51 +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. - -#include "extensions/browser/declarative_user_script_manager_factory.h" - -#include "components/keyed_service/content/browser_context_dependency_manager.h" -#include "extensions/browser/declarative_user_script_manager.h" -#include "extensions/browser/extension_registry_factory.h" -#include "extensions/browser/extensions_browser_client.h" - -using content::BrowserContext; - -namespace extensions { - -// static -DeclarativeUserScriptManager* -DeclarativeUserScriptManagerFactory::GetForBrowserContext( - BrowserContext* context) { - return static_cast<DeclarativeUserScriptManager*>( - GetInstance()->GetServiceForBrowserContext(context, true)); -} - -// static -DeclarativeUserScriptManagerFactory* -DeclarativeUserScriptManagerFactory::GetInstance() { - return base::Singleton<DeclarativeUserScriptManagerFactory>::get(); -} - -DeclarativeUserScriptManagerFactory::DeclarativeUserScriptManagerFactory() - : BrowserContextKeyedServiceFactory( - "DeclarativeUserScriptManager", - BrowserContextDependencyManager::GetInstance()) { - DependsOn(ExtensionRegistryFactory::GetInstance()); -} - -DeclarativeUserScriptManagerFactory::~DeclarativeUserScriptManagerFactory() { -} - -KeyedService* DeclarativeUserScriptManagerFactory::BuildServiceInstanceFor( - BrowserContext* context) const { - return new DeclarativeUserScriptManager(context); -} - -BrowserContext* DeclarativeUserScriptManagerFactory::GetBrowserContextToUse( - BrowserContext* context) const { - // Redirected in incognito. - return ExtensionsBrowserClient::Get()->GetOriginalContext(context); -} - -} // namespace extensions
diff --git a/extensions/browser/declarative_user_script_manager_factory.h b/extensions/browser/declarative_user_script_manager_factory.h deleted file mode 100644 index 8ba68b55..0000000 --- a/extensions/browser/declarative_user_script_manager_factory.h +++ /dev/null
@@ -1,41 +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. - -#ifndef EXTENSIONS_BROWSER_DECLARATIVE_USER_SCRIPT_MANAGER_FACTORY_H_ -#define EXTENSIONS_BROWSER_DECLARATIVE_USER_SCRIPT_MANAGER_FACTORY_H_ - -#include "base/macros.h" -#include "base/memory/singleton.h" -#include "components/keyed_service/content/browser_context_keyed_service_factory.h" - -namespace extensions { - -class DeclarativeUserScriptManager; - -class DeclarativeUserScriptManagerFactory - : public BrowserContextKeyedServiceFactory { - public: - static DeclarativeUserScriptManager* GetForBrowserContext( - content::BrowserContext* context); - static DeclarativeUserScriptManagerFactory* GetInstance(); - - private: - friend struct base::DefaultSingletonTraits< - DeclarativeUserScriptManagerFactory>; - - DeclarativeUserScriptManagerFactory(); - ~DeclarativeUserScriptManagerFactory() override; - - // BrowserContextKeyedServiceFactory implementation - KeyedService* BuildServiceInstanceFor( - content::BrowserContext* context) const override; - content::BrowserContext* GetBrowserContextToUse( - content::BrowserContext* context) const override; - - DISALLOW_COPY_AND_ASSIGN(DeclarativeUserScriptManagerFactory); -}; - -} // namespace extensions - -#endif // EXTENSIONS_BROWSER_DECLARATIVE_USER_SCRIPT_MANAGER_FACTORY_H_
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h index 9b1f45f..c24eefac 100644 --- a/extensions/browser/extension_function_histogram_value.h +++ b/extensions/browser/extension_function_histogram_value.h
@@ -1602,6 +1602,7 @@ FILEMANAGERPRIVATE_ISTABLETMODEENABLED = 1539, FILEMANAGERPRIVATE_NOTIFYDRIVEDIALOGRESULT = 1540, ENTERPRISEREPORTINGPRIVATE_GETCONTEXTINFO = 1541, + SCRIPTING_REMOVECSS = 1542, // Last entry: Add new entries above, then run: // python tools/metrics/histograms/update_extension_histograms.py ENUM_BOUNDARY
diff --git a/extensions/browser/extension_system.h b/extensions/browser/extension_system.h index efce592..1d247c8 100644 --- a/extensions/browser/extension_system.h +++ b/extensions/browser/extension_system.h
@@ -40,8 +40,8 @@ class QuotaService; class RuntimeData; class ServiceWorkerManager; -class ExtensionUserScriptManager; class StateStore; +class UserScriptManager; class ValueStoreFactory; enum class UnloadedExtensionReason; @@ -85,8 +85,8 @@ // The ServiceWorkerManager is created at startup. virtual ServiceWorkerManager* service_worker_manager() = 0; - // The ExtensionUserScriptManager is created at startup. - virtual ExtensionUserScriptManager* extension_user_script_manager() = 0; + // The UserScriptManager is created at startup. + virtual UserScriptManager* user_script_manager() = 0; // The StateStore is created at startup. virtual StateStore* state_store() = 0;
diff --git a/extensions/browser/extension_user_script_loader.h b/extensions/browser/extension_user_script_loader.h index 054b10f..0097294 100644 --- a/extensions/browser/extension_user_script_loader.h +++ b/extensions/browser/extension_user_script_loader.h
@@ -32,7 +32,7 @@ using HostsInfo = std::map<HostID, PathAndLocaleInfo>; // The listen_for_extension_system_loaded is only set true when initializing - // the Extension System, e.g, when constructs ExtensionUserScriptManager in + // the Extension System, e.g, when constructs UserScriptManager in // ExtensionSystemImpl. ExtensionUserScriptLoader(content::BrowserContext* browser_context, const HostID& host_id,
diff --git a/extensions/browser/extension_user_script_manager.cc b/extensions/browser/extension_user_script_manager.cc deleted file mode 100644 index 05d03f3..0000000 --- a/extensions/browser/extension_user_script_manager.cc +++ /dev/null
@@ -1,59 +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. - -#include "extensions/browser/extension_user_script_manager.h" - -#include "extensions/browser/extension_util.h" -#include "extensions/common/host_id.h" -#include "extensions/common/manifest_handlers/content_scripts_handler.h" - -namespace extensions { - -ExtensionUserScriptManager::ExtensionUserScriptManager( - content::BrowserContext* browser_context) - : loader_(browser_context, - HostID(), - true /* listen_for_extension_system_loaded */), - browser_context_(browser_context) { - extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_)); -} - -ExtensionUserScriptManager::~ExtensionUserScriptManager() {} - -void ExtensionUserScriptManager::OnExtensionLoaded( - content::BrowserContext* browser_context, - const Extension* extension) { - loader_.AddScripts(GetScriptsMetadata(extension)); -} - -void ExtensionUserScriptManager::OnExtensionUnloaded( - content::BrowserContext* browser_context, - const Extension* extension, - UnloadedExtensionReason reason) { - const UserScriptList& script_list = - ContentScriptsInfo::GetContentScripts(extension); - std::set<UserScriptIDPair> scripts_to_remove; - for (const std::unique_ptr<UserScript>& script : script_list) - scripts_to_remove.insert(UserScriptIDPair(script->id(), script->host_id())); - loader_.RemoveScripts(scripts_to_remove); -} - -std::unique_ptr<UserScriptList> ExtensionUserScriptManager::GetScriptsMetadata( - const Extension* extension) { - bool incognito_enabled = - util::IsIncognitoEnabled(extension->id(), browser_context_); - const UserScriptList& script_list = - ContentScriptsInfo::GetContentScripts(extension); - std::unique_ptr<UserScriptList> script_vector(new UserScriptList()); - script_vector->reserve(script_list.size()); - for (const std::unique_ptr<UserScript>& script : script_list) { - std::unique_ptr<UserScript> script_copy = - UserScript::CopyMetadataFrom(*script); - script_copy->set_incognito_enabled(incognito_enabled); - script_vector->push_back(std::move(script_copy)); - } - return script_vector; -} - -} // namespace extensions
diff --git a/extensions/browser/extension_user_script_manager.h b/extensions/browser/extension_user_script_manager.h deleted file mode 100644 index 4e3eaee..0000000 --- a/extensions/browser/extension_user_script_manager.h +++ /dev/null
@@ -1,64 +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. - -#ifndef EXTENSIONS_BROWSER_EXTENSION_USER_SCRIPT_MANAGER_H_ -#define EXTENSIONS_BROWSER_EXTENSION_USER_SCRIPT_MANAGER_H_ - -#include <memory> -#include <set> - -#include "base/macros.h" -#include "base/scoped_observer.h" -#include "extensions/browser/extension_registry.h" -#include "extensions/browser/extension_registry_observer.h" -#include "extensions/browser/extension_user_script_loader.h" -#include "extensions/common/extension.h" -#include "extensions/common/user_script.h" - -namespace content { -class BrowserContext; -} - -namespace extensions { - -// Manages statically-defined user scripts for all extensions. Owns a -// UserScriptLoader to which file loading and shared memory management -// operations are delegated. -// TODO(crbug.com/1168627): Manage declarative user scripts (from API/webview) -// from all extensions in this class. -class ExtensionUserScriptManager : public ExtensionRegistryObserver { - public: - explicit ExtensionUserScriptManager(content::BrowserContext* browser_context); - ~ExtensionUserScriptManager() override; - - UserScriptLoader* script_loader() { return &loader_; } - - private: - // ExtensionRegistryObserver implementation. - void OnExtensionLoaded(content::BrowserContext* browser_context, - const Extension* extension) override; - void OnExtensionUnloaded(content::BrowserContext* browser_context, - const Extension* extension, - UnloadedExtensionReason reason) override; - - // Gets an extension's scripts' metadata; i.e., gets a list of UserScript - // objects that contains script info, but not the contents of the scripts. - std::unique_ptr<UserScriptList> GetScriptsMetadata( - const Extension* extension); - - // Script loader that handles loading contents of scripts into shared memory - // and notifying renderers of scripts in shared memory. - ExtensionUserScriptLoader loader_; - - content::BrowserContext* browser_context_; - - ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver> - extension_registry_observer_{this}; - - DISALLOW_COPY_AND_ASSIGN(ExtensionUserScriptManager); -}; - -} // namespace extensions - -#endif // EXTENSIONS_BROWSER_EXTENSION_USER_SCRIPT_MANAGER_H_
diff --git a/extensions/browser/guest_view/web_view/web_view_content_script_manager.cc b/extensions/browser/guest_view/web_view/web_view_content_script_manager.cc index 10ec9b0..6f696b7 100644 --- a/extensions/browser/guest_view/web_view/web_view_content_script_manager.cc +++ b/extensions/browser/guest_view/web_view/web_view_content_script_manager.cc
@@ -13,11 +13,11 @@ #include "content/public/browser/navigation_details.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" -#include "extensions/browser/declarative_user_script_manager.h" #include "extensions/browser/declarative_user_script_set.h" #include "extensions/browser/extension_system.h" #include "extensions/browser/guest_view/web_view/web_view_constants.h" #include "extensions/browser/guest_view/web_view/web_view_renderer_state.h" +#include "extensions/browser/user_script_manager.h" using content::BrowserThread; @@ -54,7 +54,8 @@ DCHECK_CURRENTLY_ON(BrowserThread::UI); DeclarativeUserScriptSet* script_set = - DeclarativeUserScriptManager::Get(browser_context_) + ExtensionSystem::Get(browser_context_) + ->user_script_manager() ->GetDeclarativeUserScriptSetByID(host_id); DCHECK(script_set); @@ -147,7 +148,8 @@ return; DeclarativeUserScriptSet* script_set = - DeclarativeUserScriptManager::Get(browser_context_) + ExtensionSystem::Get(browser_context_) + ->user_script_manager() ->GetDeclarativeUserScriptSetByID(host_id); CHECK(script_set);
diff --git a/extensions/browser/mock_extension_system.cc b/extensions/browser/mock_extension_system.cc index 7e90ac1..b01b336 100644 --- a/extensions/browser/mock_extension_system.cc +++ b/extensions/browser/mock_extension_system.cc
@@ -37,8 +37,7 @@ return nullptr; } -ExtensionUserScriptManager* -MockExtensionSystem::extension_user_script_manager() { +UserScriptManager* MockExtensionSystem::user_script_manager() { return nullptr; }
diff --git a/extensions/browser/mock_extension_system.h b/extensions/browser/mock_extension_system.h index 137e0f2a..5f251675 100644 --- a/extensions/browser/mock_extension_system.h +++ b/extensions/browser/mock_extension_system.h
@@ -36,7 +36,7 @@ RuntimeData* runtime_data() override; ManagementPolicy* management_policy() override; ServiceWorkerManager* service_worker_manager() override; - ExtensionUserScriptManager* extension_user_script_manager() override; + UserScriptManager* user_script_manager() override; StateStore* state_store() override; StateStore* rules_store() override; scoped_refptr<ValueStoreFactory> store_factory() override;
diff --git a/extensions/browser/renderer_startup_helper.cc b/extensions/browser/renderer_startup_helper.cc index e50ed7c..d788bd26 100644 --- a/extensions/browser/renderer_startup_helper.cc +++ b/extensions/browser/renderer_startup_helper.cc
@@ -145,13 +145,10 @@ // Load default policy_blocked_hosts and policy_allowed_hosts settings, part // of the ExtensionSettings policy. - ExtensionMsg_UpdateDefaultPolicyHostRestrictions_Params params; int context_id = util::GetBrowserContextId(renderer_context); - params.default_policy_blocked_hosts = - PermissionsData::GetDefaultPolicyBlockedHosts(context_id); - params.default_policy_allowed_hosts = - PermissionsData::GetDefaultPolicyAllowedHosts(context_id); - process->Send(new ExtensionMsg_UpdateDefaultPolicyHostRestrictions(params)); + renderer->UpdateDefaultPolicyHostRestrictions( + PermissionsData::GetDefaultPolicyBlockedHosts(context_id), + PermissionsData::GetDefaultPolicyAllowedHosts(context_id)); // Loaded extensions. std::vector<ExtensionMsg_Loaded_Params> loaded_extensions;
diff --git a/extensions/browser/renderer_startup_helper_unittest.cc b/extensions/browser/renderer_startup_helper_unittest.cc index 9df5479..7dd4570 100644 --- a/extensions/browser/renderer_startup_helper_unittest.cc +++ b/extensions/browser/renderer_startup_helper_unittest.cc
@@ -15,6 +15,7 @@ #include "extensions/browser/test_extensions_browser_client.h" #include "extensions/common/extension_builder.h" #include "extensions/common/extension_messages.h" +#include "extensions/common/permissions/permissions_data.h" #include "mojo/public/cpp/bindings/associated_receiver_set.h" namespace extensions { @@ -32,6 +33,14 @@ size_t num_unloaded_extensions() { return unloaded_extensions_.size(); } + const URLPatternSet& default_policy_blocked_hosts() const { + return default_blocked_hosts_; + } + + const URLPatternSet& default_policy_allowed_hosts() const { + return default_allowed_hosts_; + } + protected: mojo::PendingAssociatedRemote<mojom::Renderer> BindNewRendererRemote( content::RenderProcessHost* process) override { @@ -62,6 +71,15 @@ void SetScriptingAllowlist( const std::vector<std::string>& extension_ids) override {} + void UpdateDefaultPolicyHostRestrictions( + const URLPatternSet& default_policy_blocked_hosts, + const URLPatternSet& default_policy_allowed_hosts) override { + default_blocked_hosts_.AddPatterns(default_policy_blocked_hosts); + default_allowed_hosts_.AddPatterns(default_policy_allowed_hosts); + } + + URLPatternSet default_blocked_hosts_; + URLPatternSet default_allowed_hosts_; std::vector<std::string> activated_extensions_; std::vector<std::string> unloaded_extensions_; mojo::AssociatedReceiverSet<mojom::Renderer> receivers_; @@ -272,11 +290,32 @@ EXPECT_TRUE(IsExtensionPendingActivationInProcess( *extension_, render_process_host_.get())); + // Initialize PermissionsData default policy hosts restrictions. + // During the process initialization, UpdateDefaultPolicyHostRestrictions + // will be called with the default policy values returned by PermissionsData. + URLPatternSet default_blocked_hosts; + URLPatternSet default_allowed_hosts; + default_blocked_hosts.AddPattern( + URLPattern(URLPattern::SCHEME_ALL, "*://*.example.com/*")); + default_allowed_hosts.AddPattern( + URLPattern(URLPattern::SCHEME_ALL, "*://test.example2.com/*")); + PermissionsData::SetDefaultPolicyHostRestrictions( + util::GetBrowserContextId(browser_context()), default_blocked_hosts, + default_allowed_hosts); + // Initialize the render process. SimulateRenderProcessCreated(render_process_host_.get()); // The renderer would have been sent multiple initialization messages // including the loading and activation messages for the extension. - EXPECT_LE(2u, sink.message_count()); + EXPECT_LE(1u, sink.message_count()); + + // Method UpdateDefaultPolicyHostRestrictions() from mojom::Renderer should + // have been called with the default policy for blocked/allowed hosts given by + // PermissionsData, which was initialized above. + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(default_blocked_hosts, helper_->default_policy_blocked_hosts()); + EXPECT_EQ(default_allowed_hosts, helper_->default_policy_allowed_hosts()); + EXPECT_TRUE(IsProcessInitialized(render_process_host_.get())); EXPECT_TRUE( IsExtensionLoadedInProcess(*extension_, render_process_host_.get()));
diff --git a/extensions/browser/user_script_manager.cc b/extensions/browser/user_script_manager.cc new file mode 100644 index 0000000..ced5f5e --- /dev/null +++ b/extensions/browser/user_script_manager.cc
@@ -0,0 +1,83 @@ +// Copyright 2021 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 "extensions/browser/user_script_manager.h" + +#include "content/public/browser/browser_context.h" +#include "extensions/browser/declarative_user_script_set.h" +#include "extensions/browser/extension_util.h" +#include "extensions/common/manifest_handlers/content_scripts_handler.h" + +namespace extensions { + +UserScriptManager::UserScriptManager(content::BrowserContext* browser_context) + : manifest_script_loader_(browser_context, + HostID(), + true /* listen_for_extension_system_loaded */), + browser_context_(browser_context) { + extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_)); +} + +UserScriptManager::~UserScriptManager() = default; + +DeclarativeUserScriptSet* UserScriptManager::GetDeclarativeUserScriptSetByID( + const HostID& host_id) { + auto it = declarative_user_script_sets_.find(host_id); + + if (it != declarative_user_script_sets_.end()) + return it->second.get(); + + return CreateDeclarativeUserScriptSet(host_id); +} + +void UserScriptManager::OnExtensionLoaded( + content::BrowserContext* browser_context, + const Extension* extension) { + manifest_script_loader_.AddScripts(GetManifestScriptsMetadata(extension)); +} + +void UserScriptManager::OnExtensionUnloaded( + content::BrowserContext* browser_context, + const Extension* extension, + UnloadedExtensionReason reason) { + const UserScriptList& script_list = + ContentScriptsInfo::GetContentScripts(extension); + std::set<UserScriptIDPair> scripts_to_remove; + for (const std::unique_ptr<UserScript>& script : script_list) + scripts_to_remove.insert(UserScriptIDPair(script->id(), script->host_id())); + manifest_script_loader_.RemoveScripts(scripts_to_remove); + + auto it = declarative_user_script_sets_.find( + HostID(HostID::EXTENSIONS, extension->id())); + if (it != declarative_user_script_sets_.end()) + it->second->ClearScripts(); +} + +std::unique_ptr<UserScriptList> UserScriptManager::GetManifestScriptsMetadata( + const Extension* extension) { + bool incognito_enabled = + util::IsIncognitoEnabled(extension->id(), browser_context_); + const UserScriptList& script_list = + ContentScriptsInfo::GetContentScripts(extension); + auto script_vector = std::make_unique<UserScriptList>(); + script_vector->reserve(script_list.size()); + for (const auto& script : script_list) { + std::unique_ptr<UserScript> script_copy = + UserScript::CopyMetadataFrom(*script); + script_copy->set_incognito_enabled(incognito_enabled); + script_vector->push_back(std::move(script_copy)); + } + return script_vector; +} + +DeclarativeUserScriptSet* UserScriptManager::CreateDeclarativeUserScriptSet( + const HostID& host_id) { + // Inserts a new DeclarativeUserScriptSet and returns a ptr to it. + return declarative_user_script_sets_ + .emplace(host_id, std::make_unique<DeclarativeUserScriptSet>( + browser_context_, host_id)) + .first->second.get(); +} + +} // namespace extensions
diff --git a/extensions/browser/user_script_manager.h b/extensions/browser/user_script_manager.h new file mode 100644 index 0000000..dac6d83 --- /dev/null +++ b/extensions/browser/user_script_manager.h
@@ -0,0 +1,89 @@ +// Copyright 2021 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 EXTENSIONS_BROWSER_USER_SCRIPT_MANAGER_H_ +#define EXTENSIONS_BROWSER_USER_SCRIPT_MANAGER_H_ + +#include <map> +#include <memory> +#include <set> + +#include "base/scoped_observer.h" +#include "extensions/browser/extension_registry.h" +#include "extensions/browser/extension_registry_observer.h" +#include "extensions/browser/extension_user_script_loader.h" +#include "extensions/common/extension.h" +#include "extensions/common/host_id.h" +#include "extensions/common/user_script.h" + +namespace content { +class BrowserContext; +} + +namespace extensions { +class DeclarativeUserScriptSet; + +// Manages user scripts for all extensions and webview scripts from WebUI pages. +// Owns one UserScriptLoader for manifest extension scripts, and a map of HostID +// to UserScriptLoaders for declarative extension and WebUI scripts. File +// loading and shared memory management operations are delegated to these +// UserScriptLoaders. +class UserScriptManager : public ExtensionRegistryObserver { + public: + explicit UserScriptManager(content::BrowserContext* browser_context); + ~UserScriptManager() override; + UserScriptManager(const UserScriptManager& other) = delete; + UserScriptManager& operator=(const UserScriptManager& other) = delete; + + UserScriptLoader* manifest_script_loader() { + return &manifest_script_loader_; + } + + // Gets the user script set for declarative scripts by the given HostID. + // If one does not exist, a new object will be created. + DeclarativeUserScriptSet* GetDeclarativeUserScriptSetByID( + const HostID& host_id); + + private: + using UserScriptSetMap = + std::map<HostID, std::unique_ptr<DeclarativeUserScriptSet>>; + + // ExtensionRegistryObserver implementation. + void OnExtensionLoaded(content::BrowserContext* browser_context, + const Extension* extension) override; + void OnExtensionUnloaded(content::BrowserContext* browser_context, + const Extension* extension, + UnloadedExtensionReason reason) override; + + // Gets an extension's manifest scripts' metadata; i.e., gets a list of + // UserScript objects that contains script info, but not the contents of the + // scripts. + std::unique_ptr<UserScriptList> GetManifestScriptsMetadata( + const Extension* extension); + + // Creates a DeclarativeUserScriptSet object. + DeclarativeUserScriptSet* CreateDeclarativeUserScriptSet( + const HostID& host_id); + + // A map of DeclarativeUserScriptSets for each host. Each set is lazily + // initialized, and contains scripts from APIs for an extension host, or + // webview scripts for a WebUI host. + // TODO(crbug.com/1168627): Have one UserScriptLoader per extension, and split + // WebUI loaders into another set. + UserScriptSetMap declarative_user_script_sets_; + + // Script loader for manifest extension scripts that handles loading contents + // of scripts into shared memory and notifying renderers of scripts in shared + // memory. + ExtensionUserScriptLoader manifest_script_loader_; + + content::BrowserContext* const browser_context_; + + ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver> + extension_registry_observer_{this}; +}; + +} // namespace extensions + +#endif // EXTENSIONS_BROWSER_USER_SCRIPT_MANAGER_H_
diff --git a/extensions/common/BUILD.gn b/extensions/common/BUILD.gn index 822c013..b1ec6fc 100644 --- a/extensions/common/BUILD.gn +++ b/extensions/common/BUILD.gn
@@ -46,6 +46,7 @@ "mojom/guest_view.mojom", "mojom/keep_alive.mojom", "mojom/renderer.mojom", + "mojom/url_pattern_set.mojom", ] public_deps = [ @@ -67,6 +68,22 @@ traits_headers = [ "//extensions/common/mojom/channel_mojom_traits.h" ] traits_public_deps = [ "//components/version_info:channel" ] }, + { + types = [ + { + mojom = "extensions.mojom.URLPattern" + cpp = "::URLPattern" + }, + { + mojom = "extensions.mojom.URLPatternSet" + cpp = "::extensions::URLPatternSet" + }, + ] + traits_headers = + [ "//extensions/common/mojom/url_pattern_set_mojom_traits.h" ] + traits_sources = + [ "//extensions/common/mojom/url_pattern_set_mojom_traits.cc" ] + }, ] overridden_deps = [ "//content/public/common:interfaces" ] @@ -473,6 +490,7 @@ "manifest_handlers/web_app_shortcut_icons_handler_unittest.cc", "manifest_unittest.cc", "message_bundle_unittest.cc", + "mojom/url_pattern_set_mojom_traits_unittest.cc", "permissions/api_permission_set_unittest.cc", "permissions/api_permission_unittest.cc", "permissions/base_set_operators_unittest.cc", @@ -499,6 +517,7 @@ "//extensions:extensions_resources", "//extensions/common:mojom", "//extensions/common/api", + "//mojo/public/cpp/test_support:test_utils", "//tools/json_schema_compiler:generated_api_util", # TODO(brettw) these tests should not be including headers from browser.
diff --git a/extensions/common/constants.h b/extensions/common/constants.h index a7df654a..f1f7fa4 100644 --- a/extensions/common/constants.h +++ b/extensions/common/constants.h
@@ -146,8 +146,11 @@ }; // The origin of injected CSS. -enum CSSOrigin { CSS_ORIGIN_AUTHOR, CSS_ORIGIN_USER }; -static const CSSOrigin CSS_ORIGIN_LAST = CSS_ORIGIN_USER; +enum class CSSOrigin { + kAuthor = 0, + kUser = 1, + kLast = kUser, +}; } // namespace extensions
diff --git a/extensions/common/extension_messages.h b/extensions/common/extension_messages.h index ab8d0c0..d549efb 100644 --- a/extensions/common/extension_messages.h +++ b/extensions/common/extension_messages.h
@@ -51,7 +51,7 @@ #define IPC_MESSAGE_START ExtensionMsgStart -IPC_ENUM_TRAITS_MAX_VALUE(extensions::CSSOrigin, extensions::CSS_ORIGIN_LAST) +IPC_ENUM_TRAITS_MAX_VALUE(extensions::CSSOrigin, extensions::CSSOrigin::kLast) IPC_ENUM_TRAITS_MAX_VALUE(extensions::ViewType, extensions::VIEW_TYPE_LAST) IPC_ENUM_TRAITS_MAX_VALUE(content::SocketPermissionRequest::OperationType, @@ -527,12 +527,6 @@ IPC_STRUCT_MEMBER(bool, uses_default_policy_host_restrictions) IPC_STRUCT_END() -// Parameters structure for ExtensionMsg_UpdateDefaultPolicyHostRestrictions. -IPC_STRUCT_BEGIN(ExtensionMsg_UpdateDefaultPolicyHostRestrictions_Params) - IPC_STRUCT_MEMBER(extensions::URLPatternSet, default_policy_blocked_hosts) - IPC_STRUCT_MEMBER(extensions::URLPatternSet, default_policy_allowed_hosts) -IPC_STRUCT_END() - // Messages sent from the browser to the renderer: // The browser sends this message in response to all extension api calls. The @@ -612,10 +606,6 @@ IPC_MESSAGE_CONTROL1(ExtensionMsg_UpdatePermissions, ExtensionMsg_UpdatePermissions_Params) -// Tell the renderer to update an extension's policy_blocked_hosts set. -IPC_MESSAGE_CONTROL1(ExtensionMsg_UpdateDefaultPolicyHostRestrictions, - ExtensionMsg_UpdateDefaultPolicyHostRestrictions_Params) - // Tell the render view about new tab-specific permissions for an extension. IPC_MESSAGE_CONTROL5(ExtensionMsg_UpdateTabSpecificPermissions, GURL /* url */,
diff --git a/extensions/common/extension_resource.cc b/extensions/common/extension_resource.cc index fe7bcfe..a997a63b25 100644 --- a/extensions/common/extension_resource.cc +++ b/extensions/common/extension_resource.cc
@@ -4,29 +4,27 @@ #include "extensions/common/extension_resource.h" -#include <stddef.h> - #include "base/check.h" #include "base/files/file_util.h" -#include "base/threading/thread_restrictions.h" namespace extensions { -ExtensionResource::ExtensionResource() : follow_symlinks_anywhere_(false) { -} +ExtensionResource::ExtensionResource() : follow_symlinks_anywhere_(false) {} -ExtensionResource::ExtensionResource(const std::string& extension_id, +ExtensionResource::ExtensionResource(const ExtensionId& extension_id, const base::FilePath& extension_root, const base::FilePath& relative_path) : extension_id_(extension_id), extension_root_(extension_root), relative_path_(relative_path), - follow_symlinks_anywhere_(false) { -} + follow_symlinks_anywhere_(false) {} ExtensionResource::ExtensionResource(const ExtensionResource& other) = default; +ExtensionResource::ExtensionResource(ExtensionResource&& other) = default; +ExtensionResource& ExtensionResource::operator=(ExtensionResource&& other) = + default; -ExtensionResource::~ExtensionResource() {} +ExtensionResource::~ExtensionResource() = default; void ExtensionResource::set_follow_symlinks_anywhere() { follow_symlinks_anywhere_ = true; @@ -101,32 +99,4 @@ return base::FilePath(); } -// Unit-testing helpers. -base::FilePath::StringType ExtensionResource::NormalizeSeperators( - const base::FilePath::StringType& path) const { -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - base::FilePath::StringType win_path = path; - for (size_t i = 0; i < win_path.length(); i++) { - if (base::FilePath::IsSeparator(win_path[i])) - win_path[i] = base::FilePath::kSeparators[0]; - } - return win_path; -#else - return path; -#endif // FILE_PATH_USES_WIN_SEPARATORS -} - -bool ExtensionResource::ComparePathWithDefault( - const base::FilePath& path) const { - // Make sure we have a cached value to test against... - if (full_resource_path_.empty()) - GetFilePath(); - if (NormalizeSeperators(path.value()) == - NormalizeSeperators(full_resource_path_.value())) { - return true; - } else { - return false; - } -} - } // namespace extensions
diff --git a/extensions/common/extension_resource.h b/extensions/common/extension_resource.h index 1ed42a1..260d4fd9 100644 --- a/extensions/common/extension_resource.h +++ b/extensions/common/extension_resource.h
@@ -5,9 +5,8 @@ #ifndef EXTENSIONS_COMMON_EXTENSION_RESOURCE_H_ #define EXTENSIONS_COMMON_EXTENSION_RESOURCE_H_ -#include <string> - #include "base/files/file_path.h" +#include "extensions/common/extension_id.h" namespace extensions { @@ -26,12 +25,12 @@ }; ExtensionResource(); - - ExtensionResource(const std::string& extension_id, + ExtensionResource(const ExtensionId& extension_id, const base::FilePath& extension_root, const base::FilePath& relative_path); - ExtensionResource(const ExtensionResource& other); + ExtensionResource(ExtensionResource&& other); + ExtensionResource& operator=(ExtensionResource&& other); ~ExtensionResource(); @@ -58,7 +57,7 @@ SymlinkPolicy symlink_policy); // Getters - const std::string& extension_id() const { return extension_id_; } + const ExtensionId& extension_id() const { return extension_id_; } // Note that this might be empty for a valid ExtensionResource since dummy // Extension objects may be created with an empty extension root path in code. @@ -66,16 +65,11 @@ const base::FilePath& relative_path() const { return relative_path_; } - bool empty() const { return relative_path().empty(); } - - // Unit test helpers. - base::FilePath::StringType NormalizeSeperators( - const base::FilePath::StringType& path) const; - bool ComparePathWithDefault(const base::FilePath& path) const; + bool empty() const { return relative_path_.empty(); } private: // The id of the extension that this resource is associated with. - std::string extension_id_; + ExtensionId extension_id_; // Extension root. base::FilePath extension_root_;
diff --git a/extensions/common/mojom/renderer.mojom b/extensions/common/mojom/renderer.mojom index f6e0c49..754c5ff 100644 --- a/extensions/common/mojom/renderer.mojom +++ b/extensions/common/mojom/renderer.mojom
@@ -6,6 +6,7 @@ import "extensions/common/mojom/channel.mojom"; import "extensions/common/mojom/feature_session_type.mojom"; +import "extensions/common/mojom/url_pattern_set.mojom"; // This should be used for implementing browser-to-renderer control messages // which need to retain FIFO with respect to other mojo interfaces like @@ -40,4 +41,9 @@ // Updates the scripting allowlist for extensions in the render process. This // is only used for testing. SetScriptingAllowlist(array<string> extension_ids); + + // Tells the renderer to update an extension's policy_blocked_hosts set. + UpdateDefaultPolicyHostRestrictions( + URLPatternSet default_policy_blocked_hosts, + URLPatternSet default_policy_allowed_hosts); };
diff --git a/extensions/common/mojom/url_pattern_set.mojom b/extensions/common/mojom/url_pattern_set.mojom new file mode 100644 index 0000000..5b09ae9d --- /dev/null +++ b/extensions/common/mojom/url_pattern_set.mojom
@@ -0,0 +1,21 @@ +// Copyright 2021 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. + +module extensions.mojom; + +// A pattern that can be used to match URLs. See C++ type URLPattern for full +// documentation. +struct URLPattern { + // A bitmask containing the schemes considered valid for this pattern. + int32 valid_schemes; + // A string representing this URLPattern. + string pattern; +}; + +// A set of URLs an extension uses for web content. See +// extensions::URLPatternSet for full documentation. +struct URLPatternSet { + array <URLPattern> patterns; +}; +
diff --git a/extensions/common/mojom/url_pattern_set_mojom_traits.cc b/extensions/common/mojom/url_pattern_set_mojom_traits.cc new file mode 100644 index 0000000..1aa3369 --- /dev/null +++ b/extensions/common/mojom/url_pattern_set_mojom_traits.cc
@@ -0,0 +1,45 @@ +// Copyright 2021 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 "extensions/common/mojom/url_pattern_set_mojom_traits.h" + +namespace mojo { + +bool StructTraits<extensions::mojom::URLPatternDataView, URLPattern>::Read( + extensions::mojom::URLPatternDataView data, + URLPattern* out) { + std::string pattern; + + if (!data.ReadPattern(&pattern)) + return false; + + // TODO(jstritar): We don't want the URLPattern to fail parsing when the + // scheme is invalid. Instead, the pattern should parse but it should not + // match the invalid patterns. We get around this by setting the valid + // schemes after parsing the pattern. Update these method calls once we can + // ignore scheme validation with URLPattern parse options. crbug.com/90544 + out->SetValidSchemes(URLPattern::SCHEME_ALL); + URLPattern::ParseResult result = out->Parse(pattern); + out->SetValidSchemes(data.valid_schemes()); + + return URLPattern::ParseResult::kSuccess == result; +} + +bool StructTraits<extensions::mojom::URLPatternSetDataView, + extensions::URLPatternSet>:: + Read(extensions::mojom::URLPatternSetDataView data, + extensions::URLPatternSet* out) { + std::vector<URLPattern> mojo_patterns; + if (!data.ReadPatterns(&mojo_patterns)) + return false; + for (const auto& pattern : mojo_patterns) + out->AddPattern(pattern); + + if (mojo_patterns.size() != out->patterns().size()) + return false; + + return true; +} + +} // namespace mojo
diff --git a/extensions/common/mojom/url_pattern_set_mojom_traits.h b/extensions/common/mojom/url_pattern_set_mojom_traits.h new file mode 100644 index 0000000..c4bfeb32 --- /dev/null +++ b/extensions/common/mojom/url_pattern_set_mojom_traits.h
@@ -0,0 +1,42 @@ +// Copyright 2021 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 EXTENSIONS_COMMON_MOJOM_URL_PATTERN_SET_MOJOM_TRAITS_H_ +#define EXTENSIONS_COMMON_MOJOM_URL_PATTERN_SET_MOJOM_TRAITS_H_ + +#include "extensions/common/mojom/url_pattern_set.mojom-shared.h" +#include "extensions/common/url_pattern.h" +#include "extensions/common/url_pattern_set.h" +#include "mojo/public/cpp/bindings/struct_traits.h" + +namespace mojo { + +template <> +struct StructTraits<extensions::mojom::URLPatternDataView, URLPattern> { + static int32_t valid_schemes(const URLPattern& pattern) { + return pattern.valid_schemes(); + } + + static const std::string& pattern(const URLPattern& pattern) { + return pattern.GetAsString(); + } + + static bool Read(extensions::mojom::URLPatternDataView data, URLPattern* out); +}; + +template <> +struct StructTraits<extensions::mojom::URLPatternSetDataView, + extensions::URLPatternSet> { + static const std::set<URLPattern>& patterns( + const extensions::URLPatternSet& set) { + return set.patterns(); + } + + static bool Read(extensions::mojom::URLPatternSetDataView data, + extensions::URLPatternSet* out); +}; + +} // namespace mojo + +#endif // EXTENSIONS_COMMON_MOJOM_URL_PATTERN_SET_MOJOM_TRAITS_H_
diff --git a/extensions/common/mojom/url_pattern_set_mojom_traits_unittest.cc b/extensions/common/mojom/url_pattern_set_mojom_traits_unittest.cc new file mode 100644 index 0000000..736c0e0 --- /dev/null +++ b/extensions/common/mojom/url_pattern_set_mojom_traits_unittest.cc
@@ -0,0 +1,64 @@ +// Copyright 2021 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 "extensions/common/mojom/url_pattern_set_mojom_traits.h" + +#include "extensions/common/mojom/url_pattern_set.mojom.h" +#include "extensions/common/url_pattern.h" +#include "extensions/common/url_pattern_set.h" +#include "mojo/public/cpp/test_support/test_utils.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using mojo::test::SerializeAndDeserialize; + +TEST(URLPatternSetMojomTraitsTest, BasicURLPattern) { + URLPattern input(URLPattern::SCHEME_HTTP); + EXPECT_EQ(URLPattern::ParseResult::kSuccess, + input.Parse("http://*.foo:1234/bar")) + << "Got unexpected error in the URLPattern parsing"; + + URLPattern output; + EXPECT_TRUE( + SerializeAndDeserialize<extensions::mojom::URLPattern>(input, output)); + EXPECT_EQ(input, output); + EXPECT_EQ(input.valid_schemes(), output.valid_schemes()); + EXPECT_EQ(input.scheme(), output.scheme()); + EXPECT_EQ(input.host(), output.host()); + EXPECT_EQ(input.port(), output.port()); + EXPECT_EQ(input.path(), output.path()); + EXPECT_EQ(input.match_all_urls(), output.match_all_urls()); + EXPECT_EQ(input.match_subdomains(), output.match_subdomains()); + EXPECT_EQ(input.GetAsString(), output.GetAsString()); +} + +TEST(URLPatternSetMojomTraitsTest, EmptyURLPatternSet) { + extensions::URLPatternSet input; + extensions::URLPatternSet output; + + EXPECT_TRUE( + SerializeAndDeserialize<extensions::mojom::URLPatternSet>(input, output)); + EXPECT_TRUE(output.is_empty()); +} + +TEST(URLPatternSetMojomTraitsTest, BasicURLPatternSet) { + URLPattern pattern1(URLPattern::SCHEME_ALL); + EXPECT_EQ(URLPattern::ParseResult::kSuccess, + pattern1.Parse("http://*.foo:1234/bar")) + << "Got unexpected error in the URLPattern parsing"; + + URLPattern pattern2(URLPattern::SCHEME_HTTPS); + EXPECT_EQ(URLPattern::ParseResult::kSuccess, + pattern2.Parse("https://www.google.com/foobar")) + << "Got unexpected error in the URLPattern parsing"; + + extensions::URLPatternSet input; + input.AddPattern(pattern1); + input.AddPattern(pattern2); + + extensions::URLPatternSet output; + EXPECT_TRUE( + SerializeAndDeserialize<extensions::mojom::URLPatternSet>(input, output)); + EXPECT_THAT(output.patterns(), testing::ElementsAre(pattern1, pattern2)); +}
diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc index c5fd996..6ee205f4b 100644 --- a/extensions/renderer/dispatcher.cc +++ b/extensions/renderer/dispatcher.cc
@@ -878,8 +878,6 @@ IPC_MESSAGE_HANDLER(ExtensionMsg_Suspend, OnSuspend) IPC_MESSAGE_HANDLER(ExtensionMsg_TransferBlobs, OnTransferBlobs) IPC_MESSAGE_HANDLER(ExtensionMsg_UpdatePermissions, OnUpdatePermissions) - IPC_MESSAGE_HANDLER(ExtensionMsg_UpdateDefaultPolicyHostRestrictions, - OnUpdateDefaultPolicyHostRestrictions) IPC_MESSAGE_HANDLER(ExtensionMsg_UpdateTabSpecificPermissions, OnUpdateTabSpecificPermissions) IPC_MESSAGE_HANDLER(ExtensionMsg_ClearTabSpecificPermissions, @@ -1021,6 +1019,25 @@ ExtensionsClient::Get()->SetScriptingAllowlist(extension_ids); } +void Dispatcher::UpdateDefaultPolicyHostRestrictions( + const URLPatternSet& default_policy_blocked_hosts, + const URLPatternSet& default_policy_allowed_hosts) { + PermissionsData::SetDefaultPolicyHostRestrictions( + kRendererProfileId, default_policy_blocked_hosts, + default_policy_allowed_hosts); + // Update blink host permission allowlist exceptions for all loaded + // extensions. + for (const std::string& extension_id : + RendererExtensionRegistry::Get()->GetIDs()) { + const Extension* extension = + RendererExtensionRegistry::Get()->GetByID(extension_id); + if (extension->permissions_data()->UsesDefaultPolicyHostRestrictions()) { + UpdateOriginPermissions(*extension); + } + } + UpdateAllBindings(); +} + void Dispatcher::OnCancelSuspend(const std::string& extension_id) { DispatchEvent(extension_id, kOnSuspendCanceledEvent, base::ListValue(), nullptr); @@ -1207,24 +1224,6 @@ RenderThread::Get()->Send(new ExtensionHostMsg_TransferBlobsAck(blob_uuids)); } -void Dispatcher::OnUpdateDefaultPolicyHostRestrictions( - const ExtensionMsg_UpdateDefaultPolicyHostRestrictions_Params& params) { - PermissionsData::SetDefaultPolicyHostRestrictions( - kRendererProfileId, params.default_policy_blocked_hosts, - params.default_policy_allowed_hosts); - // Update blink host permission allowlist exceptions for all loaded - // extensions. - for (const std::string& extension_id : - RendererExtensionRegistry::Get()->GetIDs()) { - const Extension* extension = - RendererExtensionRegistry::Get()->GetByID(extension_id); - if (extension->permissions_data()->UsesDefaultPolicyHostRestrictions()) { - UpdateOriginPermissions(*extension); - } - } - UpdateAllBindings(); -} - void Dispatcher::OnUpdatePermissions( const ExtensionMsg_UpdatePermissions_Params& params) { const Extension* extension =
diff --git a/extensions/renderer/dispatcher.h b/extensions/renderer/dispatcher.h index 4bb93df..d29ab233 100644 --- a/extensions/renderer/dispatcher.h +++ b/extensions/renderer/dispatcher.h
@@ -43,7 +43,6 @@ struct ExtensionMsg_Loaded_Params; struct ExtensionMsg_TabConnectionInfo; struct ExtensionMsg_UpdatePermissions_Params; -struct ExtensionMsg_UpdateDefaultPolicyHostRestrictions_Params; namespace blink { class WebLocalFrame; @@ -225,6 +224,10 @@ void SetWebViewPartitionID(const std::string& partition_id) override; void SetScriptingAllowlist( const std::vector<std::string>& extension_ids) override; + void UpdateDefaultPolicyHostRestrictions( + const extensions::URLPatternSet& default_policy_blocked_hosts, + const extensions::URLPatternSet& default_policy_allowed_hosts) override; + void OnRendererAssociatedRequest( mojo::PendingAssociatedReceiver<mojom::Renderer> receiver); void OnCancelSuspend(const std::string& extension_id); @@ -251,8 +254,6 @@ void OnSuspend(const std::string& extension_id); void OnTransferBlobs(const std::vector<std::string>& blob_uuids); void OnUpdatePermissions(const ExtensionMsg_UpdatePermissions_Params& params); - void OnUpdateDefaultPolicyHostRestrictions( - const ExtensionMsg_UpdateDefaultPolicyHostRestrictions_Params& params); void OnUpdateTabSpecificPermissions(const GURL& visible_url, const std::string& extension_id, const URLPatternSet& new_hosts,
diff --git a/extensions/renderer/script_injection.cc b/extensions/renderer/script_injection.cc index 69c5b18..faeec88 100644 --- a/extensions/renderer/script_injection.cc +++ b/extensions/renderer/script_injection.cc
@@ -390,10 +390,10 @@ blink::WebDocument::CSSOrigin blink_css_origin = blink::WebDocument::kAuthorOrigin; switch (injector_->GetCssOrigin()) { - case CSS_ORIGIN_USER: + case CSSOrigin::kUser: blink_css_origin = blink::WebDocument::kUserOrigin; break; - case CSS_ORIGIN_AUTHOR: + case CSSOrigin::kAuthor: blink_css_origin = blink::WebDocument::kAuthorOrigin; break; }
diff --git a/extensions/renderer/user_script_injector.cc b/extensions/renderer/user_script_injector.cc index e72761e..6f265a6 100644 --- a/extensions/renderer/user_script_injector.cc +++ b/extensions/renderer/user_script_injector.cc
@@ -141,7 +141,7 @@ } CSSOrigin UserScriptInjector::GetCssOrigin() const { - return CSS_ORIGIN_AUTHOR; + return CSSOrigin::kAuthor; } bool UserScriptInjector::IsRemovingCSS() const {
diff --git a/extensions/shell/browser/shell_extension_system.cc b/extensions/shell/browser/shell_extension_system.cc index 54781bf5..e095c34 100644 --- a/extensions/shell/browser/shell_extension_system.cc +++ b/extensions/shell/browser/shell_extension_system.cc
@@ -95,8 +95,7 @@ return service_worker_manager_.get(); } -ExtensionUserScriptManager* -ShellExtensionSystem::extension_user_script_manager() { +UserScriptManager* ShellExtensionSystem::user_script_manager() { return nullptr; }
diff --git a/extensions/shell/browser/shell_extension_system.h b/extensions/shell/browser/shell_extension_system.h index 459c97d..65037fc 100644 --- a/extensions/shell/browser/shell_extension_system.h +++ b/extensions/shell/browser/shell_extension_system.h
@@ -64,7 +64,7 @@ RuntimeData* runtime_data() override; ManagementPolicy* management_policy() override; ServiceWorkerManager* service_worker_manager() override; - ExtensionUserScriptManager* extension_user_script_manager() override; + UserScriptManager* user_script_manager() override; StateStore* state_store() override; StateStore* rules_store() override; scoped_refptr<ValueStoreFactory> store_factory() override;
diff --git a/fuchsia/engine/browser/web_engine_content_browser_client.cc b/fuchsia/engine/browser/web_engine_content_browser_client.cc index 18f6640..c231812 100644 --- a/fuchsia/engine/browser/web_engine_content_browser_client.cc +++ b/fuchsia/engine/browser/web_engine_content_browser_client.cc
@@ -13,6 +13,7 @@ #include "base/strings/string_split.h" #include "components/policy/content/safe_sites_navigation_throttle.h" #include "components/version_info/version_info.h" +#include "content/public/browser/client_certificate_delegate.h" #include "content/public/browser/devtools_manager_delegate.h" #include "content/public/browser/navigation_handle.h" #include "content/public/browser/network_service_instance.h" @@ -199,6 +200,16 @@ ->GetPreferredLanguages(); } +base::OnceClosure WebEngineContentBrowserClient::SelectClientCertificate( + content::WebContents* web_contents, + net::SSLCertRequestInfo* cert_request_info, + net::ClientCertIdentityList client_certs, + std::unique_ptr<content::ClientCertificateDelegate> delegate) { + // Continue without a certificate. + delegate->ContinueWithCertificate(nullptr, nullptr); + return base::OnceClosure(); +} + std::vector<std::unique_ptr<content::NavigationThrottle>> WebEngineContentBrowserClient::CreateThrottlesForNavigation( content::NavigationHandle* navigation_handle) {
diff --git a/fuchsia/engine/browser/web_engine_content_browser_client.h b/fuchsia/engine/browser/web_engine_content_browser_client.h index 7c571cd..982fe46 100644 --- a/fuchsia/engine/browser/web_engine_content_browser_client.h +++ b/fuchsia/engine/browser/web_engine_content_browser_client.h
@@ -52,6 +52,11 @@ int child_process_id) final; std::string GetApplicationLocale() final; std::string GetAcceptLangs(content::BrowserContext* context) final; + base::OnceClosure SelectClientCertificate( + content::WebContents* web_contents, + net::SSLCertRequestInfo* cert_request_info, + net::ClientCertIdentityList client_certs, + std::unique_ptr<content::ClientCertificateDelegate> delegate) final; std::vector<std::unique_ptr<content::NavigationThrottle>> CreateThrottlesForNavigation( content::NavigationHandle* navigation_handle) final;
diff --git a/infra/config/.style.yapf b/infra/config/.style.yapf new file mode 100644 index 0000000..b4ebbe2 --- /dev/null +++ b/infra/config/.style.yapf
@@ -0,0 +1,6 @@ +[style] +based_on_style = pep8 + +# New directories should use a .style.yapf that does not include the following: +column_limit = 80 +indent_width = 2
diff --git a/infra/config/generated/cr-buildbucket.cfg b/infra/config/generated/cr-buildbucket.cfg index da7736c..9ee8905e 100644 --- a/infra/config/generated/cr-buildbucket.cfg +++ b/infra/config/generated/cr-buildbucket.cfg
@@ -26599,64 +26599,6 @@ } } builders { - name: "mac10.13-updater-tester-dbg" - swarming_host: "chromium-swarm.appspot.com" - swarming_tags: "vpython:native-python-wrapper" - dimensions: "builderless:1" - dimensions: "cores:8" - dimensions: "cpu:x86-64" - dimensions: "os:Ubuntu-16.04" - dimensions: "pool:luci.chromium.ci" - dimensions: "ssd:0" - exe { - cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" - cipd_version: "refs/heads/master" - cmd: "recipes" - } - properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"$recipe_engine/isolated\":{\"server\":\"https://isolateserver.appspot.com\"},\"builder_group\":\"chromium.updater\",\"recipe\":\"chromium\"}" - execution_timeout_secs: 10800 - build_numbers: YES - service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com" - experiments { - key: "chromium.resultdb.result_sink" - value: 100 - } - experiments { - key: "chromium.resultdb.result_sink.gtests_local" - value: 100 - } - experiments { - key: "chromium.resultdb.result_sink.junit_tests" - value: 100 - } - experiments { - key: "luci.use_realms" - value: 100 - } - resultdb { - enable: true - bq_exports { - project: "luci-resultdb" - dataset: "chromium" - table: "ci_test_results" - test_results {} - } - bq_exports { - project: "luci-resultdb" - dataset: "chromium" - table: "gpu_ci_test_results" - test_results { - predicate { - test_id_regexp: "ninja://(chrome/test:|content/test:fuchsia_)telemetry_gpu_integration_test/.+" - } - } - } - history_options { - use_invocation_timestamp: true - } - } - } - builders { name: "mac10.13-updater-tester-rel" swarming_host: "chromium-swarm.appspot.com" swarming_tags: "vpython:native-python-wrapper" @@ -26773,6 +26715,64 @@ } } builders { + name: "mac10.15-updater-tester-dbg" + swarming_host: "chromium-swarm.appspot.com" + swarming_tags: "vpython:native-python-wrapper" + dimensions: "builderless:1" + dimensions: "cores:8" + dimensions: "cpu:x86-64" + dimensions: "os:Ubuntu-16.04" + dimensions: "pool:luci.chromium.ci" + dimensions: "ssd:0" + exe { + cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" + cipd_version: "refs/heads/master" + cmd: "recipes" + } + properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"$recipe_engine/isolated\":{\"server\":\"https://isolateserver.appspot.com\"},\"builder_group\":\"chromium.updater\",\"recipe\":\"chromium\"}" + execution_timeout_secs: 10800 + build_numbers: YES + service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com" + experiments { + key: "chromium.resultdb.result_sink" + value: 100 + } + experiments { + key: "chromium.resultdb.result_sink.gtests_local" + value: 100 + } + experiments { + key: "chromium.resultdb.result_sink.junit_tests" + value: 100 + } + experiments { + key: "luci.use_realms" + value: 100 + } + resultdb { + enable: true + bq_exports { + project: "luci-resultdb" + dataset: "chromium" + table: "ci_test_results" + test_results {} + } + bq_exports { + project: "luci-resultdb" + dataset: "chromium" + table: "gpu_ci_test_results" + test_results { + predicate { + test_id_regexp: "ninja://(chrome/test:|content/test:fuchsia_)telemetry_gpu_integration_test/.+" + } + } + } + history_options { + use_invocation_timestamp: true + } + } + } + builders { name: "mac10.15-updater-tester-rel" swarming_host: "chromium-swarm.appspot.com" swarming_tags: "vpython:native-python-wrapper"
diff --git a/infra/config/generated/luci-milo.cfg b/infra/config/generated/luci-milo.cfg index bb27004..db57b34 100644 --- a/infra/config/generated/luci-milo.cfg +++ b/infra/config/generated/luci-milo.cfg
@@ -9918,9 +9918,9 @@ refs: "regexp:refs/heads/master" manifest_name: "REVISION" builders { - name: "buildbucket/luci.chromium.ci/mac10.13-updater-tester-dbg" + name: "buildbucket/luci.chromium.ci/mac10.15-updater-tester-dbg" category: "debug|mac" - short_name: "10.13" + short_name: "10.15" } builders { name: "buildbucket/luci.chromium.ci/mac-updater-builder-dbg"
diff --git a/infra/config/generated/luci-scheduler.cfg b/infra/config/generated/luci-scheduler.cfg index 563ac39..01e08557 100644 --- a/infra/config/generated/luci-scheduler.cfg +++ b/infra/config/generated/luci-scheduler.cfg
@@ -6066,20 +6066,6 @@ } } job { - id: "mac10.13-updater-tester-dbg" - realm: "ci" - acls { - role: TRIGGERER - granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com" - } - acl_sets: "ci" - buildbucket { - server: "cr-buildbucket.appspot.com" - bucket: "luci.chromium.ci" - builder: "mac10.13-updater-tester-dbg" - } -} -job { id: "mac10.13-updater-tester-rel" realm: "ci" acls { @@ -6108,6 +6094,20 @@ } } job { + id: "mac10.15-updater-tester-dbg" + realm: "ci" + acls { + role: TRIGGERER + granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com" + } + acl_sets: "ci" + buildbucket { + server: "cr-buildbucket.appspot.com" + bucket: "luci.chromium.ci" + builder: "mac10.15-updater-tester-dbg" + } +} +job { id: "mac10.15-updater-tester-rel" realm: "ci" acls {
diff --git a/infra/config/scripts/.vpython3 b/infra/config/scripts/.vpython3 new file mode 100644 index 0000000..76d86bb5 --- /dev/null +++ b/infra/config/scripts/.vpython3
@@ -0,0 +1 @@ +python_version: "3.8" \ No newline at end of file
diff --git a/infra/config/scripts/branch-day.py b/infra/config/scripts/branch-day.py new file mode 100755 index 0000000..8f978703 --- /dev/null +++ b/infra/config/scripts/branch-day.py
@@ -0,0 +1,109 @@ +#!/usr/bin/env vpython +# Copyright 2021 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. +"""Script for performing the branch day tasks. + +This script will make all of the necessary binary invocations to update +input settings files based on flags and then re-generate the +configuration. No output will be produced unless one of the binary +invocations fails. + +Config can be updated on a new branch with: +``` +branch-day.py --on-branch --milestone MM --branch BBBB +``` + +Config on trunk for enabling the new branch can be updated with: +``` +branch-day.py --milestone MM --branch BBBB +``` +""" + +import argparse +import os +import subprocess +import sys + +INFRA_CONFIG_DIR = os.path.abspath(os.path.join(__file__, '..', '..')) + + +def parse_args(args=None, *, parser_type=None): + parser_type = parser_type or argparse.ArgumentParser + parser = parser_type( + description='Update the project settings for a chromium branch') + parser.set_defaults(func=_activate_milestone) + parser.add_argument('--milestones-py', + help='Path to milestones.py script', + default=os.path.join(INFRA_CONFIG_DIR, 'scripts', + 'milestones.py')) + parser.add_argument('--branch-py', + help='Path to branch.py script', + default=os.path.join(INFRA_CONFIG_DIR, 'scripts', + 'branch.py')) + parser.add_argument('--main-star', + help='Path to main.star script', + default=os.path.join(INFRA_CONFIG_DIR, 'main.star')) + parser.add_argument('--dev-star', + help='Path to dev.star script', + default=os.path.join(INFRA_CONFIG_DIR, 'dev.star')) + + parser.add_argument( + '--milestone', + required=True, + help=('The milestone identifier ' + '(e.g. the milestone number for standard release channel)')) + parser.add_argument( + '--branch', + required=True, + help='The branch name, must correspond to a ref in refs/branch-heads') + + parser.add_argument( + '--on-branch', + action='store_const', + dest='func', + const=_initialize_branch, + help='Switches to performing the branch day tasks on the new branch') + + return parser.parse_args(args) + + +def _execute(cmd): + try: + subprocess.run(cmd, + check=True, + text=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + print('Executing {} failed'.format(cmd), file=sys.stderr) + end = '' if e.output[-1] == '\n' else '\n' + print(e.output, file=sys.stderr, end=end) + sys.exit(1) + + +def _activate_milestone(args): + _execute([ + args.milestones_py, 'activate', '--milestone', args.milestone, '--branch', + args.branch + ]) + _execute([args.main_star]) + _execute([args.dev_star]) + + +def _initialize_branch(args): + _execute([ + args.branch_py, 'initialize', '--milestone', args.milestone, '--branch', + args.branch + ]) + _execute([args.main_star]) + _execute([args.dev_star]) + + +def main(): + args = parse_args() + args.func(args) + + +if __name__ == '__main__': + main()
diff --git a/infra/config/scripts/tests/branch_day_unit_test.py b/infra/config/scripts/tests/branch_day_unit_test.py new file mode 100755 index 0000000..bec1a5b --- /dev/null +++ b/infra/config/scripts/tests/branch_day_unit_test.py
@@ -0,0 +1,135 @@ +#!/usr/bin/env vpython +# Copyright 2021 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. +"""Integration test for branch-day.py""" + +import json +import os +import subprocess +import tempfile +import unittest + +INFRA_CONFIG_DIR = os.path.abspath(os.path.join(__file__, '..', '..', '..')) +BRANCH_DAY_PY = os.path.join(INFRA_CONFIG_DIR, 'scripts', 'branch-day.py') +MOCK_PY = os.path.join(INFRA_CONFIG_DIR, 'scripts', 'tests', 'utils', 'mock.py') + + +class BranchDayUnitTest(unittest.TestCase): + def setUp(self): + self._temp_dir = tempfile.TemporaryDirectory() + self._invocations_file = os.path.join(self._temp_dir.name, + 'invocations.json') + self._milestones_py = os.path.join(self._temp_dir.name, 'milestones.py') + self._branch_py = os.path.join(self._temp_dir.name, 'branch.py') + self._main_star = os.path.join(self._temp_dir.name, 'main.star') + self._dev_star = os.path.join(self._temp_dir.name, 'dev.star') + + self._binaries = (self._milestones_py, self._branch_py, self._main_star, + self._dev_star) + + for path in self._binaries: + os.symlink(MOCK_PY, path) + + def tearDown(self): + self._temp_dir.cleanup() + + def _execute_branch_day_py(self, args, mock_details=None): + def details(binary, stdout=None, stderr=None, exit_code=None): + binary = os.path.basename(binary) + d = { + 'stdout': stdout or 'fake {} stdout'.format(binary), + 'stderr': stderr or 'fake {} stderr'.format(binary), + } + if exit_code: + d['exit_code'] = exit_code + return d + + mock_details = mock_details or {} + mock_details = { + b: details(b, **mock_details.get(b, {})) + for b in self._binaries + } + + env = { + 'INVOCATIONS_FILE': self._invocations_file, + 'MOCK_DETAILS': json.dumps(mock_details), + } + + cmd = [ + BRANCH_DAY_PY, '--milestones-py', self._milestones_py, '--branch-py', + self._branch_py, '--main-star', self._main_star, '--dev-star', + self._dev_star + ] + cmd += args or [] + return subprocess.run(cmd, + env=env, + text=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + + def test_branch_day_invocation_fails(self): + result = self._execute_branch_day_py( + ['--milestone', 'XX', '--branch', 'YYYY'], + mock_details={ + self._milestones_py: { + 'stdout': 'FAKE FAILURE STDOUT', + 'stderr': 'FAKE FAILURE STDERR', + 'exit_code': 1, + } + }) + self.assertNotEqual(result.returncode, 0) + expected_output = '\n'.join([ + 'Executing {} failed'.format([ + self._milestones_py, 'activate', '--milestone', 'XX', '--branch', + 'YYYY' + ]), + 'FAKE FAILURE STDOUT', + 'FAKE FAILURE STDERR', + '', + ]) + self.assertEqual(result.stdout, expected_output) + + def test_branch_day(self): + result = self._execute_branch_day_py( + ['--milestone', 'XX', '--branch', 'YYYY']) + self.assertEqual(result.returncode, 0, + (f'subprocess failed\n***COMMAND***\n{result.args}\n' + f'***OUTPUT***\n{result.stdout}\n')) + self.assertEqual(result.stdout, '') + + with open(self._invocations_file) as f: + invocations = json.load(f) + expected_invocations = [ + [ + self._milestones_py, 'activate', '--milestone', 'XX', '--branch', + 'YYYY' + ], + [self._main_star], + [self._dev_star], + ] + self.assertEqual(invocations, expected_invocations) + + def test_branch_day_on_branch(self): + result = self._execute_branch_day_py( + ['--on-branch', '--milestone', 'XX', '--branch', 'YYYY']) + self.assertEqual(result.returncode, 0, + (f'subprocess failed\n***COMMAND***\n{result.args}\n' + f'***OUTPUT***\n{result.stdout}\n')) + self.assertEqual(result.stdout, '') + + with open(self._invocations_file) as f: + invocations = json.load(f) + expected_invocations = [ + [ + self._branch_py, 'initialize', '--milestone', 'XX', '--branch', + 'YYYY' + ], + [self._main_star], + [self._dev_star], + ] + self.assertEqual(invocations, expected_invocations) + + +if __name__ == '__main__': + unittest.main()
diff --git a/infra/config/scripts/tests/utils/mock.py b/infra/config/scripts/tests/utils/mock.py new file mode 100755 index 0000000..67533bf3 --- /dev/null +++ b/infra/config/scripts/tests/utils/mock.py
@@ -0,0 +1,61 @@ +#!/usr/bin/env vpython +# Copyright 2021 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. +"""A binary to enable mocking of binaries. + +This enables writing tests to verify that a binary was invoked as well +as controlling the output and exit code of the binary. Tests should +copy or link to this binary so that invocations for different binaries +can be distinguished. + +INVOCATIONS_FILE must be set to the location of the file to record +invocations to. The format of the recorded invocations file will be a +json list where each element is the sys.argv for the invocation. After +running the code under test, the test can load the contents of the file +and verify that the expected invocations occurred. + +Tests can control the output, error output and exit codes of the +invocations via the environment variable MOCK_DETAILS. If set, +MOCK_DETAILS must be a string containing a json-encoding mapping from +the binary path used for the invocation to a mapping containing any or +all of the following entries: +* stdout -> string containing the program's stdout +* stderr -> string containing the program's stderr +* exit_code -> integer containing the program's exit code +If both 'stdout' and 'stderr' are present in the mapping for a binary +path, the stdout will be output first, no interleaving is supported. +""" + +import json +import os +import sys + +invocations_file = os.environ['INVOCATIONS_FILE'] + +if not os.path.exists(invocations_file): + invocations = [] +else: + with open(invocations_file) as f: + invocations = json.load(f) + +invocations.append(sys.argv) + +with open(invocations_file, 'w') as f: + json.dump(invocations, f) + +mock_details = json.loads(os.environ.get('MOCK_DETAILS', '{}')) +mock_details = mock_details.get(sys.argv[0], {}) + +mock_stdout = mock_details.get('stdout') +if mock_stdout is not None: + print(mock_stdout) + sys.stdout.flush() + +mock_stderr = mock_details.get('stderr') +if mock_stderr is not None: + print(mock_stderr, file=sys.stderr) + +mock_exit_code = mock_details.get('exit_code') +if mock_exit_code is not None: + sys.exit(mock_exit_code)
diff --git a/infra/config/subprojects/chromium/ci.star b/infra/config/subprojects/chromium/ci.star index 9a9f78f..49ef2fc 100644 --- a/infra/config/subprojects/chromium/ci.star +++ b/infra/config/subprojects/chromium/ci.star
@@ -3163,15 +3163,6 @@ ) ci.updater_builder( - name = "mac10.13-updater-tester-dbg", - console_view_entry = consoles.console_view_entry( - category = "debug|mac", - short_name = "10.13", - ), - triggered_by = ["mac-updater-builder-dbg"], -) - -ci.updater_builder( name = "mac10.13-updater-tester-rel", console_view_entry = consoles.console_view_entry( category = "release|mac", @@ -3190,6 +3181,15 @@ ) ci.updater_builder( + name = "mac10.15-updater-tester-dbg", + console_view_entry = consoles.console_view_entry( + category = "debug|mac", + short_name = "10.15", + ), + triggered_by = ["mac-updater-builder-dbg"], +) + +ci.updater_builder( name = "mac10.15-updater-tester-rel", console_view_entry = consoles.console_view_entry( category = "release|mac",
diff --git a/ios/chrome/app/strings/ios_chromium_strings.grd b/ios/chrome/app/strings/ios_chromium_strings.grd index c109071..af01519 100644 --- a/ios/chrome/app/strings/ios_chromium_strings.grd +++ b/ios/chrome/app/strings/ios_chromium_strings.grd
@@ -203,7 +203,7 @@ By signing out, your bookmarks, history, passwords, and other Chromium data will no longer be synced to your Google Account. </message> <message name="IDS_IOS_ENTERPRISE_SIGNED_OUT_SUBTEXT" desc="Text displayed in an alert when the user is signed out due to browser sign-in becoming disabled by policy. [iOS only]"> - When you were signed out of Chromium, your bookmarks, history, passwords and other settings were cleared from this device. Your synced data is still saved to your account. + You can still see all your bookmarks, history, passwords and other settings on this device. If you make changes, they won't sync to your account. </message> <message name="IDS_IOS_FACE_ID_USAGE_DESCRIPTION" desc="Specifies the reason for using the device's Face ID capabilities."> Chromium uses Face ID to ensure authorized access to your passwords.
diff --git a/ios/chrome/app/strings/ios_chromium_strings_grd/IDS_IOS_ENTERPRISE_SIGNED_OUT_SUBTEXT.png.sha1 b/ios/chrome/app/strings/ios_chromium_strings_grd/IDS_IOS_ENTERPRISE_SIGNED_OUT_SUBTEXT.png.sha1 index ea97b449..1d58d9e 100644 --- a/ios/chrome/app/strings/ios_chromium_strings_grd/IDS_IOS_ENTERPRISE_SIGNED_OUT_SUBTEXT.png.sha1 +++ b/ios/chrome/app/strings/ios_chromium_strings_grd/IDS_IOS_ENTERPRISE_SIGNED_OUT_SUBTEXT.png.sha1
@@ -1 +1 @@ -b517c3c1d8a71738d33a08627b2fbd2426e59af8 \ No newline at end of file +f90c18ced0e18d66622f7feccebf974041476b3c \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_google_chrome_strings.grd b/ios/chrome/app/strings/ios_google_chrome_strings.grd index 9b6562a..91edde4 100644 --- a/ios/chrome/app/strings/ios_google_chrome_strings.grd +++ b/ios/chrome/app/strings/ios_google_chrome_strings.grd
@@ -203,7 +203,7 @@ By signing out, your bookmarks, history, passwords, and other Chrome data will no longer be synced to your Google Account. </message> <message name="IDS_IOS_ENTERPRISE_SIGNED_OUT_SUBTEXT" desc="Text displayed in an alert when the user is signed out due to browser sign-in becoming disabled by policy. [iOS only]"> - When you were signed out of Chrome, your bookmarks, history, passwords and other settings were cleared from this device. Your synced Chrome data is still saved to your Google account. + You can still see all your bookmarks, history, passwords and other settings on this device. If you make changes, they won't sync to your Google Account. </message> <message name="IDS_IOS_FACE_ID_USAGE_DESCRIPTION" desc="Specifies the reason for using the device's Face ID capabilities."> Chrome uses Face ID to ensure authorized access to your passwords.
diff --git a/ios/chrome/app/strings/ios_google_chrome_strings_grd/IDS_IOS_ENTERPRISE_SIGNED_OUT_SUBTEXT.png.sha1 b/ios/chrome/app/strings/ios_google_chrome_strings_grd/IDS_IOS_ENTERPRISE_SIGNED_OUT_SUBTEXT.png.sha1 index ea97b449..1d58d9e 100644 --- a/ios/chrome/app/strings/ios_google_chrome_strings_grd/IDS_IOS_ENTERPRISE_SIGNED_OUT_SUBTEXT.png.sha1 +++ b/ios/chrome/app/strings/ios_google_chrome_strings_grd/IDS_IOS_ENTERPRISE_SIGNED_OUT_SUBTEXT.png.sha1
@@ -1 +1 @@ -b517c3c1d8a71738d33a08627b2fbd2426e59af8 \ No newline at end of file +f90c18ced0e18d66622f7feccebf974041476b3c \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd index d420cd4..7585e89 100644 --- a/ios/chrome/app/strings/ios_strings.grd +++ b/ios/chrome/app/strings/ios_strings.grd
@@ -1731,7 +1731,7 @@ This setting is enforced by your administrator. </message> <message name="IDS_IOS_ENTERPRISE_SIGNED_OUT" desc="Text displayed in an alert when the user is signed out due to browser sign-in becoming disabled by policy. [iOS only]"> - Your organization signed you out. + Your organization signed you out </message> <message name="IDS_IOS_ENTERPRISE_SIGNED_OUT_CONTINUE" desc="The text in the 'Continue' button, displayed in an alert when the user is signed out due to browser sign-in becoming disabled by policy."> Continue
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_ENTERPRISE_SIGNED_OUT.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_ENTERPRISE_SIGNED_OUT.png.sha1 index 9e0041cd..1d58d9e 100644 --- a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_ENTERPRISE_SIGNED_OUT.png.sha1 +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_ENTERPRISE_SIGNED_OUT.png.sha1
@@ -1 +1 @@ -4391757d30991da8417e34f2763497e2b8df0798 \ No newline at end of file +f90c18ced0e18d66622f7feccebf974041476b3c \ No newline at end of file
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm index 5275545..b4aaa7c 100644 --- a/ios/chrome/browser/flags/about_flags.mm +++ b/ios/chrome/browser/flags/about_flags.mm
@@ -224,6 +224,16 @@ {"Native UI", kDiscoverFeedInNtpEnableNativeUI, base::size(kDiscoverFeedInNtpEnableNativeUI), nullptr}}; +const FeatureEntry::FeatureParam kStartSurfaceReturnImmediately[] = { + {kReturnToStartSurfaceInactiveDurationInSeconds, "0"}}; +const FeatureEntry::FeatureParam kStartSurfaceReturnInOneHour[] = { + {kReturnToStartSurfaceInactiveDurationInSeconds, "3600"}}; +const FeatureEntry::FeatureVariation kStartSurfaceVariations[] = { + {"Return immediately", kStartSurfaceReturnImmediately, + base::size(kStartSurfaceReturnImmediately), nullptr}, + {"Return in one hour", kStartSurfaceReturnInOneHour, + base::size(kStartSurfaceReturnInOneHour), nullptr}}; + const FeatureEntry::FeatureParam kWebViewNativeContextMenuWeb[] = { {web::features::kWebViewNativeContextMenuName, web::features::kWebViewNativeContextMenuParameterWeb}}; @@ -610,7 +620,9 @@ FEATURE_VALUE_TYPE(shared_highlighting::kSharedHighlightingUseBlocklist)}, {"start-surface", flag_descriptions::kStartSurfaceName, flag_descriptions::kStartSurfaceDescription, flags_ui::kOsIos, - FEATURE_VALUE_TYPE(kStartSurface)}, + FEATURE_WITH_PARAMS_VALUE_TYPE(kStartSurface, + kStartSurfaceVariations, + "StartSurface")}, {"ios-crashpad", flag_descriptions::kCrashpadIOSName, flag_descriptions::kCrashpadIOSDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(kCrashpadIOS)},
diff --git a/ios/chrome/browser/safe_browsing/chrome_password_protection_service.h b/ios/chrome/browser/safe_browsing/chrome_password_protection_service.h index 8309182..aed8eed 100644 --- a/ios/chrome/browser/safe_browsing/chrome_password_protection_service.h +++ b/ios/chrome/browser/safe_browsing/chrome_password_protection_service.h
@@ -5,6 +5,7 @@ #ifndef IOS_CHROME_BROWSER_SAFE_BROWSING_CHROME_PASSWORD_PROTECTION_SERVICE_H_ #define IOS_CHROME_BROWSER_SAFE_BROWSING_CHROME_PASSWORD_PROTECTION_SERVICE_H_ +#include <string> #include <vector> #include "base/strings/string16.h" @@ -20,38 +21,45 @@ namespace password_manager { class PasswordStore; -} +} // namespace password_manager + +namespace safe_browsing { +class PasswordProtectionRequest; +} // namespace safe_browsing namespace web { class WebState; -} +} // namespace web -namespace safe_browsing { - -class ChromePasswordProtectionService : public PasswordProtectionService, - public KeyedService { +class ChromePasswordProtectionService + : public safe_browsing::PasswordProtectionService, + public KeyedService { public: explicit ChromePasswordProtectionService(ChromeBrowserState* browser_state); ~ChromePasswordProtectionService() override; - void ShowModalWarning(PasswordProtectionRequest* request, - LoginReputationClientResponse::VerdictType verdict_type, - const std::string& verdict_token, - ReusedPasswordAccountType password_type) override; + void ShowModalWarning( + safe_browsing::PasswordProtectionRequest* request, + safe_browsing::LoginReputationClientResponse::VerdictType verdict_type, + const std::string& verdict_token, + safe_browsing::ReusedPasswordAccountType password_type) override; - void MaybeReportPasswordReuseDetected(PasswordProtectionRequest* request, - const std::string& username, - PasswordType password_type, - bool is_phishing_url) override; + void MaybeReportPasswordReuseDetected( + safe_browsing::PasswordProtectionRequest* request, + const std::string& username, + safe_browsing::PasswordType password_type, + bool is_phishing_url) override; void ReportPasswordChanged() override; - void FillReferrerChain(const GURL& event_url, - SessionID event_tab_id, // SessionID::InvalidValue() - // if tab not available. - LoginReputationClientRequest::Frame* frame) override; + void FillReferrerChain( + const GURL& event_url, + SessionID event_tab_id, // SessionID::InvalidValue() + // if tab not available. + safe_browsing::LoginReputationClientRequest::Frame* frame) override; - void SanitizeReferrerChain(ReferrerChain* referrer_chain) override; + void SanitizeReferrerChain( + safe_browsing::ReferrerChain* referrer_chain) override; void PersistPhishedSavedPasswordCredential( const std::vector<password_manager::MatchingReusedCredential>& @@ -61,23 +69,24 @@ const std::vector<password_manager::MatchingReusedCredential>& matching_reused_credentials) override; - RequestOutcome GetPingNotSentReason( - LoginReputationClientRequest::TriggerType trigger_type, + safe_browsing::RequestOutcome GetPingNotSentReason( + safe_browsing::LoginReputationClientRequest::TriggerType trigger_type, const GURL& url, - ReusedPasswordAccountType password_type) override; + safe_browsing::ReusedPasswordAccountType password_type) override; void RemoveUnhandledSyncPasswordReuseOnURLsDeleted( bool all_history, const history::URLRows& deleted_rows) override; bool UserClickedThroughSBInterstitial( - PasswordProtectionRequest* request) override; + safe_browsing::PasswordProtectionRequest* request) override; - PasswordProtectionTrigger GetPasswordProtectionWarningTriggerPref( - ReusedPasswordAccountType password_type) const override; + safe_browsing::PasswordProtectionTrigger + GetPasswordProtectionWarningTriggerPref( + safe_browsing::ReusedPasswordAccountType password_type) const override; - LoginReputationClientRequest::UrlDisplayExperiment GetUrlDisplayExperiment() - const override; + safe_browsing::LoginReputationClientRequest::UrlDisplayExperiment + GetUrlDisplayExperiment() const override; const policy::BrowserPolicyConnector* GetBrowserPolicyConnector() const override; @@ -87,20 +96,24 @@ AccountInfo GetSignedInNonSyncAccount( const std::string& username) const override; - LoginReputationClientRequest::PasswordReuseEvent::SyncAccountType - GetSyncAccountType() const override; + safe_browsing::LoginReputationClientRequest::PasswordReuseEvent:: + SyncAccountType + GetSyncAccountType() const override; - bool CanShowInterstitial(ReusedPasswordAccountType password_type, - const GURL& main_frame_url) override; + bool CanShowInterstitial( + safe_browsing::ReusedPasswordAccountType password_type, + const GURL& main_frame_url) override; bool IsURLAllowlistedForPasswordEntry(const GURL& url) const override; - bool IsInPasswordAlertMode(ReusedPasswordAccountType password_type) override; + bool IsInPasswordAlertMode( + safe_browsing::ReusedPasswordAccountType password_type) override; bool CanSendSamplePing() override; - bool IsPingingEnabled(LoginReputationClientRequest::TriggerType trigger_type, - ReusedPasswordAccountType password_type) override; + bool IsPingingEnabled( + safe_browsing::LoginReputationClientRequest::TriggerType trigger_type, + safe_browsing::ReusedPasswordAccountType password_type) override; bool IsIncognito() override; @@ -125,9 +138,9 @@ // PasswordProtectionService override. void MaybeLogPasswordReuseLookupEvent( web::WebState* web_state, - RequestOutcome outcome, - PasswordType password_type, - const LoginReputationClientResponse* response) override; + safe_browsing::RequestOutcome outcome, + safe_browsing::PasswordType password_type, + const safe_browsing::LoginReputationClientResponse* response) override; // Records a Chrome Sync event that sync password reuse was detected. void MaybeLogPasswordReuseDetectedEvent(web::WebState* web_state); @@ -144,7 +157,7 @@ // placeholders that are passed into the resource string. It is only set for // saved passwords. base::string16 GetWarningDetailText( - ReusedPasswordAccountType password_type, + safe_browsing::ReusedPasswordAccountType password_type, std::vector<size_t>* placeholder_offsets) const; // Gets the warning text for saved password reuse warnings. @@ -165,6 +178,10 @@ std::vector<base::string16> GetPlaceholdersForSavedPasswordWarningText() const; + protected: + FRIEND_TEST_ALL_PREFIXES(ChromePasswordProtectionServiceTest, + VerifySendsPingForAboutBlank); + private: password_manager::PasswordStore* GetStoreForReusedCredential( const password_manager::MatchingReusedCredential& reused_credential); @@ -178,7 +195,7 @@ password_manager::PasswordStore* GetAccountPasswordStore() const; // Gets prefs associated with |browser_state_|. - PrefService* GetPrefs(); + PrefService* GetPrefs() const; // Returns whether |browser_state_| has safe browsing service enabled. bool IsSafeBrowsingEnabled(); @@ -186,6 +203,4 @@ ChromeBrowserState* browser_state_; }; -} // namespace safe_browsing - #endif // IOS_CHROME_BROWSER_SAFE_BROWSING_CHROME_PASSWORD_PROTECTION_SERVICE_H_
diff --git a/ios/chrome/browser/safe_browsing/chrome_password_protection_service.mm b/ios/chrome/browser/safe_browsing/chrome_password_protection_service.mm index 810bfce75..b40af94 100644 --- a/ios/chrome/browser/safe_browsing/chrome_password_protection_service.mm +++ b/ios/chrome/browser/safe_browsing/chrome_password_protection_service.mm
@@ -6,10 +6,12 @@ #include <memory> +#include "base/feature_list.h" #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" #include "components/keyed_service/core/service_access_type.h" #include "components/password_manager/core/browser/password_store.h" +#include "components/prefs/pref_service.h" #include "components/safe_browsing/core/common/safe_browsing_prefs.h" #include "components/safe_browsing/core/features.h" #include "components/strings/grit/components_strings.h" @@ -23,23 +25,29 @@ #include "ios/web/public/thread/web_thread.h" #import "ios/web/public/web_state.h" #include "ui/base/l10n/l10n_util.h" +#include "url/gurl.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." #endif -using sync_pb::GaiaPasswordReuse; +using password_manager::metrics_util::PasswordType; +using safe_browsing::LoginReputationClientRequest; +using safe_browsing::LoginReputationClientResponse; +using safe_browsing::PasswordProtectionTrigger; +using safe_browsing::RequestOutcome; +using safe_browsing::ReusedPasswordAccountType; using sync_pb::UserEventSpecifics; -using InteractionResult = - GaiaPasswordReuse::PasswordReuseDialogInteraction::InteractionResult; +using safe_browsing::ReferrerChain; + +using InteractionResult = sync_pb::GaiaPasswordReuse:: + PasswordReuseDialogInteraction::InteractionResult; using PasswordReuseDialogInteraction = - GaiaPasswordReuse::PasswordReuseDialogInteraction; + sync_pb::GaiaPasswordReuse::PasswordReuseDialogInteraction; using PasswordReuseEvent = safe_browsing::LoginReputationClientRequest::PasswordReuseEvent; using SafeBrowsingStatus = - GaiaPasswordReuse::PasswordReuseDetected::SafeBrowsingStatus; - -namespace safe_browsing { + sync_pb::GaiaPasswordReuse::PasswordReuseDetected::SafeBrowsingStatus; namespace { @@ -86,13 +94,13 @@ ChromePasswordProtectionService::ChromePasswordProtectionService( ChromeBrowserState* browser_state) - : PasswordProtectionService(nullptr, nullptr, nullptr), + : safe_browsing::PasswordProtectionService(nullptr, nullptr, nullptr), browser_state_(browser_state) {} ChromePasswordProtectionService::~ChromePasswordProtectionService() = default; void ChromePasswordProtectionService::ShowModalWarning( - PasswordProtectionRequest* request, + safe_browsing::PasswordProtectionRequest* request, LoginReputationClientResponse::VerdictType verdict_type, const std::string& verdict_token, ReusedPasswordAccountType password_type) { @@ -100,7 +108,7 @@ } void ChromePasswordProtectionService::MaybeReportPasswordReuseDetected( - PasswordProtectionRequest* request, + safe_browsing::PasswordProtectionRequest* request, const std::string& username, PasswordType password_type, bool is_phishing_url) { @@ -168,7 +176,36 @@ LoginReputationClientRequest::TriggerType trigger_type, const GURL& url, ReusedPasswordAccountType password_type) { - // TODO(crbug.com/1147967): Complete PhishGuard iOS implementation. + DCHECK(!CanSendPing(trigger_type, url, password_type)); + if (IsInExcludedCountry()) { + return RequestOutcome::EXCLUDED_COUNTRY; + } + if (!IsSafeBrowsingEnabled()) { + return RequestOutcome::SAFE_BROWSING_DISABLED; + } + if (IsIncognito()) { + return RequestOutcome::DISABLED_DUE_TO_INCOGNITO; + } + if (trigger_type == LoginReputationClientRequest::PASSWORD_REUSE_EVENT && + password_type.account_type() != + ReusedPasswordAccountType::SAVED_PASSWORD && + GetPasswordProtectionWarningTriggerPref(password_type) == + safe_browsing::PASSWORD_PROTECTION_OFF) { + return RequestOutcome::TURNED_OFF_BY_ADMIN; + } + PrefService* prefs = browser_state_->GetPrefs(); + if (safe_browsing::IsURLAllowlistedByPolicy(url, *prefs)) { + return RequestOutcome::MATCHED_ENTERPRISE_ALLOWLIST; + } + if (safe_browsing::MatchesPasswordProtectionChangePasswordURL(url, *prefs)) { + return RequestOutcome::MATCHED_ENTERPRISE_CHANGE_PASSWORD_URL; + } + if (safe_browsing::MatchesPasswordProtectionLoginURL(url, *prefs)) { + return RequestOutcome::MATCHED_ENTERPRISE_LOGIN_URL; + } + if (IsInPasswordAlertMode(password_type)) { + return RequestOutcome::PASSWORD_ALERT_MODE; + } return RequestOutcome::DISABLED_DUE_TO_USER_POPULATION; } @@ -180,7 +217,7 @@ } bool ChromePasswordProtectionService::UserClickedThroughSBInterstitial( - PasswordProtectionRequest* request) { + safe_browsing::PasswordProtectionRequest* request) { // TODO(crbug.com/1147967): Complete PhishGuard iOS implementation. return false; } @@ -188,8 +225,18 @@ PasswordProtectionTrigger ChromePasswordProtectionService::GetPasswordProtectionWarningTriggerPref( ReusedPasswordAccountType password_type) const { - // TODO(crbug.com/1147967): Complete PhishGuard iOS implementation. - return PHISHING_REUSE; + if (password_type.account_type() == + ReusedPasswordAccountType::SAVED_PASSWORD && + base::FeatureList::IsEnabled( + safe_browsing::kPasswordProtectionForSavedPasswords)) + return safe_browsing::PHISHING_REUSE; + + bool is_policy_managed = + GetPrefs()->HasPrefPath(prefs::kPasswordProtectionWarningTrigger); + PasswordProtectionTrigger trigger_level = + static_cast<PasswordProtectionTrigger>( + GetPrefs()->GetInteger(prefs::kPasswordProtectionWarningTrigger)); + return is_policy_managed ? trigger_level : safe_browsing::PHISHING_REUSE; } LoginReputationClientRequest::UrlDisplayExperiment @@ -235,15 +282,16 @@ return false; PrefService* prefs = browser_state_->GetPrefs(); - return IsURLAllowlistedByPolicy(url, *prefs) || - MatchesPasswordProtectionChangePasswordURL(url, *prefs) || - MatchesPasswordProtectionLoginURL(url, *prefs); + return safe_browsing::IsURLAllowlistedByPolicy(url, *prefs) || + safe_browsing::MatchesPasswordProtectionChangePasswordURL(url, + *prefs) || + safe_browsing::MatchesPasswordProtectionLoginURL(url, *prefs); } bool ChromePasswordProtectionService::IsInPasswordAlertMode( ReusedPasswordAccountType password_type) { - // TODO(crbug.com/1147967): Complete PhishGuard iOS implementation. - return false; + return GetPasswordProtectionWarningTriggerPref(password_type) == + safe_browsing::PASSWORD_REUSE; } bool ChromePasswordProtectionService::CanSendSamplePing() { @@ -501,7 +549,7 @@ return nullptr; } -PrefService* ChromePasswordProtectionService::GetPrefs() { +PrefService* ChromePasswordProtectionService::GetPrefs() const { return browser_state_->GetPrefs(); } @@ -509,4 +557,3 @@ return ::safe_browsing::IsSafeBrowsingEnabled(*GetPrefs()); } -} // namespace safe_browsing
diff --git a/ios/chrome/browser/safe_browsing/chrome_password_protection_service_factory.h b/ios/chrome/browser/safe_browsing/chrome_password_protection_service_factory.h index 3f6a752..0d094aa 100644 --- a/ios/chrome/browser/safe_browsing/chrome_password_protection_service_factory.h +++ b/ios/chrome/browser/safe_browsing/chrome_password_protection_service_factory.h
@@ -10,11 +10,8 @@ #include "base/no_destructor.h" #include "components/keyed_service/ios/browser_state_keyed_service_factory.h" -class KeyedService; - -namespace safe_browsing { class ChromePasswordProtectionService; -} +class KeyedService; namespace web { class BrowserState; @@ -27,7 +24,7 @@ public: // Returns the instance of ChromePasswordProtectionService associated with // this browser state, creating one if none exists. - static safe_browsing::ChromePasswordProtectionService* GetForBrowserState( + static ChromePasswordProtectionService* GetForBrowserState( web::BrowserState* browser_state); // Returns the singleton instance of ChromePasswordProtectionServiceFactory.
diff --git a/ios/chrome/browser/safe_browsing/chrome_password_protection_service_factory.mm b/ios/chrome/browser/safe_browsing/chrome_password_protection_service_factory.mm index c348c3d..7584a03 100644 --- a/ios/chrome/browser/safe_browsing/chrome_password_protection_service_factory.mm +++ b/ios/chrome/browser/safe_browsing/chrome_password_protection_service_factory.mm
@@ -16,10 +16,10 @@ #endif // static -safe_browsing::ChromePasswordProtectionService* +ChromePasswordProtectionService* ChromePasswordProtectionServiceFactory::GetForBrowserState( web::BrowserState* browser_state) { - return static_cast<safe_browsing::ChromePasswordProtectionService*>( + return static_cast<ChromePasswordProtectionService*>( GetInstance()->GetServiceForBrowserState(browser_state, /*create=*/true)); } @@ -43,7 +43,7 @@ web::BrowserState* browser_state) const { ChromeBrowserState* chrome_browser_state = ChromeBrowserState::FromBrowserState(browser_state); - return std::make_unique<safe_browsing::ChromePasswordProtectionService>( + return std::make_unique<ChromePasswordProtectionService>( chrome_browser_state); }
diff --git a/ios/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.mm b/ios/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.mm index 8dbf91d..0a49c49 100644 --- a/ios/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.mm +++ b/ios/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.mm
@@ -44,13 +44,14 @@ using ::testing::_; using password_manager::metrics_util::PasswordType; using password_manager::MockPasswordStore; +using safe_browsing::LoginReputationClientRequest; +using safe_browsing::PasswordProtectionTrigger; +using safe_browsing::RequestOutcome; +using safe_browsing::ReusedPasswordAccountType; using sync_pb::GaiaPasswordReuse; -using sync_pb::UserEventSpecifics; using PasswordReuseDialogInteraction = - GaiaPasswordReuse::PasswordReuseDialogInteraction; -using PasswordReuseLookup = GaiaPasswordReuse::PasswordReuseLookup; - -namespace safe_browsing { + sync_pb::GaiaPasswordReuse::PasswordReuseDialogInteraction; +using PasswordReuseLookup = sync_pb::GaiaPasswordReuse::PasswordReuseLookup; namespace { @@ -221,7 +222,7 @@ service_->SetIsNoHostedDomainFound(true); EXPECT_FALSE(service_->IsPingingEnabled(trigger_type, reused_password_type)); chrome_browser_state_->GetPrefs()->SetInteger( - prefs::kPasswordProtectionWarningTrigger, PASSWORD_REUSE); + prefs::kPasswordProtectionWarningTrigger, safe_browsing::PASSWORD_REUSE); EXPECT_FALSE(service_->IsPingingEnabled(trigger_type, reused_password_type)); } @@ -284,12 +285,13 @@ EXPECT_FALSE(service_->IsPingingEnabled(trigger_type, reused_password_type)); chrome_browser_state_->GetPrefs()->SetInteger( - prefs::kPasswordProtectionWarningTrigger, PASSWORD_PROTECTION_OFF); + prefs::kPasswordProtectionWarningTrigger, + safe_browsing::PASSWORD_PROTECTION_OFF); service_->SetIsIncognito(false); EXPECT_FALSE(service_->IsPingingEnabled(trigger_type, reused_password_type)); chrome_browser_state_->GetPrefs()->SetInteger( - prefs::kPasswordProtectionWarningTrigger, PASSWORD_REUSE); + prefs::kPasswordProtectionWarningTrigger, safe_browsing::PASSWORD_REUSE); EXPECT_FALSE(service_->IsPingingEnabled(trigger_type, reused_password_type)); } @@ -502,4 +504,82 @@ service_->GetPlaceholdersForSavedPasswordWarningText()); } -} // namespace safe_browsing +TEST_F(ChromePasswordProtectionServiceTest, VerifySendsPingForAboutBlank) { + ReusedPasswordAccountType reused_password_type; + reused_password_type.set_account_type( + ReusedPasswordAccountType::SAVED_PASSWORD); + service_->SetIsIncognito(false); + EXPECT_TRUE( + service_->CanSendPing(LoginReputationClientRequest::PASSWORD_REUSE_EVENT, + GURL("about:blank"), reused_password_type)); +} + +TEST_F(ChromePasswordProtectionServiceTest, VerifyGetPingNotSentReason) { + { + // SBER disabled. + ReusedPasswordAccountType reused_password_type; + service_->SetIsIncognito(false); + EXPECT_EQ(RequestOutcome::DISABLED_DUE_TO_USER_POPULATION, + service_->GetPingNotSentReason( + LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE, + GURL("about:blank"), reused_password_type)); + reused_password_type.set_account_type(ReusedPasswordAccountType::UNKNOWN); + EXPECT_EQ(RequestOutcome::DISABLED_DUE_TO_USER_POPULATION, + service_->GetPingNotSentReason( + LoginReputationClientRequest::PASSWORD_REUSE_EVENT, + GURL("about:blank"), reused_password_type)); + } + { + // In Incognito. + ReusedPasswordAccountType reused_password_type; + service_->SetIsIncognito(true); + EXPECT_EQ(RequestOutcome::DISABLED_DUE_TO_INCOGNITO, + service_->GetPingNotSentReason( + LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE, + GURL("about:blank"), reused_password_type)); + } + { + // Turned off by admin. + ReusedPasswordAccountType reused_password_type; + service_->SetIsIncognito(false); + reused_password_type.set_account_type(ReusedPasswordAccountType::GSUITE); + chrome_browser_state_->GetPrefs()->SetInteger( + prefs::kPasswordProtectionWarningTrigger, + safe_browsing::PASSWORD_PROTECTION_OFF); + EXPECT_EQ(RequestOutcome::TURNED_OFF_BY_ADMIN, + service_->GetPingNotSentReason( + LoginReputationClientRequest::PASSWORD_REUSE_EVENT, + GURL("about:blank"), reused_password_type)); + } + { + // Allowlisted by policy. + ReusedPasswordAccountType reused_password_type; + service_->SetIsIncognito(false); + reused_password_type.set_account_type(ReusedPasswordAccountType::GSUITE); + chrome_browser_state_->GetPrefs()->SetInteger( + prefs::kPasswordProtectionWarningTrigger, + safe_browsing::PHISHING_REUSE); + base::ListValue allowlist; + allowlist.AppendString("mydomain.com"); + allowlist.AppendString("mydomain.net"); + chrome_browser_state_->GetPrefs()->Set(prefs::kSafeBrowsingAllowlistDomains, + allowlist); + EXPECT_EQ(RequestOutcome::MATCHED_ENTERPRISE_ALLOWLIST, + service_->GetPingNotSentReason( + LoginReputationClientRequest::PASSWORD_REUSE_EVENT, + GURL("https://www.mydomain.com"), reused_password_type)); + } + { + // Password alert mode. + ReusedPasswordAccountType reused_password_type; + service_->SetIsIncognito(false); + reused_password_type.set_account_type(ReusedPasswordAccountType::UNKNOWN); + chrome_browser_state_->GetPrefs()->SetInteger( + prefs::kPasswordProtectionWarningTrigger, + safe_browsing::PASSWORD_REUSE); + EXPECT_EQ(RequestOutcome::PASSWORD_ALERT_MODE, + service_->GetPingNotSentReason( + LoginReputationClientRequest::PASSWORD_REUSE_EVENT, + GURL("about:blank"), reused_password_type)); + } +}
diff --git a/ios/chrome/browser/ui/main/BUILD.gn b/ios/chrome/browser/ui/main/BUILD.gn index 02d1bfa..08d8515f 100644 --- a/ios/chrome/browser/ui/main/BUILD.gn +++ b/ios/chrome/browser/ui/main/BUILD.gn
@@ -128,6 +128,7 @@ "//ios/chrome/browser/ui/incognito_reauth:incognito_reauth_scene_agent", "//ios/chrome/browser/ui/settings:settings_root", "//ios/chrome/browser/ui/settings/sync", + "//ios/chrome/browser/ui/start_surface", "//ios/chrome/browser/ui/tab_switcher/tab_grid", "//ios/chrome/browser/ui/thumb_strip:feature_flags", "//ios/chrome/browser/ui/toolbar/public",
diff --git a/ios/chrome/browser/ui/main/scene_controller.mm b/ios/chrome/browser/ui/main/scene_controller.mm index ecefebf5..c15e3f95 100644 --- a/ios/chrome/browser/ui/main/scene_controller.mm +++ b/ios/chrome/browser/ui/main/scene_controller.mm
@@ -89,6 +89,8 @@ #import "ios/chrome/browser/ui/main/ui_blocker_scene_agent.h" #import "ios/chrome/browser/ui/scoped_ui_blocker/scoped_ui_blocker.h" #import "ios/chrome/browser/ui/settings/settings_navigation_controller.h" +#import "ios/chrome/browser/ui/start_surface/start_surface_scene_agent.h" +#import "ios/chrome/browser/ui/start_surface/start_surface_util.h" #include "ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.h" #include "ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator_delegate.h" #import "ios/chrome/browser/ui/thumb_strip/thumb_strip_feature.h" @@ -283,6 +285,7 @@ addAgent:[[IncognitoReauthSceneAgent alloc] initWithReauthModule:[[ReauthenticationModule alloc] init]]]; + [_sceneState addAgent:[[StartSurfaceSceneAgent alloc] init]]; } return self; } @@ -389,6 +392,8 @@ [applicationHandler openURLInNewTab:command]; [self finishActivatingBrowserDismissingTabSwitcher:YES]; } + + [self handleShowStartSurfaceIfNecessary]; } [self recordWindowCreationForSceneState:sceneState]; @@ -501,6 +506,41 @@ } } +// TODO(crbug.com/1173160): Split and move to the StartSurfaceSceneAgent after +// refactoring the scene states. +- (void)handleShowStartSurfaceIfNecessary { + // Keep showing the last active NTP tab no matter whether the Start Surface is + // enabled or not by design. + web::WebState* currentWebState = + self.currentInterface.browser->GetWebStateList()->GetActiveWebState(); + if (IsURLNtp(currentWebState->GetVisibleURL())) { + return; + } + + if (!ShouldShowStartSurfaceForSceneState(self.sceneState)) { + return; + } + self.sceneState.modifytVisibleNTPForStartSurface = YES; + + // Activate the existing NTP tab for the Start surface. + WebStateList* webStateList = self.currentInterface.browser->GetWebStateList(); + for (int i = 0; i < webStateList->count(); i++) { + if (IsURLNtp(webStateList->GetWebStateAt(i)->GetVisibleURL())) { + webStateList->ActivateWebStateAt(i); + return; + } + } + + // Open a new NTP tab if there is no existing NTP tab for the Start Surface. + OpenNewTabCommand* command = + [OpenNewTabCommand commandWithIncognito:self.currentInterface.incognito]; + command.userInitiated = NO; + Browser* browser = self.currentInterface.browser; + id<ApplicationCommands> applicationHandler = + HandlerForProtocol(browser->GetCommandDispatcher(), ApplicationCommands); + [applicationHandler openURLInNewTab:command]; +} + - (void)recordWindowCreationForSceneState:(SceneState*)sceneState { // Don't record window creation for single-window environments if (!base::ios::IsMultipleScenesSupported()) @@ -1246,6 +1286,8 @@ if (!service->IsAuthenticated()) { return; } + UMA_HISTOGRAM_BOOLEAN("Enterprise.BrowserSigninIOS.SignedOutByPolicy", + true); // Sign the user out, but keep synced data (bookmarks, passwords, etc) // locally to be consistent with the policy's behavior on other platforms. service->SignOut( @@ -1266,6 +1308,8 @@ if (self.signinCoordinator) { [self interruptSigninCoordinatorAnimated:YES completion:signOut]; + UMA_HISTOGRAM_BOOLEAN( + "Enterprise.BrowserSigninIOS.SignInInterruptedByPolicy", true); } else { signOut(); }
diff --git a/ios/chrome/browser/ui/main/scene_state.h b/ios/chrome/browser/ui/main/scene_state.h index 6349cb7b3..feab947 100644 --- a/ios/chrome/browser/ui/main/scene_state.h +++ b/ios/chrome/browser/ui/main/scene_state.h
@@ -111,6 +111,13 @@ // YES if the QR scanner is visible. @property(nonatomic, assign) BOOL QRScannerVisible; +// YES if the visible NTP should be modified for the Start Surface. +// +// This flag is set by SceneController to YES when the Start Surface should be +// shown. It is checked by the NewTabPageCoordinator to modify the NTP +// accordingly, and then reset it to NO. +@property(nonatomic, assign) BOOL modifytVisibleNTPForStartSurface; + // Adds an observer to this scene state. The observers will be notified about // scene state changes per SceneStateObserver protocol. - (void)addObserver:(id<SceneStateObserver>)observer;
diff --git a/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_egtest.mm b/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_egtest.mm index ea540c6a..c978951a 100644 --- a/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_egtest.mm +++ b/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_egtest.mm
@@ -117,7 +117,13 @@ // Tests the different fixed elements (labels, buttons) are present on the // screen. -- (void)testElementsPresent { +#if !TARGET_IPHONE_SIMULATOR +// TODO(crbug.com/1177079): Disable for Devices +#define MAYBE_testElementsPresent DISABLED_testElementsPresent +#else +#define MAYBE_testElementsPresent testElementsPresent +#endif +- (void)MAYBE_testElementsPresent { [[EarlGrey selectElementWithMatcher:NameOnCardField()] assertWithMatcher:grey_sufficientlyVisible()]; [[EarlGrey selectElementWithMatcher:CardNumberField()] @@ -137,7 +143,14 @@ #pragma mark - Test top toolbar buttons // Tests that the 'Add' button in the top toolbar is disabled by default. -- (void)testAddButtonDisabledOnDefault { +#if !TARGET_IPHONE_SIMULATOR +// TODO(crbug.com/1177079): Disable for Devices +#define MAYBE_testAddButtonDisabledOnDefault \ + DISABLED_testAddButtonDisabledOnDefault +#else +#define MAYBE_testAddButtonDisabledOnDefault testAddButtonDisabledOnDefault +#endif +- (void)MAYBE_testAddButtonDisabledOnDefault { [[EarlGrey selectElementWithMatcher:chrome_test_util::AddCreditCardButton()] assertWithMatcher:grey_allOf(grey_sufficientlyVisible(), grey_not(grey_enabled()), nil)]; @@ -145,7 +158,14 @@ // Tests that the 'Cancel' button dismisses the screen. // TODO(crbug.com/1149306): test flaky on iPads. -- (void)testCancelButtonDismissesScreen { +#if !TARGET_IPHONE_SIMULATOR +// TODO(crbug.com/1177079): Disable for Devices +#define MAYBE_testCancelButtonDismissesScreen \ + DISABLED_testCancelButtonDismissesScreen +#else +#define MAYBE_testCancelButtonDismissesScreen testCancelButtonDismissesScreen +#endif +- (void)MAYBE_testCancelButtonDismissesScreen { if ([ChromeEarlGrey isIPadIdiom]) { EARL_GREY_TEST_DISABLED(@"Fails on iPad."); } @@ -163,7 +183,15 @@ // Tests when a user tries to add an invalid card number, the "Add" button is // not enabled. -- (void)testAddButtonDisabledOnInvalidNumber { +#if !TARGET_IPHONE_SIMULATOR +// TODO(crbug.com/1177079): Disable for Devices +#define MAYBE_testAddButtonDisabledOnInvalidNumber \ + DISABLED_testAddButtonDisabledOnInvalidNumber +#else +#define MAYBE_testAddButtonDisabledOnInvalidNumber \ + testAddButtonDisabledOnInvalidNumber +#endif +- (void)MAYBE_testAddButtonDisabledOnInvalidNumber { [[EarlGrey selectElementWithMatcher:CardNumberTextField()] performAction:grey_replaceText(@"1234")]; @@ -174,7 +202,15 @@ // Tests when a user tries to add an invalid card number, the "Add" button is // not enabled. -- (void)testAddButtonDisabledOnInvalidExpiryDate { +#if !TARGET_IPHONE_SIMULATOR +// TODO(crbug.com/1177079): Disable for Devices +#define MAYBE_testAddButtonDisabledOnInvalidExpiryDate \ + DISABLED_testAddButtonDisabledOnInvalidExpiryDate +#else +#define MAYBE_testAddButtonDisabledOnInvalidExpiryDate \ + testAddButtonDisabledOnInvalidExpiryDate +#endif +- (void)MAYBE_testAddButtonDisabledOnInvalidExpiryDate { [[EarlGrey selectElementWithMatcher:CardNumberTextField()] performAction:grey_replaceText(@"4111111111111111")]; [[EarlGrey selectElementWithMatcher:MonthOfExpiryTextField()] @@ -189,7 +225,15 @@ // Tests when a user tries to add an invalid card nickname, the "Add" button is // not enabled. -- (void)testAddButtonDisabledOnInvalidNickname { +#if !TARGET_IPHONE_SIMULATOR +// TODO(crbug.com/1177079): Disable for Devices +#define MAYBE_testAddButtonDisabledOnInvalidNickname \ + DISABLED_testAddButtonDisabledOnInvalidNickname +#else +#define MAYBE_testAddButtonDisabledOnInvalidNickname \ + testAddButtonDisabledOnInvalidNickname +#endif +- (void)MAYBE_testAddButtonDisabledOnInvalidNickname { [[EarlGrey selectElementWithMatcher:CardNumberTextField()] performAction:grey_replaceText(@"4111111111111111")]; [[EarlGrey selectElementWithMatcher:MonthOfExpiryTextField()] @@ -206,7 +250,15 @@ // Tests when a user tries to add an empty card nickname, the "Add" button is // enabled. -- (void)testAddButtonEnabledOnEmptyNickname { +#if !TARGET_IPHONE_SIMULATOR +// TODO(crbug.com/1177079): Disable for Devices +#define MAYBE_testAddButtonEnabledOnEmptyNickname \ + DISABLED_testAddButtonEnabledOnEmptyNickname +#else +#define MAYBE_testAddButtonEnabledOnEmptyNickname \ + testAddButtonEnabledOnEmptyNickname +#endif +- (void)MAYBE_testAddButtonEnabledOnEmptyNickname { [[EarlGrey selectElementWithMatcher:CardNumberTextField()] performAction:grey_replaceText(@"4111111111111111")]; [[EarlGrey selectElementWithMatcher:MonthOfExpiryTextField()] @@ -223,7 +275,13 @@ // and the new card number appears on the Autofill Credit Card 'Payment Methods' // screen. // TODO(crbug.com/1149306): test flaky on iPads. -- (void)testAddButtonOnValidNumber { +#if !TARGET_IPHONE_SIMULATOR +// TODO(crbug.com/1177079): Disable for Devices +#define MAYBE_testAddButtonOnValidNumber DISABLED_testAddButtonOnValidNumber +#else +#define MAYBE_testAddButtonOnValidNumber testAddButtonOnValidNumber +#endif +- (void)MAYBE_testAddButtonOnValidNumber { if ([ChromeEarlGrey isIPadIdiom]) { EARL_GREY_TEST_DISABLED(@"Fails on iPad."); } @@ -253,7 +311,13 @@ // Tests when a user add a card with a nickname, the screen is dismissed // and the new card number appears on the Autofill Credit Card 'Payment Methods' // screen with the nickname. -- (void)testAddButtonOnValidNickname { +#if !TARGET_IPHONE_SIMULATOR +// TODO(crbug.com/1177079): Disable for Devices +#define MAYBE_testAddButtonOnValidNickname DISABLED_testAddButtonOnValidNickname +#else +#define MAYBE_testAddButtonOnValidNickname testAddButtonOnValidNickname +#endif +- (void)MAYBE_testAddButtonOnValidNickname { [AutofillAppInterface clearCreditCardStore]; [[EarlGrey selectElementWithMatcher:CardNumberTextField()] performAction:grey_replaceText(@"4111111111111111")]; @@ -278,7 +342,15 @@ // Tests that an error icon is displayed when a field has invalid text. The icon // is displayed if the field is not currently being editted. -- (void)testInvalidInputDisplaysInlineError { +#if !TARGET_IPHONE_SIMULATOR +// TODO(crbug.com/1177079): Disable for Devices +#define MAYBE_testInvalidInputDisplaysInlineError \ + DISABLED_testInvalidInputDisplaysInlineError +#else +#define MAYBE_testInvalidInputDisplaysInlineError \ + testInvalidInputDisplaysInlineError +#endif +- (void)MAYBE_testInvalidInputDisplaysInlineError { [[EarlGrey selectElementWithMatcher:CardNumberIconView(kEditIconIdentifier)] assertWithMatcher:grey_sufficientlyVisible()]; @@ -309,7 +381,15 @@ // Tests that add button is disabled until typing a single character makes all // the fields valid. -- (void)testAddButtonDisabledTillValidForm { +#if !TARGET_IPHONE_SIMULATOR +// TODO(crbug.com/1177079): Disable for Devices +#define MAYBE_testAddButtonDisabledTillValidForm \ + DISABLED_testAddButtonDisabledTillValidForm +#else +#define MAYBE_testAddButtonDisabledTillValidForm \ + testAddButtonDisabledTillValidForm +#endif +- (void)MAYBE_testAddButtonDisabledTillValidForm { [[EarlGrey selectElementWithMatcher:CardNumberTextField()] performAction:grey_typeText(@"4111111111111111")]; [[EarlGrey selectElementWithMatcher:MonthOfExpiryTextField()]
diff --git a/ios/chrome/browser/ui/settings/autofill/autofill_credit_card_settings_egtest.mm b/ios/chrome/browser/ui/settings/autofill/autofill_credit_card_settings_egtest.mm index ddd26e4..27f61f3 100644 --- a/ios/chrome/browser/ui/settings/autofill/autofill_credit_card_settings_egtest.mm +++ b/ios/chrome/browser/ui/settings/autofill/autofill_credit_card_settings_egtest.mm
@@ -124,7 +124,13 @@ } // Test that the page for viewing Autofill credit card details is as expected. -- (void)testCreditCardViewPage { +#if !TARGET_IPHONE_SIMULATOR +// TODO(crbug.com/1177079): Disable for Devices +#define MAYBE_testCreditCardViewPage DISABLED_testCreditCardViewPage +#else +#define MAYBE_testCreditCardViewPage testCreditCardViewPage +#endif +- (void)MAYBE_testCreditCardViewPage { NSString* lastDigits = [AutofillAppInterface saveLocalCreditCard]; [self openEditCreditCard:[self creditCardLabel:lastDigits]]; @@ -147,7 +153,15 @@ } // Test that the page for viewing Autofill credit card details is accessible. -- (void)testAccessibilityOnCreditCardViewPage { +#if !TARGET_IPHONE_SIMULATOR +// TODO(crbug.com/1177079): Disable for Devices +#define MAYBE_testAccessibilityOnCreditCardViewPage \ + DISABLED_testAccessibilityOnCreditCardViewPage +#else +#define MAYBE_testAccessibilityOnCreditCardViewPage \ + testAccessibilityOnCreditCardViewPage +#endif +- (void)MAYBE_testAccessibilityOnCreditCardViewPage { NSString* lastDigits = [AutofillAppInterface saveLocalCreditCard]; [self openEditCreditCard:[self creditCardLabel:lastDigits]]; @@ -161,7 +175,15 @@ } // Test that the page for editing Autofill credit card details is accessible. -- (void)testAccessibilityOnCreditCardEditPage { +#if !TARGET_IPHONE_SIMULATOR +// TODO(crbug.com/1177079): Disable for Devices +#define MAYBE_testAccessibilityOnCreditCardEditPage \ + DISABLED_testAccessibilityOnCreditCardEditPage +#else +#define MAYBE_testAccessibilityOnCreditCardEditPage \ + testAccessibilityOnCreditCardEditPage +#endif +- (void)MAYBE_testAccessibilityOnCreditCardEditPage { NSString* lastDigits = [AutofillAppInterface saveLocalCreditCard]; [self openEditCreditCard:[self creditCardLabel:lastDigits]]; @@ -179,7 +201,13 @@ // Checks that the Autofill credit cards list view is in edit mode and the // Autofill credit cards switch is disabled. -- (void)testListViewEditMode { +#if !TARGET_IPHONE_SIMULATOR +// TODO(crbug.com/1177079): Disable for Devices +#define MAYBE_testListViewEditMode DISABLED_testListViewEditMode +#else +#define MAYBE_testListViewEditMode testListViewEditMode +#endif +- (void)MAYBE_testListViewEditMode { [AutofillAppInterface saveLocalCreditCard]; [self openCreditCardsSettings]; @@ -197,7 +225,13 @@ // Checks that the Autofill credit card switch can be toggled on/off and the // list of Autofill credit cards is not affected by it. -- (void)testToggleCreditCardSwitch { +#if !TARGET_IPHONE_SIMULATOR +// TODO(crbug.com/1177079): Disable for Devices +#define MAYBE_testToggleCreditCardSwitch DISABLED_testToggleCreditCardSwitch +#else +#define MAYBE_testToggleCreditCardSwitch testToggleCreditCardSwitch +#endif +- (void)MAYBE_testToggleCreditCardSwitch { NSString* lastDigits = [AutofillAppInterface saveLocalCreditCard]; [self openCreditCardsSettings]; @@ -227,7 +261,15 @@ } // Checks that the toolbar always appears in edit mode. -- (void)testToolbarInEditModeAddPaymentMethodFeatureEnabled { +#if !TARGET_IPHONE_SIMULATOR +// TODO(crbug.com/1177079): Disable for Devices +#define MAYBE_testToolbarInEditModeAddPaymentMethodFeatureEnabled \ + DISABLED_testToolbarInEditModeAddPaymentMethodFeatureEnabled +#else +#define MAYBE_testToolbarInEditModeAddPaymentMethodFeatureEnabled \ + testToolbarInEditModeAddPaymentMethodFeatureEnabled +#endif +- (void)MAYBE_testToolbarInEditModeAddPaymentMethodFeatureEnabled { NSString* lastDigits = [AutofillAppInterface saveLocalCreditCard]; [self openCreditCardListInEditMode]; @@ -247,7 +289,15 @@ // Checks the 'Add Payment Method' button is always visible and directs a user // to the Add Payent method view. -- (void)testToolbarAddPaymentMethodButtonFeatureEnabled { +#if !TARGET_IPHONE_SIMULATOR +// TODO(crbug.com/1177079): Disable for Devices +#define MAYBE_testToolbarAddPaymentMethodButtonFeatureEnabled \ + DISABLED_testToolbarAddPaymentMethodButtonFeatureEnabled +#else +#define MAYBE_testToolbarAddPaymentMethodButtonFeatureEnabled \ + testToolbarAddPaymentMethodButtonFeatureEnabled +#endif +- (void)MAYBE_testToolbarAddPaymentMethodButtonFeatureEnabled { [AutofillAppInterface saveLocalCreditCard]; [self openCreditCardListInEditMode]; @@ -264,7 +314,15 @@ // Checks the 'Delete' button is always visible. // The button is enabled when a card is selected and disabled when a card is not // selected. -- (void)testToolbarDeleteButtonWithAddPaymentMethodFeatureEnabled { +#if !TARGET_IPHONE_SIMULATOR +// TODO(crbug.com/1177079): Disable for Devices +#define MAYBE_testToolbarDeleteButtonWithAddPaymentMethodFeatureEnabled \ + DISABLED_testToolbarDeleteButtonWithAddPaymentMethodFeatureEnabled +#else +#define MAYBE_testToolbarDeleteButtonWithAddPaymentMethodFeatureEnabled \ + testToolbarDeleteButtonWithAddPaymentMethodFeatureEnabled +#endif +- (void)MAYBE_testToolbarDeleteButtonWithAddPaymentMethodFeatureEnabled { NSString* lastDigits = [AutofillAppInterface saveLocalCreditCard]; [[EarlGrey selectElementWithMatcher:chrome_test_util:: SettingsBottomToolbarDeleteButton()] @@ -289,7 +347,13 @@ } // Checks that deleting a card exits from edit mode. -- (void)testDeletingCreditCard { +#if !TARGET_IPHONE_SIMULATOR +// TODO(crbug.com/1177079): Disable for Devices +#define MAYBE_testDeletingCreditCard DISABLED_testDeletingCreditCard +#else +#define MAYBE_testDeletingCreditCard testDeletingCreditCard +#endif +- (void)MAYBE_testDeletingCreditCard { NSString* lastDigits = [AutofillAppInterface saveLocalCreditCard]; [self openCreditCardListInEditMode]; [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(
diff --git a/ios/chrome/browser/ui/settings/autofill/autofill_edit_credit_card_egtest.mm b/ios/chrome/browser/ui/settings/autofill/autofill_edit_credit_card_egtest.mm index 40fc230..03cf955 100644 --- a/ios/chrome/browser/ui/settings/autofill/autofill_edit_credit_card_egtest.mm +++ b/ios/chrome/browser/ui/settings/autofill/autofill_edit_credit_card_egtest.mm
@@ -82,7 +82,13 @@ #pragma mark - Test that all fields on the 'Add Credit Card' screen appear // Tests that editing the credit card nickname is possible. -- (void)testValidNickname { +#if !TARGET_IPHONE_SIMULATOR +// TODO(crbug.com/1177079): Disable for Devices +#define MAYBE_testValidNickname DISABLED_testValidNickname +#else +#define MAYBE_testValidNickname testValidNickname +#endif +- (void)MAYBE_testValidNickname { [self typeNickname:@"Nickname"]; [[EarlGrey selectElementWithMatcher:NavigationBarDoneButton()] @@ -94,7 +100,13 @@ } // Tests that invalid nicknames are not allowed when editing a card. -- (void)testInvalidNickname { +#if !TARGET_IPHONE_SIMULATOR +// TODO(crbug.com/1177079): Disable for Devices +#define MAYBE_testInvalidNickname DISABLED_testInvalidNickname +#else +#define MAYBE_testInvalidNickname testInvalidNickname +#endif +- (void)MAYBE_testInvalidNickname { [self typeNickname:@"1233"]; [[EarlGrey selectElementWithMatcher:NavigationBarDoneButton()] @@ -103,7 +115,13 @@ } // Tests that clearing a nickname is allowed. -- (void)testEmptyNickname { +#if !TARGET_IPHONE_SIMULATOR +// TODO(crbug.com/1177079): Disable for Devices +#define MAYBE_testEmptyNickname DISABLED_testEmptyNickname +#else +#define MAYBE_testEmptyNickname testEmptyNickname +#endif +- (void)MAYBE_testEmptyNickname { [self typeNickname:@"To be removed"]; [[EarlGrey selectElementWithMatcher:NicknameTextField()]
diff --git a/ios/chrome/browser/ui/settings/autofill/autofill_profile_settings_egtest.mm b/ios/chrome/browser/ui/settings/autofill/autofill_profile_settings_egtest.mm index fba1bb10..4c35c2e 100644 --- a/ios/chrome/browser/ui/settings/autofill/autofill_profile_settings_egtest.mm +++ b/ios/chrome/browser/ui/settings/autofill/autofill_profile_settings_egtest.mm
@@ -215,7 +215,15 @@ } // Test that the page for editing Autofill profile details is accessible. -- (void)testAccessibilityOnAutofillProfileEditPage { +#if !TARGET_IPHONE_SIMULATOR +// TODO(crbug.com/1177079): Disable for Devices +#define MAYBE_testAccessibilityOnAutofillProfileEditPage \ + DISABLED_testAccessibilityOnAutofillProfileEditPage +#else +#define MAYBE_testAccessibilityOnAutofillProfileEditPage \ + testAccessibilityOnAutofillProfileEditPage +#endif +- (void)MAYBE_testAccessibilityOnAutofillProfileEditPage { [AutofillAppInterface saveExampleProfile]; [self openEditProfile:kProfileLabel];
diff --git a/ios/chrome/browser/ui/settings/google_services/accounts_table_egtest.mm b/ios/chrome/browser/ui/settings/google_services/accounts_table_egtest.mm index 245b436..bdcca1d 100644 --- a/ios/chrome/browser/ui/settings/google_services/accounts_table_egtest.mm +++ b/ios/chrome/browser/ui/settings/google_services/accounts_table_egtest.mm
@@ -87,7 +87,15 @@ // Tests that the Account Settings screen is correctly popped if the signed in // account is removed while the "Disconnect Account" dialog is up. -- (void)testSignInPopUpAccountOnDisconnectAccount { +#if !TARGET_IPHONE_SIMULATOR +// TODO(crbug.com/1177079): Disable for Devices +#define MAYBE_testSignInPopUpAccountOnDisconnectAccount \ + DISABLED_testSignInPopUpAccountOnDisconnectAccount +#else +#define MAYBE_testSignInPopUpAccountOnDisconnectAccount \ + testSignInPopUpAccountOnDisconnectAccount +#endif +- (void)MAYBE_testSignInPopUpAccountOnDisconnectAccount { FakeChromeIdentity* fakeIdentity = [SigninEarlGrey fakeIdentity1]; [SigninEarlGrey addFakeIdentity:fakeIdentity]; @@ -111,7 +119,14 @@ // Tests that the Account Settings screen is correctly reloaded when one of // the non-primary account is removed. -- (void)testSignInReloadOnRemoveAccount { +#if !TARGET_IPHONE_SIMULATOR +// TODO(crbug.com/1177079): Disable for Devices +#define MAYBE_testSignInReloadOnRemoveAccount \ + DISABLED_testSignInReloadOnRemoveAccount +#else +#define MAYBE_testSignInReloadOnRemoveAccount testSignInReloadOnRemoveAccount +#endif +- (void)MAYBE_testSignInReloadOnRemoveAccount { FakeChromeIdentity* fakeIdentity1 = [SigninEarlGrey fakeIdentity1]; FakeChromeIdentity* fakeIdentity2 = [SigninEarlGrey fakeIdentity2]; [SigninEarlGrey addFakeIdentity:fakeIdentity2]; @@ -137,7 +152,13 @@ // Tests that the Account Settings screen is popped and the user signed out // when the account is removed. -- (void)testSignOutOnRemoveAccount { +#if !TARGET_IPHONE_SIMULATOR +// TODO(crbug.com/1177079): Disable for Devices +#define MAYBE_testSignOutOnRemoveAccount DISABLED_testSignOutOnRemoveAccount +#else +#define MAYBE_testSignOutOnRemoveAccount testSignOutOnRemoveAccount +#endif +- (void)MAYBE_testSignOutOnRemoveAccount { FakeChromeIdentity* fakeIdentity = [SigninEarlGrey fakeIdentity1]; // Sign In |fakeIdentity|, then open the Account Settings. @@ -158,7 +179,15 @@ // Tests that selecting sign-out from a non-managed account keeps the user's // synced data. -- (void)testSignOutFromNonManagedAccountKeepsData { +#if !TARGET_IPHONE_SIMULATOR +// TODO(crbug.com/1177079): Disable for Devices +#define MAYBE_testSignOutFromNonManagedAccountKeepsData \ + DISABLED_testSignOutFromNonManagedAccountKeepsData +#else +#define MAYBE_testSignOutFromNonManagedAccountKeepsData \ + testSignOutFromNonManagedAccountKeepsData +#endif +- (void)MAYBE_testSignOutFromNonManagedAccountKeepsData { FakeChromeIdentity* fakeIdentity = [SigninEarlGrey fakeIdentity1]; // Sign In |fakeIdentity|. @@ -183,7 +212,15 @@ // Tests that selecting sign-out and clear data from a non-managed user account // clears the user's synced data. -- (void)testSignOutAndClearDataFromNonManagedAccountClearsData { +#if !TARGET_IPHONE_SIMULATOR +// TODO(crbug.com/1177079): Disable for Devices +#define MAYBE_testSignOutAndClearDataFromNonManagedAccountClearsData \ + DISABLED_testSignOutAndClearDataFromNonManagedAccountClearsData +#else +#define MAYBE_testSignOutAndClearDataFromNonManagedAccountClearsData \ + testSignOutAndClearDataFromNonManagedAccountClearsData +#endif +- (void)MAYBE_testSignOutAndClearDataFromNonManagedAccountClearsData { FakeChromeIdentity* fakeIdentity = [SigninEarlGrey fakeIdentity1]; // Sign In |fakeIdentity|. @@ -213,7 +250,14 @@ } // Tests that signing out from a managed user account clears the user's data. -- (void)testsSignOutFromManagedAccount { +#if !TARGET_IPHONE_SIMULATOR +// TODO(crbug.com/1177079): Disable for Devices +#define MAYBE_testsSignOutFromManagedAccount \ + DISABLED_testsSignOutFromManagedAccount +#else +#define MAYBE_testsSignOutFromManagedAccount testsSignOutFromManagedAccount +#endif +- (void)MAYBE_testsSignOutFromManagedAccount { // Sign In |fakeManagedIdentity|. [SigninEarlGreyUI signinWithFakeIdentity:[SigninEarlGrey fakeManagedIdentity]]; @@ -244,7 +288,15 @@ // Tests that given two accounts A and B that are available on the device - // signing in and out from account A, then signing in to account B, properly // identifies the user with account B. -- (void)testSwitchingAccountsWithClearedData { +#if !TARGET_IPHONE_SIMULATOR +// TODO(crbug.com/1177079): Disable for Devices +#define MAYBE_testSwitchingAccountsWithClearedData \ + DISABLED_testSwitchingAccountsWithClearedData +#else +#define MAYBE_testSwitchingAccountsWithClearedData \ + testSwitchingAccountsWithClearedData +#endif +- (void)MAYBE_testSwitchingAccountsWithClearedData { FakeChromeIdentity* fakeIdentity1 = [SigninEarlGrey fakeIdentity1]; FakeChromeIdentity* fakeIdentity2 = [SigninEarlGrey fakeIdentity2]; [SigninEarlGrey addFakeIdentity:fakeIdentity1];
diff --git a/ios/chrome/browser/ui/start_surface/BUILD.gn b/ios/chrome/browser/ui/start_surface/BUILD.gn index 36a149dd..7912b6a 100644 --- a/ios/chrome/browser/ui/start_surface/BUILD.gn +++ b/ios/chrome/browser/ui/start_surface/BUILD.gn
@@ -10,5 +10,26 @@ configs += [ "//build/config/compiler:enable_arc" ] - deps = [ "//base" ] + deps = [ + "//base", + "//ui/base", + ] +} + +source_set("start_surface") { + sources = [ + "start_surface_scene_agent.h", + "start_surface_scene_agent.mm", + "start_surface_util.h", + "start_surface_util.mm", + ] + + configs += [ "//build/config/compiler:enable_arc" ] + + deps = [ + ":feature_flags", + "//base", + "//ios/chrome/browser/ui/main:observing_scene_agent", + "//ios/chrome/browser/ui/main:scene_state_header", + ] }
diff --git a/ios/chrome/browser/ui/start_surface/start_surface_features.h b/ios/chrome/browser/ui/start_surface/start_surface_features.h index a63b0ce..109f449 100644 --- a/ios/chrome/browser/ui/start_surface/start_surface_features.h +++ b/ios/chrome/browser/ui/start_surface/start_surface_features.h
@@ -10,6 +10,14 @@ // The feature to enable or disable the Start Surface. extern const base::Feature kStartSurface; +// The feature parameter to indicate inactive duration to return to the Start +// Surface in seconds. +extern const char kReturnToStartSurfaceInactiveDurationInSeconds[]; + +// Checks whether the Start Surface should be enabled. bool IsStartSurfaceEnabled(); +// Returns the inactive duration to show the Start Surface. +double GetReturnToStartSurfaceDuration(); + #endif // IOS_CHROME_BROWSER_UI_START_SURFACE_START_SURFACE_FEATURES_H_.
diff --git a/ios/chrome/browser/ui/start_surface/start_surface_features.mm b/ios/chrome/browser/ui/start_surface/start_surface_features.mm index c61b9aa..93c3a3a8 100644 --- a/ios/chrome/browser/ui/start_surface/start_surface_features.mm +++ b/ios/chrome/browser/ui/start_surface/start_surface_features.mm
@@ -3,6 +3,7 @@ // found in the LICENSE file. #import "ios/chrome/browser/ui/start_surface/start_surface_features.h" +#include "base/metrics/field_trial_params.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -11,6 +12,15 @@ const base::Feature kStartSurface{"StartSurface", base::FEATURE_DISABLED_BY_DEFAULT}; +const char kReturnToStartSurfaceInactiveDurationInSeconds[] = + "ReturnToStartSurfaceInactiveDurationInSeconds"; + bool IsStartSurfaceEnabled() { return base::FeatureList::IsEnabled(kStartSurface); } + +double GetReturnToStartSurfaceDuration() { + return base::GetFieldTrialParamByFeatureAsDouble( + kStartSurface, kReturnToStartSurfaceInactiveDurationInSeconds, + 60 * 60 /*default to 1 hour*/); +}
diff --git a/ios/chrome/browser/ui/start_surface/start_surface_scene_agent.h b/ios/chrome/browser/ui/start_surface/start_surface_scene_agent.h new file mode 100644 index 0000000..aa30b52 --- /dev/null +++ b/ios/chrome/browser/ui/start_surface/start_surface_scene_agent.h
@@ -0,0 +1,14 @@ +// Copyright 2021 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 IOS_CHROME_BROWSER_UI_START_SURFACE_START_SURFACE_SCENE_AGENT_H_ +#define IOS_CHROME_BROWSER_UI_START_SURFACE_START_SURFACE_SCENE_AGENT_H_ + +#import "ios/chrome/browser/ui/main/observing_scene_state_agent.h" + +// A scene agent for the Start Surface. +@interface StartSurfaceSceneAgent : ObservingSceneAgent +@end + +#endif // IOS_CHROME_BROWSER_UI_START_SURFACE_START_SURFACE_SCENE_AGENT_H_ \ No newline at end of file
diff --git a/ios/chrome/browser/ui/start_surface/start_surface_scene_agent.mm b/ios/chrome/browser/ui/start_surface/start_surface_scene_agent.mm new file mode 100644 index 0000000..cb611e03 --- /dev/null +++ b/ios/chrome/browser/ui/start_surface/start_surface_scene_agent.mm
@@ -0,0 +1,26 @@ +// Copyright 2021 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. + +#import "ios/chrome/browser/ui/start_surface/start_surface_scene_agent.h" +#import "ios/chrome/browser/ui/start_surface/start_surface_util.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +@implementation StartSurfaceSceneAgent + +#pragma mark - SceneStateObserver + +- (void)sceneState:(SceneState*)sceneState + transitionedToActivationLevel:(SceneActivationLevel)level { + if (level == SceneActivationLevelBackground) { + // TODO(crbug.com/1173160): Consider when to clear the session object since + // Chrome may be closed without transiting to background, e.g. device power + // off, then the previous session object is staled. + SetStartSurfaceSessionObjectForSceneState(sceneState); + } +} + +@end
diff --git a/ios/chrome/browser/ui/start_surface/start_surface_util.h b/ios/chrome/browser/ui/start_surface/start_surface_util.h new file mode 100644 index 0000000..d5bba69 --- /dev/null +++ b/ios/chrome/browser/ui/start_surface/start_surface_util.h
@@ -0,0 +1,16 @@ +// Copyright 2021 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 IOS_CHROME_BROWSER_UI_START_SURFACE_START_SURFACE_UTIL_H_ +#define IOS_CHROME_BROWSER_UI_START_SURFACE_START_SURFACE_UTIL_H_ + +#import "ios/chrome/browser/ui/main/scene_state.h" + +// Checks whether the Start Surface should be shown for the given scene state. +bool ShouldShowStartSurfaceForSceneState(SceneState* sceneState); + +// Sets the session related objects for the Start Surface. +void SetStartSurfaceSessionObjectForSceneState(SceneState* sceneState); + +#endif // IOS_CHROME_BROWSER_UI_START_SURFACE_START_SURFACE_UTIL_H_.
diff --git a/ios/chrome/browser/ui/start_surface/start_surface_util.mm b/ios/chrome/browser/ui/start_surface/start_surface_util.mm new file mode 100644 index 0000000..c98607a --- /dev/null +++ b/ios/chrome/browser/ui/start_surface/start_surface_util.mm
@@ -0,0 +1,48 @@ +// Copyright 2021 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. + +#import "ios/chrome/browser/ui/start_surface/start_surface_util.h" +#import "ios/chrome/browser/ui/start_surface/start_surface_features.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +namespace { + +// The key to store the timestamp when the scene enters into background. +NSString* kStartSurfaceSceneEnterIntoBackgroundTime = + @"StartSurfaceSceneEnterIntoBackgroundTime"; + +} // namespace + +bool ShouldShowStartSurfaceForSceneState(SceneState* sceneState) { + if (!IsStartSurfaceEnabled()) { + return NO; + } + + NSDate* timestamp = (NSDate*)[sceneState + sessionObjectForKey:kStartSurfaceSceneEnterIntoBackgroundTime]; + if (timestamp == nil || [[NSDate date] timeIntervalSinceDate:timestamp] < + GetReturnToStartSurfaceDuration()) { + return NO; + } + + if (sceneState.presentingFirstRunUI || sceneState.presentingModalOverlay || + sceneState.startupHadExternalIntent || sceneState.pendingUserActivity || + sceneState.incognitoContentVisible) { + return NO; + } + + return YES; +} + +void SetStartSurfaceSessionObjectForSceneState(SceneState* sceneState) { + if (!IsStartSurfaceEnabled()) { + return; + } + + [sceneState setSessionObject:[NSDate date] + forKey:kStartSurfaceSceneEnterIntoBackgroundTime]; +}
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1 index ed8db72..d081488d 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@ -b8de1b4cdd6a35913f42e169de5310fda618ddf2 \ No newline at end of file +cc1ae3b752b97191e19d2e4d7ab25b7b318bb42e \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1 index 36db25f..354de70 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@ -9a853bfc5db4617dce5bd34a6df88e66ed4acbde \ No newline at end of file +bd34b10a2b3c387cfba4faa855fd30c42410b617 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1 index 9ee892e..6cdc8ec 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@ -702c6e398942a19f78609874cb209eb9d878e496 \ No newline at end of file +b201a526d008461a2dc14664e874a6b852f81d45 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1 index 7d4cf31..44036741 100644 --- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@ -2d781e223a4a32b65d630fab358a7561dd12c042 \ No newline at end of file +ecb04848c777b30975232b24e3139ef941f8b810 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1 index 98d2b34..a1d6c596 100644 --- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@ -d005ca1b4e45ed8168898cb4c5f7083aab3c65d5 \ No newline at end of file +0be4694310f67b620c5d578dd8a70bce8af4b503 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1 index eb60bde..01e4443 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@ -b28105db86a9c331b65476dfb097921d2b019871 \ No newline at end of file +7f4306a40ba90ad2b28a35401432f725befc7147 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1 index 00dd4be..0cfae55 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@ -23a47068a930eafe296219513ec8da22155078c6 \ No newline at end of file +1b245ff90aa3d55a4264af24191235f2b8fbb509 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1 index 47c3d64..3dc65a56 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@ -53fe2415d0a445a3407cc55a761ed9bb145750ae \ No newline at end of file +b281d533981e6a27c7c9f26e54fd95e1429ac667 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1 index c0f8e08e..9383421 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@ -33c787e880ef5c04c19b709b3b4b85a799e4d93e \ No newline at end of file +ad1902081171a8b89e72ad529b77d2f40d0ac06f \ No newline at end of file
diff --git a/ios/web/js_features/context_menu/context_menu_java_script_feature.h b/ios/web/js_features/context_menu/context_menu_java_script_feature.h index 2e0ca85..3ea3784f 100644 --- a/ios/web/js_features/context_menu/context_menu_java_script_feature.h +++ b/ios/web/js_features/context_menu/context_menu_java_script_feature.h
@@ -9,7 +9,6 @@ #include <map> #include <string> -#include <vector> #include "base/callback.h" #include "base/supports_user_data.h" @@ -45,7 +44,7 @@ ElementDetailsCallback callback); // JavaScriptFeature: - std::vector<std::string> GetScriptMessageHandlerNames() const override; + base::Optional<std::string> GetScriptMessageHandlerName() const override; void ScriptMessageReceived(BrowserState* browser_state, WKScriptMessage* message) override;
diff --git a/ios/web/js_features/context_menu/context_menu_java_script_feature.mm b/ios/web/js_features/context_menu/context_menu_java_script_feature.mm index 36d8f2ba..1429f978 100644 --- a/ios/web/js_features/context_menu/context_menu_java_script_feature.mm +++ b/ios/web/js_features/context_menu/context_menu_java_script_feature.mm
@@ -78,9 +78,9 @@ CallJavaScriptFunction(main_frame, "findElementAtPoint", parameters); } -std::vector<std::string> -ContextMenuJavaScriptFeature::GetScriptMessageHandlerNames() const { - return {kFindElementResultHandlerName}; +base::Optional<std::string> +ContextMenuJavaScriptFeature::GetScriptMessageHandlerName() const { + return kFindElementResultHandlerName; } void ContextMenuJavaScriptFeature::ScriptMessageReceived(
diff --git a/ios/web/js_features/window_error/window_error_java_script_feature.h b/ios/web/js_features/window_error/window_error_java_script_feature.h index b711a8e..b9461aa1 100644 --- a/ios/web/js_features/window_error/window_error_java_script_feature.h +++ b/ios/web/js_features/window_error/window_error_java_script_feature.h
@@ -49,7 +49,7 @@ private: // JavaScriptFeature: - std::vector<std::string> GetScriptMessageHandlerNames() const override; + base::Optional<std::string> GetScriptMessageHandlerName() const override; void ScriptMessageReceived(BrowserState* browser_state, WKScriptMessage* message) override;
diff --git a/ios/web/js_features/window_error/window_error_java_script_feature.mm b/ios/web/js_features/window_error/window_error_java_script_feature.mm index 01c1caa..ecec9a9c 100644 --- a/ios/web/js_features/window_error/window_error_java_script_feature.mm +++ b/ios/web/js_features/window_error/window_error_java_script_feature.mm
@@ -45,9 +45,9 @@ } WindowErrorJavaScriptFeature::~WindowErrorJavaScriptFeature() = default; -std::vector<std::string> -WindowErrorJavaScriptFeature::GetScriptMessageHandlerNames() const { - return {kWindowErrorResultHandlerName}; +base::Optional<std::string> +WindowErrorJavaScriptFeature::GetScriptMessageHandlerName() const { + return kWindowErrorResultHandlerName; } void WindowErrorJavaScriptFeature::ScriptMessageReceived(
diff --git a/ios/web/js_messaging/java_script_content_world.mm b/ios/web/js_messaging/java_script_content_world.mm index 6375fa8..d5cc9c0 100644 --- a/ios/web/js_messaging/java_script_content_world.mm +++ b/ios/web/js_messaging/java_script_content_world.mm
@@ -126,26 +126,31 @@ [user_content_controller_ addUserScript:user_script]; } - // Setup Javascript message callbacks. - for (auto handlers_by_name : feature->GetScriptMessageHandlers()) { + // Setup Javascript message callback. + auto optional_handler_name = feature->GetScriptMessageHandlerName(); + if (optional_handler_name) { + auto handler = feature->GetScriptMessageHandler(); + DCHECK(handler); + + NSString* handler_name = + base::SysUTF8ToNSString(optional_handler_name.value()); + std::unique_ptr<ScopedWKScriptMessageHandler> script_message_handler; #if defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0 if (@available(iOS 14, *)) { if (content_world_) { script_message_handler = std::make_unique<ScopedWKScriptMessageHandler>( - user_content_controller_, - base::SysUTF8ToNSString(handlers_by_name.first), content_world_, - base::BindRepeating(handlers_by_name.second, browser_state_)); + user_content_controller_, handler_name, content_world_, + base::BindRepeating(handler.value(), browser_state_)); } } #endif // defined(__IPHONE14_0) if (!script_message_handler.get()) { script_message_handler = std::make_unique<ScopedWKScriptMessageHandler>( - user_content_controller_, - base::SysUTF8ToNSString(handlers_by_name.first), - base::BindRepeating(handlers_by_name.second, browser_state_)); + user_content_controller_, handler_name, + base::BindRepeating(handler.value(), browser_state_)); } script_message_handlers_[feature] = std::move(script_message_handler); }
diff --git a/ios/web/js_messaging/java_script_feature.mm b/ios/web/js_messaging/java_script_feature.mm index 0c1db3c61..6a637ff82 100644 --- a/ios/web/js_messaging/java_script_feature.mm +++ b/ios/web/js_messaging/java_script_feature.mm
@@ -132,21 +132,19 @@ return dependent_features_; } -std::vector<std::string> JavaScriptFeature::GetScriptMessageHandlerNames() +base::Optional<std::string> JavaScriptFeature::GetScriptMessageHandlerName() const { - return {}; + return base::nullopt; } -std::map<std::string, JavaScriptFeature::ScriptMessageHandler> -JavaScriptFeature::GetScriptMessageHandlers() const { - auto handler = base::BindRepeating(&JavaScriptFeature::ScriptMessageReceived, - weak_factory_.GetWeakPtr()); - auto handlers = - std::map<std::string, JavaScriptFeature::ScriptMessageHandler>(); - for (auto handler_name : GetScriptMessageHandlerNames()) { - handlers[handler_name] = handler; +base::Optional<JavaScriptFeature::ScriptMessageHandler> +JavaScriptFeature::GetScriptMessageHandler() const { + if (!GetScriptMessageHandlerName()) { + return base::nullopt; } - return handlers; + + return base::BindRepeating(&JavaScriptFeature::ScriptMessageReceived, + weak_factory_.GetWeakPtr()); } void JavaScriptFeature::ScriptMessageReceived(BrowserState* browser_state,
diff --git a/ios/web/public/js_messaging/java_script_feature.h b/ios/web/public/js_messaging/java_script_feature.h index 74f900b..c7374ee 100644 --- a/ios/web/public/js_messaging/java_script_feature.h +++ b/ios/web/public/js_messaging/java_script_feature.h
@@ -11,6 +11,7 @@ #include "base/callback.h" #include "base/memory/weak_ptr.h" +#include "base/optional.h" @class NSString; @class WKScriptMessage; @@ -131,17 +132,16 @@ virtual const std::vector<const JavaScriptFeature*> GetDependentFeatures() const; - // Returns the script message handler names which this feature will receive - // messages from JavaScript. Returning an empty vector will not register any - // handlers. - virtual std::vector<std::string> GetScriptMessageHandlerNames() const; + // Returns the script message handler name which this feature will receive + // messages from JavaScript. Returning null will not register any handler. + virtual base::Optional<std::string> GetScriptMessageHandlerName() const; using ScriptMessageHandler = base::RepeatingCallback<void(BrowserState* browser_state, WKScriptMessage* message)>; - // Returns the names from |GetScriptMessageHandlerNames| mapped to handler - // callbacks. - std::map<std::string, ScriptMessageHandler> GetScriptMessageHandlers() const; + // Returns the script message handler callback if + // |GetScriptMessageHandlerName()| returns a handler name. + base::Optional<ScriptMessageHandler> GetScriptMessageHandler() const; JavaScriptFeature(const JavaScriptFeature&) = delete; @@ -159,7 +159,7 @@ base::OnceCallback<void(const base::Value*)> callback, base::TimeDelta timeout); - // Callback for script messages registered through |GetScriptMessageHandlers|. + // Callback for script messages registered through |GetScriptMessageHandler|. // Called when a web view associated with |browser_state| sent |message|. virtual void ScriptMessageReceived(BrowserState* browser_state, WKScriptMessage* message);
diff --git a/ios/web/test/fakes/fake_java_script_feature.h b/ios/web/test/fakes/fake_java_script_feature.h index 554d6f2..7d0290c 100644 --- a/ios/web/test/fakes/fake_java_script_feature.h +++ b/ios/web/test/fakes/fake_java_script_feature.h
@@ -57,7 +57,7 @@ private: // JavaScriptFeature: - std::vector<std::string> GetScriptMessageHandlerNames() const override; + base::Optional<std::string> GetScriptMessageHandlerName() const override; void ScriptMessageReceived(BrowserState* browser_state, WKScriptMessage* message) override;
diff --git a/ios/web/test/fakes/fake_java_script_feature.mm b/ios/web/test/fakes/fake_java_script_feature.mm index 12a753d..478ded8 100644 --- a/ios/web/test/fakes/fake_java_script_feature.mm +++ b/ios/web/test/fakes/fake_java_script_feature.mm
@@ -78,9 +78,9 @@ base::TimeDelta::FromSeconds(kGetErrorCountTimeout)); } -std::vector<std::string> FakeJavaScriptFeature::GetScriptMessageHandlerNames() +base::Optional<std::string> FakeJavaScriptFeature::GetScriptMessageHandlerName() const { - return {std::string(kFakeJavaScriptFeatureScriptHandlerName)}; + return std::string(kFakeJavaScriptFeatureScriptHandlerName); } void FakeJavaScriptFeature::ScriptMessageReceived(BrowserState* browser_state,
diff --git a/ipc/ipc_channel_mojo.cc b/ipc/ipc_channel_mojo.cc index 1537642..d2db77cd6 100644 --- a/ipc/ipc_channel_mojo.cc +++ b/ipc/ipc_channel_mojo.cc
@@ -27,6 +27,7 @@ #include "ipc/ipc_mojo_handle_attachment.h" #include "ipc/native_handle_type_converters.h" #include "ipc/trace_ipc_message.h" +#include "mojo/public/cpp/bindings/associated_receiver.h" #include "mojo/public/cpp/bindings/associated_remote.h" #include "mojo/public/cpp/bindings/lib/message_quota_checker.h" #include "mojo/public/cpp/bindings/pending_associated_receiver.h"
diff --git a/ipc/ipc_sync_message_filter.cc b/ipc/ipc_sync_message_filter.cc index 113f989..a6c8e9a 100644 --- a/ipc/ipc_sync_message_filter.cc +++ b/ipc/ipc_sync_message_filter.cc
@@ -13,7 +13,7 @@ #include "base/threading/thread_task_runner_handle.h" #include "ipc/ipc_channel.h" #include "ipc/ipc_sync_message.h" -#include "mojo/public/cpp/bindings/associated_interface_ptr.h" +#include "mojo/public/cpp/bindings/associated_receiver.h" #include "mojo/public/cpp/bindings/sync_handle_registry.h" namespace IPC {
diff --git a/media/audio/audio_opus_encoder.cc b/media/audio/audio_opus_encoder.cc index 1ee0f8b5..52f89fd 100644 --- a/media/audio/audio_opus_encoder.cc +++ b/media/audio/audio_opus_encoder.cc
@@ -220,15 +220,18 @@ // timestamp for the next audio sample. It means there is a gap/overlap, // if it's big enough we flash and start anew, otherwise we ignore it. auto capture_ts = ComputeTimestamp(audio_bus.frames(), capture_time); - auto end_of_existing_buffer_ts = - next_timestamp_ + - AudioTimestampHelper::FramesToTime(fifo_.queued_frames(), - audio_input_params().sample_rate()); + auto existing_buffer_duration = AudioTimestampHelper::FramesToTime( + fifo_.queued_frames(), audio_input_params().sample_rate()); + auto end_of_existing_buffer_ts = next_timestamp_ + existing_buffer_duration; base::TimeDelta gap = (capture_ts - end_of_existing_buffer_ts).magnitude(); constexpr base::TimeDelta max_gap = base::TimeDelta::FromMilliseconds(1); if (gap > max_gap) { - DLOG(ERROR) << "Large gap in sound. Forced flush. " - << "Gap/overlap duration: " << gap; + DLOG(ERROR) << "Large gap in sound. Forced flush." + << " Gap/overlap duration: " << gap + << " capture_ts: " << capture_ts + << " next_timestamp_: " << next_timestamp_ + << " existing_buffer_duration: " << existing_buffer_duration + << " end_of_existing_buffer_ts: " << end_of_existing_buffer_ts; FlushImpl(); next_timestamp_ = capture_ts; }
diff --git a/media/gpu/android/direct_shared_image_video_provider.cc b/media/gpu/android/direct_shared_image_video_provider.cc index 2a70088..11efbbe4 100644 --- a/media/gpu/android/direct_shared_image_video_provider.cc +++ b/media/gpu/android/direct_shared_image_video_provider.cc
@@ -64,10 +64,11 @@ // TODO(liberato): add a thread hop to create the default texture owner, but // not as part of this class. just post something from VideoFrameFactory. void DirectSharedImageVideoProvider::Initialize(GpuInitCB gpu_init_cb) { - // Note that we do not BindToCurrentLoop |gpu_init_cb|, since it is supposed - // to be called on the gpu main thread, which is somewhat hacky. - gpu_factory_.Post(FROM_HERE, &GpuSharedImageVideoFactory::Initialize, - std::move(gpu_init_cb)); + // Note that we do use not `AsyncCall()` + `Then()` to call `gpu_init_cb`, + // since it is supposed to be called on the gpu main thread, which is somewhat + // hacky. + gpu_factory_.AsyncCall(&GpuSharedImageVideoFactory::Initialize) + .WithArgs(std::move(gpu_init_cb)); } void DirectSharedImageVideoProvider::RequestImage( @@ -83,9 +84,11 @@ // group anyway. The thing that owns buffer management is all we really // care about, and that doesn't have anything to do with GLImage. - gpu_factory_.Post(FROM_HERE, &GpuSharedImageVideoFactory::CreateImage, - BindToCurrentLoop(std::move(cb)), spec, - std::move(texture_owner)); + // Note: `cb` is only run on successful creation, so this does not use + // `AsyncCall()` + `Then()` to chain the callbacks. + gpu_factory_.AsyncCall(&GpuSharedImageVideoFactory::CreateImage) + .WithArgs(BindToCurrentLoop(std::move(cb)), spec, + std::move(texture_owner)); } GpuSharedImageVideoFactory::GpuSharedImageVideoFactory(
diff --git a/media/gpu/android/frame_info_helper.cc b/media/gpu/android/frame_info_helper.cc index cf18f96..6d4b209 100644 --- a/media/gpu/android/frame_info_helper.cc +++ b/media/gpu/android/frame_info_helper.cc
@@ -196,8 +196,8 @@ base::BindOnce(&FrameInfoHelperImpl::OnFrameInfoReady, weak_factory_.GetWeakPtr())); - on_gpu_.Post(FROM_HERE, &OnGpu::GetFrameInfo, - std::move(request.buffer_renderer), std::move(cb)); + on_gpu_.AsyncCall(&OnGpu::GetFrameInfo) + .WithArgs(std::move(request.buffer_renderer), std::move(cb)); // We didn't complete this request quite yet, so we can't process queue // any further. break;
diff --git a/media/gpu/android/maybe_render_early_manager.cc b/media/gpu/android/maybe_render_early_manager.cc index 84c2b9c..3ba450a3 100644 --- a/media/gpu/android/maybe_render_early_manager.cc +++ b/media/gpu/android/maybe_render_early_manager.cc
@@ -89,18 +89,18 @@ // Give the image group to |gpu_impl_|. Note that we don't drop our ref to // |image_group| on this thread. It can only be constructed here. - gpu_impl_.Post(FROM_HERE, &GpuMaybeRenderEarlyImpl::SetCodecImageGroup, - std::move(image_group)); + gpu_impl_.AsyncCall(&GpuMaybeRenderEarlyImpl::SetCodecImageGroup) + .WithArgs(std::move(image_group)); } void AddCodecImage( scoped_refptr<CodecImageHolder> codec_image_holder) override { - gpu_impl_.Post(FROM_HERE, &GpuMaybeRenderEarlyImpl::AddCodecImage, - std::move(codec_image_holder)); + gpu_impl_.AsyncCall(&GpuMaybeRenderEarlyImpl::AddCodecImage) + .WithArgs(std::move(codec_image_holder)); } void MaybeRenderEarly() override { - gpu_impl_.Post(FROM_HERE, &GpuMaybeRenderEarlyImpl::MaybeRenderEarly); + gpu_impl_.AsyncCall(&GpuMaybeRenderEarlyImpl::MaybeRenderEarly); } private:
diff --git a/media/gpu/android/pooled_shared_image_video_provider.cc b/media/gpu/android/pooled_shared_image_video_provider.cc index f46a8ca0..a4b10ff 100644 --- a/media/gpu/android/pooled_shared_image_video_provider.cc +++ b/media/gpu/android/pooled_shared_image_video_provider.cc
@@ -122,11 +122,11 @@ const gpu::SyncToken& sync_token) { // An image has been returned to us. Wait for |sync_token| and then send it // to ProcessFreePooledImage to re-use / pool / delete. - gpu_helper_.Post(FROM_HERE, &GpuHelper::OnImageReturned, sync_token, - pooled_image->record.codec_image_holder, - BindToCurrentLoop(base::BindOnce( - &PooledSharedImageVideoProvider::ProcessFreePooledImage, - weak_factory_.GetWeakPtr(), pooled_image))); + gpu_helper_.AsyncCall(&GpuHelper::OnImageReturned) + .WithArgs(sync_token, pooled_image->record.codec_image_holder, + BindToCurrentLoop(base::BindOnce( + &PooledSharedImageVideoProvider::ProcessFreePooledImage, + weak_factory_.GetWeakPtr(), pooled_image))); } void PooledSharedImageVideoProvider::ProcessFreePooledImage(
diff --git a/media/gpu/windows/d3d11_texture_wrapper.cc b/media/gpu/windows/d3d11_texture_wrapper.cc index 4fa6fd72..d06737ca 100644 --- a/media/gpu/windows/d3d11_texture_wrapper.cc +++ b/media/gpu/windows/d3d11_texture_wrapper.cc
@@ -165,10 +165,10 @@ // device for decoding. Sharing seems not to work very well. Otherwise, we // would create the texture with KEYED_MUTEX and NTHANDLE, then send along // a handle that we get from |texture| as an IDXGIResource1. - gpu_resources_.Post(FROM_HERE, &GpuResources::Init, std::move(get_helper_cb), - std::move(mailboxes), GL_TEXTURE_EXTERNAL_OES, size_, - textures_per_picture, texture_formats, pixel_format_, - texture, array_slice); + gpu_resources_.AsyncCall(&GpuResources::Init) + .WithArgs(std::move(get_helper_cb), std::move(mailboxes), + GL_TEXTURE_EXTERNAL_OES, size_, textures_per_picture, + texture_formats, pixel_format_, texture, array_slice); return OkStatus(); }
diff --git a/media/gpu/windows/d3d11_video_decoder.cc b/media/gpu/windows/d3d11_video_decoder.cc index 669ae99..d0468591 100644 --- a/media/gpu/windows/d3d11_video_decoder.cc +++ b/media/gpu/windows/d3d11_video_decoder.cc
@@ -453,8 +453,8 @@ // the originals on some other thread. // Important but subtle note: base::Bind will copy |config_| since it's a // const ref. - impl_.Post(FROM_HERE, &D3D11VideoDecoderImpl::Initialize, - BindToCurrentLoop(std::move(impl_init_cb))); + impl_.AsyncCall(&D3D11VideoDecoderImpl::Initialize) + .WithArgs(BindToCurrentLoop(std::move(impl_init_cb))); } void D3D11VideoDecoder::AddLifetimeProgressionStage(
diff --git a/media/test/pipeline_integration_test.cc b/media/test/pipeline_integration_test.cc index 5a3d8c1..b91e21c 100644 --- a/media/test/pipeline_integration_test.cc +++ b/media/test/pipeline_integration_test.cc
@@ -448,6 +448,25 @@ public testing::WithParamInterface<PlaybackTestData> { }; +TEST_P(BasicPlaybackTest, PlayToEnd) { + PlaybackTestData data = GetParam(); + + ASSERT_EQ(PIPELINE_OK, Start(data.filename, kUnreliableDuration)); + EXPECT_EQ(data.start_time_ms, demuxer_->GetStartTime().InMilliseconds()); + EXPECT_EQ(data.duration_ms, pipeline_->GetMediaDuration().InMilliseconds()); + + Play(); + ASSERT_TRUE(WaitUntilOnEnded()); +} + +const PlaybackTestData kOpenCodecsTests[] = {{"bear-vp9-i422.webm", 0, 2736}}; + +INSTANTIATE_TEST_SUITE_P(OpenCodecs, + BasicPlaybackTest, + testing::ValuesIn(kOpenCodecsTests)); + +#if BUILDFLAG(USE_PROPRIETARY_CODECS) + class BasicMSEPlaybackTest : public ::testing::WithParamInterface<MSEPlaybackTestData>, public PipelineIntegrationTest { @@ -475,29 +494,10 @@ } }; -TEST_P(BasicPlaybackTest, PlayToEnd) { - PlaybackTestData data = GetParam(); - - ASSERT_EQ(PIPELINE_OK, Start(data.filename, kUnreliableDuration)); - EXPECT_EQ(data.start_time_ms, demuxer_->GetStartTime().InMilliseconds()); - EXPECT_EQ(data.duration_ms, pipeline_->GetMediaDuration().InMilliseconds()); - - Play(); - ASSERT_TRUE(WaitUntilOnEnded()); -} - TEST_P(BasicMSEPlaybackTest, PlayToEnd) { PlayToEnd(); } -const PlaybackTestData kOpenCodecsTests[] = {{"bear-vp9-i422.webm", 0, 2736}}; - -INSTANTIATE_TEST_SUITE_P(OpenCodecs, - BasicPlaybackTest, - testing::ValuesIn(kOpenCodecsTests)); - -#if BUILDFLAG(USE_PROPRIETARY_CODECS) - const PlaybackTestData kADTSTests[] = { {"bear-audio-main-aac.aac", 0, 2708}, {"bear-audio-lc-aac.aac", 0, 2791},
diff --git a/mojo/public/cpp/bindings/BUILD.gn b/mojo/public/cpp/bindings/BUILD.gn index 3e04090..af1b7eb 100644 --- a/mojo/public/cpp/bindings/BUILD.gn +++ b/mojo/public/cpp/bindings/BUILD.gn
@@ -57,8 +57,6 @@ "lib/bindings_internal.h", "lib/buffer.cc", "lib/buffer.h", - "lib/fixed_buffer.cc", - "lib/fixed_buffer.h", "lib/handle_serialization.cc", "lib/handle_serialization.h", "lib/hash_util.h", @@ -128,7 +126,6 @@ component("bindings") { sources = [ - "associated_interface_ptr.h", "associated_interface_ptr_info.h", "associated_interface_request.h", "associated_receiver.h", @@ -147,7 +144,6 @@ "interface_ptr.h", "interface_ptr_info.h", "interface_request.h", - "lib/associated_interface_ptr.cc", "lib/associated_interface_ptr_state.cc", "lib/associated_interface_ptr_state.h", "lib/associated_receiver.cc",
diff --git a/mojo/public/cpp/bindings/associated_interface_ptr.h b/mojo/public/cpp/bindings/associated_interface_ptr.h deleted file mode 100644 index 956138c4..0000000 --- a/mojo/public/cpp/bindings/associated_interface_ptr.h +++ /dev/null
@@ -1,266 +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. - -#ifndef MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_INTERFACE_PTR_H_ -#define MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_INTERFACE_PTR_H_ - -#include <stdint.h> - -#include <cstddef> -#include <string> -#include <utility> - -#include "base/callback.h" -#include "base/check.h" -#include "base/component_export.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/sequenced_task_runner.h" -#include "mojo/public/cpp/bindings/associated_interface_ptr_info.h" -#include "mojo/public/cpp/bindings/associated_interface_request.h" -#include "mojo/public/cpp/bindings/connection_error_callback.h" -#include "mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h" -#include "mojo/public/cpp/bindings/lib/multiplex_router.h" -#include "mojo/public/cpp/system/message_pipe.h" - -namespace mojo { - -// DEPRECATED: Do not introduce new uses of this type. Instead use the -// AssociatedRemote type defined in associated_remote.h. -// -// Represents the client side of an associated interface. It is similar to -// InterfacePtr, except that it doesn't own a message pipe handle. -template <typename Interface> -class AssociatedInterfacePtr { - public: - using InterfaceType = Interface; - using PtrInfoType = AssociatedInterfacePtrInfo<Interface>; - using Proxy = typename Interface::Proxy_; - - // Constructs an unbound AssociatedInterfacePtr. - AssociatedInterfacePtr() {} - AssociatedInterfacePtr(std::nullptr_t) {} - - AssociatedInterfacePtr(AssociatedInterfacePtr&& other) { - internal_state_.Swap(&other.internal_state_); - } - - explicit AssociatedInterfacePtr(PtrInfoType&& info) { Bind(std::move(info)); } - - AssociatedInterfacePtr& operator=(AssociatedInterfacePtr&& other) { - reset(); - internal_state_.Swap(&other.internal_state_); - return *this; - } - - // Assigning nullptr to this class causes it to closes the associated - // interface (if any) and returns the pointer to the unbound state. - AssociatedInterfacePtr& operator=(std::nullptr_t) { - reset(); - return *this; - } - - ~AssociatedInterfacePtr() {} - - // Sets up this object as the client side of an associated interface. - // Calling with an invalid |info| has the same effect as reset(). In this - // case, the AssociatedInterfacePtr is not considered as bound. - // - // Optionally, |runner| is a SequencedTaskRunner bound to the current sequence - // on which all callbacks and connection error notifications will be - // dispatched. It is only useful to specify this to use a different - // SequencedTaskRunner than SequencedTaskRunnerHandle::Get(). - // - // NOTE: The corresponding AssociatedInterfaceRequest must be sent over - // another interface before using this object to make calls. Please see the - // comments of MakeRequest(AssociatedInterfacePtr<Interface>*) for more - // details. - void Bind(AssociatedInterfacePtrInfo<Interface> info, - scoped_refptr<base::SequencedTaskRunner> runner = nullptr) { - reset(); - - if (info.is_valid()) - internal_state_.Bind(std::move(info), std::move(runner)); - } - - bool is_bound() const { return internal_state_.is_bound(); } - - Proxy* get() const { return internal_state_.instance(); } - - // Functions like a pointer to Interface. Must already be bound. - Proxy* operator->() const { return get(); } - Proxy& operator*() const { return *get(); } - - // Returns the version number of the interface that the remote side supports. - uint32_t version() const { return internal_state_.version(); } - - // Queries the max version that the remote side supports. On completion, the - // result will be returned as the input of |callback|. The version number of - // this object will also be updated. - void QueryVersion(base::OnceCallback<void(uint32_t)> callback) { - internal_state_.QueryVersion(std::move(callback)); - } - - // If the remote side doesn't support the specified version, it will close the - // associated interface asynchronously. This does nothing if it's already - // known that the remote side supports the specified version, i.e., if - // |version <= this->version()|. - // - // After calling RequireVersion() with a version not supported by the remote - // side, all subsequent calls to interface methods will be ignored. - void RequireVersion(uint32_t version) { - internal_state_.RequireVersion(version); - } - - // Sends a message on the underlying message pipe and runs the current - // message loop until its response is received. This can be used in tests to - // verify that no message was sent on a message pipe in response to some - // stimulus. - void FlushForTesting() { internal_state_.FlushForTesting(); } - - // Closes the associated interface (if any) and returns the pointer to the - // unbound state. - void reset() { - State doomed; - internal_state_.Swap(&doomed); - } - - // Similar to the method above, but also specifies a disconnect reason. - void ResetWithReason(uint32_t custom_reason, const std::string& description) { - if (internal_state_.is_bound()) - internal_state_.CloseWithReason(custom_reason, description); - reset(); - } - - // Indicates whether an error has been encountered. If true, method calls made - // on this interface will be dropped (and may already have been dropped). - bool encountered_error() const { return internal_state_.encountered_error(); } - - // Registers a handler to receive error notifications. - // - // This method may only be called after the AssociatedInterfacePtr has been - // bound. - void set_connection_error_handler(base::OnceClosure error_handler) { - internal_state_.set_connection_error_handler(std::move(error_handler)); - } - - void set_connection_error_with_reason_handler( - ConnectionErrorWithReasonCallback error_handler) { - internal_state_.set_connection_error_with_reason_handler( - std::move(error_handler)); - } - - // Unbinds and returns the associated interface pointer information which - // could be used to setup an AssociatedInterfacePtr again. This method may be - // used to move the proxy to a different sequence. - // - // It is an error to call PassInterface() while there are pending responses. - // TODO: fix this restriction, it's not always obvious when there is a - // pending response. - AssociatedInterfacePtrInfo<Interface> PassInterface() { - DCHECK(!internal_state_.has_pending_callbacks()); - State state; - internal_state_.Swap(&state); - - return state.PassInterface(); - } - - // DO NOT USE. Exposed only for internal use and for testing. - internal::AssociatedInterfacePtrState<Interface>* internal_state() { - return &internal_state_; - } - - // Allow AssociatedInterfacePtr<> to be used in boolean expressions. - explicit operator bool() const { return internal_state_.is_bound(); } - - private: - typedef internal::AssociatedInterfacePtrState<Interface> State; - mutable State internal_state_; - - DISALLOW_COPY_AND_ASSIGN(AssociatedInterfacePtr); -}; - -// Creates an associated interface. The returned request is supposed to be sent -// over another interface (either associated or non-associated). -// -// NOTE: |ptr| must NOT be used to make calls before the request is sent. -// Violating that will lead to crash. On the other hand, as soon as the request -// is sent, |ptr| is usable. There is no need to wait until the request is bound -// to an implementation at the remote side. -template <typename Interface> -AssociatedInterfaceRequest<Interface> MakeRequest( - AssociatedInterfacePtr<Interface>* ptr, - scoped_refptr<base::SequencedTaskRunner> runner = nullptr) { - AssociatedInterfacePtrInfo<Interface> ptr_info; - auto request = MakeRequest(&ptr_info); - ptr->Bind(std::move(ptr_info), std::move(runner)); - return request; -} - -// Creates an associated interface. One of the two endpoints is supposed to be -// sent over another interface (either associated or non-associated); while the -// other is used locally. -// -// NOTE: If |ptr_info| is used locally and bound to an AssociatedInterfacePtr, -// the interface pointer must NOT be used to make calls before the request is -// sent. Please see NOTE of the previous function for more details. -template <typename Interface> -AssociatedInterfaceRequest<Interface> MakeRequest( - AssociatedInterfacePtrInfo<Interface>* ptr_info) { - ScopedInterfaceEndpointHandle handle0; - ScopedInterfaceEndpointHandle handle1; - ScopedInterfaceEndpointHandle::CreatePairPendingAssociation(&handle0, - &handle1); - - ptr_info->set_handle(std::move(handle0)); - ptr_info->set_version(0); - - return AssociatedInterfaceRequest<Interface>(std::move(handle1)); -} - -// Like MakeRequest() above, but it creates a dedicated message pipe. The -// returned request can be bound directly to an implementation, without being -// first passed through a message pipe endpoint. -// -// This function has two main uses: -// -// * In testing, where the returned request is bound to e.g. a mock and there -// are no other interfaces involved. -// -// * When discarding messages sent on an interface, which can be done by -// discarding the returned request. -template <typename Interface> -AssociatedInterfaceRequest<Interface> MakeRequestAssociatedWithDedicatedPipe( - AssociatedInterfacePtr<Interface>* ptr) { - MessagePipe pipe; - scoped_refptr<internal::MultiplexRouter> router0 = - new internal::MultiplexRouter( - std::move(pipe.handle0), internal::MultiplexRouter::MULTI_INTERFACE, - false, base::SequencedTaskRunnerHandle::Get()); - scoped_refptr<internal::MultiplexRouter> router1 = - new internal::MultiplexRouter( - std::move(pipe.handle1), internal::MultiplexRouter::MULTI_INTERFACE, - true, base::SequencedTaskRunnerHandle::Get()); - - ScopedInterfaceEndpointHandle endpoint0, endpoint1; - ScopedInterfaceEndpointHandle::CreatePairPendingAssociation(&endpoint0, - &endpoint1); - InterfaceId id = router1->AssociateInterface(std::move(endpoint0)); - endpoint0 = router0->CreateLocalEndpointHandle(id); - - ptr->Bind(AssociatedInterfacePtrInfo<Interface>(std::move(endpoint0), - Interface::Version_)); - return AssociatedInterfaceRequest<Interface>(std::move(endpoint1)); -} - -// |handle| is supposed to be the request of an associated interface. This -// method associates the interface with a dedicated, disconnected message pipe. -// That way, the corresponding associated interface pointer of |handle| can -// safely make calls (although those calls are silently dropped). -COMPONENT_EXPORT(MOJO_CPP_BINDINGS) -void AssociateWithDisconnectedPipe(ScopedInterfaceEndpointHandle handle); - -} // namespace mojo - -#endif // MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_INTERFACE_PTR_H_
diff --git a/mojo/public/cpp/bindings/associated_receiver.h b/mojo/public/cpp/bindings/associated_receiver.h index 3e0d68c0..92b4c0e 100644 --- a/mojo/public/cpp/bindings/associated_receiver.h +++ b/mojo/public/cpp/bindings/associated_receiver.h
@@ -293,6 +293,13 @@ base::WeakPtrFactory<AssociatedReceiver> weak_ptr_factory_{this}; }; +// Associates |handle| with a dedicated and disconnected message pipe. +// Generally, |handle| should be the receiving side of an entangled +// AssociatedReceiver/AssociatedRemote pair, which allows the AssociatedRemote +// to be used to make calls that will be silently dropped. +COMPONENT_EXPORT(MOJO_CPP_BINDINGS) +void AssociateWithDisconnectedPipe(ScopedInterfaceEndpointHandle handle); + } // namespace mojo #endif // MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_RECEIVER_H_
diff --git a/mojo/public/cpp/bindings/deprecated_interface_types_forward.h b/mojo/public/cpp/bindings/deprecated_interface_types_forward.h index d5fae3b5..46a4908 100644 --- a/mojo/public/cpp/bindings/deprecated_interface_types_forward.h +++ b/mojo/public/cpp/bindings/deprecated_interface_types_forward.h
@@ -15,8 +15,6 @@ template <typename Interface> class InterfaceRequest; template <typename Interface> -class AssociatedInterfacePtr; -template <typename Interface> class AssociatedInterfacePtrInfo; template <typename Interface> class AssociatedInterfaceRequest;
diff --git a/mojo/public/cpp/bindings/lib/associated_interface_ptr.cc b/mojo/public/cpp/bindings/lib/associated_interface_ptr.cc deleted file mode 100644 index 453e47a..0000000 --- a/mojo/public/cpp/bindings/lib/associated_interface_ptr.cc +++ /dev/null
@@ -1,18 +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 "mojo/public/cpp/bindings/associated_interface_ptr.h" - -namespace mojo { - -void AssociateWithDisconnectedPipe(ScopedInterfaceEndpointHandle handle) { - MessagePipe pipe; - scoped_refptr<internal::MultiplexRouter> router = - new internal::MultiplexRouter( - std::move(pipe.handle0), internal::MultiplexRouter::MULTI_INTERFACE, - false, base::SequencedTaskRunnerHandle::Get()); - router->AssociateInterface(std::move(handle)); -} - -} // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/associated_receiver.cc b/mojo/public/cpp/bindings/lib/associated_receiver.cc index 060aa85..a1c1d80 100644 --- a/mojo/public/cpp/bindings/lib/associated_receiver.cc +++ b/mojo/public/cpp/bindings/lib/associated_receiver.cc
@@ -5,7 +5,9 @@ #include "mojo/public/cpp/bindings/associated_receiver.h" #include "base/sequenced_task_runner.h" +#include "mojo/public/cpp/bindings/lib/multiplex_router.h" #include "mojo/public/cpp/bindings/lib/task_runner_helper.h" +#include "mojo/public/cpp/system/message_pipe.h" namespace mojo { @@ -67,4 +69,13 @@ } // namespace internal +void AssociateWithDisconnectedPipe(ScopedInterfaceEndpointHandle handle) { + MessagePipe pipe; + scoped_refptr<internal::MultiplexRouter> router = + new internal::MultiplexRouter( + std::move(pipe.handle0), internal::MultiplexRouter::MULTI_INTERFACE, + false, base::SequencedTaskRunnerHandle::Get()); + router->AssociateInterface(std::move(handle)); +} + } // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/fixed_buffer.cc b/mojo/public/cpp/bindings/lib/fixed_buffer.cc deleted file mode 100644 index 3d595cc0..0000000 --- a/mojo/public/cpp/bindings/lib/fixed_buffer.cc +++ /dev/null
@@ -1,22 +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. - -#include "mojo/public/cpp/bindings/lib/fixed_buffer.h" - -#include <stdlib.h> - -#include "mojo/public/cpp/bindings/lib/bindings_internal.h" - -namespace mojo { -namespace internal { - -FixedBufferForTesting::FixedBufferForTesting(size_t size) - : Buffer(calloc(Align(size), 1), Align(size), 0) {} - -FixedBufferForTesting::~FixedBufferForTesting() { - free(data()); -} - -} // namespace internal -} // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/fixed_buffer.h b/mojo/public/cpp/bindings/lib/fixed_buffer.h deleted file mode 100644 index 147ce7b..0000000 --- a/mojo/public/cpp/bindings/lib/fixed_buffer.h +++ /dev/null
@@ -1,32 +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. - -#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_FIXED_BUFFER_H_ -#define MOJO_PUBLIC_CPP_BINDINGS_LIB_FIXED_BUFFER_H_ - -#include <cstddef> - -#include "base/component_export.h" -#include "base/macros.h" -#include "mojo/public/cpp/bindings/lib/buffer.h" - -namespace mojo { -namespace internal { - -// FixedBufferForTesting owns its buffer. The Leak method may be used to steal -// the underlying memory. -class COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE) FixedBufferForTesting - : public Buffer { - public: - explicit FixedBufferForTesting(size_t size); - ~FixedBufferForTesting(); - - private: - DISALLOW_COPY_AND_ASSIGN(FixedBufferForTesting); -}; - -} // namespace internal -} // namespace mojo - -#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_FIXED_BUFFER_H_
diff --git a/mojo/public/cpp/bindings/tests/BUILD.gn b/mojo/public/cpp/bindings/tests/BUILD.gn index 459a4dc..37692a4 100644 --- a/mojo/public/cpp/bindings/tests/BUILD.gn +++ b/mojo/public/cpp/bindings/tests/BUILD.gn
@@ -13,7 +13,6 @@ "binder_map_unittest.cc", "bindings_test_base.cc", "bindings_test_base.h", - "buffer_unittest.cc", "callback_helpers_unittest.cc", "connection_group_unittest.cc", "connector_unittest.cc",
diff --git a/mojo/public/cpp/bindings/tests/buffer_unittest.cc b/mojo/public/cpp/bindings/tests/buffer_unittest.cc deleted file mode 100644 index 2370454b..0000000 --- a/mojo/public/cpp/bindings/tests/buffer_unittest.cc +++ /dev/null
@@ -1,33 +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. - -#include <stddef.h> - -#include <limits> - -#include "mojo/public/cpp/bindings/lib/fixed_buffer.h" -#include "mojo/public/cpp/bindings/lib/serialization_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace mojo { -namespace test { -namespace { - -// Tests that FixedBuffer allocates memory aligned to 8 byte boundaries. -TEST(FixedBufferTest, Alignment) { - internal::FixedBufferForTesting buf(internal::Align(10) * 2); - ASSERT_EQ(buf.size(), 16u * 2); - - size_t a = buf.Allocate(10); - EXPECT_EQ(0u, a); - - size_t b = buf.Allocate(10); - ASSERT_EQ(16u, b); - - // Any more allocations would result in an assert, but we can't test that. -} - -} // namespace -} // namespace test -} // namespace mojo
diff --git a/mojo/public/cpp/bindings/tests/data_view_unittest.cc b/mojo/public/cpp/bindings/tests/data_view_unittest.cc index f5628d1..701c5c1e 100644 --- a/mojo/public/cpp/bindings/tests/data_view_unittest.cc +++ b/mojo/public/cpp/bindings/tests/data_view_unittest.cc
@@ -8,7 +8,6 @@ #include <vector> #include "base/test/task_environment.h" -#include "mojo/public/cpp/bindings/lib/fixed_buffer.h" #include "mojo/public/cpp/bindings/lib/serialization.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/receiver.h"
diff --git a/mojo/public/cpp/bindings/tests/enum_headers_unittest.cc b/mojo/public/cpp/bindings/tests/enum_headers_unittest.cc index d69d738..2a71a79 100644 --- a/mojo/public/cpp/bindings/tests/enum_headers_unittest.cc +++ b/mojo/public/cpp/bindings/tests/enum_headers_unittest.cc
@@ -19,11 +19,6 @@ for a mojom containing only an enum. #endif -#ifdef MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_INTERFACE_PTR_H_ -#error associated_interface_ptr.h should not be included by the generated \ - header for a mojom containing only an enum. -#endif - #ifdef MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_REQUEST_H_ #error interface_request.h should not be included by the generated header \ for a mojom containing only an enum.
diff --git a/mojo/public/cpp/bindings/tests/serialization_warning_unittest.cc b/mojo/public/cpp/bindings/tests/serialization_warning_unittest.cc index 75b5841..38c18ca 100644 --- a/mojo/public/cpp/bindings/tests/serialization_warning_unittest.cc +++ b/mojo/public/cpp/bindings/tests/serialization_warning_unittest.cc
@@ -9,7 +9,6 @@ #include <utility> #include "mojo/public/cpp/bindings/lib/array_internal.h" -#include "mojo/public/cpp/bindings/lib/fixed_buffer.h" #include "mojo/public/cpp/bindings/lib/serialization.h" #include "mojo/public/cpp/bindings/lib/validation_errors.h" #include "mojo/public/cpp/system/message_pipe.h"
diff --git a/mojo/public/cpp/bindings/tests/struct_headers_unittest.cc b/mojo/public/cpp/bindings/tests/struct_headers_unittest.cc index d711870..e15caf3 100644 --- a/mojo/public/cpp/bindings/tests/struct_headers_unittest.cc +++ b/mojo/public/cpp/bindings/tests/struct_headers_unittest.cc
@@ -19,11 +19,6 @@ for a mojom containing only a struct. #endif -#ifdef MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_INTERFACE_PTR_H_ -#error associated_interface_ptr.h should not be included by the generated \ - header for a mojom containing only a struct. -#endif - #ifdef MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_REQUEST_H_ #error interface_request.h should not be included by the generated header \ for a mojom containing only a struct.
diff --git a/mojo/public/cpp/bindings/tests/struct_unittest.cc b/mojo/public/cpp/bindings/tests/struct_unittest.cc index 7fdec87..04b4ff0 100644 --- a/mojo/public/cpp/bindings/tests/struct_unittest.cc +++ b/mojo/public/cpp/bindings/tests/struct_unittest.cc
@@ -7,7 +7,6 @@ #include <string.h> #include <utility> -#include "mojo/public/cpp/bindings/lib/fixed_buffer.h" #include "mojo/public/cpp/system/message_pipe.h" #include "mojo/public/interfaces/bindings/tests/test_export2.mojom.h" #include "mojo/public/interfaces/bindings/tests/test_structs.mojom.h"
diff --git a/mojo/public/cpp/bindings/tests/union_unittest.cc b/mojo/public/cpp/bindings/tests/union_unittest.cc index 6326f71..096bd33 100644 --- a/mojo/public/cpp/bindings/tests/union_unittest.cc +++ b/mojo/public/cpp/bindings/tests/union_unittest.cc
@@ -12,7 +12,6 @@ #include "base/run_loop.h" #include "base/test/task_environment.h" #include "mojo/public/cpp/bindings/lib/array_internal.h" -#include "mojo/public/cpp/bindings/lib/fixed_buffer.h" #include "mojo/public/cpp/bindings/lib/serialization.h" #include "mojo/public/cpp/bindings/lib/validation_context.h" #include "mojo/public/cpp/bindings/lib/validation_errors.h" @@ -287,13 +286,15 @@ TEST(UnionTest, SerializeIsNullInlined) { PodUnionPtr pod; - Message message; - mojo::internal::FixedBufferForTesting buffer(16); + Message message(0, 0, 0, 0, nullptr); + mojo::internal::Buffer& buffer = *message.payload_buffer(); + EXPECT_EQ(sizeof(mojo::internal::MessageHeader), buffer.cursor()); + internal::PodUnion_Data::BufferWriter writer; writer.Allocate(&buffer); mojo::internal::Serialize<PodUnionDataView>(pod, &writer, true, &message); EXPECT_TRUE(writer.data()->is_null()); - EXPECT_EQ(16U, buffer.cursor()); + EXPECT_EQ(16U + sizeof(mojo::internal::MessageHeader), buffer.cursor()); PodUnionPtr pod2; mojo::internal::Deserialize<PodUnionDataView>(writer.data(), &pod2, nullptr); @@ -423,7 +424,8 @@ TEST(UnionTest, NullStringValidation) { constexpr size_t size = sizeof(internal::ObjectUnion_Data); - mojo::internal::FixedBufferForTesting buffer(size); + Message message(0, 0, 0, 0, nullptr); + mojo::internal::Buffer& buffer = *message.payload_buffer(); internal::ObjectUnion_Data::BufferWriter writer; writer.Allocate(&buffer); writer->tag = internal::ObjectUnion_Data::ObjectUnion_Tag::F_STRING; @@ -436,7 +438,8 @@ TEST(UnionTest, StringPointerOverflowValidation) { constexpr size_t size = sizeof(internal::ObjectUnion_Data); - mojo::internal::FixedBufferForTesting buffer(size); + Message message(0, 0, 0, 0, nullptr); + mojo::internal::Buffer& buffer = *message.payload_buffer(); internal::ObjectUnion_Data::BufferWriter writer; writer.Allocate(&buffer); writer->tag = internal::ObjectUnion_Data::ObjectUnion_Tag::F_STRING; @@ -448,8 +451,8 @@ } TEST(UnionTest, StringValidateOOB) { - constexpr size_t size = 32; - mojo::internal::FixedBufferForTesting buffer(size); + Message message(0, 0, 0, 0, nullptr); + mojo::internal::Buffer& buffer = *message.payload_buffer(); internal::ObjectUnion_Data::BufferWriter writer; writer.Allocate(&buffer); writer->tag = internal::ObjectUnion_Data::ObjectUnion_Tag::F_STRING; @@ -643,8 +646,8 @@ SmallStructNonNullableUnion::New()); constexpr size_t size = sizeof(internal::SmallStructNonNullableUnion_Data); - mojo::internal::FixedBufferForTesting buffer(size); - mojo::Message message; + Message message(0, 0, 0, 0, nullptr); + mojo::internal::Buffer& buffer = *message.payload_buffer(); internal::SmallStructNonNullableUnion_Data::BufferWriter writer; writer.Allocate(&buffer); mojo::internal::ValidationContext validation_context(
diff --git a/mojo/public/cpp/bindings/tests/wtf_types_unittest.cc b/mojo/public/cpp/bindings/tests/wtf_types_unittest.cc index 3f9614e..b439ecf 100644 --- a/mojo/public/cpp/bindings/tests/wtf_types_unittest.cc +++ b/mojo/public/cpp/bindings/tests/wtf_types_unittest.cc
@@ -6,7 +6,6 @@ #include "base/run_loop.h" #include "base/stl_util.h" #include "base/test/task_environment.h" -#include "mojo/public/cpp/bindings/lib/fixed_buffer.h" #include "mojo/public/cpp/bindings/lib/serialization.h" #include "mojo/public/cpp/bindings/lib/wtf_serialization.h" #include "mojo/public/cpp/bindings/receiver.h"
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module-forward.h.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module-forward.h.tmpl index 627293e..807845a 100644 --- a/mojo/public/tools/bindings/generators/cpp_templates/module-forward.h.tmpl +++ b/mojo/public/tools/bindings/generators/cpp_templates/module-forward.h.tmpl
@@ -180,9 +180,6 @@ using {{interface.name}}PtrInfo = mojo::InterfacePtrInfo<{{interface.name}}>; {{ kythe_annotation("%s.%s"|format(module_prefix, interface.name)) }} using {{interface.name}}Request = mojo::InterfaceRequest<{{interface.name}}>; -{{ kythe_annotation("%s.%s"|format(module_prefix, interface.name)) }} -using {{interface.name}}AssociatedPtr = - mojo::AssociatedInterfacePtr<{{interface.name}}>; using {{interface.name}}AssociatedPtrInfo = mojo::AssociatedInterfacePtrInfo<{{interface.name}}>; {{ kythe_annotation("%s.%s"|format(module_prefix, interface.name)) }}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl index 0c36f12..567eac0 100644 --- a/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl +++ b/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl
@@ -91,7 +91,6 @@ {%- endif %} {% if not disallow_interfaces and uses_interfaces -%} -#include "mojo/public/cpp/bindings/associated_interface_ptr.h" #include "mojo/public/cpp/bindings/associated_interface_ptr_info.h" #include "mojo/public/cpp/bindings/associated_interface_request.h" #include "mojo/public/cpp/bindings/interface_ptr.h"
diff --git a/net/base/network_change_notifier_fuchsia_unittest.cc b/net/base/network_change_notifier_fuchsia_unittest.cc index 138d0192..ca92d80 100644 --- a/net/base/network_change_notifier_fuchsia_unittest.cc +++ b/net/base/network_change_notifier_fuchsia_unittest.cc
@@ -187,17 +187,17 @@ ~FakeWatcherAsync() = default; void Bind(fidl::InterfaceRequest<fuchsia::net::interfaces::Watcher> request) { - watcher_.Post(FROM_HERE, &FakeWatcher::Bind, std::move(request)); + watcher_.AsyncCall(&FakeWatcher::Bind).WithArgs(std::move(request)); } // Asynchronously push an event to the watcher. void PushEvent(fuchsia::net::interfaces::Event event) { - watcher_.Post(FROM_HERE, &FakeWatcher::PushEvent, std::move(event)); + watcher_.AsyncCall(&FakeWatcher::PushEvent).WithArgs(std::move(event)); } // Asynchronously push an initial set of interfaces to the watcher. void SetInitial(std::vector<fuchsia::net::interfaces::Properties> props) { - watcher_.Post(FROM_HERE, &FakeWatcher::SetInitial, std::move(props)); + watcher_.AsyncCall(&FakeWatcher::SetInitial).WithArgs(std::move(props)); } // Asynchronously push an initial single intface to the watcher.
diff --git a/net/http/transport_security_state_static.json b/net/http/transport_security_state_static.json index 2fe00708..4f286b8 100644 --- a/net/http/transport_security_state_static.json +++ b/net/http/transport_security_state_static.json
@@ -307,6 +307,7 @@ { "name": "cloud.google.com", "policy": "google", "mode": "force-https", "include_subdomains": true, "pins": "google" }, { "name": "code.google.com", "policy": "google", "mode": "force-https", "include_subdomains": true, "pins": "google" }, { "name": "contributor.google.com", "policy": "google", "mode": "force-https", "include_subdomains": true, "pins": "google" }, + { "name": "datastudio.google.com", "policy": "google", "mode": "force-https", "include_subdomains": true, "pins": "google" }, { "name": "dl.google.com", "policy": "google", "mode": "force-https", "include_subdomains": true, "pins": "google" }, { "name": "docs.google.com", "policy": "google", "mode": "force-https", "include_subdomains": true, "pins": "google" }, { "name": "domains.google.com", "policy": "google", "mode": "force-https", "include_subdomains": true, "pins": "google" },
diff --git a/net/third_party/quiche/BUILD.gn b/net/third_party/quiche/BUILD.gn index 66b90190..3d7d6db 100644 --- a/net/third_party/quiche/BUILD.gn +++ b/net/third_party/quiche/BUILD.gn
@@ -48,7 +48,6 @@ "src/common/platform/api/quiche_string_piece.h", "src/common/platform/api/quiche_text_utils.h", "src/common/platform/api/quiche_time_utils.h", - "src/common/platform/api/quiche_unordered_containers.h", "src/common/quiche_data_reader.cc", "src/common/quiche_data_reader.h", "src/common/quiche_data_writer.cc", @@ -633,7 +632,6 @@ "src/spdy/platform/api/spdy_estimate_memory_usage.h", "src/spdy/platform/api/spdy_flags.h", "src/spdy/platform/api/spdy_logging.h", - "src/spdy/platform/api/spdy_macros.h", "src/spdy/platform/api/spdy_mem_slice.h", "src/spdy/platform/api/spdy_string_utils.h", ]
diff --git a/printing/backend/cups_ipp_helper.cc b/printing/backend/cups_ipp_helper.cc index 570a3a9..6e66d620 100644 --- a/printing/backend/cups_ipp_helper.cc +++ b/printing/backend/cups_ipp_helper.cc
@@ -336,8 +336,7 @@ #if BUILDFLAG(IS_CHROMEOS_ASH) printer_info->pin_supported = PinSupported(printer); - if (base::FeatureList::IsEnabled(printing::features::kAdvancedPpdAttributes)) - ExtractAdvancedCapabilities(printer, printer_info); + ExtractAdvancedCapabilities(printer, printer_info); #endif // BUILDFLAG(IS_CHROMEOS_ASH) ExtractCopies(printer, printer_info);
diff --git a/printing/backend/cups_ipp_helper_unittest.cc b/printing/backend/cups_ipp_helper_unittest.cc index 683f25b..3a1fb8b 100644 --- a/printing/backend/cups_ipp_helper_unittest.cc +++ b/printing/backend/cups_ipp_helper_unittest.cc
@@ -11,12 +11,9 @@ #include "base/notreached.h" #include "base/test/metrics/histogram_tester.h" -#include "base/test/scoped_feature_list.h" #include "build/build_config.h" -#include "build/chromeos_buildflags.h" #include "printing/backend/cups_printer.h" #include "printing/mojom/print.mojom.h" -#include "printing/printing_features.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -327,8 +324,6 @@ TEST_F(PrintBackendCupsIppHelperTest, AdvancedCaps) { base::HistogramTester histograms; - base::test::ScopedFeatureList features; - features.InitAndEnableFeature(printing::features::kAdvancedPpdAttributes); printer_->SetSupportedOptions( "job-creation-attributes",
diff --git a/printing/printing_context_chromeos.cc b/printing/printing_context_chromeos.cc index 29be6f8..fcba4f00 100644 --- a/printing/printing_context_chromeos.cc +++ b/printing/printing_context_chromeos.cc
@@ -200,38 +200,36 @@ options.push_back(ConstructOption(kIppResolution, dpi + "dpi")); } - if (base::FeatureList::IsEnabled( - printing::features::kAdvancedPpdAttributes)) { - size_t regular_attr_count = options.size(); - std::map<std::string, std::vector<std::string>> multival; - for (const auto& setting : settings.advanced_settings()) { - const std::string& key = setting.first; - const std::string& value = setting.second.GetString(); - if (value.empty()) - continue; + size_t regular_attr_count = options.size(); + std::map<std::string, std::vector<std::string>> multival; + for (const auto& setting : settings.advanced_settings()) { + const std::string& key = setting.first; + const std::string& value = setting.second.GetString(); + if (value.empty()) + continue; - // Check for multivalue enum ("attribute/value"). - size_t pos = key.find('/'); - if (pos == std::string::npos) { - // Regular value. - ReportEnumUsage(key); - options.push_back(ConstructOption(key, value)); - continue; - } - // Store selected enum values. - if (value == kOptionTrue) - multival[key.substr(0, pos)].push_back(key.substr(pos + 1)); + // Check for multivalue enum ("attribute/value"). + size_t pos = key.find('/'); + if (pos == std::string::npos) { + // Regular value. + ReportEnumUsage(key); + options.push_back(ConstructOption(key, value)); + continue; } - // Pass multivalue enums as comma-separated lists. - for (const auto& it : multival) { - ReportEnumUsage(it.first); - options.push_back( - ConstructOption(it.first, base::JoinString(it.second, ","))); - } - base::UmaHistogramCounts1000("Printing.CUPS.IppAttributesUsed", - options.size() - regular_attr_count); + // Store selected enum values. + if (value == kOptionTrue) + multival[key.substr(0, pos)].push_back(key.substr(pos + 1)); } + // Pass multivalue enums as comma-separated lists. + for (const auto& it : multival) { + ReportEnumUsage(it.first); + options.push_back( + ConstructOption(it.first, base::JoinString(it.second, ","))); + } + base::UmaHistogramCounts1000("Printing.CUPS.IppAttributesUsed", + options.size() - regular_attr_count); + return options; }
diff --git a/printing/printing_features.cc b/printing/printing_features.cc index 637f7ff4..237a9d9 100644 --- a/printing/printing_features.cc +++ b/printing/printing_features.cc
@@ -9,12 +9,6 @@ namespace printing { namespace features { -#if BUILDFLAG(IS_CHROMEOS_ASH) -// Enables Advanced PPD Attributes. -const base::Feature kAdvancedPpdAttributes{"AdvancedPpdAttributes", - base::FEATURE_ENABLED_BY_DEFAULT}; -#endif // BUILDFLAG(IS_CHROMEOS_ASH) - #if defined(OS_MAC) // Use the CUPS IPP printing backend instead of the original CUPS backend that // calls the deprecated PPD API.
diff --git a/printing/printing_features.h b/printing/printing_features.h index 35faf4a..72b155a 100644 --- a/printing/printing_features.h +++ b/printing/printing_features.h
@@ -16,10 +16,6 @@ // The following features are declared alphabetically. The features should be // documented with descriptions of their behaviors in the .cc file. -#if BUILDFLAG(IS_CHROMEOS_ASH) -PRINTING_EXPORT extern const base::Feature kAdvancedPpdAttributes; -#endif // BUILDFLAG(IS_CHROMEOS_ASH) - #if defined(OS_MAC) PRINTING_EXPORT extern const base::Feature kCupsIppPrintingBackend; #endif // defined(OS_MAC)
diff --git a/remoting/base/task_util.h b/remoting/base/task_util.h index c876fe4..a95e5fa2 100644 --- a/remoting/base/task_util.h +++ b/remoting/base/task_util.h
@@ -37,7 +37,8 @@ // Say if you want to call this method and make |callback| run on the current // sequence: // -// client_.Post(FROM_HERE, &DirectoryClient::DeleteHost, host_id, callback); +// client_.AsyncCall(&DirectoryClient::DeleteHost).WithArgs(host_id, +// callback); // // You can just do: // @@ -59,8 +60,9 @@ void (SequenceBoundType::*method)(MethodArgs...), base::OnceCallback<void(CallbackArgs...)> callback, Args&&... args) { - client->Post(from_here, method, std::forward<Args>(args)..., - WrapCallbackToCurrentSequence(from_here, std::move(callback))); + client->AsyncCall(method, from_here) + .WithArgs(std::forward<Args>(args)..., + WrapCallbackToCurrentSequence(from_here, std::move(callback))); } } // namespace remoting
diff --git a/remoting/host/file_transfer/file_chooser_mac.mm b/remoting/host/file_transfer/file_chooser_mac.mm index 45f7389e..71d8af4 100644 --- a/remoting/host/file_transfer/file_chooser_mac.mm +++ b/remoting/host/file_transfer/file_chooser_mac.mm
@@ -146,8 +146,7 @@ } void FileChooserMac::Show() { - mac_file_chooser_on_ui_thread_.Post(FROM_HERE, - &MacFileChooserOnUiThread::Show); + mac_file_chooser_on_ui_thread_.AsyncCall(&MacFileChooserOnUiThread::Show); } void FileChooserMac::RunCallback(FileChooser::Result result) {
diff --git a/remoting/host/remoting_me2me_host.cc b/remoting/host/remoting_me2me_host.cc index 03fa3de..ce9bca0 100644 --- a/remoting/host/remoting_me2me_host.cc +++ b/remoting/host/remoting_me2me_host.cc
@@ -1590,11 +1590,6 @@ host_->AddExtension(std::make_unique<TestEchoExtension>()); - // TODO(joedow): Remove in M90. -#if defined(OS_LINUX) || defined(OS_CHROMEOS) - host_->SetMaximumSessionDuration(base::TimeDelta::FromHours(20)); -#endif - if (max_session_duration_minutes_ > 0) { host_->SetMaximumSessionDuration( base::TimeDelta::FromMinutes(max_session_duration_minutes_));
diff --git a/remoting/ios/facade/host_list_service.mm b/remoting/ios/facade/host_list_service.mm index a728840a..13c87f6 100644 --- a/remoting/ios/facade/host_list_service.mm +++ b/remoting/ios/facade/host_list_service.mm
@@ -177,8 +177,7 @@ } void HostListService::OnUserUpdated(bool is_user_signed_in) { - directory_client_.Post(FROM_HERE, - &DirectoryServiceClient::CancelPendingRequests); + directory_client_.AsyncCall(&DirectoryServiceClient::CancelPendingRequests); SetState(State::NOT_FETCHED); if (is_user_signed_in) { RequestFetch();
diff --git a/sandbox/policy/mac/gpu_v2.sb b/sandbox/policy/mac/gpu_v2.sb index 1bb5edc..a01030e 100644 --- a/sandbox/policy/mac/gpu_v2.sb +++ b/sandbox/policy/mac/gpu_v2.sb
@@ -14,6 +14,8 @@ (allow ipc-posix-shm) +(define disable-metal-shader-cache "DISABLE_METAL_SHADER_CACHE") + ; TODO(https://crbug.com/1126350): Remove this after debugging. These blocks ; enumerate known denials, while turning unknown denials into fatal crashes. (define crash-on-unknown-denials #f) ; Single-line kill switch. @@ -171,3 +173,11 @@ (syscall-number SYS_write) (syscall-number SYS_write_nocancel) ))) + +; crbug.com/1159113 +(if (param-true? disable-metal-shader-cache) + (let ((metal-cache-dir (subpath (string-append (param darwin-user-cache-dir) + "/com.apple.metal")))) + (deny file-read* metal-cache-dir) + (deny file-write* metal-cache-dir)) +)
diff --git a/sandbox/policy/mac/sandbox_mac.h b/sandbox/policy/mac/sandbox_mac.h index 6d10a37..7740d30 100644 --- a/sandbox/policy/mac/sandbox_mac.h +++ b/sandbox/policy/mac/sandbox_mac.h
@@ -60,6 +60,7 @@ static const char* kSandboxFieldTrialSeverName; static const char* kSandboxBundleVersionPath; + static const char* kSandboxDisableMetalShaderCache; private: FRIEND_TEST_ALL_PREFIXES(MacDirAccessSandboxTest, StringEscape);
diff --git a/sandbox/policy/mac/sandbox_mac.mm b/sandbox/policy/mac/sandbox_mac.mm index 9d2de6d6..179675d 100644 --- a/sandbox/policy/mac/sandbox_mac.mm +++ b/sandbox/policy/mac/sandbox_mac.mm
@@ -73,6 +73,8 @@ const char* SandboxMac::kSandboxMacOS1013 = "MACOS_1013"; const char* SandboxMac::kSandboxFieldTrialSeverName = "FIELD_TRIAL_SERVER_NAME"; const char* SandboxMac::kSandboxBundleVersionPath = "BUNDLE_VERSION_PATH"; +const char* SandboxMac::kSandboxDisableMetalShaderCache = + "DISABLE_METAL_SHADER_CACHE"; // Warm up System APIs that empirically need to be accessed before the Sandbox // is turned on.
diff --git a/sandbox/policy/switches.cc b/sandbox/policy/switches.cc index 7530bef..5abf7ed 100644 --- a/sandbox/policy/switches.cc +++ b/sandbox/policy/switches.cc
@@ -108,6 +108,9 @@ // Cause the OS X sandbox write to syslog every time an access to a resource // is denied by the sandbox. const char kEnableSandboxLogging[] = "enable-sandbox-logging"; + +// Disables Metal's shader cache, using the GPU sandbox to prevent access to it. +const char kDisableMetalShaderCache[] = "disable-metal-shader-cache"; #endif // Flags spied upon from other layers.
diff --git a/sandbox/policy/switches.h b/sandbox/policy/switches.h index f5d88277..3db13f3 100644 --- a/sandbox/policy/switches.h +++ b/sandbox/policy/switches.h
@@ -65,6 +65,7 @@ #endif #if defined(OS_MAC) SANDBOX_POLICY_EXPORT extern const char kEnableSandboxLogging[]; +SANDBOX_POLICY_EXPORT extern const char kDisableMetalShaderCache[]; #endif // Flags spied upon from other layers.
diff --git a/sandbox/policy/win/sandbox_win.cc b/sandbox/policy/win/sandbox_win.cc index 8cecfab..998b1a68 100644 --- a/sandbox/policy/win/sandbox_win.cc +++ b/sandbox/policy/win/sandbox_win.cc
@@ -745,6 +745,41 @@ return SBOX_ALL_OK; } +// Launches outside of the sandbox - the process will not be associated with +// a Policy or TargetProcess. This supports both kNoSandbox and the --no-sandbox +// command line flag. +ResultCode LaunchWithoutSandbox( + base::CommandLine* cmd_line, + const base::HandlesToInheritVector& handles_to_inherit, + SandboxDelegate* delegate, + base::Process* process) { + base::LaunchOptions options; + options.handles_to_inherit = handles_to_inherit; + // Network process runs in a job even when unsandboxed. This is to ensure it + // does not outlive the browser, which could happen if there is a lot of I/O + // on process shutdown, in which case TerminateProcess can fail. See + // https://crbug.com/820996. + if (delegate->ShouldUnsandboxedRunInJob()) { + BOOL in_job = true; + // Prior to Windows 8 nested jobs aren't possible. + if (base::win::GetVersion() >= base::win::Version::WIN8 || + (::IsProcessInJob(::GetCurrentProcess(), nullptr, &in_job) && + !in_job)) { + static HANDLE job_object_handle = nullptr; + if (!job_object_handle) { + Job job_obj; + DWORD result = job_obj.Init(JOB_UNPROTECTED, nullptr, 0, 0); + if (result != ERROR_SUCCESS) + return SBOX_ERROR_CANNOT_INIT_JOB; + job_object_handle = job_obj.Take().Take(); + } + options.job_handle = job_object_handle; + } + } + *process = base::LaunchProcess(*cmd_line, options); + return SBOX_ALL_OK; +} + } // namespace // static @@ -921,34 +956,12 @@ } SandboxType sandbox_type = delegate->GetSandboxType(); + // --no-sandbox and kNoSandbox are launched without creating a Policy. if (IsUnsandboxedSandboxType(sandbox_type) || cmd_line->HasSwitch(switches::kNoSandbox) || launcher_process_command_line.HasSwitch(switches::kNoSandbox)) { - base::LaunchOptions options; - options.handles_to_inherit = handles_to_inherit; - // Network process runs in a job even when unsandboxed. This is to ensure it - // does not outlive the browser, which could happen if there is a lot of I/O - // on process shutdown, in which case TerminateProcess can fail. See - // https://crbug.com/820996. - if (delegate->ShouldUnsandboxedRunInJob()) { - BOOL in_job = true; - // Prior to Windows 8 nested jobs aren't possible. - if (base::win::GetVersion() >= base::win::Version::WIN8 || - (::IsProcessInJob(::GetCurrentProcess(), nullptr, &in_job) && - !in_job)) { - static HANDLE job_object_handle = nullptr; - if (!job_object_handle) { - Job job_obj; - DWORD result = job_obj.Init(JOB_UNPROTECTED, nullptr, 0, 0); - if (result != ERROR_SUCCESS) - return SBOX_ERROR_CANNOT_INIT_JOB; - job_object_handle = job_obj.Take().Take(); - } - options.job_handle = job_object_handle; - } - } - *process = base::LaunchProcess(*cmd_line, options); - return SBOX_ALL_OK; + return LaunchWithoutSandbox(cmd_line, handles_to_inherit, delegate, + process); } scoped_refptr<TargetPolicy> policy = g_broker_services->CreatePolicy();
diff --git a/services/network/restricted_cookie_manager.cc b/services/network/restricted_cookie_manager.cc index 1edf8b62..1515a8af 100644 --- a/services/network/restricted_cookie_manager.cc +++ b/services/network/restricted_cookie_manager.cc
@@ -627,6 +627,7 @@ base::debug::ScopedCrashKeyString scoped_key_string_url( url_origin, url::Origin::Create(url).GetDebugString()); + NOTREACHED(); base::debug::DumpWithoutCrashing(); return false; }
diff --git a/services/network/web_bundle_chunked_buffer.cc b/services/network/web_bundle_chunked_buffer.cc index 2c3a5e2..8d5a84b 100644 --- a/services/network/web_bundle_chunked_buffer.cc +++ b/services/network/web_bundle_chunked_buffer.cc
@@ -121,6 +121,11 @@ CreatePartialBuffer(offset, length), offset, length); } +uint64_t WebBundleChunkedBuffer::size() const { + DCHECK_GE(end_pos(), start_pos()); + return end_pos() - start_pos(); +} + WebBundleChunkedBuffer::ChunkVector::const_iterator WebBundleChunkedBuffer::FindChunk(uint64_t pos) const { if (empty())
diff --git a/services/network/web_bundle_chunked_buffer.h b/services/network/web_bundle_chunked_buffer.h index 3c297a8..b28471f0 100644 --- a/services/network/web_bundle_chunked_buffer.h +++ b/services/network/web_bundle_chunked_buffer.h
@@ -47,6 +47,9 @@ uint64_t offset, uint64_t max_length) const; + // Returns the buffer size. + uint64_t size() const; + private: friend class WebBundleChunkedBufferTest; FRIEND_TEST_ALL_PREFIXES(WebBundleChunkedBufferTest, EmptyBuffer);
diff --git a/services/network/web_bundle_manager.cc b/services/network/web_bundle_manager.cc index 017b3e9..db1abe9 100644 --- a/services/network/web_bundle_manager.cc +++ b/services/network/web_bundle_manager.cc
@@ -177,6 +177,12 @@ return false; } memory_usage_per_process_[process_id] += num_bytes; + + if (max_memory_usage_per_process_[process_id] < + memory_usage_per_process_[process_id]) { + max_memory_usage_per_process_[process_id] = + memory_usage_per_process_[process_id]; + } return true; } @@ -187,6 +193,10 @@ memory_usage_per_process_[process_id] -= num_bytes; if (memory_usage_per_process_[process_id] == 0) { memory_usage_per_process_.erase(process_id); + base::UmaHistogramCustomCounts( + "SubresourceWebBundles.MaxMemoryUsagePerProcess", + max_memory_usage_per_process_[process_id], 1, 50000000, 50); + max_memory_usage_per_process_.erase(process_id); } }
diff --git a/services/network/web_bundle_manager.h b/services/network/web_bundle_manager.h index f92d9e6..7c843df 100644 --- a/services/network/web_bundle_manager.h +++ b/services/network/web_bundle_manager.h
@@ -73,6 +73,7 @@ uint64_t max_memory_per_process_; std::map<int32_t, uint64_t> memory_usage_per_process_; + std::map<int32_t, uint64_t> max_memory_usage_per_process_; SEQUENCE_CHECKER(sequence_checker_);
diff --git a/services/network/web_bundle_manager_unittest.cc b/services/network/web_bundle_manager_unittest.cc index 137546a..1ffaba6 100644 --- a/services/network/web_bundle_manager_unittest.cc +++ b/services/network/web_bundle_manager_unittest.cc
@@ -4,6 +4,7 @@ #include "services/network/web_bundle_manager.h" +#include "base/test/metrics/histogram_tester.h" #include "base/test/task_environment.h" #include "base/unguessable_token.h" #include "components/web_package/test_support/web_bundle_builder.h" @@ -297,6 +298,7 @@ } TEST_F(WebBundleManagerTest, MemoryQuota_StartRequestAfterError) { + base::HistogramTester histogram_tester; WebBundleManager manager; std::string bundle = CreateSmallBundleString(); @@ -317,6 +319,11 @@ EXPECT_EQ(handle->last_bundle_error()->first, mojom::WebBundleErrorType::kMemoryQuotaExceeded); EXPECT_EQ(handle->last_bundle_error()->second, kQuotaExceededErrorMessage); + histogram_tester.ExpectUniqueSample( + "SubresourceWebBundles.LoadResult", + WebBundleURLLoaderFactory::SubresourceWebBundleLoadResult:: + kMemoryQuotaExceeded, + 1); // Start the subresource request after triggering the quota error. mojo::Remote<network::mojom::URLLoader> loader; @@ -479,13 +486,14 @@ } TEST_F(WebBundleManagerTest, MemoryQuota_ProcessIsolation) { + base::HistogramTester histogram_tester; WebBundleManager manager; std::string bundle = CreateSmallBundleString(); - // Set the max memory to trigger the quota error while loading the second + // Set the max memory to trigger the quota error while loading the third // web bundle. - SetMaxMemoryPerProces(manager, bundle.size() * 1.5); + SetMaxMemoryPerProces(manager, bundle.size() * 2.5); // Start loading the first web bundle in the process 1. base::WeakPtr<WebBundleURLLoaderFactory> factory1_1; @@ -508,6 +516,11 @@ EXPECT_TRUE( mojo::BlockingCopyToString(client1_1->response_body_release(), &body1_1)); EXPECT_EQ("body", body1_1); + histogram_tester.ExpectUniqueSample("SubresourceWebBundles.ReceivedSize", + bundle.size(), 1); + histogram_tester.ExpectUniqueSample( + "SubresourceWebBundles.LoadResult", + WebBundleURLLoaderFactory::SubresourceWebBundleLoadResult::kSuccess, 1); // Start loading the second web bundle in the process 1. base::WeakPtr<WebBundleURLLoaderFactory> factory1_2; @@ -517,21 +530,53 @@ auto producer1_2 = SetBundleStream(*factory1_2); mojo::BlockingCopyFromString(bundle, producer1_2); producer1_2.reset(); - // TestWebBundleHandle must receive the error. - handle1_2->RunUntilBundleError(); - ASSERT_TRUE(handle1_2->last_bundle_error().has_value()); - EXPECT_EQ(handle1_2->last_bundle_error()->first, - mojom::WebBundleErrorType::kMemoryQuotaExceeded); - EXPECT_EQ(handle1_2->last_bundle_error()->second, kQuotaExceededErrorMessage); // Start loading the subresource from the second web bundle. mojo::Remote<network::mojom::URLLoader> loader1_2; std::unique_ptr<network::TestURLLoaderClient> client1_2; std::tie(loader1_2, client1_2) = StartSubresourceLoad(*factory1_2); - // The subresource request must fail. + // Confirm that the subresource is correctly loaded. client1_2->RunUntilComplete(); + EXPECT_EQ(net::OK, client1_2->completion_status().error_code); + EXPECT_EQ(client1_2->response_head()->web_bundle_url, GURL(kBundleUrl)); + std::string body1_2; + EXPECT_TRUE( + mojo::BlockingCopyToString(client1_2->response_body_release(), &body1_2)); + EXPECT_EQ("body", body1_2); + histogram_tester.ExpectUniqueSample("SubresourceWebBundles.ReceivedSize", + bundle.size(), 2); + histogram_tester.ExpectUniqueSample( + "SubresourceWebBundles.LoadResult", + WebBundleURLLoaderFactory::SubresourceWebBundleLoadResult::kSuccess, 2); + + // Start loading the third web bundle in the process 1. + base::WeakPtr<WebBundleURLLoaderFactory> factory1_3; + std::unique_ptr<TestWebBundleHandle> handle1_3; + std::tie(factory1_3, handle1_3) = + CreateWebBundleLoaderFactory(manager, process_id1); + auto producer1_3 = SetBundleStream(*factory1_3); + mojo::BlockingCopyFromString(bundle, producer1_3); + producer1_3.reset(); + // TestWebBundleHandle must receive the error. + handle1_3->RunUntilBundleError(); + ASSERT_TRUE(handle1_3->last_bundle_error().has_value()); + EXPECT_EQ(handle1_3->last_bundle_error()->first, + mojom::WebBundleErrorType::kMemoryQuotaExceeded); + EXPECT_EQ(handle1_3->last_bundle_error()->second, kQuotaExceededErrorMessage); + + // Start loading the subresource from the second web bundle. + mojo::Remote<network::mojom::URLLoader> loader1_3; + std::unique_ptr<network::TestURLLoaderClient> client1_3; + std::tie(loader1_3, client1_3) = StartSubresourceLoad(*factory1_3); + // The subresource request must fail. + client1_3->RunUntilComplete(); EXPECT_EQ(net::ERR_INVALID_WEB_BUNDLE, - client1_2->completion_status().error_code); + client1_3->completion_status().error_code); + histogram_tester.ExpectBucketCount( + "SubresourceWebBundles.LoadResult", + WebBundleURLLoaderFactory::SubresourceWebBundleLoadResult:: + kMemoryQuotaExceeded, + 1); // Start loading the third web bundle in the process 2. base::WeakPtr<WebBundleURLLoaderFactory> factory2; @@ -553,6 +598,23 @@ EXPECT_TRUE( mojo::BlockingCopyToString(client2->response_body_release(), &body2)); EXPECT_EQ("body", body2); + histogram_tester.ExpectUniqueSample("SubresourceWebBundles.ReceivedSize", + bundle.size(), 3); + histogram_tester.ExpectBucketCount( + "SubresourceWebBundles.LoadResult", + WebBundleURLLoaderFactory::SubresourceWebBundleLoadResult::kSuccess, 3); + + // Reset handles and RunUntilIdle to trigger MaxMemoryUsagePerProcess + // histogram count. + handle1_1.reset(); + handle1_2.reset(); + handle1_3.reset(); + handle2.reset(); + base::RunLoop().RunUntilIdle(); + histogram_tester.ExpectBucketCount( + "SubresourceWebBundles.MaxMemoryUsagePerProcess", bundle.size() * 2, 1); + histogram_tester.ExpectBucketCount( + "SubresourceWebBundles.MaxMemoryUsagePerProcess", bundle.size(), 1); } } // namespace network
diff --git a/services/network/web_bundle_url_loader_factory.cc b/services/network/web_bundle_url_loader_factory.cc index 2c38387..d5d12ca 100644 --- a/services/network/web_bundle_url_loader_factory.cc +++ b/services/network/web_bundle_url_loader_factory.cc
@@ -4,6 +4,7 @@ #include "services/network/web_bundle_url_loader_factory.h" +#include "base/metrics/histogram_functions.h" #include "base/optional.h" #include "base/threading/sequenced_task_runner_handle.h" #include "components/web_package/web_bundle_parser.h" @@ -23,6 +24,11 @@ constexpr size_t kBlockedBodyAllocationSize = 1; +void RecordLoadResult( + WebBundleURLLoaderFactory::SubresourceWebBundleLoadResult result) { + base::UmaHistogramEnumeration("SubresourceWebBundles.LoadResult", result); +} + void DeleteProducerAndRunCallback( std::unique_ptr<mojo::DataPipeProducer> producer, base::OnceCallback<void(MojoResult result)> callback, @@ -42,6 +48,10 @@ // network::mojom::URLLoaderClient implementation: void OnReceiveResponse( network::mojom::URLResponseHeadPtr response_head) override { + base::UmaHistogramCustomCounts( + "SubresourceWebBundles.ContentLength", + response_head->content_length < 0 ? 0 : response_head->content_length, + 1, 50000000, 50); wrapped_->OnReceiveResponse(std::move(response_head)); } @@ -234,7 +244,8 @@ mojo::ScopedDataPipeConsumerHandle bundle_body, std::unique_ptr<WebBundleMemoryQuotaConsumer> web_bundle_memory_quota_consumer, - base::OnceClosure memory_quota_exceeded_closure) + base::OnceClosure memory_quota_exceeded_closure, + base::OnceClosure data_completed_closure) : data_source_receiver_(this, std::move(data_source_receiver)), pipe_drainer_( std::make_unique<mojo::DataPipeDrainer>(this, @@ -242,7 +253,8 @@ web_bundle_memory_quota_consumer_( std::move(web_bundle_memory_quota_consumer)), memory_quota_exceeded_closure_( - std::move(memory_quota_exceeded_closure)) {} + std::move(memory_quota_exceeded_closure)), + data_completed_closure_(std::move(data_completed_closure)) {} ~BundleDataSource() override { // The receiver must be closed before destructing pending callbacks in @@ -321,6 +333,15 @@ void OnDataComplete() override { DCHECK(!finished_loading_); + base::UmaHistogramCustomCounts( + "SubresourceWebBundles.ReceivedSize", + base::saturated_cast<base::Histogram::Sample>(buffer_.size()), 1, + 50000000, 50); + DCHECK(data_completed_closure_); + // Defer calling |data_completed_closure_| not to run + // |data_completed_closure_| before |memory_quota_exceeded_closure_|. + base::SequencedTaskRunnerHandle::Get()->PostTask( + FROM_HERE, std::move(data_completed_closure_)); finished_loading_ = true; ProcessPendingReads(); } @@ -375,6 +396,7 @@ std::unique_ptr<WebBundleMemoryQuotaConsumer> web_bundle_memory_quota_consumer_; base::OnceClosure memory_quota_exceeded_closure_; + base::OnceClosure data_completed_closure_; }; WebBundleURLLoaderFactory::WebBundleURLLoaderFactory( @@ -408,6 +430,8 @@ data_source.InitWithNewPipeAndPassReceiver(), std::move(body), std::move(web_bundle_memory_quota_consumer_), base::BindOnce(&WebBundleURLLoaderFactory::OnMemoryQuotaExceeded, + weak_ptr_factory_.GetWeakPtr()), + base::BindOnce(&WebBundleURLLoaderFactory::OnDataCompleted, weak_ptr_factory_.GetWeakPtr())); // WebBundleParser will self-destruct on remote mojo ends' disconnection. new web_package::WebBundleParser(parser_.BindNewPipeAndPassReceiver(), @@ -481,6 +505,7 @@ TRACE_EVENT0("loading", "WebBundleURLLoaderFactory::OnMetadataParsed"); if (error) { metadata_error_ = std::move(error); + MaybeRecordLoadResult(); web_bundle_handle_->OnWebBundleError( mojom::WebBundleErrorType::kMetadataParseError, metadata_error_->message); @@ -496,6 +521,7 @@ } metadata_ = std::move(metadata); + MaybeRecordLoadResult(); for (auto loader : pending_loaders_) StartLoad(loader.get()); pending_loaders_.clear(); @@ -561,6 +587,7 @@ void WebBundleURLLoaderFactory::OnMemoryQuotaExceeded() { TRACE_EVENT0("loading", "WebBundleURLLoaderFactory::OnMemoryQuotaExceeded"); quota_exceeded_error_ = true; + MaybeRecordLoadResult(); web_bundle_handle_->OnWebBundleError( mojom::WebBundleErrorType::kMemoryQuotaExceeded, "Memory quota exceeded. Currently, there is an upper limit on the total " @@ -576,4 +603,29 @@ parser_.reset(); } +void WebBundleURLLoaderFactory::OnDataCompleted() { + data_completed_ = true; + MaybeRecordLoadResult(); +} + +void WebBundleURLLoaderFactory::MaybeRecordLoadResult() { + if (load_result_recorded_) + return; + if (quota_exceeded_error_) { + RecordLoadResult(SubresourceWebBundleLoadResult::kMemoryQuotaExceeded); + load_result_recorded_ = true; + return; + } + if (metadata_error_) { + RecordLoadResult(SubresourceWebBundleLoadResult::kMetadataParseError); + load_result_recorded_ = true; + return; + } + if (metadata_ && data_completed_) { + RecordLoadResult(SubresourceWebBundleLoadResult::kSuccess); + load_result_recorded_ = true; + return; + } +} + } // namespace network
diff --git a/services/network/web_bundle_url_loader_factory.h b/services/network/web_bundle_url_loader_factory.h index c1d0375..a5e5e85 100644 --- a/services/network/web_bundle_url_loader_factory.h +++ b/services/network/web_bundle_url_loader_factory.h
@@ -19,6 +19,14 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) WebBundleURLLoaderFactory { public: + // Used for UMA. Append-only. + enum class SubresourceWebBundleLoadResult { + kSuccess = 0, + kMetadataParseError = 1, + kMemoryQuotaExceeded = 2, + kMaxValue = kMemoryQuotaExceeded, + }; + WebBundleURLLoaderFactory( const GURL& bundle_url, mojo::Remote<mojom::WebBundleHandle> web_bundle_handle, @@ -52,6 +60,8 @@ web_package::mojom::BundleResponsePtr response, web_package::mojom::BundleResponseParseErrorPtr error); void OnMemoryQuotaExceeded(); + void OnDataCompleted(); + void MaybeRecordLoadResult(); GURL bundle_url_; mojo::Remote<mojom::WebBundleHandle> web_bundle_handle_; @@ -63,6 +73,8 @@ web_package::mojom::BundleMetadataPtr metadata_; web_package::mojom::BundleMetadataParseErrorPtr metadata_error_; bool quota_exceeded_error_ = false; + bool data_completed_ = false; + bool load_result_recorded_ = false; std::vector<base::WeakPtr<URLLoader>> pending_loaders_; base::WeakPtrFactory<WebBundleURLLoaderFactory> weak_ptr_factory_{this};
diff --git a/services/network/web_bundle_url_loader_factory_unittest.cc b/services/network/web_bundle_url_loader_factory_unittest.cc index 58270e9..0afde55 100644 --- a/services/network/web_bundle_url_loader_factory_unittest.cc +++ b/services/network/web_bundle_url_loader_factory_unittest.cc
@@ -4,6 +4,7 @@ #include "services/network/web_bundle_url_loader_factory.h" +#include "base/test/metrics/histogram_tester.h" #include "base/test/task_environment.h" #include "components/web_package/test_support/web_bundle_builder.h" #include "mojo/public/cpp/bindings/remote.h" @@ -174,6 +175,7 @@ }; TEST_F(WebBundleURLLoaderFactoryTest, Basic) { + base::HistogramTester histogram_tester; WriteBundle(CreateSmallBundle()); FinishWritingBundle(); @@ -187,9 +189,13 @@ EXPECT_TRUE(mojo::BlockingCopyToString( request.client->response_body_release(), &body)); EXPECT_EQ("body", body); + histogram_tester.ExpectUniqueSample( + "SubresourceWebBundles.LoadResult", + WebBundleURLLoaderFactory::SubresourceWebBundleLoadResult::kSuccess, 1); } TEST_F(WebBundleURLLoaderFactoryTest, MetadataParseError) { + base::HistogramTester histogram_tester; auto request = StartRequest(GURL(kResourceUrl)); std::vector<uint8_t> bundle = CreateSmallBundle(); @@ -212,6 +218,11 @@ EXPECT_EQ(net::ERR_INVALID_WEB_BUNDLE, request2.client->completion_status().error_code); + histogram_tester.ExpectUniqueSample( + "SubresourceWebBundles.LoadResult", + WebBundleURLLoaderFactory::SubresourceWebBundleLoadResult:: + kMetadataParseError, + 1); } TEST_F(WebBundleURLLoaderFactoryTest, ResponseParseError) {
diff --git a/testing/buildbot/chrome.json b/testing/buildbot/chrome.json index a0e34a57..55e4161 100644 --- a/testing/buildbot/chrome.json +++ b/testing/buildbot/chrome.json
@@ -1,31 +1,11 @@ { "AAAAA1 AUTOGENERATED FILE DO NOT EDIT": {}, "AAAAA2 See generate_buildbot_json.py to make changes": {}, - "chromeos-arm-generic-beta": { - "additional_compile_targets": [ - "chromiumos_preflight" - ] - }, "chromeos-arm-generic-cfi-thin-lto-chrome": { "additional_compile_targets": [ "chromiumos_preflight" ] }, - "chromeos-arm-generic-ltc": { - "additional_compile_targets": [ - "chromiumos_preflight" - ] - }, - "chromeos-arm-generic-lts": { - "additional_compile_targets": [ - "chromiumos_preflight" - ] - }, - "chromeos-arm-generic-stable": { - "additional_compile_targets": [ - "chromiumos_preflight" - ] - }, "chromeos-betty-pi-arc-cfi-thin-lto-chrome": { "additional_compile_targets": [ "chromiumos_preflight"
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json index 80da521..9a446fe 100644 --- a/testing/buildbot/chromium.android.fyi.json +++ b/testing/buildbot/chromium.android.fyi.json
@@ -75,6 +75,13 @@ "results_handler": "layout tests", "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "device_os": "PQ3A.190801.002", @@ -106,6 +113,13 @@ "results_handler": "layout tests", "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "device_os": "PQ3A.190801.002", @@ -137,6 +151,13 @@ "results_handler": "layout tests", "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "device_os": "PQ3A.190801.002", @@ -178,11 +199,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 88.0.4324.175" + "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 88.0.4324.176" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 88.0.4324.175", + "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 88.0.4324.176", "resultdb": { "enable": true }, @@ -192,7 +213,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M88", - "revision": "version:88.0.4324.175" + "revision": "version:88.0.4324.176" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -257,11 +278,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.46" + "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.48" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.46", + "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.48", "resultdb": { "enable": true }, @@ -271,7 +292,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M89", - "revision": "version:89.0.4389.46" + "revision": "version:89.0.4389.48" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -415,11 +436,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 88.0.4324.175" + "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 88.0.4324.176" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 88.0.4324.175", + "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 88.0.4324.176", "resultdb": { "enable": true }, @@ -429,7 +450,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M88", - "revision": "version:88.0.4324.175" + "revision": "version:88.0.4324.176" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -494,11 +515,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.46" + "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.48" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.46", + "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.48", "resultdb": { "enable": true }, @@ -508,7 +529,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M89", - "revision": "version:89.0.4389.46" + "revision": "version:89.0.4389.48" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -656,11 +677,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 88.0.4324.175" + "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 88.0.4324.176" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 88.0.4324.175", + "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 88.0.4324.176", "resultdb": { "enable": true }, @@ -670,7 +691,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M88", - "revision": "version:88.0.4324.175" + "revision": "version:88.0.4324.176" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -735,11 +756,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.46" + "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.48" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.46", + "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.48", "resultdb": { "enable": true }, @@ -749,7 +770,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M89", - "revision": "version:89.0.4389.46" + "revision": "version:89.0.4389.48" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -893,11 +914,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 88.0.4324.175" + "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 88.0.4324.176" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 88.0.4324.175", + "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 88.0.4324.176", "resultdb": { "enable": true }, @@ -907,7 +928,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M88", - "revision": "version:88.0.4324.175" + "revision": "version:88.0.4324.176" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -972,11 +993,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.46" + "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.48" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.46", + "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.48", "resultdb": { "enable": true }, @@ -986,7 +1007,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M89", - "revision": "version:89.0.4389.46" + "revision": "version:89.0.4389.48" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -1197,11 +1218,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 88.0.4324.175" + "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 88.0.4324.176" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 88.0.4324.175", + "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 88.0.4324.176", "resultdb": { "enable": true }, @@ -1211,7 +1232,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M88", - "revision": "version:88.0.4324.175" + "revision": "version:88.0.4324.176" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -1276,11 +1297,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.46" + "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.48" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.46", + "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.48", "resultdb": { "enable": true }, @@ -1290,7 +1311,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M89", - "revision": "version:89.0.4389.46" + "revision": "version:89.0.4389.48" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -1434,11 +1455,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 88.0.4324.175" + "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 88.0.4324.176" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 88.0.4324.175", + "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 88.0.4324.176", "resultdb": { "enable": true }, @@ -1448,7 +1469,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M88", - "revision": "version:88.0.4324.175" + "revision": "version:88.0.4324.176" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -1513,11 +1534,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.46" + "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.48" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.46", + "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.48", "resultdb": { "enable": true }, @@ -1527,7 +1548,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M89", - "revision": "version:89.0.4389.46" + "revision": "version:89.0.4389.48" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -1738,11 +1759,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 88.0.4324.175" + "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 88.0.4324.176" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 88.0.4324.175", + "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 88.0.4324.176", "resultdb": { "enable": true }, @@ -1752,7 +1773,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M88", - "revision": "version:88.0.4324.175" + "revision": "version:88.0.4324.176" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -1817,11 +1838,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.46" + "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.48" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.46", + "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.48", "resultdb": { "enable": true }, @@ -1831,7 +1852,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M89", - "revision": "version:89.0.4389.46" + "revision": "version:89.0.4389.48" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -1975,11 +1996,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 88.0.4324.175" + "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 88.0.4324.176" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 88.0.4324.175", + "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 88.0.4324.176", "resultdb": { "enable": true }, @@ -1989,7 +2010,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M88", - "revision": "version:88.0.4324.175" + "revision": "version:88.0.4324.176" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -2054,11 +2075,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.46" + "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.48" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.46", + "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.48", "resultdb": { "enable": true }, @@ -2068,7 +2089,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M89", - "revision": "version:89.0.4389.46" + "revision": "version:89.0.4389.48" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -2213,6 +2234,13 @@ "results_handler": "layout tests", "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "cpu": "x86-64",
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json index e1e0242..f74c362 100644 --- a/testing/buildbot/chromium.android.json +++ b/testing/buildbot/chromium.android.json
@@ -2233,6 +2233,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "device_os": "LMY48M|LMY48I", @@ -5887,6 +5894,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "device_os": "LMY49B", @@ -9537,6 +9551,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "device_os": "MMB29Q", @@ -13174,6 +13195,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "device_os": "MRA58Z", @@ -18090,6 +18118,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "device_os": "MMB29Q", @@ -21521,6 +21556,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "cpu": "x86-64", @@ -22419,6 +22461,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "cpu": "x86", @@ -24703,6 +24752,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "device_os": "LMY48M", @@ -27692,6 +27748,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "device_os": "MMB29Q", @@ -30792,6 +30855,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "device_os": "MMB29Q", @@ -30820,6 +30890,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "device_os": "MMB29Q", @@ -30852,6 +30929,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "device_os": "MMB29Q", @@ -31740,6 +31824,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "cpu": "x86-64", @@ -35407,6 +35498,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "cpu": "x86-64", @@ -35446,6 +35544,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "cpu": "x86-64", @@ -35689,6 +35794,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "device_os": "NJH47F", @@ -39326,6 +39438,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "device_os": "NJH47F", @@ -39353,6 +39472,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "device_os": "NJH47F", @@ -39377,6 +39503,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "device_os": "NJH47F", @@ -39408,6 +39541,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "device_os": "NJH47F", @@ -39439,6 +39579,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "device_os": "NJH47F", @@ -41126,6 +41273,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "cpu": "x86-64",
diff --git a/testing/buildbot/chromium.angle.json b/testing/buildbot/chromium.angle.json index b3d718e..2df0831 100644 --- a/testing/buildbot/chromium.angle.json +++ b/testing/buildbot/chromium.angle.json
@@ -20,6 +20,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -52,6 +59,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -84,6 +98,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -116,6 +137,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -146,6 +174,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -186,6 +221,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -227,6 +269,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -266,6 +315,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -305,6 +361,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -338,6 +401,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -371,6 +441,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -404,6 +481,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -437,6 +521,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -469,6 +560,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -502,6 +600,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -534,6 +639,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -567,6 +679,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -598,6 +717,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -639,6 +765,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -677,6 +810,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -715,6 +855,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -746,6 +893,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -787,6 +941,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -825,6 +986,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ {
diff --git a/testing/buildbot/chromium.clang.json b/testing/buildbot/chromium.clang.json index a3e7e96..23f8642 100644 --- a/testing/buildbot/chromium.clang.json +++ b/testing/buildbot/chromium.clang.json
@@ -5337,6 +5337,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "device_os": "LMY48M", @@ -8323,6 +8330,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "cpu": "x86-64", @@ -8820,6 +8834,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "device_os": "MMB29Q", @@ -23882,6 +23903,9 @@ "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, "name": "chromedriver_py_tests", + "resultdb": { + "enable": true + }, "swarming": { "can_use_on_swarming_builders": true, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -26354,6 +26378,9 @@ "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, "name": "chromedriver_py_tests", + "resultdb": { + "enable": true + }, "swarming": { "can_use_on_swarming_builders": true, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index fa90c5b..4bf15b9 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json
@@ -1636,6 +1636,9 @@ "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, "name": "chromedriver_py_tests", + "resultdb": { + "enable": true + }, "swarming": { "can_use_on_swarming_builders": true, "dimension_sets": [ @@ -3607,6 +3610,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "device_os": "MMB29Q", @@ -7595,6 +7605,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "device_os": "PQ3A.190801.002", @@ -46558,6 +46575,9 @@ "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, "name": "chromedriver_py_tests", + "resultdb": { + "enable": true + }, "swarming": { "can_use_on_swarming_builders": true, "dimension_sets": [ @@ -48641,6 +48661,9 @@ "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, "name": "chromedriver_py_tests", + "resultdb": { + "enable": true + }, "swarming": { "can_use_on_swarming_builders": true, "dimension_sets": [ @@ -53818,6 +53841,9 @@ "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, "name": "chromedriver_py_tests", + "resultdb": { + "enable": true + }, "swarming": { "can_use_on_swarming_builders": true, "dimension_sets": [ @@ -57199,6 +57225,9 @@ "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, "name": "chromedriver_py_tests", + "resultdb": { + "enable": true + }, "swarming": { "can_use_on_swarming_builders": true, "dimension_sets": [
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json index e8d01d5..ba42340 100644 --- a/testing/buildbot/chromium.gpu.fyi.json +++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -16,6 +16,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -43,6 +50,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -80,6 +94,13 @@ "name": "angle_perftests", "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -116,6 +137,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -2621,6 +2649,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -2652,6 +2687,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -2693,6 +2735,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -2731,6 +2780,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -2765,6 +2821,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -2798,6 +2861,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -2831,6 +2901,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -2864,6 +2941,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -2897,6 +2981,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -2929,6 +3020,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -2962,6 +3060,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -2994,6 +3099,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -3034,6 +3146,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -3072,6 +3191,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -3103,6 +3229,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -3144,6 +3277,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -3182,6 +3322,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -3216,6 +3363,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -3249,6 +3403,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -3282,6 +3443,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -3315,6 +3483,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -3348,6 +3523,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -3380,6 +3562,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -3413,6 +3602,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -3445,6 +3641,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -3480,6 +3683,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -3659,6 +3869,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -3695,6 +3912,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -3731,6 +3955,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -3767,6 +3998,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -3807,6 +4045,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -3852,6 +4097,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -3897,6 +4149,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -3934,6 +4193,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -3970,6 +4236,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -4007,6 +4280,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -4041,6 +4321,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -4220,6 +4507,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -4256,6 +4550,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -4292,6 +4593,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -4328,6 +4636,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -4368,6 +4683,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -4413,6 +4735,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -4458,6 +4787,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -4495,6 +4831,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -4531,6 +4874,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -4568,6 +4918,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -4604,6 +4961,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -4697,6 +5061,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -4734,6 +5105,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -4769,6 +5147,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -4804,6 +5189,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -4839,6 +5231,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -4874,6 +5273,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -4913,6 +5319,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -4957,6 +5370,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -5001,6 +5421,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -5032,6 +5459,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -5067,6 +5501,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -5102,6 +5543,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -5138,6 +5586,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -5175,6 +5630,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -5208,6 +5670,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -5387,6 +5856,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -5423,6 +5899,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -5459,6 +5942,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -5495,6 +5985,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -5535,6 +6032,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -5580,6 +6084,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -5625,6 +6136,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -5662,6 +6180,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -5698,6 +6223,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -5735,6 +6267,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -5769,6 +6308,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -5950,6 +6496,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -5986,6 +6539,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -6022,6 +6582,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -6058,6 +6625,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -6094,6 +6668,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -6134,6 +6715,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -6179,6 +6767,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -6224,6 +6819,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -6261,6 +6863,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -6297,6 +6906,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -6334,6 +6950,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -6384,6 +7007,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -6421,6 +7051,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -6459,6 +7096,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -6498,6 +7142,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -6539,6 +7190,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -6588,6 +7246,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -6690,6 +7355,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -6722,6 +7394,13 @@ "name": "angle_deqp_egl_gles_tests", "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -6751,6 +7430,13 @@ "name": "angle_deqp_gles2_gles_tests", "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -6780,6 +7466,13 @@ "name": "angle_deqp_gles3_gles_tests", "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ {
diff --git a/testing/buildbot/chromium.gpu.json b/testing/buildbot/chromium.gpu.json index 36b2d951..ed2e670e 100644 --- a/testing/buildbot/chromium.gpu.json +++ b/testing/buildbot/chromium.gpu.json
@@ -24,6 +24,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -59,6 +66,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -94,6 +108,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -129,6 +150,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -168,6 +196,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -212,6 +247,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -256,6 +298,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -285,6 +334,13 @@ "name": "rendering_representative_perf_tests", "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -320,6 +376,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -355,6 +418,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ { @@ -391,6 +461,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "containment_type": "AUTO", "dimension_sets": [ {
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json index 311271fc..9dd69c3 100644 --- a/testing/buildbot/chromium.linux.json +++ b/testing/buildbot/chromium.linux.json
@@ -7768,6 +7768,9 @@ "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, "name": "chromedriver_py_tests", + "resultdb": { + "enable": true + }, "swarming": { "can_use_on_swarming_builders": true, "dimension_sets": [ @@ -11784,6 +11787,9 @@ "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, "name": "chromedriver_py_tests", + "resultdb": { + "enable": true + }, "swarming": { "can_use_on_swarming_builders": true, "dimension_sets": [ @@ -14049,6 +14055,9 @@ "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, "name": "chromedriver_py_tests", + "resultdb": { + "enable": true + }, "swarming": { "can_use_on_swarming_builders": true, "dimension_sets": [
diff --git a/testing/buildbot/chromium.mac.json b/testing/buildbot/chromium.mac.json index affcbdd5..a3438e9 100644 --- a/testing/buildbot/chromium.mac.json +++ b/testing/buildbot/chromium.mac.json
@@ -1433,6 +1433,9 @@ "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, "name": "chromedriver_py_tests", + "resultdb": { + "enable": true + }, "swarming": { "can_use_on_swarming_builders": true, "dimension_sets": [ @@ -3152,6 +3155,9 @@ "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, "name": "chromedriver_py_tests", + "resultdb": { + "enable": true + }, "swarming": { "can_use_on_swarming_builders": true, "dimension_sets": [ @@ -4945,6 +4951,9 @@ "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, "name": "chromedriver_py_tests", + "resultdb": { + "enable": true + }, "swarming": { "can_use_on_swarming_builders": true, "dimension_sets": [ @@ -8272,6 +8281,9 @@ "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, "name": "chromedriver_py_tests", + "resultdb": { + "enable": true + }, "swarming": { "can_use_on_swarming_builders": true, "dimension_sets": [ @@ -9984,6 +9996,9 @@ "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, "name": "chromedriver_py_tests", + "resultdb": { + "enable": true + }, "swarming": { "can_use_on_swarming_builders": true, "dimension_sets": [
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json index 871b1714..87b63bd 100644 --- a/testing/buildbot/chromium.memory.json +++ b/testing/buildbot/chromium.memory.json
@@ -199,6 +199,13 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "device_os": "MMB29Q",
diff --git a/testing/buildbot/chromium.perf.fyi.json b/testing/buildbot/chromium.perf.fyi.json index 2de5c975..deaa736 100644 --- a/testing/buildbot/chromium.perf.fyi.json +++ b/testing/buildbot/chromium.perf.fyi.json
@@ -239,7 +239,9 @@ "--browser=web-engine-shell", "--passthrough", "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", + "--device=custom", + "--custom-device-target=internal.astro_target" ], "isolate_name": "fuchsia_telemetry_gpu_integration_test", "merge": { @@ -253,6 +255,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { + "cpu": null, "device_type": "Astro", "os": "Fuchsia", "pool": "chrome.tests" @@ -285,13 +288,13 @@ "--test-shard-map-filename=lacros-eve-perf-fyi_map.json", "--remote=variable_chromeos_device_hostname" ], - "isolate_name": "performance_test_suite", + "isolate_name": "performance_test_suite_eve", "merge": { "script": "//tools/perf/process_perf_results.py" }, - "name": "performance_test_suite", + "name": "performance_test_suite_eve", "override_compile_targets": [ - "performance_test_suite" + "performance_test_suite_eve" ], "swarming": { "can_use_on_swarming_builders": true,
diff --git a/testing/buildbot/chromium.perf.json b/testing/buildbot/chromium.perf.json index 813faec5..e6608795 100644 --- a/testing/buildbot/chromium.perf.json +++ b/testing/buildbot/chromium.perf.json
@@ -1104,7 +1104,6 @@ }, "linux-builder-perf-rel": { "additional_compile_targets": [ - "chromedriver", "chromium_builder_perf" ] },
diff --git a/testing/buildbot/chromium.updater.json b/testing/buildbot/chromium.updater.json index 450418ac..c0b1684598 100644 --- a/testing/buildbot/chromium.updater.json +++ b/testing/buildbot/chromium.updater.json
@@ -132,49 +132,6 @@ } ] }, - "mac10.13-updater-tester-dbg": { - "gtest_tests": [ - { - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" - }, - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "os": "Mac-10.13", - "pool": "chromium.updater.mac" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "updater_tests", - "test_id_prefix": "ninja://chrome/updater:updater_tests/" - } - ], - "isolated_scripts": [ - { - "isolate_name": "updater_integration_tests", - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "updater_integration_tests", - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "os": "Mac-10.13", - "pool": "chromium.updater.mac" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test_id_prefix": "ninja://chrome/updater:updater_integration_tests/" - } - ] - }, "mac10.13-updater-tester-rel": { "gtest_tests": [ { @@ -261,6 +218,49 @@ } ] }, + "mac10.15-updater-tester-dbg": { + "gtest_tests": [ + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "os": "Mac-10.15", + "pool": "chromium.updater.mac" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "updater_tests", + "test_id_prefix": "ninja://chrome/updater:updater_tests/" + } + ], + "isolated_scripts": [ + { + "isolate_name": "updater_integration_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "updater_integration_tests", + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "os": "Mac-10.15", + "pool": "chromium.updater.mac" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://chrome/updater:updater_integration_tests/" + } + ] + }, "mac10.15-updater-tester-rel": { "gtest_tests": [ {
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json index a13f76d..62f19f5 100644 --- a/testing/buildbot/chromium.win.json +++ b/testing/buildbot/chromium.win.json
@@ -1276,6 +1276,9 @@ "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, "name": "chromedriver_py_tests", + "resultdb": { + "enable": true + }, "swarming": { "can_use_on_swarming_builders": true, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -3644,6 +3647,9 @@ "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, "name": "chromedriver_py_tests", + "resultdb": { + "enable": true + }, "swarming": { "can_use_on_swarming_builders": true, "dimension_sets": [ @@ -7397,6 +7403,9 @@ "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, "name": "chromedriver_py_tests", + "resultdb": { + "enable": true + }, "swarming": { "can_use_on_swarming_builders": true, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
diff --git a/testing/buildbot/client.v8.fyi.json b/testing/buildbot/client.v8.fyi.json index 1dfd8e3f..5f5434d 100644 --- a/testing/buildbot/client.v8.fyi.json +++ b/testing/buildbot/client.v8.fyi.json
@@ -24,6 +24,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "device_os": "MMB29Q", @@ -58,6 +65,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "device_os": "MMB29Q", @@ -92,6 +106,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "device_os": "MMB29Q", @@ -126,6 +147,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "device_os": "MMB29Q", @@ -169,6 +197,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "device_os": "MMB29Q", @@ -212,6 +247,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "device_os": "MMB29Q", @@ -247,6 +289,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "device_os": "MMB29Q", @@ -281,6 +330,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "device_os": "MMB29Q", @@ -316,6 +372,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "device_os": "MMB29Q", @@ -352,6 +415,13 @@ "should_retry_with_patch": false, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "device_os": "MMB29Q",
diff --git a/testing/buildbot/generate_buildbot_json.py b/testing/buildbot/generate_buildbot_json.py index 35ca8dd..f2d2750d 100755 --- a/testing/buildbot/generate_buildbot_json.py +++ b/testing/buildbot/generate_buildbot_json.py
@@ -698,6 +698,24 @@ 'script': '//testing/trigger_scripts/chromeos_device_trigger.py', } + def add_logdog_butler_cipd_package(self, tester_config, result): + if not tester_config.get('skip_cipd_packages', False): + cipd_packages = result['swarming'].get('cipd_packages', []) + already_added = len([ + package for package in cipd_packages + if package.get('cipd_package', "").find('logdog/butler') > 0 + ]) > 0 + if not already_added: + cipd_packages.append({ + 'cipd_package': + 'infra/tools/luci/logdog/butler/${platform}', + 'location': + 'bin', + 'revision': + 'git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c', + }) + result['swarming']['cipd_packages'] = cipd_packages + def add_android_presentation_args(self, tester_config, test_name, result): args = result.get('args', []) bucket = tester_config.get('results_bucket', 'chromium-result-details') @@ -714,16 +732,6 @@ 'script': '//build/android/pylib/results/presentation/' 'test_results_presentation.py', } - if not tester_config.get('skip_cipd_packages', False): - cipd_packages = result['swarming'].get('cipd_packages', []) - cipd_packages.append( - { - 'cipd_package': 'infra/tools/luci/logdog/butler/${platform}', - 'location': 'bin', - 'revision': 'git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c', - } - ) - result['swarming']['cipd_packages'] = cipd_packages if not tester_config.get('skip_output_links', False): result['swarming']['output_links'] = [ { @@ -754,10 +762,13 @@ self.initialize_args_for_test( result, tester_config, additional_arg_keys=['gtest_args']) if self.is_android(tester_config) and tester_config.get( - 'use_swarming', - True) and not test_config.get('use_isolated_scripts_api', False): - self.add_android_presentation_args(tester_config, test_name, result) - result['args'] = result.get('args', []) + ['--recover-devices'] + 'use_swarming', True): + if not test_config.get('use_isolated_scripts_api', False): + # TODO(https://crbug.com/1137998) make Android presentation work with + # isolated scripts in test_results_presentation.py merge script + self.add_android_presentation_args(tester_config, test_name, result) + result['args'] = result.get('args', []) + ['--recover-devices'] + self.add_logdog_butler_cipd_package(tester_config, result) result = self.update_and_cleanup_test( result, test_name, tester_name, tester_config, waterfall) @@ -788,8 +799,13 @@ result['name'] = result.get('name', test_name) self.initialize_swarming_dictionary_for_test(result, tester_config) self.initialize_args_for_test(result, tester_config) - if tester_config.get('use_android_presentation', False): - self.add_android_presentation_args(tester_config, test_name, result) + if self.is_android(tester_config) and tester_config.get( + 'use_swarming', True): + if tester_config.get('use_android_presentation', False): + # TODO(https://crbug.com/1137998) make Android presentation work with + # isolated scripts in test_results_presentation.py merge script + self.add_android_presentation_args(tester_config, test_name, result) + self.add_logdog_butler_cipd_package(tester_config, result) result = self.update_and_cleanup_test( result, test_name, tester_name, tester_config, waterfall) self.add_common_test_properties(result, tester_config)
diff --git a/testing/buildbot/generate_buildbot_json_unittest.py b/testing/buildbot/generate_buildbot_json_unittest.py index 6999848..83c8982d 100755 --- a/testing/buildbot/generate_buildbot_json_unittest.py +++ b/testing/buildbot/generate_buildbot_json_unittest.py
@@ -248,6 +248,7 @@ 'name': 'chromium.test', 'machines': { 'Fake Tester': { + 'os_type': 'android', 'test_suites': { 'isolated_scripts': 'composition_tests', }, @@ -1417,7 +1418,8 @@ "--test-name", "foo_test" ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + "script": \ +"//build/android/pylib/results/presentation/test_results_presentation.py" }, "name": "foo_test", "swarming": { @@ -1426,7 +1428,8 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": \ +"git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" } ], "output_links": [
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl index 586546d..186cea8 100644 --- a/testing/buildbot/gn_isolate_map.pyl +++ b/testing/buildbot/gn_isolate_map.pyl
@@ -1439,6 +1439,10 @@ "label": "//chrome/test:performance_test_suite", "type": "generated_script", }, + "performance_test_suite_eve": { + "label": "//chrome/test:performance_test_suite_eve", + "type": "generated_script", + }, "performance_webview_test_suite": { "args": [ "remove", @@ -1930,9 +1934,6 @@ }, "webview_cts_tests": { "args": [ - "--logdog-bin-cmd", - "../../bin/logdog_butler", - "../../android_webview/tools/run_cts.py", "--skip-expected-failures", "--use-webview-provider", "apks/SystemWebView.apk", @@ -1942,7 +1943,7 @@ "-v", ], "label": "//android_webview/test:webview_cts_tests", - "script": "//build/android/test_wrapper/logdog_wrapper.py", + "script": "//android_webview/tools/run_cts.py", "type": "script", }, "webview_instrumentation_test_apk": {
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl index a660215..a7bd0eb 100644 --- a/testing/buildbot/test_suites.pyl +++ b/testing/buildbot/test_suites.pyl
@@ -458,9 +458,12 @@ 'chromedriver_py_tests_isolated_scripts': { 'chromedriver_py_tests': { - "args": [ - "--test-type=integration", + 'args': [ + '--test-type=integration', ], + 'resultdb': { + 'enable': True, + }, }, 'chromedriver_replay_unittests': {}, },
diff --git a/testing/buildbot/tryserver.chromium.android.json b/testing/buildbot/tryserver.chromium.android.json index 92059ee3..20caee5 100644 --- a/testing/buildbot/tryserver.chromium.android.json +++ b/testing/buildbot/tryserver.chromium.android.json
@@ -172,6 +172,13 @@ "results_handler": "layout tests", "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { "device_os": "LMY48M",
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl index f2d649c3..c3eff50 100644 --- a/testing/buildbot/variants.pyl +++ b/testing/buildbot/variants.pyl
@@ -320,13 +320,13 @@ '../../weblayer/browser/android/javatests/skew/expectations.txt', '--impl-version=89', ], - 'identifier': 'Implementation Library Skew Tests For 89.0.4389.46', + 'identifier': 'Implementation Library Skew Tests For 89.0.4389.48', 'swarming': { 'cipd_packages': [ { 'cipd_package': 'chromium/testing/weblayer-x86', 'location': 'weblayer_instrumentation_test_M89', - 'revision': 'version:89.0.4389.46', + 'revision': 'version:89.0.4389.48', } ], }, @@ -344,13 +344,13 @@ '../../weblayer/browser/android/javatests/skew/expectations.txt', '--impl-version=88', ], - 'identifier': 'Implementation Library Skew Tests For 88.0.4324.175', + 'identifier': 'Implementation Library Skew Tests For 88.0.4324.176', 'swarming': { 'cipd_packages': [ { 'cipd_package': 'chromium/testing/weblayer-x86', 'location': 'weblayer_instrumentation_test_M88', - 'revision': 'version:88.0.4324.175', + 'revision': 'version:88.0.4324.176', } ], }, @@ -392,13 +392,13 @@ '../../weblayer/browser/android/javatests/skew/expectations.txt', '--impl-version=89', ], - 'identifier': 'Implementation Library Skew Tests For 89.0.4389.46', + 'identifier': 'Implementation Library Skew Tests For 89.0.4389.48', 'swarming': { 'cipd_packages': [ { 'cipd_package': 'chromium/testing/weblayer-x86', 'location': 'weblayer_instrumentation_test_M89', - 'revision': 'version:89.0.4389.46', + 'revision': 'version:89.0.4389.48', } ], }, @@ -416,13 +416,13 @@ '../../weblayer/browser/android/javatests/skew/expectations.txt', '--impl-version=88', ], - 'identifier': 'Implementation Library Skew Tests For 88.0.4324.175', + 'identifier': 'Implementation Library Skew Tests For 88.0.4324.176', 'swarming': { 'cipd_packages': [ { 'cipd_package': 'chromium/testing/weblayer-x86', 'location': 'weblayer_instrumentation_test_M88', - 'revision': 'version:88.0.4324.175', + 'revision': 'version:88.0.4324.176', } ], }, @@ -464,13 +464,13 @@ '../../weblayer/browser/android/javatests/skew/expectations.txt', '--client-version=89', ], - 'identifier': 'Client Library Skew Tests For 89.0.4389.46', + 'identifier': 'Client Library Skew Tests For 89.0.4389.48', 'swarming': { 'cipd_packages': [ { 'cipd_package': 'chromium/testing/weblayer-x86', 'location': 'weblayer_instrumentation_test_M89', - 'revision': 'version:89.0.4389.46', + 'revision': 'version:89.0.4389.48', } ], }, @@ -488,13 +488,13 @@ '../../weblayer/browser/android/javatests/skew/expectations.txt', '--client-version=88', ], - 'identifier': 'Client Library Skew Tests For 88.0.4324.175', + 'identifier': 'Client Library Skew Tests For 88.0.4324.176', 'swarming': { 'cipd_packages': [ { 'cipd_package': 'chromium/testing/weblayer-x86', 'location': 'weblayer_instrumentation_test_M88', - 'revision': 'version:88.0.4324.175', + 'revision': 'version:88.0.4324.176', } ], },
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl index 149ccd6..1b72d97 100644 --- a/testing/buildbot/waterfalls.pyl +++ b/testing/buildbot/waterfalls.pyl
@@ -13,31 +13,11 @@ 'name': 'chrome', 'mixins': ['chrome-tester-service-account'], 'machines': { - 'chromeos-arm-generic-beta': { - 'additional_compile_targets': [ - 'chromiumos_preflight', - ], - }, 'chromeos-arm-generic-cfi-thin-lto-chrome': { 'additional_compile_targets': [ 'chromiumos_preflight', ], }, - 'chromeos-arm-generic-ltc': { - 'additional_compile_targets': [ - 'chromiumos_preflight', - ], - }, - 'chromeos-arm-generic-lts': { - 'additional_compile_targets': [ - 'chromiumos_preflight', - ], - }, - 'chromeos-arm-generic-stable': { - 'additional_compile_targets': [ - 'chromiumos_preflight', - ], - }, 'chromeos-betty-pi-arc-cfi-thin-lto-chrome': { 'additional_compile_targets': [ 'chromiumos_preflight', @@ -5635,20 +5615,6 @@ ] }, }, - 'mac10.13-updater-tester-dbg': { - 'test_suites': { - 'gtest_tests': 'updater_gtests', - 'isolated_scripts': 'updater_isolated_scripts', - }, - 'swarming': { - 'dimension_sets': [ - { - 'pool': 'chromium.updater.mac', - 'os': 'Mac-10.13', - } - ] - }, - }, 'mac10.13-updater-tester-rel': { 'test_suites': { 'gtest_tests': 'updater_gtests', @@ -5677,6 +5643,20 @@ ] }, }, + 'mac10.15-updater-tester-dbg': { + 'test_suites': { + 'gtest_tests': 'updater_gtests', + 'isolated_scripts': 'updater_isolated_scripts', + }, + 'swarming': { + 'dimension_sets': [ + { + 'pool': 'chromium.updater.mac', + 'os': 'Mac-10.15', + } + ] + }, + }, 'mac10.15-updater-tester-rel': { 'test_suites': { 'gtest_tests': 'updater_gtests',
diff --git a/testing/scripts/run_performance_tests.py b/testing/scripts/run_performance_tests.py index ada2604..4c23f81 100755 --- a/testing/scripts/run_performance_tests.py +++ b/testing/scripts/run_performance_tests.py
@@ -363,7 +363,7 @@ Returns: list of strings, the executable and its arguments. """ - return ([sys.executable, self._options.executable] + + return ([sys.executable] + self._options.executable.split(' ') + [self.benchmark] + self._generate_filter_args() + self._generate_also_run_disabled_tests_args() +
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 7f22e352..bd1bdfd 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -3264,6 +3264,22 @@ ] } ], + "FormControlsRefreshAndroid": [ + { + "platforms": [ + "android", + "android_webview" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "FormControlsRefresh" + ] + } + ] + } + ], "FreezeBackgroundTabOnNetworkIdle": [ { "platforms": [ @@ -5751,28 +5767,6 @@ ] } ], - "ReparseServerPredictionsFollowingFormChange": [ - { - "platforms": [ - "android", - "android_webview", - "chromeos", - "chromeos_lacros", - "ios", - "linux", - "mac", - "windows" - ], - "experiments": [ - { - "name": "Enabled", - "enable_features": [ - "ReparseServerPredictionsFollowingFormChange" - ] - } - ] - } - ], "ReportCertificateErrors": [ { "platforms": [ @@ -5932,7 +5926,7 @@ ] } ], - "SafeBrowsingEnhancedProtectionAndroid": [ + "SafeBrowsingPasswordProtectionReferringAppEnabledAndroid": [ { "platforms": [ "android" @@ -5941,29 +5935,7 @@ { "name": "Enabled", "enable_features": [ - "PrivacyReorderedAndroid", - "SafeBrowsingEnhancedProtection", - "SafeBrowsingSecuritySectionUIAndroid" - ] - } - ] - } - ], - "SafeBrowsingEnhancedProtectionMessageInInterstitials": [ - { - "platforms": [ - "android", - "chromeos", - "chromeos_lacros", - "linux", - "mac", - "windows" - ], - "experiments": [ - { - "name": "Enabled", - "enable_features": [ - "SafeBrowsingEnhancedProtectionMessageInInterstitials" + "SafeBrowsingPasswordProtectionReferringAppEnabledAndroid" ] } ] @@ -6006,21 +5978,6 @@ ] } ], - "SafeBrowsingRealTimeUrlLookupEnabledWithTokenAndroid": [ - { - "platforms": [ - "android" - ], - "experiments": [ - { - "name": "Enabled", - "enable_features": [ - "SafeBrowsingRealTimeUrlLookupEnabledWithToken" - ] - } - ] - } - ], "SafetyAndPasswordCheckAndroid": [ { "platforms": [ @@ -6142,28 +6099,6 @@ ] } ], - "SecondaryServerFieldPredictions": [ - { - "platforms": [ - "android", - "android_webview", - "chromeos", - "chromeos_lacros", - "ios", - "linux", - "mac", - "windows" - ], - "experiments": [ - { - "name": "Enabled", - "enable_features": [ - "SecondaryServerFieldPredictions" - ] - } - ] - } - ], "ServiceManagerForBackgroundPrefetch": [ { "platforms": [
diff --git a/third_party/.gitignore b/third_party/.gitignore index e03d2e0..fed5bb89 100644 --- a/third_party/.gitignore +++ b/third_party/.gitignore
@@ -56,6 +56,7 @@ /checkstyle/*.jar /chromeos_login_manager /chromeos_text_input +/chromevox/third_party/sre/src /chromite /cld_2/src /cld_3/src
diff --git a/third_party/blink/renderer/bindings/generated_in_modules.gni b/third_party/blink/renderer/bindings/generated_in_modules.gni index 050e3386..6f0b62b 100644 --- a/third_party/blink/renderer/bindings/generated_in_modules.gni +++ b/third_party/blink/renderer/bindings/generated_in_modules.gni
@@ -53,6 +53,8 @@ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_session_description_callback.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_stats_callback.cc", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_stats_callback.h", + "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_scheduler_post_task_callback.cc", + "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_scheduler_post_task_callback.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_state_callback.cc", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_state_callback.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_storage_error_callback.cc",
diff --git a/third_party/blink/renderer/bindings/idl_in_modules.gni b/third_party/blink/renderer/bindings/idl_in_modules.gni index c93c96c..b11cb53 100644 --- a/third_party/blink/renderer/bindings/idl_in_modules.gni +++ b/third_party/blink/renderer/bindings/idl_in_modules.gni
@@ -601,6 +601,7 @@ "//third_party/blink/renderer/modules/sanitizer_api/sanitizer.idl", "//third_party/blink/renderer/modules/sanitizer_api/sanitizer_config.idl", "//third_party/blink/renderer/modules/scheduler/scheduler.idl", + "//third_party/blink/renderer/modules/scheduler/scheduler_post_task_callback.idl", "//third_party/blink/renderer/modules/scheduler/scheduler_post_task_options.idl", "//third_party/blink/renderer/modules/scheduler/task_controller.idl", "//third_party/blink/renderer/modules/scheduler/task_signal.idl",
diff --git a/third_party/blink/renderer/core/animation/css_length_interpolation_type.cc b/third_party/blink/renderer/core/animation/css_length_interpolation_type.cc index 12c18f3..936b3fbf 100644 --- a/third_party/blink/renderer/core/animation/css_length_interpolation_type.cc +++ b/third_party/blink/renderer/core/animation/css_length_interpolation_type.cc
@@ -155,12 +155,14 @@ const float kSlack = 1e-6; const float before_length = FloatValueForLength(before, 100); const float after_length = FloatValueForLength(after, 100); - // Test relative difference for large values to avoid floating point - // inaccuracies tripping the check. - const float delta = std::abs(before_length) < kSlack - ? after_length - before_length - : (after_length - before_length) / before_length; - DCHECK_LT(std::abs(delta), kSlack); + if (std::isfinite(before_length) && std::isfinite(after_length)) { + // Test relative difference for large values to avoid floating point + // inaccuracies tripping the check. + const float delta = std::abs(before_length) < kSlack + ? after_length - before_length + : (after_length - before_length) / before_length; + DCHECK_LT(std::abs(delta), kSlack); + } #endif return; }
diff --git a/third_party/blink/renderer/core/css/counter_style.cc b/third_party/blink/renderer/core/css/counter_style.cc index 71fc781..a42437c 100644 --- a/third_party/blink/renderer/core/css/counter_style.cc +++ b/third_party/blink/renderer/core/css/counter_style.cc
@@ -400,7 +400,7 @@ } CounterStyle::CounterStyle(const StyleRuleCounterStyle& rule) - : style_rule_(rule) { + : style_rule_(rule), style_rule_version_(rule.GetVersion()) { if (const CSSValue* system = rule.GetSystem()) { system_ = ToCounterStyleSystemEnum(system); @@ -685,7 +685,8 @@ return; visited_counter_styles.insert(this); - if (has_inexistent_references_) { + if (has_inexistent_references_ || + style_rule_version_ != style_rule_->GetVersion()) { SetIsDirty(); return; }
diff --git a/third_party/blink/renderer/core/css/counter_style.h b/third_party/blink/renderer/core/css/counter_style.h index 83317946..3058e1ab 100644 --- a/third_party/blink/renderer/core/css/counter_style.h +++ b/third_party/blink/renderer/core/css/counter_style.h
@@ -114,6 +114,9 @@ // The corresponding style rule in CSS. Member<const StyleRuleCounterStyle> style_rule_; + // Tracks mutations of |style_rule_|. + int style_rule_version_; + // The actual system of the counter style with 'extends' resolved. The value // is kUnresolvedExtends temporarily before the resolution. CounterStyleSystem system_ = CounterStyleSystem::kSymbolic;
diff --git a/third_party/blink/renderer/core/css/css_counter_style_rule.cc b/third_party/blink/renderer/core/css/css_counter_style_rule.cc index 2d09aec..366180df 100644 --- a/third_party/blink/renderer/core/css/css_counter_style_rule.cc +++ b/third_party/blink/renderer/core/css/css_counter_style_rule.cc
@@ -3,7 +3,13 @@ // found in the LICENSE file. #include "third_party/blink/renderer/core/css/css_counter_style_rule.h" +#include "third_party/blink/renderer/core/css/css_style_sheet.h" +#include "third_party/blink/renderer/core/css/parser/at_rule_descriptor_parser.h" +#include "third_party/blink/renderer/core/css/parser/css_parser_context.h" +#include "third_party/blink/renderer/core/css/parser/css_tokenizer.h" +#include "third_party/blink/renderer/core/css/style_engine.h" #include "third_party/blink/renderer/core/css/style_rule_counter_style.h" +#include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/platform/wtf/text/string_builder.h" namespace blink { @@ -165,48 +171,124 @@ return String(); } +void CSSCounterStyleRule::SetterInternal( + const ExecutionContext* execution_context, + AtRuleDescriptorID descriptor_id, + const String& text) { + CSSStyleSheet* style_sheet = parentStyleSheet(); + auto& context = *MakeGarbageCollected<CSSParserContext>( + ParserContext(execution_context->GetSecureContextMode()), style_sheet); + CSSTokenizer tokenizer(text); + auto tokens = tokenizer.TokenizeToEOF(); + CSSParserTokenRange token_range(tokens); + CSSValue* new_value = AtRuleDescriptorParser::ParseAtCounterStyleDescriptor( + descriptor_id, token_range, context); + if (!new_value) + return; + + switch (descriptor_id) { + case AtRuleDescriptorID::System: + if (!counter_style_rule_->SetSystem(new_value)) + return; + break; + case AtRuleDescriptorID::Negative: + if (!counter_style_rule_->SetNegative(new_value)) + return; + break; + case AtRuleDescriptorID::Prefix: + if (!counter_style_rule_->SetPrefix(new_value)) + return; + break; + case AtRuleDescriptorID::Suffix: + if (!counter_style_rule_->SetSuffix(new_value)) + return; + break; + case AtRuleDescriptorID::Range: + if (!counter_style_rule_->SetRange(new_value)) + return; + break; + case AtRuleDescriptorID::Pad: + if (!counter_style_rule_->SetPad(new_value)) + return; + break; + case AtRuleDescriptorID::Fallback: + if (!counter_style_rule_->SetFallback(new_value)) + return; + break; + case AtRuleDescriptorID::Symbols: + if (!counter_style_rule_->SetSymbols(new_value)) + return; + break; + case AtRuleDescriptorID::AdditiveSymbols: + if (!counter_style_rule_->SetAdditiveSymbols(new_value)) + return; + break; + case AtRuleDescriptorID::SpeakAs: + if (!counter_style_rule_->SetSpeakAs(new_value)) + return; + break; + default: + NOTREACHED(); + return; + } + + if (Document* document = style_sheet->OwnerDocument()) + document->GetStyleEngine().MarkCounterStylesNeedUpdate(); +} + void CSSCounterStyleRule::setName(const String&) { // TODO(crbug.com/687225): Implement } -void CSSCounterStyleRule::setSystem(const String&) { - // TODO(crbug.com/687225): Implement +void CSSCounterStyleRule::setSystem(const ExecutionContext* execution_context, + const String& text) { + SetterInternal(execution_context, AtRuleDescriptorID::System, text); } -void CSSCounterStyleRule::setSymbols(const String&) { - // TODO(crbug.com/687225): Implement +void CSSCounterStyleRule::setSymbols(const ExecutionContext* execution_context, + const String& text) { + SetterInternal(execution_context, AtRuleDescriptorID::Symbols, text); } -void CSSCounterStyleRule::setAdditiveSymbols(const String&) { - // TODO(crbug.com/687225): Implement +void CSSCounterStyleRule::setAdditiveSymbols( + const ExecutionContext* execution_context, + const String& text) { + SetterInternal(execution_context, AtRuleDescriptorID::AdditiveSymbols, text); } -void CSSCounterStyleRule::setNegative(const String&) { - // TODO(crbug.com/687225): Implement +void CSSCounterStyleRule::setNegative(const ExecutionContext* execution_context, + const String& text) { + SetterInternal(execution_context, AtRuleDescriptorID::Negative, text); } -void CSSCounterStyleRule::setPrefix(const String&) { - // TODO(crbug.com/687225): Implement +void CSSCounterStyleRule::setPrefix(const ExecutionContext* execution_context, + const String& text) { + SetterInternal(execution_context, AtRuleDescriptorID::Prefix, text); } -void CSSCounterStyleRule::setSuffix(const String&) { - // TODO(crbug.com/687225): Implement +void CSSCounterStyleRule::setSuffix(const ExecutionContext* execution_context, + const String& text) { + SetterInternal(execution_context, AtRuleDescriptorID::Suffix, text); } -void CSSCounterStyleRule::setRange(const String&) { - // TODO(crbug.com/687225): Implement +void CSSCounterStyleRule::setRange(const ExecutionContext* execution_context, + const String& text) { + SetterInternal(execution_context, AtRuleDescriptorID::Range, text); } -void CSSCounterStyleRule::setPad(const String&) { - // TODO(crbug.com/687225): Implement +void CSSCounterStyleRule::setPad(const ExecutionContext* execution_context, + const String& text) { + SetterInternal(execution_context, AtRuleDescriptorID::Pad, text); } -void CSSCounterStyleRule::setSpeakAs(const String&) { - // TODO(crbug.com/687225): Implement +void CSSCounterStyleRule::setSpeakAs(const ExecutionContext* execution_context, + const String& text) { + SetterInternal(execution_context, AtRuleDescriptorID::SpeakAs, text); } -void CSSCounterStyleRule::setFallback(const String&) { - // TODO(crbug.com/687225): Implement +void CSSCounterStyleRule::setFallback(const ExecutionContext* execution_context, + const String& text) { + SetterInternal(execution_context, AtRuleDescriptorID::Fallback, text); } void CSSCounterStyleRule::Trace(Visitor* visitor) const {
diff --git a/third_party/blink/renderer/core/css/css_counter_style_rule.h b/third_party/blink/renderer/core/css/css_counter_style_rule.h index 7581cb9c..524ef61 100644 --- a/third_party/blink/renderer/core/css/css_counter_style_rule.h +++ b/third_party/blink/renderer/core/css/css_counter_style_rule.h
@@ -6,10 +6,12 @@ #define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_COUNTER_STYLE_RULE_H_ #include "third_party/blink/renderer/core/css/css_rule.h" +#include "third_party/blink/renderer/core/css/parser/at_rule_descriptors.h" #include "third_party/blink/renderer/platform/wtf/casting.h" namespace blink { +class ExecutionContext; class StyleRuleCounterStyle; class CSSCounterStyleRule final : public CSSRule { @@ -35,22 +37,26 @@ String fallback() const; void setName(const String&); - void setSystem(const String&); - void setSymbols(const String&); - void setAdditiveSymbols(const String&); - void setNegative(const String&); - void setPrefix(const String&); - void setSuffix(const String&); - void setRange(const String&); - void setPad(const String&); - void setSpeakAs(const String&); - void setFallback(const String&); + void setSystem(const ExecutionContext*, const String&); + void setSymbols(const ExecutionContext*, const String&); + void setAdditiveSymbols(const ExecutionContext*, const String&); + void setNegative(const ExecutionContext*, const String&); + void setPrefix(const ExecutionContext*, const String&); + void setSuffix(const ExecutionContext*, const String&); + void setRange(const ExecutionContext*, const String&); + void setPad(const ExecutionContext*, const String&); + void setSpeakAs(const ExecutionContext*, const String&); + void setFallback(const ExecutionContext*, const String&); void Trace(Visitor*) const override; private: CSSRule::Type GetType() const override { return kCounterStyleRule; } + void SetterInternal(const ExecutionContext*, + AtRuleDescriptorID, + const String&); + Member<StyleRuleCounterStyle> counter_style_rule_; };
diff --git a/third_party/blink/renderer/core/css/css_counter_style_rule.idl b/third_party/blink/renderer/core/css/css_counter_style_rule.idl index 4b1f8ef..c8147ae6 100644 --- a/third_party/blink/renderer/core/css/css_counter_style_rule.idl +++ b/third_party/blink/renderer/core/css/css_counter_style_rule.idl
@@ -6,14 +6,14 @@ [Exposed=Window, RuntimeEnabled=CSSAtRuleCounterStyle] interface CSSCounterStyleRule : CSSRule { attribute CSSOMString name; - attribute CSSOMString system; - attribute CSSOMString symbols; - attribute CSSOMString additiveSymbols; - attribute CSSOMString negative; - attribute CSSOMString prefix; - attribute CSSOMString suffix; - attribute CSSOMString range; - attribute CSSOMString pad; - attribute CSSOMString speakAs; - attribute CSSOMString fallback; + [SetterCallWith=ExecutionContext] attribute CSSOMString system; + [SetterCallWith=ExecutionContext] attribute CSSOMString symbols; + [SetterCallWith=ExecutionContext] attribute CSSOMString additiveSymbols; + [SetterCallWith=ExecutionContext] attribute CSSOMString negative; + [SetterCallWith=ExecutionContext] attribute CSSOMString prefix; + [SetterCallWith=ExecutionContext] attribute CSSOMString suffix; + [SetterCallWith=ExecutionContext] attribute CSSOMString range; + [SetterCallWith=ExecutionContext] attribute CSSOMString pad; + [SetterCallWith=ExecutionContext] attribute CSSOMString speakAs; + [SetterCallWith=ExecutionContext] attribute CSSOMString fallback; };
diff --git a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc index caf654b4..f7821e93 100644 --- a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc +++ b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
@@ -1585,10 +1585,10 @@ const CSSValue* ClipRule::CSSValueFromComputedStyleInternal( const ComputedStyle& style, - const SVGComputedStyle& svg_style, + const SVGComputedStyle&, const LayoutObject*, bool allow_visited_style) const { - return CSSIdentifierValue::Create(svg_style.ClipRule()); + return CSSIdentifierValue::Create(style.ClipRule()); } const CSSValue* Color::ParseSingleValue(CSSParserTokenRange& range, @@ -1650,26 +1650,26 @@ const CSSValue* ColorInterpolation::CSSValueFromComputedStyleInternal( const ComputedStyle& style, - const SVGComputedStyle& svg_style, + const SVGComputedStyle&, const LayoutObject*, bool allow_visited_style) const { - return CSSIdentifierValue::Create(svg_style.ColorInterpolation()); + return CSSIdentifierValue::Create(style.ColorInterpolation()); } const CSSValue* ColorInterpolationFilters::CSSValueFromComputedStyleInternal( const ComputedStyle& style, - const SVGComputedStyle& svg_style, + const SVGComputedStyle&, const LayoutObject*, bool allow_visited_style) const { - return CSSIdentifierValue::Create(svg_style.ColorInterpolationFilters()); + return CSSIdentifierValue::Create(style.ColorInterpolationFilters()); } const CSSValue* ColorRendering::CSSValueFromComputedStyleInternal( const ComputedStyle& style, - const SVGComputedStyle& svg_style, + const SVGComputedStyle&, const LayoutObject*, bool allow_visited_style) const { - return CSSIdentifierValue::Create(svg_style.ColorRendering()); + return CSSIdentifierValue::Create(style.ColorRendering()); } const CSSValue* ColorScheme::ParseSingleValue( @@ -2655,10 +2655,10 @@ const CSSValue* DominantBaseline::CSSValueFromComputedStyleInternal( const ComputedStyle& style, - const SVGComputedStyle& svg_style, + const SVGComputedStyle&, const LayoutObject*, bool allow_visited_style) const { - return CSSIdentifierValue::Create(svg_style.DominantBaseline()); + return CSSIdentifierValue::Create(style.DominantBaseline()); } const CSSValue* EmptyCells::CSSValueFromComputedStyleInternal( @@ -2712,10 +2712,10 @@ const CSSValue* FillRule::CSSValueFromComputedStyleInternal( const ComputedStyle& style, - const SVGComputedStyle& svg_style, + const SVGComputedStyle&, const LayoutObject*, bool allow_visited_style) const { - return CSSIdentifierValue::Create(svg_style.FillRule()); + return CSSIdentifierValue::Create(style.FillRule()); } const CSSValue* Filter::ParseSingleValue(CSSParserTokenRange& range, @@ -5474,11 +5474,11 @@ } const CSSValue* PaintOrder::CSSValueFromComputedStyleInternal( - const ComputedStyle&, - const SVGComputedStyle& svg_style, + const ComputedStyle& style, + const SVGComputedStyle&, const LayoutObject*, bool allow_visited_style) const { - const EPaintOrder paint_order = svg_style.PaintOrder(); + const EPaintOrder paint_order = style.PaintOrder(); if (paint_order == kPaintOrderNormal) return CSSIdentifierValue::Create(CSSValueID::kNormal); @@ -6345,10 +6345,10 @@ const CSSValue* ShapeRendering::CSSValueFromComputedStyleInternal( const ComputedStyle& style, - const SVGComputedStyle& svg_style, + const SVGComputedStyle&, const LayoutObject*, bool allow_visited_style) const { - return CSSIdentifierValue::Create(svg_style.ShapeRendering()); + return CSSIdentifierValue::Create(style.ShapeRendering()); } static CSSValue* ConsumePageSize(CSSParserTokenRange& range) { @@ -6784,10 +6784,10 @@ const CSSValue* TextAnchor::CSSValueFromComputedStyleInternal( const ComputedStyle& style, - const SVGComputedStyle& svg_style, + const SVGComputedStyle&, const LayoutObject*, bool allow_visited_style) const { - return CSSIdentifierValue::Create(svg_style.TextAnchor()); + return CSSIdentifierValue::Create(style.TextAnchor()); } const CSSValue* TextCombineUpright::CSSValueFromComputedStyleInternal(
diff --git a/third_party/blink/renderer/core/css/style_engine.cc b/third_party/blink/renderer/core/css/style_engine.cc index dd570c4e..84f1f72 100644 --- a/third_party/blink/renderer/core/css/style_engine.cc +++ b/third_party/blink/renderer/core/css/style_engine.cc
@@ -546,13 +546,6 @@ // Moving the initialization to other places causes test failures, which // needs investigation and fixing. CounterStyleMap::GetUACounterStyleMap(); - - if (counter_styles_need_update_) { - CounterStyleMap::MarkAllDirtyCounterStyles(GetDocument(), - active_tree_scopes_); - CounterStyleMap::ResolveAllReferences(GetDocument(), active_tree_scopes_); - counter_styles_need_update_ = false; - } } probe::ActiveStyleSheetsUpdated(document_); @@ -563,6 +556,16 @@ user_style_dirty_ = false; } +void StyleEngine::UpdateCounterStyles() { + if (!counter_styles_need_update_) + return; + DCHECK(RuntimeEnabledFeatures::CSSAtRuleCounterStyleEnabled()); + CounterStyleMap::MarkAllDirtyCounterStyles(GetDocument(), + active_tree_scopes_); + CounterStyleMap::ResolveAllReferences(GetDocument(), active_tree_scopes_); + counter_styles_need_update_ = false; +} + void StyleEngine::UpdateViewport() { if (viewport_resolver_) viewport_resolver_->UpdateViewport(GetDocumentStyleSheetCollection());
diff --git a/third_party/blink/renderer/core/css/style_engine.h b/third_party/blink/renderer/core/css/style_engine.h index 16f6c6c2..595ba53 100644 --- a/third_party/blink/renderer/core/css/style_engine.h +++ b/third_party/blink/renderer/core/css/style_engine.h
@@ -378,6 +378,7 @@ void InvalidateStyleAndLayoutForFontUpdates(); void MarkCounterStylesNeedUpdate(); + void UpdateCounterStyles(); StyleRuleKeyframes* KeyframeStylesForAnimation( const AtomicString& animation_name);
diff --git a/third_party/blink/renderer/core/css/style_rule_counter_style.h b/third_party/blink/renderer/core/css/style_rule_counter_style.h index c3c76e8..e45bfa3bd 100644 --- a/third_party/blink/renderer/core/css/style_rule_counter_style.h +++ b/third_party/blink/renderer/core/css/style_rule_counter_style.h
@@ -15,6 +15,8 @@ StyleRuleCounterStyle(const StyleRuleCounterStyle&); ~StyleRuleCounterStyle(); + int GetVersion() const { return version_; } + AtomicString GetName() const { return name_; } const CSSValue* GetSystem() const { return system_; } const CSSValue* GetNegative() const { return negative_; } @@ -27,19 +29,58 @@ const CSSValue* GetAdditiveSymbols() const { return additive_symbols_; } const CSSValue* GetSpeakAs() const { return speak_as_; } - void SetName(const AtomicString& name) { name_ = name; } - void SetSystem(const CSSValue* system) { system_ = system; } - void SetNegative(const CSSValue* negative) { negative_ = negative; } - void SetPrefix(const CSSValue* prefix) { prefix_ = prefix; } - void SetSuffix(const CSSValue* suffix) { suffix_ = suffix; } - void SetRange(const CSSValue* range) { range_ = range; } - void SetPad(const CSSValue* pad) { pad_ = pad; } - void SetFallback(const CSSValue* fallback) { fallback_ = fallback; } - void SetSymbols(const CSSValue* symbols) { symbols_ = symbols; } - void SetAdditiveSymbols(const CSSValue* additive_symbols) { - additive_symbols_ = additive_symbols; + // Returns false if the setter fails due to invalid new value. + bool SetName(const AtomicString& name) { + // TODO(crbug.com/687225): Implement. + return false; } - void SetSpeakAs(const CSSValue* speak_as) { speak_as_ = speak_as; } + bool SetSystem(const CSSValue* system) { + // TODO(crbug.com/687225): Implement. + return false; + } + bool SetNegative(const CSSValue* negative) { + negative_ = negative; + ++version_; + return true; + } + bool SetPrefix(const CSSValue* prefix) { + prefix_ = prefix; + ++version_; + return true; + } + bool SetSuffix(const CSSValue* suffix) { + suffix_ = suffix; + ++version_; + return true; + } + bool SetRange(const CSSValue* range) { + range_ = range; + ++version_; + return true; + } + bool SetPad(const CSSValue* pad) { + pad_ = pad; + ++version_; + return true; + } + bool SetFallback(const CSSValue* fallback) { + fallback_ = fallback; + ++version_; + return true; + } + bool SetSymbols(const CSSValue* symbols) { + // TODO(crbug.com/687225): Implement. + return false; + } + bool SetAdditiveSymbols(const CSSValue* additive_symbols) { + // TODO(crbug.com/687225): Implement. + return false; + } + bool SetSpeakAs(const CSSValue* speak_as) { + speak_as_ = speak_as; + ++version_; + return true; + } bool HasFailedOrCanceledSubresources() const { // TODO(crbug.com/687225): Implement. @@ -64,6 +105,9 @@ Member<const CSSValue> symbols_; Member<const CSSValue> additive_symbols_; Member<const CSSValue> speak_as_; + + // Tracks mutations due to setter functions. + int version_ = 0; }; template <>
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc index 682af22..b576a68f 100644 --- a/third_party/blink/renderer/core/dom/document.cc +++ b/third_party/blink/renderer/core/dom/document.cc
@@ -2358,6 +2358,7 @@ UpdateUseShadowTreesIfNeeded(); GetStyleEngine().UpdateActiveStyle(); + GetStyleEngine().UpdateCounterStyles(); InvalidateStyleAndLayoutForFontUpdates(); UpdateStyleInvalidationIfNeeded(); UpdateStyle(); @@ -3309,49 +3310,56 @@ if (ignore_opens_and_writes_for_abort_) return; - // If this document is fully active, change |document|'s URL to the URL of the - // responsible document specified by the entry settings object. - if (dom_window_ && entered_window && dom_window_ != entered_window) { - auto* csp = MakeGarbageCollected<ContentSecurityPolicy>(); - csp->CopyStateFrom(entered_window->GetContentSecurityPolicy()); - // We inherit the sandbox flags of the entered document, so mask on - // the ones contained in the CSP. The operator| is a bitwise operation on - // the sandbox flags bits. It makes the sandbox policy stricter (or as - // strict) as both policy. - // - // TODO(arthursonzogni): Why merging sandbox flags? - // This doesn't look great at many levels: - // - The browser process won't be notified of the update. - // - The origin won't be made opaque, despite the new flags. - // - The sandbox flags of the document can't be considered to be an - // immutable property anymore. - // - // Ideally: - // - javascript-url document. - // - XSLT document. - // - document.open. - // should not mutate the security properties of the current document. From - // the browser process point of view, all of those operations are not - // considered to produce new documents. No IPCs are sent, it is as if it was - // a no-op. - dom_window_->GetSecurityContext().SetSandboxFlags( - dom_window_->GetSecurityContext().GetSandboxFlags() | - entered_window->GetSandboxFlags()); - dom_window_->GetSecurityContext().SetContentSecurityPolicy(csp); - dom_window_->GetContentSecurityPolicy()->BindToDelegate( - dom_window_->GetContentSecurityPolicyDelegate()); + // If this document is fully active, then run the URL and history update steps + // for this document with the entered window's url. + if (dom_window_ && entered_window) { + KURL new_url = entered_window->Url(); // Clear the hash fragment from the inherited URL to prevent a // scroll-into-view for any document.open()'d frame. - KURL new_url = entered_window->Url(); - new_url.SetFragmentIdentifier(String()); + if (dom_window_ != entered_window) + new_url.SetFragmentIdentifier(String()); SetURL(new_url); - if (Loader()) - Loader()->UpdateUrlForDocumentOpen(new_url); - dom_window_->GetSecurityContext().SetSecurityOrigin( - entered_window->GetMutableSecurityOrigin()); - dom_window_->SetReferrerPolicy(entered_window->GetReferrerPolicy()); - cookie_url_ = entered_window->document()->CookieURL(); + auto* state_object = Loader()->GetHistoryItem() + ? Loader()->GetHistoryItem()->StateObject() + : nullptr; + Loader()->RunURLAndHistoryUpdateSteps(new_url, state_object); + + if (dom_window_ != entered_window) { + auto* csp = MakeGarbageCollected<ContentSecurityPolicy>(); + csp->CopyStateFrom(entered_window->GetContentSecurityPolicy()); + // We inherit the sandbox flags of the entered document, so mask on + // the ones contained in the CSP. The operator| is a bitwise operation on + // the sandbox flags bits. It makes the sandbox policy stricter (or as + // strict) as both policy. + // + // TODO(arthursonzogni): Why merging sandbox flags? + // This doesn't look great at many levels: + // - The browser process won't be notified of the update. + // - The origin won't be made opaque, despite the new flags. + // - The sandbox flags of the document can't be considered to be an + // immutable property anymore. + // + // Ideally: + // - javascript-url document. + // - XSLT document. + // - document.open. + // should not mutate the security properties of the current document. From + // the browser process point of view, all of those operations are not + // considered to produce new documents. No IPCs are sent, it is as if it + // was a no-op. + dom_window_->GetSecurityContext().SetSandboxFlags( + dom_window_->GetSecurityContext().GetSandboxFlags() | + entered_window->GetSandboxFlags()); + dom_window_->GetSecurityContext().SetContentSecurityPolicy(csp); + dom_window_->GetContentSecurityPolicy()->BindToDelegate( + dom_window_->GetContentSecurityPolicyDelegate()); + + dom_window_->GetSecurityContext().SetSecurityOrigin( + entered_window->GetMutableSecurityOrigin()); + dom_window_->SetReferrerPolicy(entered_window->GetReferrerPolicy()); + cookie_url_ = entered_window->document()->CookieURL(); + } } open(); @@ -7305,28 +7313,21 @@ return nullptr; } -void Document::PushNewPopupElement(HTMLPopupElement* popup) { - DCHECK(!popup_element_stack_.Contains(popup)); - popup_element_stack_.push_back(popup); - AddToTopLayer(popup); +bool Document::PopupShowing() const { + return !popup_element_stack_.IsEmpty(); } - -void Document::PopPopupElement(HTMLPopupElement* popup) { - DCHECK(popup_element_stack_.back() == popup); - popup_element_stack_.pop_back(); - RemoveFromTopLayer(popup); +void Document::HideTopmostPopupElement() const { + if (popup_element_stack_.IsEmpty()) + return; + popup_element_stack_.back()->hide(); } - -HTMLPopupElement* Document::TopmostPopupElement() { - return popup_element_stack_.IsEmpty() ? nullptr : popup_element_stack_.back(); -} - void Document::HideAllPopupsUntil(HTMLPopupElement* endpoint) { - HTMLPopupElement* element; - while ((element = TopmostPopupElement()) != endpoint) { - DCHECK(element) << "popup element not found in element stack"; - element->hide(); + while (!popup_element_stack_.IsEmpty() && + popup_element_stack_.back() != endpoint) { + popup_element_stack_.back()->hide(); } + DCHECK(!endpoint || popup_element_stack_.back() == endpoint) + << "popup element not found in element stack"; } void Document::exitPointerLock() {
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h index 2509ca5f..7d28874 100644 --- a/third_party/blink/renderer/core/dom/document.h +++ b/third_party/blink/renderer/core/dom/document.h
@@ -1376,22 +1376,21 @@ const HeapVector<Member<Element>>& TopLayerElements() const { return top_layer_elements_; } - const HeapVector<Member<HTMLPopupElement>>& PopupElementStack() const { + + HTMLDialogElement* ActiveModalDialog() const; + + HeapVector<Member<HTMLPopupElement>>& PopupElementStack() { return popup_element_stack_; } + bool PopupShowing() const; + void HideTopmostPopupElement() const; // This hides all visible popups up to, but not including, // |endpoint|. If |endpoint| is nullptr, all popups are hidden. void HideAllPopupsUntil(HTMLPopupElement* endpoint); - HTMLDialogElement* ActiveModalDialog() const; - - void PushNewPopupElement(HTMLPopupElement*); - void PopPopupElement(HTMLPopupElement*); - HTMLPopupElement* TopmostPopupElement(); - // A non-null template_document_host_ implies that |this| was created by // EnsureTemplateDocument(). - bool IsTemplateDocument() const { return !!template_document_host_; } + bool IsTemplateDocument() const { return template_document_host_; } Document& EnsureTemplateDocument(); Document* TemplateDocumentHost() { return template_document_host_; }
diff --git a/third_party/blink/renderer/core/dom/document_init.cc b/third_party/blink/renderer/core/dom/document_init.cc index 9ad270e3..a43dcce 100644 --- a/third_party/blink/renderer/core/dom/document_init.cc +++ b/third_party/blink/renderer/core/dom/document_init.cc
@@ -217,7 +217,30 @@ } const KURL& DocumentInit::GetCookieUrl() const { - return owner_document_ ? owner_document_->CookieURL() : url_; + const KURL& cookie_url = + owner_document_ ? owner_document_->CookieURL() : url_; + + // An "about:blank" should inherit the `cookie_url` from the initiator of the + // navigation, but sometimes "about:blank" may commit without an + // `owner_document` (e.g. if the original initiator has been navigated away). + // In such scenario, it is important to use a safe `cookie_url` (e.g. + // kCookieAverseUrl) to avoid triggering mojo::ReportBadMessage and renderer + // kills via RestrictedCookieManager::ValidateAccessToCookiesAt. + // + // TODO(https://crbug.com/1176291): Correctly inherit the `cookie_url` from + // the initiator. + if (cookie_url.IsAboutBlankURL()) { + // Signify a cookie-averse document [1] with an null URL. See how + // CookiesJar::GetCookies and other methods check `cookie_url` against + // KURL::IsEmpty. + // + // [1] https://html.spec.whatwg.org/#cookie-averse-document-object + const KURL& kCookieAverseUrl = NullURL(); + + return kCookieAverseUrl; + } + + return cookie_url; } DocumentInit& DocumentInit::WithSrcdocDocument(bool is_srcdoc_document) {
diff --git a/third_party/blink/renderer/core/dom/node.cc b/third_party/blink/renderer/core/dom/node.cc index caf2a77..13caf93f 100644 --- a/third_party/blink/renderer/core/dom/node.cc +++ b/third_party/blink/renderer/core/dom/node.cc
@@ -101,6 +101,7 @@ #include "third_party/blink/renderer/core/html/custom/custom_element.h" #include "third_party/blink/renderer/core/html/html_dialog_element.h" #include "third_party/blink/renderer/core/html/html_frame_owner_element.h" +#include "third_party/blink/renderer/core/html/html_popup_element.h" #include "third_party/blink/renderer/core/html/html_slot_element.h" #include "third_party/blink/renderer/core/html_names.h" #include "third_party/blink/renderer/core/input/event_handler.h" @@ -2853,6 +2854,24 @@ } void Node::HandleLocalEvents(Event& event) { + if (IsDocumentNode() && GetDocument().PopupShowing() && + event.eventPhase() == Event::kCapturingPhase) { + // There is a popup visible - check if this event should "light dismiss" + // one or more popups. + const AtomicString& event_type = event.type(); + if (event_type == event_type_names::kClick) { + HTMLPopupElement* closest_popup_parent = nullptr; + for (Node* current_node = event.target()->ToNode(); current_node; + current_node = current_node->parentNode()) { + if (auto* popup = DynamicTo<HTMLPopupElement>(current_node)) { + closest_popup_parent = popup; + break; + } + } + GetDocument().HideAllPopupsUntil(closest_popup_parent); + } + } + if (!HasEventTargetData()) return;
diff --git a/third_party/blink/renderer/core/frame/history.cc b/third_party/blink/renderer/core/frame/history.cc index 2db3ecfc..1c0cc93 100644 --- a/third_party/blink/renderer/core/frame/history.cc +++ b/third_party/blink/renderer/core/frame/history.cc
@@ -341,9 +341,8 @@ return; } - DomWindow()->document()->Loader()->UpdateForSameDocumentNavigation( - full_url, kSameDocumentNavigationHistoryApi, std::move(data), - restoration_type, type, DomWindow()->document()); + DomWindow()->document()->Loader()->RunURLAndHistoryUpdateSteps( + full_url, std::move(data), restoration_type, type); } } // namespace blink
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc index bc6f08d9..ec38e8ed 100644 --- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc +++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
@@ -1139,9 +1139,8 @@ return false; // The command line flag --disable-accelerated-2d-canvas toggles this option - if (!RuntimeEnabledFeatures::Accelerated2dCanvasEnabled()) { + if (!RuntimeEnabledFeatures::Accelerated2dCanvasEnabled()) return false; - } // Webview crashes with accelerated small canvases (crbug.com/1004304) // Experimenting to see if this still causes crashes (crbug.com/1136603)
diff --git a/third_party/blink/renderer/core/html/html_popup_element.cc b/third_party/blink/renderer/core/html/html_popup_element.cc index c05bbf7a..9a6757c 100644 --- a/third_party/blink/renderer/core/html/html_popup_element.cc +++ b/third_party/blink/renderer/core/html/html_popup_element.cc
@@ -32,7 +32,7 @@ if (!open_) return; GetDocument().HideAllPopupsUntil(this); - GetDocument().PopPopupElement(this); + PopPopupElement(this); open_ = false; PseudoStateChanged(CSSSelector::kPseudoPopupOpen); MarkStyleDirty(); @@ -65,10 +65,29 @@ GetDocument().HideAllPopupsUntil(parent_popup); open_ = true; PseudoStateChanged(CSSSelector::kPseudoPopupOpen); - GetDocument().PushNewPopupElement(this); + PushNewPopupElement(this); MarkStyleDirty(); } +void HTMLPopupElement::PushNewPopupElement(HTMLPopupElement* popup) { + auto& stack = GetDocument().PopupElementStack(); + DCHECK(!stack.Contains(popup)); + stack.push_back(popup); + GetDocument().AddToTopLayer(popup); +} + +void HTMLPopupElement::PopPopupElement(HTMLPopupElement* popup) { + auto& stack = GetDocument().PopupElementStack(); + DCHECK(stack.back() == popup); + stack.pop_back(); + GetDocument().RemoveFromTopLayer(popup); +} + +HTMLPopupElement* HTMLPopupElement::TopmostPopupElement() { + auto& stack = GetDocument().PopupElementStack(); + return stack.IsEmpty() ? nullptr : stack.back(); +} + Element* HTMLPopupElement::AnchorElement() const { const AtomicString& anchor_id = FastGetAttribute(html_names::kAnchorAttr); if (anchor_id.IsNull())
diff --git a/third_party/blink/renderer/core/html/html_popup_element.h b/third_party/blink/renderer/core/html/html_popup_element.h index a38c76b..b6e4ec7 100644 --- a/third_party/blink/renderer/core/html/html_popup_element.h +++ b/third_party/blink/renderer/core/html/html_popup_element.h
@@ -34,6 +34,10 @@ void ScheduleHideEvent(); void MarkStyleDirty(); + void PushNewPopupElement(HTMLPopupElement*); + void PopPopupElement(HTMLPopupElement*); + HTMLPopupElement* TopmostPopupElement(); + bool open_; };
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc index 34f7f61..206c9698 100644 --- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc
@@ -27,7 +27,7 @@ scoped_refptr<const NGLayoutResult> NGGridLayoutAlgorithm::Layout() { // Measure items. - Vector<GridItemData> grid_items; + GridItems grid_items; Vector<GridItemData> out_of_flow_items; ConstructAndAppendGridItems(&grid_items, &out_of_flow_items); @@ -40,23 +40,16 @@ BuildAlgorithmTrackCollections(&grid_items, &column_track_collection, &row_track_collection, &grid_placement); - // Create a vector of grid item indices using |NGGridChildIterator| order. - Vector<wtf_size_t> reordered_item_indices(grid_items.size()); - for (wtf_size_t i = 0; i < grid_items.size(); ++i) - reordered_item_indices[i] = i; - // Cache track span properties for grid items. - CacheGridItemsTrackSpanProperties(column_track_collection, &grid_items, - &reordered_item_indices); - CacheGridItemsTrackSpanProperties(row_track_collection, &grid_items, - &reordered_item_indices); + CacheGridItemsTrackSpanProperties(column_track_collection, &grid_items); + CacheGridItemsTrackSpanProperties(row_track_collection, &grid_items); // Resolve inline size. ComputeUsedTrackSizes(SizingConstraint::kLayout, &column_track_collection, - &grid_items, &reordered_item_indices); + &grid_items); // Resolve block size. ComputeUsedTrackSizes(SizingConstraint::kLayout, &row_track_collection, - &grid_items, &reordered_item_indices); + &grid_items); // Determine the final (used) set geometry. const SetGeometry column_set_geometry = ComputeSetGeometry( @@ -92,7 +85,7 @@ } // Cache set indices for grid items, as all of them will be used. - for (GridItemData& grid_item : grid_items) { + for (auto& grid_item : grid_items.item_data) { grid_item.SetIndices(column_track_collection); grid_item.SetIndices(row_track_collection); } @@ -141,8 +134,8 @@ // TODO(janewman): Handle the cases typically done via: // CalculateMinMaxSizesIgnoringChildren. - // Measure Items - Vector<GridItemData> grid_items; + // Measure items. + GridItems grid_items; ConstructAndAppendGridItems(&grid_items); NGGridLayoutAlgorithmTrackCollection column_track_collection_for_min_size; @@ -155,14 +148,9 @@ &column_track_collection_for_min_size, &row_track_collection, &grid_placement); - // Create a vector of grid item indices using |NGGridChildIterator| order. - Vector<wtf_size_t> reordered_item_indices(grid_items.size()); - for (wtf_size_t i = 0; i < grid_items.size(); ++i) - reordered_item_indices[i] = i; - // Cache track span properties for grid items. CacheGridItemsTrackSpanProperties(column_track_collection_for_min_size, - &grid_items, &reordered_item_indices); + &grid_items); // Before the track sizing algorithm, create a copy of the column collection; // one will be used to compute the min size and the other for the max size. @@ -171,12 +159,10 @@ // Resolve inline size under a 'min-content' constraint. ComputeUsedTrackSizes(SizingConstraint::kMinContent, - &column_track_collection_for_min_size, &grid_items, - &reordered_item_indices); + &column_track_collection_for_min_size, &grid_items); // Resolve inline size under a 'max-content' constraint. ComputeUsedTrackSizes(SizingConstraint::kMaxContent, - &column_track_collection_for_max_size, &grid_items, - &reordered_item_indices); + &column_track_collection_for_max_size, &grid_items); const LayoutUnit grid_gap = GridGap(kForColumns); MinMaxSizes sizes{ @@ -351,49 +337,24 @@ return set_indices; } -NGGridLayoutAlgorithm::ReorderedGridItems::Iterator::Iterator( - Vector<wtf_size_t>::const_iterator current_index, - Vector<GridItemData>* grid_items) - : current_index_(current_index), grid_items_(grid_items) {} - -bool NGGridLayoutAlgorithm::ReorderedGridItems::Iterator::operator!=( - const Iterator& other) const { - return grid_items_ != other.grid_items_ || - current_index_ != other.current_index_; +NGGridLayoutAlgorithm::GridItems::Iterator +NGGridLayoutAlgorithm::GridItems::begin() { + return Iterator(&item_data, reordered_item_indices.begin()); } -NGGridLayoutAlgorithm::GridItemData* -NGGridLayoutAlgorithm::ReorderedGridItems::Iterator::operator->() { - DCHECK_LT(*current_index_, grid_items_->size()); - return &(grid_items_->at(*current_index_)); +NGGridLayoutAlgorithm::GridItems::Iterator +NGGridLayoutAlgorithm::GridItems::end() { + return Iterator(&item_data, reordered_item_indices.end()); } -NGGridLayoutAlgorithm::GridItemData& -NGGridLayoutAlgorithm::ReorderedGridItems::Iterator::operator*() { - DCHECK_LT(*current_index_, grid_items_->size()); - return grid_items_->at(*current_index_); +void NGGridLayoutAlgorithm::GridItems::Append( + const GridItemData& new_item_data) { + reordered_item_indices.push_back(item_data.size()); + item_data.emplace_back(new_item_data); } -NGGridLayoutAlgorithm::ReorderedGridItems::Iterator& -NGGridLayoutAlgorithm::ReorderedGridItems::Iterator::operator++() { - ++current_index_; - return *this; -} - -NGGridLayoutAlgorithm::ReorderedGridItems::ReorderedGridItems( - const Vector<wtf_size_t>& reordered_item_indices, - Vector<GridItemData>& grid_items) - : reordered_item_indices_(reordered_item_indices), - grid_items_(grid_items) {} - -NGGridLayoutAlgorithm::ReorderedGridItems::Iterator -NGGridLayoutAlgorithm::ReorderedGridItems::begin() { - return Iterator(reordered_item_indices_.begin(), &grid_items_); -} - -NGGridLayoutAlgorithm::ReorderedGridItems::Iterator -NGGridLayoutAlgorithm::ReorderedGridItems::end() { - return Iterator(reordered_item_indices_.end(), &grid_items_); +bool NGGridLayoutAlgorithm::GridItems::IsEmpty() const { + return item_data.IsEmpty(); } namespace { @@ -586,7 +547,7 @@ } void NGGridLayoutAlgorithm::ConstructAndAppendGridItems( - Vector<GridItemData>* grid_items, + GridItems* grid_items, Vector<GridItemData>* out_of_flow_items) const { DCHECK(grid_items); NGGridChildIterator iterator(Node()); @@ -596,7 +557,7 @@ // If |out_of_flow_items| is provided, store out-of-flow items separately, // as they do not contribute to track sizing or auto-placement. if (grid_item.item_type == ItemType::kInGridFlow) - grid_items->emplace_back(grid_item); + grid_items->Append(grid_item); else if (out_of_flow_items) out_of_flow_items->emplace_back(grid_item); } @@ -866,7 +827,7 @@ } void NGGridLayoutAlgorithm::BuildBlockTrackCollections( - Vector<GridItemData>* grid_items, + GridItems* grid_items, NGGridBlockTrackCollection* column_track_collection, NGGridBlockTrackCollection* row_track_collection, NGGridPlacement* grid_placement) const { @@ -889,7 +850,7 @@ } void NGGridLayoutAlgorithm::BuildAlgorithmTrackCollections( - Vector<GridItemData>* grid_items, + GridItems* grid_items, NGGridLayoutAlgorithmTrackCollection* column_track_collection, NGGridLayoutAlgorithmTrackCollection* row_track_collection, NGGridPlacement* grid_placement) const { @@ -933,12 +894,12 @@ } void NGGridLayoutAlgorithm::EnsureTrackCoverageForGridItems( - const Vector<GridItemData>& grid_items, + const GridItems& grid_items, NGGridBlockTrackCollection* track_collection) const { DCHECK(track_collection); const GridTrackSizingDirection track_direction = track_collection->Direction(); - for (const auto& grid_item : grid_items) { + for (const auto& grid_item : grid_items.item_data) { track_collection->EnsureTrackCoverage(grid_item.StartLine(track_direction), grid_item.SpanSize(track_direction)); } @@ -946,18 +907,17 @@ void NGGridLayoutAlgorithm::CacheGridItemsTrackSpanProperties( const NGGridLayoutAlgorithmTrackCollection& track_collection, - Vector<GridItemData>* grid_items, - Vector<wtf_size_t>* reordered_item_indices) const { - DCHECK(grid_items && reordered_item_indices); + GridItems* grid_items) const { + DCHECK(grid_items); const GridTrackSizingDirection track_direction = track_collection.Direction(); auto CompareGridItemsByStartLine = [grid_items, track_direction]( - wtf_size_t index_a, - wtf_size_t index_b) -> bool { - return grid_items->at(index_a).StartLine(track_direction) < - grid_items->at(index_b).StartLine(track_direction); + wtf_size_t a, wtf_size_t b) -> bool { + return grid_items->item_data[a].StartLine(track_direction) < + grid_items->item_data[b].StartLine(track_direction); }; - std::sort(reordered_item_indices->begin(), reordered_item_indices->end(), + std::sort(grid_items->reordered_item_indices.begin(), + grid_items->reordered_item_indices.end(), CompareGridItemsByStartLine); auto CacheTrackSpanPropertyForAllGridItems = @@ -967,8 +927,7 @@ // the ranges in the track collection and the grid items, incrementally. auto range_iterator = track_collection.RangeIterator(); - for (GridItemData& grid_item : - ReorderedGridItems(*reordered_item_indices, *grid_items)) { + for (auto& grid_item : *grid_items) { // We want to find the first range in the collection that: // - Spans tracks located AFTER the start line of the current grid // item; this can be done by checking that the last track number of @@ -1016,8 +975,7 @@ void NGGridLayoutAlgorithm::ComputeUsedTrackSizes( SizingConstraint sizing_constraint, NGGridLayoutAlgorithmTrackCollection* track_collection, - Vector<GridItemData>* grid_items, - Vector<wtf_size_t>* reordered_item_indices) const { + GridItems* grid_items) const { DCHECK(track_collection && grid_items); const GridTrackSizingDirection track_direction = track_collection->Direction(); @@ -1073,8 +1031,7 @@ } // 2. Resolve intrinsic track sizing functions to absolute lengths. - ResolveIntrinsicTrackSizes(track_collection, grid_items, - reordered_item_indices); + ResolveIntrinsicTrackSizes(track_collection, grid_items); // 3. If the free space is positive, distribute it equally to the base sizes // of all tracks, freezing tracks as they reach their growth limits (and @@ -1474,8 +1431,8 @@ } // namespace void NGGridLayoutAlgorithm::IncreaseTrackSizesToAccommodateGridItems( - ReorderedGridItems::Iterator group_begin, - ReorderedGridItems::Iterator group_end, + GridItems::Iterator group_begin, + GridItems::Iterator group_end, const bool is_group_spanning_flex_track, GridItemContributionType contribution_type, NGGridLayoutAlgorithmTrackCollection* track_collection) const { @@ -1568,9 +1525,8 @@ // https://drafts.csswg.org/css-grid-2/#algo-content void NGGridLayoutAlgorithm::ResolveIntrinsicTrackSizes( NGGridLayoutAlgorithmTrackCollection* track_collection, - Vector<GridItemData>* grid_items, - Vector<wtf_size_t>* reordered_item_indices) const { - DCHECK(grid_items && track_collection && reordered_item_indices); + GridItems* grid_items) const { + DCHECK(track_collection && grid_items); const GridTrackSizingDirection track_direction = track_collection->Direction(); @@ -1581,25 +1537,23 @@ // not spanning a flexible track have been considered. // - Finally, consider all items spanning a flexible track. auto CompareGridItemsForIntrinsicTrackResolution = - [grid_items, track_direction](wtf_size_t index_a, - wtf_size_t index_b) -> bool { - if (grid_items->at(index_a).IsSpanningFlexibleTrack(track_direction) || - grid_items->at(index_b).IsSpanningFlexibleTrack(track_direction)) { + [grid_items, track_direction](wtf_size_t a, wtf_size_t b) -> bool { + if (grid_items->item_data[a].IsSpanningFlexibleTrack(track_direction) || + grid_items->item_data[b].IsSpanningFlexibleTrack(track_direction)) { // Ignore span sizes if one of the items spans a track with a flexible // sizing function; items not spanning such tracks should come first. - return !grid_items->at(index_a).IsSpanningFlexibleTrack(track_direction); + return !grid_items->item_data[a].IsSpanningFlexibleTrack(track_direction); } - return grid_items->at(index_a).SpanSize(track_direction) < - grid_items->at(index_b).SpanSize(track_direction); + return grid_items->item_data[a].SpanSize(track_direction) < + grid_items->item_data[b].SpanSize(track_direction); }; - std::sort(reordered_item_indices->begin(), reordered_item_indices->end(), + std::sort(grid_items->reordered_item_indices.begin(), + grid_items->reordered_item_indices.end(), CompareGridItemsForIntrinsicTrackResolution); - auto reordered_items = - ReorderedGridItems(*reordered_item_indices, *grid_items); // First, process the items that don't span a flexible track. - auto current_group_begin = reordered_items.begin(); - while (current_group_begin != reordered_items.end() && + auto current_group_begin = grid_items->begin(); + while (current_group_begin != grid_items->end() && !current_group_begin->IsSpanningFlexibleTrack(track_direction)) { // Each iteration considers all items with the same span size. wtf_size_t current_group_span_size = @@ -1609,7 +1563,7 @@ do { DCHECK(!current_group_end->IsSpanningFlexibleTrack(track_direction)); ++current_group_end; - } while (current_group_end != reordered_items.end() && + } while (current_group_end != grid_items->end() && !current_group_end->IsSpanningFlexibleTrack(track_direction) && current_group_end->SpanSize(track_direction) == current_group_span_size); @@ -1646,24 +1600,24 @@ // sizing function... #if DCHECK_IS_ON() // Every grid item of the remaining group should span a flexible track. - for (auto it = current_group_begin; it != reordered_items.end(); ++it) + for (auto it = current_group_begin; it != grid_items->end(); ++it) DCHECK(it->IsSpanningFlexibleTrack(track_direction)); #endif // Now, process items spanning flexible tracks (if any). - if (current_group_begin != reordered_items.end()) { + if (current_group_begin != grid_items->end()) { // We can safely skip contributions for maximums since a <flex> definition // does not have an intrinsic max track sizing function. IncreaseTrackSizesToAccommodateGridItems( - current_group_begin, reordered_items.end(), + current_group_begin, grid_items->end(), /* is_group_spanning_flex_track */ true, GridItemContributionType::kForIntrinsicMinimums, track_collection); IncreaseTrackSizesToAccommodateGridItems( - current_group_begin, reordered_items.end(), + current_group_begin, grid_items->end(), /* is_group_spanning_flex_track */ true, GridItemContributionType::kForContentBasedMinimums, track_collection); IncreaseTrackSizesToAccommodateGridItems( - current_group_begin, reordered_items.end(), + current_group_begin, grid_items->end(), /* is_group_spanning_flex_track */ true, GridItemContributionType::kForMaxContentMinimums, track_collection); } @@ -1688,7 +1642,7 @@ return; GridSetVector sets_to_grow; - sets_to_grow.ReserveCapacity(track_collection->SetCount()); + sets_to_grow.ReserveInitialCapacity(track_collection->SetCount()); for (auto set_iterator = track_collection->GetSetIterator(); !set_iterator.IsAtEnd(); set_iterator.MoveToNextSet()) { sets_to_grow.push_back(&set_iterator.CurrentSet()); @@ -1928,10 +1882,11 @@ BorderScrollbarPadding().block_start, GridGap(kForRows, available_size)); - LayoutUnit set_offset = track_alignment_geometry.start_offset; Vector<LayoutUnit> offsets; - offsets.ReserveCapacity(track_collection.SetCount() + 1); + offsets.ReserveInitialCapacity(track_collection.SetCount() + 1); + LayoutUnit set_offset = track_alignment_geometry.start_offset; offsets.push_back(set_offset); + for (auto set_iterator = track_collection.GetSetIterator(); !set_iterator.IsAtEnd(); set_iterator.MoveToNextSet()) { const auto& set = set_iterator.CurrentSet(); @@ -2052,7 +2007,7 @@ } // namespace void NGGridLayoutAlgorithm::PlaceGridItems( - const Vector<GridItemData>& grid_items, + const GridItems& grid_items, const SetGeometry& column_set_geometry, const SetGeometry& row_set_geometry, LayoutUnit block_size) { @@ -2070,7 +2025,7 @@ base::Optional<PositionAndBaseline> alignment_baseline; base::Optional<PositionAndBaseline> fallback_baseline; - for (const GridItemData& grid_item : grid_items) { + for (const auto& grid_item : grid_items.item_data) { DCHECK(grid_item.column_set_indices.has_value()); DCHECK(grid_item.row_set_indices.has_value());
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h index a3c13e4b..15a8b18 100644 --- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h +++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h
@@ -97,6 +97,56 @@ base::Optional<ItemSetIndices> row_set_indices; }; + struct GridItems { + class Iterator + : public std::iterator<std::input_iterator_tag, GridItemData> { + public: + Iterator(Vector<GridItemData>* item_data, + Vector<wtf_size_t>::const_iterator current_index) + : item_data_(item_data), current_index_(current_index) { + DCHECK(item_data_); + } + + bool operator!=(const Iterator& other) const { + return current_index_ != other.current_index_ || + item_data_ != other.item_data_; + } + + Iterator& operator++() { + ++current_index_; + return *this; + } + + GridItemData* operator->() { + DCHECK(current_index_ && *current_index_ < item_data_->size()); + return &(item_data_->at(*current_index_)); + } + + GridItemData& operator*() { + DCHECK(current_index_ && *current_index_ < item_data_->size()); + return item_data_->at(*current_index_); + } + + private: + Vector<GridItemData>* item_data_; + Vector<wtf_size_t>::const_iterator current_index_; + }; + + Iterator begin(); + Iterator end(); + + void Append(const GridItemData& new_item_data); + + bool IsEmpty() const; + + // Grid items are appended to |item_data_| in the same order provided by + // |NGGridChildIterator|, which iterates over its children in order-modified + // document order; we want to keep such order since auto-placement and + // painting order rely on it later in the algorithm. + Vector<GridItemData> item_data; + Vector<wtf_size_t> reordered_item_indices; + }; + explicit NGGridLayoutAlgorithm(const NGLayoutAlgorithmParams& params); scoped_refptr<const NGLayoutResult> Layout() override; @@ -107,34 +157,6 @@ enum class SizingConstraint { kLayout, kMinContent, kMaxContent }; - class ReorderedGridItems { - public: - class Iterator - : public std::iterator<std::input_iterator_tag, GridItemData> { - public: - Iterator(Vector<wtf_size_t>::const_iterator current_index, - Vector<GridItemData>* grid_items); - - bool operator!=(const Iterator& other) const; - GridItemData* operator->(); - GridItemData& operator*(); - Iterator& operator++(); - - private: - Vector<wtf_size_t>::const_iterator current_index_; - Vector<GridItemData>* grid_items_; - }; - - ReorderedGridItems(const Vector<wtf_size_t>& reordered_item_indices, - Vector<GridItemData>& grid_items); - Iterator begin(); - Iterator end(); - - private: - const Vector<wtf_size_t>& reordered_item_indices_; - Vector<GridItemData>& grid_items_; - }; - // Returns the size that a grid item will distribute across the tracks with an // intrinsic sizing function it spans in the relevant track direction. LayoutUnit ContributionSizeForGridItem( @@ -146,18 +168,18 @@ GridTrackSizingDirection track_direction) const; void ConstructAndAppendGridItems( - Vector<GridItemData>* grid_items, + GridItems* grid_items, Vector<GridItemData>* out_of_flow_items = nullptr) const; GridItemData MeasureGridItem(const NGBlockNode node) const; void BuildBlockTrackCollections( - Vector<GridItemData>* grid_items, + GridItems* grid_items, NGGridBlockTrackCollection* column_track_collection, NGGridBlockTrackCollection* row_track_collection, NGGridPlacement* grid_placement) const; void BuildAlgorithmTrackCollections( - Vector<GridItemData>* grid_items, + GridItems* grid_items, NGGridLayoutAlgorithmTrackCollection* column_track_collection, NGGridLayoutAlgorithmTrackCollection* row_track_collection, NGGridPlacement* grid_placement) const; @@ -167,33 +189,30 @@ NGGridBlockTrackCollection* track_collection) const; // Ensure coverage in block collection after grid items have been placed. void EnsureTrackCoverageForGridItems( - const Vector<GridItemData>& grid_items, + const GridItems& grid_items, NGGridBlockTrackCollection* track_collection) const; // For every grid item, caches properties of the track sizing functions it // spans (i.e. whether an item spans intrinsic or flexible tracks). void CacheGridItemsTrackSpanProperties( const NGGridLayoutAlgorithmTrackCollection& track_collection, - Vector<GridItemData>* grid_items, - Vector<wtf_size_t>* reordered_item_indices) const; + GridItems* grid_items) const; // Calculates from the min and max track sizing functions the used track size. void ComputeUsedTrackSizes( SizingConstraint sizing_constraint, NGGridLayoutAlgorithmTrackCollection* track_collection, - Vector<GridItemData>* grid_items, - Vector<wtf_size_t>* reordered_item_indices) const; + GridItems* grid_items) const; // These methods implement the steps of the algorithm for intrinsic track size // resolution defined in https://drafts.csswg.org/css-grid-2/#algo-content. void ResolveIntrinsicTrackSizes( NGGridLayoutAlgorithmTrackCollection* track_collection, - Vector<GridItemData>* grid_items, - Vector<wtf_size_t>* reordered_item_indices) const; + GridItems* grid_items) const; void IncreaseTrackSizesToAccommodateGridItems( - ReorderedGridItems::Iterator group_begin, - ReorderedGridItems::Iterator group_end, + GridItems::Iterator group_begin, + GridItems::Iterator group_end, const bool is_group_spanning_flex_track, GridItemContributionType contribution_type, NGGridLayoutAlgorithmTrackCollection* track_collection) const; @@ -225,7 +244,7 @@ const NGGridLayoutAlgorithmTrackCollection& track_collection) const; // Layout the |grid_items| based on the offsets provided. - void PlaceGridItems(const Vector<GridItemData>& grid_items, + void PlaceGridItems(const GridItems& grid_items, const SetGeometry& column_set_geometry, const SetGeometry& row_set_geometry, LayoutUnit block_size);
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm_test.cc b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm_test.cc index 9d7475fd..575d2b9 100644 --- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm_test.cc +++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm_test.cc
@@ -54,25 +54,20 @@ &grid_items_, &column_track_collection_, &row_track_collection_, &grid_placement); - // Create a vector of grid item indices using |NGGridChildIterator| order. - Vector<wtf_size_t> reordered_item_indices(grid_items_.size()); - for (wtf_size_t i = 0; i < grid_items_.size(); ++i) - reordered_item_indices[i] = i; - // Cache track span properties for grid items. - algorithm.CacheGridItemsTrackSpanProperties( - column_track_collection_, &grid_items_, &reordered_item_indices); - algorithm.CacheGridItemsTrackSpanProperties( - row_track_collection_, &grid_items_, &reordered_item_indices); + algorithm.CacheGridItemsTrackSpanProperties(column_track_collection_, + &grid_items_); + algorithm.CacheGridItemsTrackSpanProperties(row_track_collection_, + &grid_items_); // Resolve inline size. algorithm.ComputeUsedTrackSizes( NGGridLayoutAlgorithm::SizingConstraint::kLayout, - &column_track_collection_, &grid_items_, &reordered_item_indices); + &column_track_collection_, &grid_items_); // Resolve block size. algorithm.ComputeUsedTrackSizes( NGGridLayoutAlgorithm::SizingConstraint::kLayout, - &row_track_collection_, &grid_items_, &reordered_item_indices); + &row_track_collection_, &grid_items_); } NGGridLayoutAlgorithmTrackCollection& TrackCollection( @@ -83,24 +78,20 @@ // Helper methods to access private data on NGGridLayoutAlgorithm. This class // is a friend of NGGridLayoutAlgorithm but the individual tests are not. - wtf_size_t GridItemCount(const NGGridLayoutAlgorithm& algorithm) { - return grid_items_.size(); - } + wtf_size_t GridItemCount() { return grid_items_.item_data.size(); } Vector<LayoutUnit> GridItemInlineMarginSum( const NGGridLayoutAlgorithm& algorithm) { Vector<LayoutUnit> results; - for (const auto& item : grid_items_) { + for (const auto& item : grid_items_.item_data) results.push_back(item.margins.InlineSum()); - } return results; } Vector<GridArea> GridItemGridAreas(const NGGridLayoutAlgorithm& algorithm) { Vector<GridArea> results; - for (const auto& item : grid_items_) { + for (const auto& item : grid_items_.item_data) results.push_back(item.resolved_position); - } return results; } @@ -108,8 +99,8 @@ const NGGridLayoutAlgorithm& algorithm, TrackSpanProperties::PropertyId property) { Vector<wtf_size_t> results; - for (wtf_size_t i = 0; i < grid_items_.size(); ++i) { - if (grid_items_[i].column_span_properties.HasProperty(property)) + for (wtf_size_t i = 0; i < GridItemCount(); ++i) { + if (grid_items_.item_data[i].column_span_properties.HasProperty(property)) results.push_back(i); } return results; @@ -119,8 +110,8 @@ const NGGridLayoutAlgorithm& algorithm, TrackSpanProperties::PropertyId property) { Vector<wtf_size_t> results; - for (wtf_size_t i = 0; i < grid_items_.size(); ++i) { - if (grid_items_[i].row_span_properties.HasProperty(property)) + for (wtf_size_t i = 0; i < GridItemCount(); ++i) { + if (grid_items_.item_data[i].row_span_properties.HasProperty(property)) results.push_back(i); } return results; @@ -175,7 +166,7 @@ return fragment->DumpFragmentTree(flags); } - Vector<NGGridLayoutAlgorithm::GridItemData> grid_items_; + NGGridLayoutAlgorithm::GridItems grid_items_; Vector<NGGridLayoutAlgorithm::GridItemData> out_of_flow_items_; NGGridLayoutAlgorithmTrackCollection column_track_collection_; @@ -321,20 +312,20 @@ CalculateInitialFragmentGeometry(space, node); NGGridLayoutAlgorithm algorithm({node, fragment_geometry, space}); - EXPECT_EQ(GridItemCount(algorithm), 0U); + EXPECT_EQ(GridItemCount(), 0U); BuildGridItemsAndTrackCollections(algorithm); - EXPECT_EQ(GridItemCount(algorithm), 9U); + EXPECT_EQ(GridItemCount(), 9U); Vector<LayoutUnit> actual_inline_margin_sums = GridItemInlineMarginSum(algorithm); - EXPECT_EQ(GridItemCount(algorithm), actual_inline_margin_sums.size()); + EXPECT_EQ(GridItemCount(), actual_inline_margin_sums.size()); LayoutUnit expected_inline_margin_sums[] = { LayoutUnit(100), LayoutUnit(30), LayoutUnit(0), LayoutUnit(0), LayoutUnit(0), LayoutUnit(0), LayoutUnit(10), LayoutUnit(100), LayoutUnit(0)}; - for (size_t i = 0; i < GridItemCount(algorithm); ++i) { + for (size_t i = 0; i < GridItemCount(); ++i) { EXPECT_EQ(actual_inline_margin_sums[i], expected_inline_margin_sums[i]) << " index: " << i; } @@ -372,9 +363,9 @@ CalculateInitialFragmentGeometry(space, node); NGGridLayoutAlgorithm algorithm({node, fragment_geometry, space}); - EXPECT_EQ(GridItemCount(algorithm), 0U); + EXPECT_EQ(GridItemCount(), 0U); BuildGridItemsAndTrackCollections(algorithm); - EXPECT_EQ(GridItemCount(algorithm), 4U); + EXPECT_EQ(GridItemCount(), 4U); NGGridTrackCollectionBase::RangeRepeatIterator row_iterator( &TrackCollection(kForRows), 0u); @@ -429,9 +420,9 @@ CalculateInitialFragmentGeometry(space, node); NGGridLayoutAlgorithm algorithm({node, fragment_geometry, space}); - EXPECT_EQ(GridItemCount(algorithm), 0U); + EXPECT_EQ(GridItemCount(), 0U); BuildGridItemsAndTrackCollections(algorithm); - EXPECT_EQ(GridItemCount(algorithm), 4U); + EXPECT_EQ(GridItemCount(), 4U); NGGridTrackCollectionBase::RangeRepeatIterator row_iterator( &TrackCollection(kForRows), 0u); @@ -517,9 +508,9 @@ CalculateInitialFragmentGeometry(space, node); NGGridLayoutAlgorithm algorithm({node, fragment_geometry, space}); - EXPECT_EQ(GridItemCount(algorithm), 0U); + EXPECT_EQ(GridItemCount(), 0U); BuildGridItemsAndTrackCollections(algorithm); - EXPECT_EQ(GridItemCount(algorithm), 4U); + EXPECT_EQ(GridItemCount(), 4U); NGGridTrackCollectionBase::RangeRepeatIterator column_iterator( &TrackCollection(kForColumns), 0u); @@ -588,9 +579,9 @@ CalculateInitialFragmentGeometry(space, node); NGGridLayoutAlgorithm algorithm({node, fragment_geometry, space}); - EXPECT_EQ(GridItemCount(algorithm), 0U); + EXPECT_EQ(GridItemCount(), 0U); BuildGridItemsAndTrackCollections(algorithm); - EXPECT_EQ(GridItemCount(algorithm), 4U); + EXPECT_EQ(GridItemCount(), 4U); NGGridTrackCollectionBase::RangeRepeatIterator column_iterator( &TrackCollection(kForColumns), 0u); @@ -655,9 +646,9 @@ CalculateInitialFragmentGeometry(space, node); NGGridLayoutAlgorithm algorithm({node, fragment_geometry, space}); - EXPECT_EQ(GridItemCount(algorithm), 0U); + EXPECT_EQ(GridItemCount(), 0U); BuildGridItemsAndTrackCollections(algorithm); - EXPECT_EQ(GridItemCount(algorithm), 4U); + EXPECT_EQ(GridItemCount(), 4U); NGGridTrackCollectionBase::RangeRepeatIterator column_iterator( &TrackCollection(kForColumns), 0u); @@ -714,9 +705,9 @@ CalculateInitialFragmentGeometry(space, node); NGGridLayoutAlgorithm algorithm({node, fragment_geometry, space}); - EXPECT_EQ(GridItemCount(algorithm), 0U); + EXPECT_EQ(GridItemCount(), 0U); BuildGridItemsAndTrackCollections(algorithm); - EXPECT_EQ(GridItemCount(algorithm), 5U); + EXPECT_EQ(GridItemCount(), 5U); NGGridTrackCollectionBase::RangeRepeatIterator column_iterator( &TrackCollection(kForColumns), 0u); @@ -802,9 +793,9 @@ CalculateInitialFragmentGeometry(space, node); NGGridLayoutAlgorithm algorithm({node, fragment_geometry, space}); - EXPECT_EQ(GridItemCount(algorithm), 0U); + EXPECT_EQ(GridItemCount(), 0U); BuildGridItemsAndTrackCollections(algorithm); - EXPECT_EQ(GridItemCount(algorithm), 4U); + EXPECT_EQ(GridItemCount(), 4U); Vector<GridArea> grid_positions = GridItemGridAreas(algorithm); ASSERT_EQ(grid_positions.size(), 4U); @@ -931,9 +922,9 @@ CalculateInitialFragmentGeometry(space, node); NGGridLayoutAlgorithm algorithm({node, fragment_geometry, space}); - EXPECT_EQ(GridItemCount(algorithm), 0U); + EXPECT_EQ(GridItemCount(), 0U); BuildGridItemsAndTrackCollections(algorithm); - EXPECT_EQ(GridItemCount(algorithm), 16U); + EXPECT_EQ(GridItemCount(), 16U); Vector<GridArea> grid_positions = GridItemGridAreas(algorithm); ASSERT_EQ(grid_positions.size(), 16U); @@ -1016,9 +1007,9 @@ CalculateInitialFragmentGeometry(space, node); NGGridLayoutAlgorithm algorithm({node, fragment_geometry, space}); - EXPECT_EQ(GridItemCount(algorithm), 0U); + EXPECT_EQ(GridItemCount(), 0U); BuildGridItemsAndTrackCollections(algorithm); - EXPECT_EQ(GridItemCount(algorithm), 3U); + EXPECT_EQ(GridItemCount(), 3U); NGGridTrackCollectionBase::RangeRepeatIterator column_iterator( &TrackCollection(kForColumns), 0u);
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_placement.cc b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_placement.cc index b109667c0..561e4cd4 100644 --- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_placement.cc +++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_placement.cc
@@ -30,8 +30,7 @@ row_auto_repetitions_(row_auto_repetitions) {} // https://drafts.csswg.org/css-grid/#auto-placement-algo -void NGGridPlacement::RunAutoPlacementAlgorithm( - Vector<GridItemData>* grid_items) { +void NGGridPlacement::RunAutoPlacementAlgorithm(GridItems* grid_items) { DCHECK(grid_items); minor_max_end_line_ = (minor_direction_ == kForColumns) ? GridPositionsResolver::ExplicitGridColumnCount( @@ -57,7 +56,7 @@ // Step 4. Position remaining grid items. AutoPlacementCursor placement_cursor; - for (GridItemData& grid_item : *grid_items) { + for (GridItemData& grid_item : grid_items->item_data) { switch (grid_item.AutoPlacement(major_direction_)) { case AutoPlacementType::kBoth: PlaceAutoBothAxisGridItem(&grid_item, &placement_cursor, *grid_items); @@ -75,11 +74,11 @@ } wtf_size_t NGGridPlacement::DetermineTrackStartOffset( - const Vector<GridItemData>& grid_items, + const GridItems& grid_items, GridTrackSizingDirection track_direction) const { wtf_size_t track_start_offset = 0; - for (const GridItemData& grid_item : grid_items) { + for (const auto& grid_item : grid_items.item_data) { GridSpan grid_item_span = GridPositionsResolver::ResolveGridPositionsFromStyle( grid_style_, grid_item.node.Style(), track_direction, @@ -94,11 +93,11 @@ return track_start_offset; } -bool NGGridPlacement::PlaceNonAutoGridItems(Vector<GridItemData>* grid_items) { +bool NGGridPlacement::PlaceNonAutoGridItems(GridItems* grid_items) { DCHECK(grid_items); bool has_auto_placed_items = false; - for (GridItemData& grid_item : *grid_items) { + for (GridItemData& grid_item : grid_items->item_data) { bool has_definite_major_placement = PlaceGridItem(&grid_item, major_direction_); bool has_definite_minor_placement = @@ -118,8 +117,7 @@ return has_auto_placed_items; } -void NGGridPlacement::PlaceGridItemsLockedToMajorAxis( - Vector<GridItemData>* grid_items) { +void NGGridPlacement::PlaceGridItemsLockedToMajorAxis(GridItems* grid_items) { DCHECK(grid_items); // Mapping between the major axis tracks and the last auto-placed item's end @@ -128,7 +126,7 @@ // See https://drafts.csswg.org/css-grid/#auto-placement-algo. HashMap<wtf_size_t, wtf_size_t> minor_cursors; - for (GridItemData& grid_item : *grid_items) { + for (GridItemData& grid_item : grid_items->item_data) { // Only consider grid items that require minor axis auto-placement. if (grid_item.AutoPlacement(major_direction_) != AutoPlacementType::kMinor) continue; @@ -165,7 +163,7 @@ void NGGridPlacement::PlaceAutoMajorAxisGridItem( GridItemData* grid_item, AutoPlacementCursor* placement_cursor, - const Vector<GridItemData>& grid_items) { + const GridItems& grid_items) { DCHECK(grid_item); if (HasSparsePacking()) { @@ -205,7 +203,7 @@ void NGGridPlacement::PlaceAutoBothAxisGridItem( GridItemData* grid_item, AutoPlacementCursor* placement_cursor, - const Vector<GridItemData>& grid_items) { + const GridItems& grid_items) { DCHECK(grid_item); // For dense packing, set the cursor’s major and minor positions to the @@ -269,17 +267,16 @@ return true; } -bool NGGridPlacement::DoesItemOverlap( - wtf_size_t major_start, - wtf_size_t major_end, - wtf_size_t minor_start, - wtf_size_t minor_end, - const Vector<GridItemData>& grid_items) const { +bool NGGridPlacement::DoesItemOverlap(wtf_size_t major_start, + wtf_size_t major_end, + wtf_size_t minor_start, + wtf_size_t minor_end, + const GridItems& grid_items) const { DCHECK_LE(major_start, major_end); DCHECK_LE(minor_start, minor_end); // TODO(janewman): Implement smarter collision detection, iterating over all // items is not ideal and has large performance implications. - for (const GridItemData& grid_item : grid_items) { + for (const auto& grid_item : grid_items.item_data) { if (grid_item.Span(major_direction_).IsIndefinite()) continue; // Only test against definite positions.
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_placement.h b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_placement.h index c98aa392..b2d331c3 100644 --- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_placement.h +++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_placement.h
@@ -20,6 +20,7 @@ public: enum class PackingBehavior { kSparse, kDense }; + using GridItems = NGGridLayoutAlgorithm::GridItems; using GridItemData = NGGridLayoutAlgorithm::GridItemData; using AutoPlacementType = NGGridLayoutAlgorithm::AutoPlacementType; @@ -27,7 +28,7 @@ const wtf_size_t column_auto_repetitions, const wtf_size_t row_auto_repetitions); - void RunAutoPlacementAlgorithm(Vector<GridItemData>* grid_items); + void RunAutoPlacementAlgorithm(GridItems* grid_items); // Helper function to resolve start and end lines of out of flow items. void ResolveOutOfFlowItemGridLines( const NGGridLayoutAlgorithmTrackCollection& track_collection, @@ -46,24 +47,24 @@ // Compute the track start offset from the grid items positioned at negative // indices. wtf_size_t DetermineTrackStartOffset( - const Vector<GridItemData>& grid_items, + const GridItems& grid_items, GridTrackSizingDirection track_direction) const; // Place non auto-positioned elements from |grid_items|; returns true if any // item needs to resolve an automatic position. Otherwise, false. - bool PlaceNonAutoGridItems(Vector<GridItemData>* grid_items); + bool PlaceNonAutoGridItems(GridItems* grid_items); // Place elements from |grid_items| that have a definite position on the major // axis but need auto-placement on the minor axis. - void PlaceGridItemsLockedToMajorAxis(Vector<GridItemData>* grid_items); + void PlaceGridItemsLockedToMajorAxis(GridItems* grid_items); // Place an item that has a definite position on the minor axis but need // auto-placement on the major axis. void PlaceAutoMajorAxisGridItem(GridItemData* grid_item, AutoPlacementCursor* placement_cursor, - const Vector<GridItemData>& grid_items); + const GridItems& grid_items); // Place an item that needs auto-placement on both the major and minor axis. void PlaceAutoBothAxisGridItem(GridItemData* grid_item, AutoPlacementCursor* placement_cursor, - const Vector<GridItemData>& grid_items); + const GridItems& grid_items); // Places a grid item; returns true if it has a definite position in the given // direction, false if the item needs auto-placement. @@ -75,7 +76,7 @@ wtf_size_t major_end, wtf_size_t minor_start, wtf_size_t minor_end, - const Vector<GridItemData>& grid_items) const; + const GridItems& grid_items) const; wtf_size_t StartOffset(GridTrackSizingDirection track_direction) const; wtf_size_t AutoRepeatTrackCount(
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.h b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.h index 50ae6a13..16b85d4 100644 --- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.h +++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.h
@@ -300,8 +300,8 @@ wtf_size_t end_set_index_; }; - using SetIterator = SetIteratorBase<false>; - using ConstSetIterator = SetIteratorBase<true>; + typedef SetIteratorBase<false> SetIterator; + typedef SetIteratorBase<true> ConstSetIterator; NGGridLayoutAlgorithmTrackCollection() = default; // |is_content_box_size_indefinite| is used to normalize percentage track
diff --git a/third_party/blink/renderer/core/layout/ng/table/layout_ng_table.cc b/third_party/blink/renderer/core/layout/ng/table/layout_ng_table.cc index c4474e9..41301a3 100644 --- a/third_party/blink/renderer/core/layout/ng/table/layout_ng_table.cc +++ b/third_party/blink/renderer/core/layout/ng/table/layout_ng_table.cc
@@ -369,6 +369,28 @@ return LayoutRectOutsets(); } +// Effective column index is index of columns with mergeable +// columns skipped. Used in a11y. +unsigned LayoutNGTable::AbsoluteColumnToEffectiveColumn( + unsigned absolute_column_index) const { + NOT_DESTROYED(); + if (!cached_table_columns_) { + NOTREACHED(); + return absolute_column_index; + } + unsigned effective_column_index = 0; + unsigned column_count = cached_table_columns_.get()->data.size(); + for (unsigned current_column_index = 0; current_column_index < column_count; + ++current_column_index) { + if (current_column_index != 0 && + !cached_table_columns_.get()->data[current_column_index].is_mergeable) + ++effective_column_index; + if (current_column_index == absolute_column_index) + return effective_column_index; + } + return effective_column_index; +} + bool LayoutNGTable::IsFirstCell(const LayoutNGTableCellInterface& cell) const { NOT_DESTROYED(); const LayoutNGTableRowInterface* row = cell.RowInterface();
diff --git a/third_party/blink/renderer/core/layout/ng/table/layout_ng_table.h b/third_party/blink/renderer/core/layout/ng/table/layout_ng_table.h index 5c70f14..c3eb81b 100644 --- a/third_party/blink/renderer/core/layout/ng/table/layout_ng_table.h +++ b/third_party/blink/renderer/core/layout/ng/table/layout_ng_table.h
@@ -172,14 +172,8 @@ return ShouldCollapseBorders() ? 0 : StyleRef().VerticalBorderSpacing(); } - // Legacy had a concept of colspan column compression. This is a legacy - // method to map between absolute and compressed columns. - // Because NG does not compress columns, absolute and effective are the same. unsigned AbsoluteColumnToEffectiveColumn( - unsigned absolute_column_index) const final { - NOT_DESTROYED(); - return absolute_column_index; - } + unsigned absolute_column_index) const final; // NG does not need this method. Sections are not cached. void RecalcSectionsIfNeeded() const final {}
diff --git a/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_section.cc b/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_section.cc index b94c476..e675fd2 100644 --- a/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_section.cc +++ b/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_section.cc
@@ -132,7 +132,12 @@ // behaviour is correct. Consider removing these methods. unsigned LayoutNGTableSection::NumEffectiveColumns() const { NOT_DESTROYED(); - return To<LayoutNGTable>(TableInterface()->ToLayoutObject())->ColumnCount(); + const LayoutNGTable* table = Table(); + DCHECK(table); + wtf_size_t column_count = table->ColumnCount(); + if (column_count == 0) + return 0; + return table->AbsoluteColumnToEffectiveColumn(column_count - 1) + 1; } // TODO(crbug.com/1079133): Used by AXLayoutObject::IsDataTable/ColumnCount,
diff --git a/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm.cc index 768b3733..4621a92cc 100644 --- a/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm.cc
@@ -55,9 +55,17 @@ const NGTableTypes::Columns& column_constraints, LayoutUnit inline_table_border_padding, LayoutUnit inline_border_spacing) { - unsigned inline_space_count = 2 + (column_constraints.data.size() > 1 - ? column_constraints.data.size() - 1 - : 0); + unsigned inline_space_count = 2; + bool is_first_column = true; + for (const NGTableTypes::Column& column : column_constraints.data) { + if (!column.is_mergeable) { + if (is_first_column) + is_first_column = false; + else + inline_space_count++; + } + } + return inline_table_border_padding + inline_space_count * inline_border_spacing; } @@ -146,7 +154,13 @@ *has_collapsed_columns = *has_collapsed_columns || column_constraint.is_collapsed; column_location.offset = column_offset; - if (shrink_collapsed && column_constraint.is_collapsed) { + if (column_constraints.data[i].is_mergeable && + (column_sizes[i] == kIndefiniteSize || + column_sizes[i] == LayoutUnit())) { + // Empty mergeable columns are treated as collapsed. + column_location.size = LayoutUnit(); + column_location.is_collapsed = true; + } else if (shrink_collapsed && column_constraint.is_collapsed) { column_location.is_collapsed = true; column_location.size = LayoutUnit(); } else {
diff --git a/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_helpers.cc b/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_helpers.cc index 98b84d70..d7e735e 100644 --- a/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_helpers.cc +++ b/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_helpers.cc
@@ -22,7 +22,6 @@ unsigned percent_columns_count = 0; unsigned fixed_columns_count = 0; unsigned auto_columns_count = 0; - // What guesses mean is described in table specification. // https://www.w3.org/TR/css-tables-3/#width-distribution-algorithm enum { kMinGuess, kPercentageGuess, kSpecifiedGuess, kMaxGuess, kAboveMax }; @@ -38,7 +37,10 @@ all_columns_count++; DCHECK(column->min_inline_size); DCHECK(column->max_inline_size); - if (column->percent) { + + if (column->is_mergeable) { + ; // Mergeable columns are ignored. + } else if (column->percent) { percent_columns_count++; total_percent += *column->percent; LayoutUnit percent_inline_size = @@ -92,6 +94,8 @@ LayoutUnit* computed_size = computed_sizes.begin(); for (const NGTableTypes::Column* column = start_column; column != end_column; ++column, ++computed_size) { + if (column->is_mergeable) + continue; *computed_size = column->min_inline_size.value_or(LayoutUnit()); } } break; @@ -106,6 +110,8 @@ LayoutUnit* last_computed_size = nullptr; for (const NGTableTypes::Column* column = start_column; column != end_column; ++column, ++computed_size) { + if (column->is_mergeable) + continue; if (column->percent) { last_computed_size = computed_size; LayoutUnit percent_inline_size = @@ -144,6 +150,8 @@ LayoutUnit* computed_size = computed_sizes.begin(); for (const NGTableTypes::Column* column = start_column; column != end_column; ++column, ++computed_size) { + if (column->is_mergeable) + continue; if (column->percent) { *computed_size = column->ResolvePercentInlineSize(target_inline_size); } else if (column->is_constrained) { @@ -190,6 +198,8 @@ LayoutUnit* computed_size = computed_sizes.begin(); for (const NGTableTypes::Column* column = start_column; column != end_column; ++column, ++computed_size) { + if (column->is_mergeable) + continue; if (column->percent) { *computed_size = column->ResolvePercentInlineSize(target_inline_size); } else if (column->is_constrained || is_exact_match) { @@ -226,6 +236,8 @@ LayoutUnit* computed_size = computed_sizes.begin(); for (const NGTableTypes::Column* column = start_column; column != end_column; ++column, ++computed_size) { + if (column->is_mergeable) + continue; if (column->percent) { *computed_size = column->ResolvePercentInlineSize(target_inline_size); @@ -256,6 +268,8 @@ LayoutUnit* computed_size = computed_sizes.begin(); for (const NGTableTypes::Column* column = start_column; column != end_column; ++column, ++computed_size) { + if (column->is_mergeable) + continue; if (column->percent) { *computed_size = column->ResolvePercentInlineSize(target_inline_size); @@ -286,6 +300,8 @@ LayoutUnit* computed_size = computed_sizes.begin(); for (const NGTableTypes::Column* column = start_column; column != end_column; ++column, ++computed_size) { + if (column->is_mergeable) + continue; DCHECK(column->percent); last_computed_size = computed_size; if (total_percent > 0.0f) { @@ -447,18 +463,32 @@ NGTableTypes::Column* end_column = start_column + colspan_cell.span; DCHECK_NE(start_column, end_column); + // Inline sizes for redistribution exclude border spacing. + LayoutUnit total_inner_border_spacing; + unsigned effective_span = 0; + bool is_first_column = true; + for (NGTableTypes::Column* column = start_column; column != end_column; + ++column) { + if (column->is_mergeable) + continue; + ++effective_span; + if (!is_first_column) + total_inner_border_spacing += inline_border_spacing; + else + is_first_column = false; + } LayoutUnit colspan_cell_min_inline_size; LayoutUnit colspan_cell_max_inline_size; // Colspanned cells only distribute min inline size if constrained. if (colspan_cell.cell_inline_constraint.is_constrained) { colspan_cell_min_inline_size = (colspan_cell.cell_inline_constraint.min_inline_size - - (colspan_cell.span - 1) * inline_border_spacing) + total_inner_border_spacing) .ClampNegativeToZero(); } colspan_cell_max_inline_size = (colspan_cell.cell_inline_constraint.max_inline_size - - (colspan_cell.span - 1) * inline_border_spacing) + total_inner_border_spacing) .ClampNegativeToZero(); // Distribute min/max/percentage evenly between all cells. @@ -468,18 +498,19 @@ colspan_cell.cell_inline_constraint.percent.value_or(0.0f); LayoutUnit new_min_size = LayoutUnit(colspan_cell_min_inline_size / - static_cast<float>(colspan_cell.span)); + static_cast<float>(effective_span)); LayoutUnit new_max_size = LayoutUnit(colspan_cell_max_inline_size / - static_cast<float>(colspan_cell.span)); + static_cast<float>(effective_span)); base::Optional<float> new_percent; if (colspan_cell.cell_inline_constraint.percent) { - new_percent = - *colspan_cell.cell_inline_constraint.percent / colspan_cell.span; + new_percent = *colspan_cell.cell_inline_constraint.percent / effective_span; } NGTableTypes::Column* last_column; for (NGTableTypes::Column* column = start_column; column < end_column; ++column) { + if (column->is_mergeable) + continue; last_column = column; rounding_error_min_inline_size -= new_min_size; rounding_error_max_inline_size -= new_max_size; @@ -521,13 +552,25 @@ NGTableTypes::Column* end_column = start_column + effective_span; // Inline sizes for redistribution exclude border spacing. + LayoutUnit total_inner_border_spacing; + bool is_first_column = true; + for (NGTableTypes::Column* column = start_column; column != end_column; + ++column) { + if (!column->is_mergeable) { + if (!is_first_column) + total_inner_border_spacing += inline_border_spacing; + else + is_first_column = false; + } + } + LayoutUnit colspan_cell_min_inline_size = (colspan_cell.cell_inline_constraint.min_inline_size - - (effective_span - 1) * inline_border_spacing) + total_inner_border_spacing) .ClampNegativeToZero(); LayoutUnit colspan_cell_max_inline_size = (colspan_cell.cell_inline_constraint.max_inline_size - - (effective_span - 1) * inline_border_spacing) + total_inner_border_spacing) .ClampNegativeToZero(); base::Optional<float> colspan_cell_percent = colspan_cell.cell_inline_constraint.percent; @@ -544,6 +587,8 @@ column->max_inline_size = LayoutUnit(); if (!column->min_inline_size) column->min_inline_size = LayoutUnit(); + if (column->is_mergeable) + continue; all_columns_count++; if (column->percent) { percent_columns_count++; @@ -559,7 +604,7 @@ // max_inline_size. for (NGTableTypes::Column* column = start_column; column != end_column; ++column) { - if (column->percent) + if (column->percent || column->is_mergeable) continue; float column_percent; if (nonpercent_columns_max_inline_size != LayoutUnit()) {
diff --git a/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_helpers_test.cc b/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_helpers_test.cc index ac8f540..cc9c95a17 100644 --- a/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_helpers_test.cc +++ b/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_helpers_test.cc
@@ -21,7 +21,9 @@ percent, /* border_padding */ LayoutUnit(), is_constrained, - /* is_collapsed */ false}; + /* is_collapsed */ false, + /* is_table_fixed */ false, + /* is_mergeable */ false}; } NGTableTypes::Row MakeRow(int block_size, @@ -155,16 +157,16 @@ column_constraints->data.Shrink(0); column_constraints->data.push_back( NGTableTypes::Column{LayoutUnit(0), column_widths[0], base::nullopt, - LayoutUnit(), false, false}); + LayoutUnit(), false, false, false, false}); column_constraints->data.push_back( NGTableTypes::Column{LayoutUnit(3.33333), column_widths[1], base::nullopt, - LayoutUnit(), false, false}); + LayoutUnit(), false, false, false, false}); column_constraints->data.push_back( NGTableTypes::Column{LayoutUnit(3.33333), column_widths[2], base::nullopt, - LayoutUnit(), false, false}); + LayoutUnit(), false, false, false, false}); column_constraints->data.push_back( NGTableTypes::Column{LayoutUnit(0), column_widths[3], base::nullopt, - LayoutUnit(), false, false}); + LayoutUnit(), false, false, false, false}); LayoutUnit assignable_table_inline_size = column_widths[0] + column_widths[1] + column_widths[2] + column_widths[3];
diff --git a/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_types.cc b/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_types.cc index a3a0b4b..bf9f8b0d 100644 --- a/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_types.cc +++ b/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_types.cc
@@ -85,6 +85,7 @@ InlineSizesFromStyle(style, /* inline_border_padding */ LayoutUnit(), /* is_parallel */ true, &inline_size, &min_inline_size, &max_inline_size, &percentage_inline_size); + bool is_mergeable; if (!inline_size) inline_size = default_inline_size; if (min_inline_size && inline_size) @@ -93,13 +94,16 @@ if (percentage_inline_size && *percentage_inline_size == 0.0f) percentage_inline_size.reset(); bool is_collapsed = style.Visibility() == EVisibility::kCollapse; - return Column{min_inline_size.value_or(LayoutUnit()), - inline_size, + if (is_table_fixed) { + is_mergeable = false; + } else { + is_mergeable = (inline_size.value_or(LayoutUnit()) == LayoutUnit()) && + (percentage_inline_size.value_or(0.0f) == 0.0f); + } + return Column(min_inline_size.value_or(LayoutUnit()), inline_size, percentage_inline_size, - LayoutUnit() /* percent_border_padding */, - is_constrained, - is_collapsed, - is_table_fixed}; + LayoutUnit() /* percent_border_padding */, is_constrained, + is_collapsed, is_table_fixed, is_mergeable); } // Implements https://www.w3.org/TR/css-tables-3/#computing-cell-measures @@ -286,7 +290,8 @@ // Constrained columns in fixed tables take precedence over cells. if (is_constrained && is_table_fixed) return; - + if (!is_table_fixed) + is_mergeable = false; if (min_inline_size) { if (min_inline_size < cell->min_inline_size) { min_inline_size = cell->min_inline_size;
diff --git a/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_types.h b/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_types.h index 47e7177..b892c3f2 100644 --- a/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_types.h +++ b/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_types.h
@@ -57,6 +57,23 @@ // Constraint for a column. struct Column { DISALLOW_NEW(); + Column(const base::Optional<LayoutUnit>& min_inline_size, + const base::Optional<LayoutUnit>& max_inline_size, + const base::Optional<float>& percent, + LayoutUnit percent_border_padding, + bool is_constrained, + bool is_collapsed, + bool is_table_fixed, + bool is_mergeable) + : min_inline_size(min_inline_size), + max_inline_size(max_inline_size), + percent(percent), + percent_border_padding(percent_border_padding), + is_constrained(is_constrained), + is_collapsed(is_collapsed), + is_table_fixed(is_table_fixed), + is_mergeable(is_mergeable) {} + Column() = default; // These members are initialized from <col> and <colgroup>, then they // accumulate data from |CellInlineConstraint|s. base::Optional<LayoutUnit> min_inline_size; @@ -68,6 +85,7 @@ bool is_constrained = false; bool is_collapsed = false; bool is_table_fixed = false; + bool is_mergeable = false; void Encompass(const base::Optional<NGTableTypes::CellInlineConstraint>&); LayoutUnit ResolvePercentInlineSize(
diff --git a/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_utils.cc b/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_utils.cc index d981861a..03c16f5 100644 --- a/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_utils.cc +++ b/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_utils.cc
@@ -24,6 +24,55 @@ namespace { +// Mergeable columns cannot be distributed to. +// Make at least one spanned column is distributable. +void EnsureDistributableColumnExists( + wtf_size_t start_column_index, + wtf_size_t span, + NGTableTypes::Columns* column_constraints) { + if (span == 0) + return; + DCHECK_LT(start_column_index, column_constraints->data.size()); + wtf_size_t effective_span = + std::min(span, column_constraints->data.size() - start_column_index); + if (effective_span == 0) + return; + NGTableTypes::Column* start_column = + &column_constraints->data[start_column_index]; + NGTableTypes::Column* end_column = start_column + effective_span; + + NGTableTypes::Column* first_mergeable_column = nullptr; + for (NGTableTypes::Column* column = start_column; column != end_column; + ++column) { + if (!column->is_collapsed) { + if (!column->is_mergeable) { + // Found non-collapsed, non mergeable column, nothing to do. + return; + } else if (!first_mergeable_column) { + // Found first non-collapsed, mergeable column. + first_mergeable_column = column; + } + } + } + // The interesting problem being solved here is interaction between + // collapsed and mergeable columns. + // All columns that are created by colspanned cell are mergeable by + // default. Without collapsing, the first column would always be + // marked as !mergeable. + // What to do if the first column collapses? If that was the only + // non-mergeable column, the entire cell would merge into first column, + // and collapse. + // To prevent "whole cell hidden if 1st cell is collapsed", + // we try to make first non-collapsed column mergeable. + // If all columns collapse, first cell is marked as meargable. + if (first_mergeable_column) { + // Some columns were not collapsed, mark first as mergeable. + first_mergeable_column->is_mergeable = false; + } else { + start_column->is_mergeable = false; + } +} + // Applies cell/wide cell constraints to columns. // Guarantees columns min/max widths have non-empty values. void ApplyCellConstraintsToColumnConstraints( @@ -32,8 +81,37 @@ bool is_fixed_layout, NGTableTypes::ColspanCells* colspan_cell_constraints, NGTableTypes::Columns* column_constraints) { - if (column_constraints->data.size() < cell_constraints.size()) - column_constraints->data.resize(cell_constraints.size()); + // Satisfy prerequisites for cell merging: + + if (column_constraints->data.size() < cell_constraints.size()) { + // Column constraint must exist for each cell. + NGTableTypes::Column default_column; + default_column.is_table_fixed = is_fixed_layout; + default_column.is_mergeable = !is_fixed_layout; + wtf_size_t column_count = + cell_constraints.size() - column_constraints->data.size(); + // Must loop because WTF::Vector does not support resize with default value. + for (wtf_size_t i = 0; i < column_count; ++i) + column_constraints->data.push_back(default_column); + DCHECK_EQ(column_constraints->data.size(), cell_constraints.size()); + + } else if (column_constraints->data.size() > cell_constraints.size()) { + // Trim mergeable columns off the end. + wtf_size_t last_non_merged_column = column_constraints->data.size() - 1; + while (last_non_merged_column + 1 > cell_constraints.size() && + column_constraints->data[last_non_merged_column].is_mergeable) { + --last_non_merged_column; + } + column_constraints->data.resize(last_non_merged_column + 1); + DCHECK_GE(column_constraints->data.size(), cell_constraints.size()); + } + // Make sure there exists a non-mergeable column for each colspanned cell. + for (const NGTableTypes::ColspanCell& colspan_cell : + *colspan_cell_constraints) { + EnsureDistributableColumnExists(colspan_cell.start_column, + colspan_cell.span, column_constraints); + } + // Distribute cell constraints to column constraints. for (wtf_size_t i = 0; i < cell_constraints.size(); ++i) { column_constraints->data[i].Encompass(cell_constraints[i]);
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_filter_primitive.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_filter_primitive.cc index b1a37a9a..cbd8f30 100644 --- a/third_party/blink/renderer/core/layout/svg/layout_svg_filter_primitive.cc +++ b/third_party/blink/renderer/core/layout/svg/layout_svg_filter_primitive.cc
@@ -72,9 +72,8 @@ CheckForColorChange(element, svg_names::kLightingColorAttr, diff, old_style->LightingColor(), style.LightingColor()); } - const SVGComputedStyle& new_style = style.SvgStyle(); - if (new_style.ColorInterpolationFilters() != - old_style->SvgStyle().ColorInterpolationFilters()) { + if (style.ColorInterpolationFilters() != + old_style->ColorInterpolationFilters()) { element.PrimitiveAttributeChanged( svg_names::kColorInterpolationFiltersAttr); }
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.cc index 37a57a9..90d34cd 100644 --- a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.cc +++ b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.cc
@@ -56,7 +56,7 @@ PaintRecordBuilder builder(context); ColorFilter mask_content_filter = - StyleRef().SvgStyle().ColorInterpolation() == CI_LINEARRGB + StyleRef().ColorInterpolation() == CI_LINEARRGB ? kColorFilterSRGBToLinearRGB : kColorFilterNone; builder.Context().SetColorFilter(mask_content_filter);
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc index 222aba7c..671dc58 100644 --- a/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc +++ b/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc
@@ -423,14 +423,15 @@ return true; // TODO(chrishtr): support rect-based intersections in the cases below. - const SVGComputedStyle& svg_style = StyleRef().SvgStyle(); + const ComputedStyle& style = StyleRef(); + const SVGComputedStyle& svg_style = style.SvgStyle(); if (hit_rules.can_hit_stroke && (svg_style.HasStroke() || !hit_rules.require_stroke) && StrokeContains(local_location, hit_rules.require_stroke)) return true; - WindRule fill_rule = svg_style.FillRule(); + WindRule fill_rule = style.FillRule(); if (request.SvgClipContent()) - fill_rule = svg_style.ClipRule(); + fill_rule = style.ClipRule(); if (hit_rules.can_hit_fill && (svg_style.HasFill() || !hit_rules.require_fill) && FillContains(local_location, hit_rules.require_fill, fill_rule))
diff --git a/third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.cc b/third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.cc index 26e0bf8..d2e64cc 100644 --- a/third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.cc +++ b/third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.cc
@@ -307,10 +307,10 @@ if (WriteSVGPaint(ts, object, svg_style.FillPaint(), GetCSSPropertyFill(), "fill")) { WriteIfNotDefault(ts, "opacity", svg_style.FillOpacity(), 1.0f); - WriteIfNotDefault(ts, "fill rule", svg_style.FillRule(), RULE_NONZERO); + WriteIfNotDefault(ts, "fill rule", style.FillRule(), RULE_NONZERO); ts << "}]"; } - WriteIfNotDefault(ts, "clip rule", svg_style.ClipRule(), RULE_NONZERO); + WriteIfNotDefault(ts, "clip rule", style.ClipRule(), RULE_NONZERO); } TreeScope& tree_scope = object.GetDocument(); @@ -433,7 +433,7 @@ LineLayoutSVGInlineText text_line_layout = LineLayoutSVGInlineText(text_box->GetLineLayoutItem()); - const SVGComputedStyle& svg_style = text_line_layout.StyleRef().SvgStyle(); + const ComputedStyle& style = text_line_layout.StyleRef(); String text = text_box->GetLineLayoutItem().GetText(); unsigned fragments_size = fragments.size(); @@ -447,9 +447,8 @@ // FIXME: Remove this hack, once the new text layout engine is completly // landed. We want to preserve the old web test results for now. ts << "chunk 1 "; - ETextAnchor anchor = svg_style.TextAnchor(); - bool is_vertical_text = - !text_line_layout.StyleRef().IsHorizontalWritingMode(); + ETextAnchor anchor = style.TextAnchor(); + bool is_vertical_text = !style.IsHorizontalWritingMode(); if (anchor == TA_MIDDLE) { ts << "(middle anchor"; if (is_vertical_text)
diff --git a/third_party/blink/renderer/core/layout/svg/svg_text_chunk_builder.cc b/third_party/blink/renderer/core/layout/svg/svg_text_chunk_builder.cc index f097849..b9d9ef7 100644 --- a/third_party/blink/renderer/core/layout/svg/svg_text_chunk_builder.cc +++ b/third_party/blink/renderer/core/layout/svg/svg_text_chunk_builder.cc
@@ -29,7 +29,7 @@ float CalculateTextAnchorShift(const ComputedStyle& style, float length) { bool is_ltr = style.IsLeftToRightDirection(); - switch (style.SvgStyle().TextAnchor()) { + switch (style.TextAnchor()) { default: NOTREACHED(); FALLTHROUGH; @@ -46,7 +46,7 @@ bool NeedsTextAnchorAdjustment(const ComputedStyle& style) { bool is_ltr = style.IsLeftToRightDirection(); - switch (style.SvgStyle().TextAnchor()) { + switch (style.TextAnchor()) { default: NOTREACHED(); FALLTHROUGH;
diff --git a/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine_baseline.cc b/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine_baseline.cc index edf089d..2ee571b 100644 --- a/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine_baseline.cc +++ b/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine_baseline.cc
@@ -62,9 +62,7 @@ DCHECK(text_line_layout); DCHECK(text_line_layout.Style()); - const SVGComputedStyle& style = text_line_layout.StyleRef().SvgStyle(); - - EDominantBaseline baseline = style.DominantBaseline(); + EDominantBaseline baseline = text_line_layout.StyleRef().DominantBaseline(); if (baseline == DB_AUTO) { if (is_vertical_text) baseline = DB_CENTRAL;
diff --git a/third_party/blink/renderer/core/loader/document_loader.cc b/third_party/blink/renderer/core/loader/document_loader.cc index e95c2dd0..a0102a98 100644 --- a/third_party/blink/renderer/core/loader/document_loader.cc +++ b/third_party/blink/renderer/core/loader/document_loader.cc
@@ -631,6 +631,16 @@ return kSPANavTypeSameDocumentBackwardOrForward; } +void DocumentLoader::RunURLAndHistoryUpdateSteps( + const KURL& new_url, + scoped_refptr<SerializedScriptValue> data, + mojom::blink::ScrollRestorationType scroll_restoration_type, + WebFrameLoadType type) { + UpdateForSameDocumentNavigation(new_url, kSameDocumentNavigationHistoryApi, + std::move(data), scroll_restoration_type, + type, true); +} + void DocumentLoader::UpdateForSameDocumentNavigation( const KURL& new_url, SameDocumentNavigationSource same_document_navigation_source, @@ -950,7 +960,14 @@ } } -void DocumentLoader::HandleRedirect(const KURL& current_request_url) { +void DocumentLoader::HandleRedirect( + WebNavigationParams::RedirectInfo& redirect) { + ResourceResponse redirect_response = + redirect.redirect_response.ToResourceResponse(); + const KURL& url_before_redirect = redirect_response.CurrentRequestUrl(); + url_ = redirect.new_url; + const KURL& url_after_redirect = url_; + // Browser process should have already checked that redirecting url is // allowed to display content from the target origin. // When the referrer page is in an unsigned Web Bundle file in local @@ -959,12 +976,35 @@ // to the file's URL (file:///tmp/a.wbn?https://example.com/page.html). In // this case, CanDisplay() returns false, and web_bundle_claimed_url must not // be null. - CHECK(SecurityOrigin::Create(current_request_url)->CanDisplay(url_) || + CHECK(SecurityOrigin::Create(url_before_redirect) + ->CanDisplay(url_after_redirect) || !params_->web_bundle_claimed_url.IsNull()); + // Update the HTTP method of this document to the method used by the redirect. + AtomicString new_http_method = redirect.new_http_method; + if (http_method_ != new_http_method) { + http_body_ = nullptr; + http_content_type_ = g_null_atom; + http_method_ = new_http_method; + } + + if (redirect.new_referrer.IsEmpty()) { + referrer_ = Referrer(Referrer::NoReferrer(), redirect.new_referrer_policy); + } else { + referrer_ = Referrer(redirect.new_referrer, redirect.new_referrer_policy); + } + + // TODO(dgozman): check whether clearing origin policy is intended behavior. + origin_policy_ = base::nullopt; + probe::WillSendNavigationRequest( + probe::ToCoreProbeSink(GetFrame()), main_resource_identifier_, this, + url_after_redirect, http_method_, http_body_.get()); + + navigation_timing_info_->AddRedirect(redirect_response, url_after_redirect); + DCHECK(!GetTiming().FetchStart().is_null()); - redirect_chain_.push_back(url_); - GetTiming().AddRedirect(current_request_url, url_); + redirect_chain_.push_back(url_after_redirect); + GetTiming().AddRedirect(url_before_redirect, url_after_redirect); } bool DocumentLoader::ShouldReportTimingInfoToParent() { @@ -1387,31 +1427,8 @@ main_resource_identifier_, this, url_, http_method_, http_body_.get()); - for (size_t i = 0; i < params_->redirects.size(); ++i) { - WebNavigationParams::RedirectInfo& redirect = params_->redirects[i]; - url_ = redirect.new_url; - AtomicString new_http_method = redirect.new_http_method; - if (http_method_ != new_http_method) { - http_body_ = nullptr; - http_content_type_ = g_null_atom; - http_method_ = new_http_method; - } - if (redirect.new_referrer.IsEmpty()) { - referrer_ = - Referrer(Referrer::NoReferrer(), redirect.new_referrer_policy); - } else { - referrer_ = Referrer(redirect.new_referrer, redirect.new_referrer_policy); - } - - // TODO(dgozman): check whether clearing origin policy is intended behavior. - origin_policy_ = base::nullopt; - probe::WillSendNavigationRequest(probe::ToCoreProbeSink(GetFrame()), - main_resource_identifier_, this, url_, - http_method_, http_body_.get()); - ResourceResponse redirect_response = - redirect.redirect_response.ToResourceResponse(); - navigation_timing_info_->AddRedirect(redirect_response, url_); - HandleRedirect(redirect_response.CurrentRequestUrl()); + for (WebNavigationParams::RedirectInfo& redirect : params_->redirects) { + HandleRedirect(redirect); } if (!frame_->IsMainFrame()) { @@ -1904,6 +1921,10 @@ // SameSiteSiblingToAboutBlank_CrossSiteTop testcase). To limit (but not // eliminate :-/) incorrect cases we require that `owner_document`'s origin // is same origin with `requestor_origin`. + // + // TODO(https://crbug.com/1176291): Improve heuristics for finding the + // correct initiator, to properly inherit/alias `document.domain` in more + // cases. auto* owner_local_frame = DynamicTo<LocalFrame>(owner_frame); if (owner_local_frame && (url_.IsAboutSrcdocURL() || !requestor_origin_ ||
diff --git a/third_party/blink/renderer/core/loader/document_loader.h b/third_party/blink/renderer/core/loader/document_loader.h index abbb471..1d1353a 100644 --- a/third_party/blink/renderer/core/loader/document_loader.h +++ b/third_party/blink/renderer/core/loader/document_loader.h
@@ -142,7 +142,11 @@ return subresource_filter_.Get(); } + // TODO(dcheng, japhet): Some day, Document::Url() will always match + // DocumentLoader::Url(), and one of them will be removed. Today is not that + // day though. const KURL& Url() const; + const KURL& UrlForHistory() const; const AtomicString& HttpMethod() const; const Referrer& GetReferrer() const; @@ -153,12 +157,21 @@ void DidChangePerformanceTiming(); void DidObserveInputDelay(base::TimeDelta input_delay); void DidObserveLoadingBehavior(LoadingBehaviorFlag); + + // https://html.spec.whatwg.org/multipage/history.html#url-and-history-update-steps + void RunURLAndHistoryUpdateSteps( + const KURL&, + scoped_refptr<SerializedScriptValue>, + mojom::blink::ScrollRestorationType = + mojom::blink::ScrollRestorationType::kAuto, + WebFrameLoadType = WebFrameLoadType::kReplaceCurrentItem); void UpdateForSameDocumentNavigation(const KURL&, SameDocumentNavigationSource, scoped_refptr<SerializedScriptValue>, mojom::blink::ScrollRestorationType, WebFrameLoadType, bool is_content_initiated); + const ResourceResponse& GetResponse() const { return response_; } bool IsClientRedirect() const { return is_client_redirect_; } bool ReplacesCurrentHistoryItem() const { @@ -287,11 +300,6 @@ bool IsSameOriginNavigation() const { return is_same_origin_navigation_; } - // TODO(dcheng, japhet): Some day, Document::Url() will always match - // DocumentLoader::Url(), and one of them will be removed. Today is not that - // day though. - void UpdateUrlForDocumentOpen(const KURL& url) { url_ = url; } - enum class HistoryNavigationType { kDifferentDocument, kFragment, @@ -394,7 +402,9 @@ void FinishedLoading(base::TimeTicks finish_time); void CancelLoadAfterCSPDenied(const ResourceResponse&); - void HandleRedirect(const KURL& current_request_url); + // Process a redirect to update the redirect chain, current URL, referrer, + // etc. + void HandleRedirect(WebNavigationParams::RedirectInfo& redirect); void HandleResponse(); void InitializeEmptyResponse();
diff --git a/third_party/blink/renderer/core/paint/paint_timing.cc b/third_party/blink/renderer/core/paint/paint_timing.cc index 9002164..c77d38a 100644 --- a/third_party/blink/renderer/core/paint/paint_timing.cc +++ b/third_party/blink/renderer/core/paint/paint_timing.cc
@@ -337,7 +337,7 @@ void PaintTiming::SetFirstContentfulPaintPresentation(base::TimeTicks stamp) { DCHECK(first_contentful_paint_presentation_.is_null()); TRACE_EVENT_INSTANT_WITH_TIMESTAMP0("benchmark,loading", - "FirstContentfulPaint", + "GlobalFirstContentfulPaint", TRACE_EVENT_SCOPE_GLOBAL, stamp); first_contentful_paint_presentation_ = stamp; probe::PaintTiming(
diff --git a/third_party/blink/renderer/core/paint/svg_inline_text_box_painter.cc b/third_party/blink/renderer/core/paint/svg_inline_text_box_painter.cc index cc25334e..888f677c 100644 --- a/third_party/blink/renderer/core/paint/svg_inline_text_box_painter.cc +++ b/third_party/blink/renderer/core/paint/svg_inline_text_box_painter.cc
@@ -172,7 +172,7 @@ } for (int i = 0; i < 3; i++) { - switch (svg_style.PaintOrderType(i)) { + switch (style.PaintOrderType(i)) { case PT_FILL: if (has_fill) { PaintText(paint_info, style, *selection_style, fragment, @@ -345,7 +345,7 @@ const SVGComputedStyle& svg_decoration_style = decoration_style.SvgStyle(); for (int i = 0; i < 3; i++) { - switch (svg_decoration_style.PaintOrderType(i)) { + switch (decoration_style.PaintOrderType(i)) { case PT_FILL: if (svg_decoration_style.HasFill()) { PaintFlags fill_flags;
diff --git a/third_party/blink/renderer/core/paint/svg_shape_painter.cc b/third_party/blink/renderer/core/paint/svg_shape_painter.cc index fee3b8b2..dc3a1756 100644 --- a/third_party/blink/renderer/core/paint/svg_shape_painter.cc +++ b/third_party/blink/renderer/core/paint/svg_shape_painter.cc
@@ -35,10 +35,10 @@ } static SkPathFillType FillRuleFromStyle(const PaintInfo& paint_info, - const SVGComputedStyle& svg_style) { + const ComputedStyle& style) { return WebCoreWindRuleToSkFillType(paint_info.IsRenderingClipPathAsMaskImage() - ? svg_style.ClipRule() - : svg_style.FillRule()); + ? style.ClipRule() + : style.FillRule()); } void SVGShapePainter::Paint(const PaintInfo& paint_info) { @@ -63,23 +63,23 @@ SVGModelObjectPainter::RecordHitTestData(layout_svg_shape_, paint_info); SVGDrawingRecorder recorder(paint_info.context, layout_svg_shape_, paint_info.phase); - const SVGComputedStyle& svg_style = - layout_svg_shape_.StyleRef().SvgStyle(); + const ComputedStyle& style = layout_svg_shape_.StyleRef(); + const SVGComputedStyle& svg_style = style.SvgStyle(); - bool should_anti_alias = svg_style.ShapeRendering() != SR_CRISPEDGES && - svg_style.ShapeRendering() != SR_OPTIMIZESPEED; + bool should_anti_alias = style.ShapeRendering() != SR_CRISPEDGES && + style.ShapeRendering() != SR_OPTIMIZESPEED; for (int i = 0; i < 3; i++) { - switch (svg_style.PaintOrderType(i)) { + switch (style.PaintOrderType(i)) { case PT_FILL: { PaintFlags fill_flags; if (!SVGObjectPainter(layout_svg_shape_) - .PreparePaint(paint_info, layout_svg_shape_.StyleRef(), - kApplyToFillMode, fill_flags)) + .PreparePaint(paint_info, style, kApplyToFillMode, + fill_flags)) break; fill_flags.setAntiAlias(should_anti_alias); FillShape(paint_info.context, fill_flags, - FillRuleFromStyle(paint_info, svg_style)); + FillRuleFromStyle(paint_info, style)); break; } case PT_STROKE: @@ -99,15 +99,14 @@ PaintFlags stroke_flags; if (!SVGObjectPainter(layout_svg_shape_) .PreparePaint( - paint_info, layout_svg_shape_.StyleRef(), - kApplyToStrokeMode, stroke_flags, + paint_info, style, kApplyToStrokeMode, stroke_flags, base::OptionalOrNullptr(non_scaling_transform))) break; stroke_flags.setAntiAlias(should_anti_alias); StrokeData stroke_data; SVGLayoutSupport::ApplyStrokeStyleToStrokeData( - stroke_data, layout_svg_shape_.StyleRef(), layout_svg_shape_, + stroke_data, style, layout_svg_shape_, layout_svg_shape_.DashScaleFactor()); stroke_data.SetupPaint(&stroke_flags);
diff --git a/third_party/blink/renderer/core/style/computed_style.cc b/third_party/blink/renderer/core/style/computed_style.cc index 34d2fd1..812182b 100644 --- a/third_party/blink/renderer/core/style/computed_style.cc +++ b/third_party/blink/renderer/core/style/computed_style.cc
@@ -2434,6 +2434,45 @@ return GetListStyleType()->GetStringValue(); } +static const int kPaintOrderBitwidth = 2; + +static unsigned PaintOrderSequence(EPaintOrderType first, + EPaintOrderType second, + EPaintOrderType third) { + return (((third << kPaintOrderBitwidth) | second) << kPaintOrderBitwidth) | + first; +} + +EPaintOrderType ComputedStyle::PaintOrderType(unsigned index) const { + unsigned pt = 0; + DCHECK(index < ((1 << kPaintOrderBitwidth) - 1)); + switch (PaintOrder()) { + case kPaintOrderNormal: + case kPaintOrderFillStrokeMarkers: + pt = PaintOrderSequence(PT_FILL, PT_STROKE, PT_MARKERS); + break; + case kPaintOrderFillMarkersStroke: + pt = PaintOrderSequence(PT_FILL, PT_MARKERS, PT_STROKE); + break; + case kPaintOrderStrokeFillMarkers: + pt = PaintOrderSequence(PT_STROKE, PT_FILL, PT_MARKERS); + break; + case kPaintOrderStrokeMarkersFill: + pt = PaintOrderSequence(PT_STROKE, PT_MARKERS, PT_FILL); + break; + case kPaintOrderMarkersFillStroke: + pt = PaintOrderSequence(PT_MARKERS, PT_FILL, PT_STROKE); + break; + case kPaintOrderMarkersStrokeFill: + pt = PaintOrderSequence(PT_MARKERS, PT_STROKE, PT_FILL); + break; + } + + pt = + (pt >> (kPaintOrderBitwidth * index)) & ((1u << kPaintOrderBitwidth) - 1); + return static_cast<EPaintOrderType>(pt); +} + STATIC_ASSERT_ENUM(cc::OverscrollBehavior::Type::kAuto, EOverscrollBehavior::kAuto); STATIC_ASSERT_ENUM(cc::OverscrollBehavior::Type::kContain,
diff --git a/third_party/blink/renderer/core/style/computed_style.h b/third_party/blink/renderer/core/style/computed_style.h index 73a6470..d4a11ff 100644 --- a/third_party/blink/renderer/core/style/computed_style.h +++ b/third_party/blink/renderer/core/style/computed_style.h
@@ -1151,6 +1151,19 @@ const Length& Ry() const { return SvgStyle().Ry(); } void SetRy(const Length& ry) { AccessSVGStyle().SetRy(ry); } + WindRule ClipRule() const { return SvgStyle().ClipRule(); } + EColorInterpolation ColorInterpolation() const { + return SvgStyle().ColorInterpolation(); + } + EColorInterpolation ColorInterpolationFilters() const { + return SvgStyle().ColorInterpolationFilters(); + } + EColorRendering ColorRendering() const { return SvgStyle().ColorRendering(); } + EDominantBaseline DominantBaseline() const { + return SvgStyle().DominantBaseline(); + } + WindRule FillRule() const { return SvgStyle().FillRule(); } + // fill-opacity float FillOpacity() const { return SvgStyle().FillOpacity(); } void SetFillOpacity(float f) { AccessSVGStyle().SetFillOpacity(f); } @@ -1181,6 +1194,12 @@ float StopOpacity() const { return SvgStyle().StopOpacity(); } void SetStopOpacity(float f) { AccessSVGStyle().SetStopOpacity(f); } + // paint-order helper + EPaintOrder PaintOrder() const { return SvgStyle().PaintOrder(); } + EPaintOrderType PaintOrderType(unsigned index) const; + + EShapeRendering ShapeRendering() const { return SvgStyle().ShapeRendering(); } + // stroke-dasharray SVGDashArray* StrokeDashArray() const { return SvgStyle().StrokeDashArray(); } void SetStrokeDashArray(scoped_refptr<SVGDashArray> array) { @@ -1209,6 +1228,7 @@ AccessSVGStyle().SetStrokeWidth(w); } + ETextAnchor TextAnchor() const { return SvgStyle().TextAnchor(); } EVectorEffect VectorEffect() const { return SvgStyle().VectorEffect(); } // Comparison operators
diff --git a/third_party/blink/renderer/core/style/svg_computed_style.cc b/third_party/blink/renderer/core/style/svg_computed_style.cc index 6d4354b..ab67196 100644 --- a/third_party/blink/renderer/core/style/svg_computed_style.cc +++ b/third_party/blink/renderer/core/style/svg_computed_style.cc
@@ -33,8 +33,6 @@ namespace blink { -static const int kPaintOrderBitwidth = 2; - SVGComputedStyle::SVGComputedStyle() { static SVGComputedStyle* initial_style = new SVGComputedStyle(kCreateInitial); @@ -249,43 +247,6 @@ return false; } -unsigned PaintOrderSequence(EPaintOrderType first, - EPaintOrderType second, - EPaintOrderType third) { - return (((third << kPaintOrderBitwidth) | second) << kPaintOrderBitwidth) | - first; -} - -EPaintOrderType SVGComputedStyle::PaintOrderType(unsigned index) const { - unsigned pt = 0; - DCHECK(index < ((1 << kPaintOrderBitwidth) - 1)); - switch (this->PaintOrder()) { - case kPaintOrderNormal: - case kPaintOrderFillStrokeMarkers: - pt = PaintOrderSequence(PT_FILL, PT_STROKE, PT_MARKERS); - break; - case kPaintOrderFillMarkersStroke: - pt = PaintOrderSequence(PT_FILL, PT_MARKERS, PT_STROKE); - break; - case kPaintOrderStrokeFillMarkers: - pt = PaintOrderSequence(PT_STROKE, PT_FILL, PT_MARKERS); - break; - case kPaintOrderStrokeMarkersFill: - pt = PaintOrderSequence(PT_STROKE, PT_MARKERS, PT_FILL); - break; - case kPaintOrderMarkersFillStroke: - pt = PaintOrderSequence(PT_MARKERS, PT_FILL, PT_STROKE); - break; - case kPaintOrderMarkersStrokeFill: - pt = PaintOrderSequence(PT_MARKERS, PT_STROKE, PT_FILL); - break; - } - - pt = - (pt >> (kPaintOrderBitwidth * index)) & ((1u << kPaintOrderBitwidth) - 1); - return (EPaintOrderType)pt; -} - void SVGComputedStyle::SetMaskerResource( scoped_refptr<StyleSVGResource> resource) { if (!(resources->masker == resource))
diff --git a/third_party/blink/renderer/core/style/svg_computed_style.h b/third_party/blink/renderer/core/style/svg_computed_style.h index a70adb7e7..319bda6 100644 --- a/third_party/blink/renderer/core/style/svg_computed_style.h +++ b/third_party/blink/renderer/core/style/svg_computed_style.h
@@ -347,7 +347,6 @@ EPaintOrder PaintOrder() const { return (EPaintOrder)svg_inherited_flags.paint_order; } - EPaintOrderType PaintOrderType(unsigned index) const; const SVGPaint& InternalVisitedFillPaint() const { return fill->visited_link_paint;
diff --git a/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc b/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc index fd4521d..8a6f613 100644 --- a/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc +++ b/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc
@@ -668,7 +668,7 @@ return SMILRepeatCount::Indefinite(); bool ok; double result = value.ToDouble(&ok); - if (ok && result > 0) + if (ok && result > 0 && std::isfinite(result)) return SMILRepeatCount::Numeric(result); return SMILRepeatCount::Unspecified(); }
diff --git a/third_party/blink/renderer/core/svg/graphics/filters/svg_filter_builder.cc b/third_party/blink/renderer/core/svg/graphics/filters/svg_filter_builder.cc index 3dd66330..9c6d6c6 100644 --- a/third_party/blink/renderer/core/svg/graphics/filters/svg_filter_builder.cc +++ b/third_party/blink/renderer/core/svg/graphics/filters/svg_filter_builder.cc
@@ -137,7 +137,7 @@ SVGElement& element, EColorInterpolation parent_color_interpolation) { if (const LayoutObject* layout_object = element.GetLayoutObject()) - return layout_object->StyleRef().SvgStyle().ColorInterpolationFilters(); + return layout_object->StyleRef().ColorInterpolationFilters(); // No layout has been performed, try to determine the property value // "manually" (used by external SVG files.)
diff --git a/third_party/blink/renderer/core/svg/svg_filter_primitive_standard_attributes.cc b/third_party/blink/renderer/core/svg/svg_filter_primitive_standard_attributes.cc index ea88fd7..6bf7616c 100644 --- a/third_party/blink/renderer/core/svg/svg_filter_primitive_standard_attributes.cc +++ b/third_party/blink/renderer/core/svg/svg_filter_primitive_standard_attributes.cc
@@ -86,7 +86,7 @@ DCHECK(attr_name == svg_names::kColorInterpolationFiltersAttr); DCHECK(GetLayoutObject()); EColorInterpolation color_interpolation = - GetLayoutObject()->StyleRef().SvgStyle().ColorInterpolationFilters(); + GetLayoutObject()->StyleRef().ColorInterpolationFilters(); InterpolationSpace resolved_interpolation_space = SVGFilterBuilder::ResolveInterpolationSpace(color_interpolation); if (resolved_interpolation_space == effect->OperatingInterpolationSpace())
diff --git a/third_party/blink/renderer/core/svg/svg_geometry_element.cc b/third_party/blink/renderer/core/svg/svg_geometry_element.cc index 448c482..4a54d968 100644 --- a/third_party/blink/renderer/core/svg/svg_geometry_element.cc +++ b/third_party/blink/renderer/core/svg/svg_geometry_element.cc
@@ -94,7 +94,7 @@ return false; // Path::Contains will reject points with a non-finite component. - WindRule fill_rule = layout_object->StyleRef().SvgStyle().FillRule(); + WindRule fill_rule = layout_object->StyleRef().FillRule(); return AsPath().Contains(point->Target()->Value(), fill_rule); } @@ -140,7 +140,7 @@ DCHECK(GetLayoutObject()); DCHECK(GetLayoutObject()->Style()); - path.SetWindRule(GetLayoutObject()->StyleRef().SvgStyle().ClipRule()); + path.SetWindRule(GetLayoutObject()->StyleRef().ClipRule()); return path; }
diff --git a/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.cc b/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.cc index 3c40a9b..ade1a80 100644 --- a/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.cc +++ b/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.cc
@@ -85,12 +85,6 @@ local_frame->GetSettings()->GetWebSecurityEnabled()) { return ApiStatus::kNotAvailableDueToCrossOriginIsolation; } - // CrossOriginIsolated is also set for same-agent cross-origin iframe. - // Allow only iframes that have the same origin as the main frame. - // Note that COOP guarantees that all main frames have the same origin. - if (local_frame->IsCrossOriginToMainFrame()) { - return ApiStatus::kNotAvailableDueToCrossOriginContext; - } // We need DocumentResourceCoordinator to query PerformanceManager. if (!window->document()) {
diff --git a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc index d5a3bcbf..b3e8286 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
@@ -133,7 +133,6 @@ ax::mojom::blink::Role role = obj->RoleValue(); return role == ax::mojom::blink::Role::kGroup || role == ax::mojom::blink::Role::kGenericContainer || - role == ax::mojom::blink::Role::kIgnored || role == ax::mojom::blink::Role::kRowGroup; } @@ -293,12 +292,6 @@ return kIgnoreObject; } - if (RoleValue() == ax::mojom::blink::Role::kIgnored) { - if (ignored_reasons) - ignored_reasons->push_back(IgnoredReason(kAXUninteresting)); - return kIgnoreObject; - } - if (HasInheritedPresentationalRole()) { if (ignored_reasons) { const AXObject* inherits_from = InheritsPresentationalRoleFrom(); @@ -715,7 +708,7 @@ return ax::mojom::blink::Role::kGenericContainer; if (parent->RoleValue() == ax::mojom::blink::Role::kLayoutTable) - return ax::mojom::blink::Role::kIgnored; + return ax::mojom::blink::Role::kGenericContainer; return ax::mojom::blink::Role::kRowGroup; }
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object.cc b/third_party/blink/renderer/modules/accessibility/ax_object.cc index 808fa8eb..ffcad28 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_object.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_object.cc
@@ -105,6 +105,23 @@ return node->parentNode(); } +#if DCHECK_IS_ON() +bool IsValidRole(ax::mojom::blink::Role role, bool is_virtual_object) { + // Check for illegal roles that should not be assigned in Blink. + switch (role) { + case ax::mojom::blink::Role::kUnknown: + // Role::kUnknown is allowed on virtual objects with no set role. + return is_virtual_object; + case ax::mojom::blink::Role::kColumn: + case ax::mojom::blink::Role::kTableHeaderContainer: + case ax::mojom::blink::Role::kIgnored: + return false; + default: + return true; + } +} +#endif + struct RoleHashTraits : HashTraits<ax::mojom::blink::Role> { static const bool kEmptyValueIsZero = true; static ax::mojom::blink::Role EmptyValue() { @@ -645,8 +662,11 @@ // Note: in order to avoid reentrancy, the role computation cannot use the // ParentObject(), although it can use the DOM parent. role_ = DetermineAccessibilityRole(); - DCHECK(role_ != ax::mojom::blink::Role::kUnknown || IsVirtualObject()) - << "Illegal Role::kUnknown for " << GetNode() << " " << GetLayoutObject(); +#if DCHECK_IS_ON() + DCHECK(IsValidRole(role_, IsVirtualObject())) + << "Illegal " << role_ << " for " << GetNode() << " " + << GetLayoutObject(); +#endif // Determine the parent as soon as possible. // Every AXObject must have a parent unless it's the root. @@ -2235,13 +2255,10 @@ if (IsA<HTMLHtmlElement>(GetNode())) return RuntimeEnabledFeatures::AccessibilityExposeHTMLElementEnabled(); - // If the node is part of the user agent shadow dom, or has the explicit - // internal Role::kIgnored, they aren't interesting for paragraph navigation - // or LabelledBy/DescribedBy relationships. - if (RoleValue() == ax::mojom::blink::Role::kIgnored || - GetNode()->IsInUserAgentShadowRoot()) { + // If the node is part of the user agent shadow dom, it isn't interesting for + // paragraph navigation or LabelledBy/DescribedBy relationships. + if (GetNode()->IsInUserAgentShadowRoot()) return false; - } // Keep the internal accessibility tree consistent for videos which lack // a player and also inner text. @@ -4983,7 +5000,6 @@ case ax::mojom::blink::Role::kFooterAsNonLandmark: case ax::mojom::blink::Role::kGenericContainer: case ax::mojom::blink::Role::kHeaderAsNonLandmark: - case ax::mojom::blink::Role::kIgnored: case ax::mojom::blink::Role::kImageMap: case ax::mojom::blink::Role::kInlineTextBox: case ax::mojom::blink::Role::kLabelText: @@ -5071,6 +5087,7 @@ } case ax::mojom::blink::Role::kColumn: + case ax::mojom::blink::Role::kIgnored: case ax::mojom::blink::Role::kTableHeaderContainer: case ax::mojom::blink::Role::kUnknown: NOTREACHED() << "Role shouldn't occur in Blink: " << ToString(true, true);
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc index 41e72af..b5dcead9 100644 --- a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc +++ b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc
@@ -674,7 +674,7 @@ if (GetState().GetTransform() == new_transform) return; - // Must call setTransform to set the IsTransformInvertible flag. + // We need to call SetTransform() to set the IsTransformInvertible flag. ModifiableState().SetTransform(new_transform); if (!GetState().IsTransformInvertible()) return; @@ -683,6 +683,34 @@ path_.Transform(translation_matrix.Inverse()); } +void BaseRenderingContext2D::perspective(double length) { + cc::PaintCanvas* c = GetOrCreatePaintCanvas(); + if (!c) + return; + + if (length == 0 || !std::isfinite(length)) + return; + + float flength = clampTo<float>(length); + + TransformationMatrix perspective_matrix = + TransformationMatrix().ApplyPerspective(flength); + + // Check if the transformation is a no-op and early out if that is the case. + TransformationMatrix new_transform = + GetState().GetTransform().ApplyPerspective(flength); + if (GetState().GetTransform() == new_transform) + return; + + // We need to call SetTransform() to set the IsTransformInvertible flag. + ModifiableState().SetTransform(new_transform); + if (!GetState().IsTransformInvertible()) + return; + + c->concat(TransformationMatrix::ToSkM44(perspective_matrix)); + path_.Transform(perspective_matrix.Inverse()); +} + void BaseRenderingContext2D::transform(double m11, double m12, double m13,
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h index df1c44e..56541ea 100644 --- a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h +++ b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h
@@ -91,6 +91,7 @@ double angle_in_radians); void translate(double tx, double ty); void translate(double tx, double ty, double tz); + void perspective(double length); void transform(double m11, double m12, double m21,
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.idl b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.idl index 6d74856a..0956b79 100644 --- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.idl +++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.idl
@@ -63,6 +63,7 @@ [RuntimeEnabled=NewCanvas2DAPI] void rotateAxis(unrestricted double axisX, unrestricted double axisY, unrestricted double axisZ, unrestricted double angle); void translate(unrestricted double x, unrestricted double y); [RuntimeEnabled=NewCanvas2DAPI] void translate(unrestricted double x, unrestricted double y, unrestricted double z); + [RuntimeEnabled=NewCanvas2DAPI] void perspective(unrestricted double length); void transform(unrestricted double a, unrestricted double b, unrestricted double c, unrestricted double d, unrestricted double e, unrestricted double f); [RuntimeEnabled=NewCanvas2DAPI] void transform( unrestricted double m11, unrestricted double m12, unrestricted double m13, unrestricted double m14,
diff --git a/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.idl b/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.idl index 27317048..50727f90 100644 --- a/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.idl +++ b/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.idl
@@ -27,6 +27,7 @@ [RuntimeEnabled=NewCanvas2DAPI] void rotateAxis(unrestricted double axisX, unrestricted double axisY, unrestricted double axisZ, unrestricted double angle); void translate(unrestricted double x, unrestricted double y); [RuntimeEnabled=NewCanvas2DAPI] void translate(unrestricted double x, unrestricted double y, unrestricted double z); + [RuntimeEnabled=NewCanvas2DAPI] void perspective(unrestricted double length); void transform(unrestricted double a, unrestricted double b, unrestricted double c, unrestricted double d, unrestricted double e, unrestricted double f); [RuntimeEnabled=NewCanvas2DAPI] void transform( unrestricted double m11, unrestricted double m12, unrestricted double m13, unrestricted double m14,
diff --git a/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.idl b/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.idl index 29a721f..6e4ef60d 100644 --- a/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.idl +++ b/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.idl
@@ -19,6 +19,7 @@ [RuntimeEnabled=NewCanvas2DAPI] void rotateAxis(unrestricted double axisX, unrestricted double axisY, unrestricted double axisZ, unrestricted double angle); void translate(unrestricted double x, unrestricted double y); [RuntimeEnabled=NewCanvas2DAPI] void translate(unrestricted double x, unrestricted double y, unrestricted double z); + [RuntimeEnabled=NewCanvas2DAPI] void perspective(unrestricted double length); void transform(unrestricted double a, unrestricted double b, unrestricted double c, unrestricted double d, unrestricted double e, unrestricted double f); [RuntimeEnabled=NewCanvas2DAPI] void transform( unrestricted double m11, unrestricted double m12, unrestricted double m13, unrestricted double m14,
diff --git a/third_party/blink/renderer/modules/mediastream/pushable_media_stream_audio_source.cc b/third_party/blink/renderer/modules/mediastream/pushable_media_stream_audio_source.cc index 9c069b9..4de9496a 100644 --- a/third_party/blink/renderer/modules/mediastream/pushable_media_stream_audio_source.cc +++ b/third_party/blink/renderer/modules/mediastream/pushable_media_stream_audio_source.cc
@@ -4,6 +4,7 @@ #include "third_party/blink/renderer/modules/mediastream/pushable_media_stream_audio_source.h" +#include "media/base/audio_timestamp_helper.h" #include "third_party/blink/public/mojom/mediastream/media_stream.mojom-blink.h" #include "third_party/blink/renderer/modules/webcodecs/audio_frame_serialization_data.h" #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h" @@ -78,7 +79,13 @@ last_frames_ = audio_bus.frames(); } - DeliverDataToTracks(audio_bus, base::TimeTicks() + data->timestamp()); + // data->timestamp() is the time at the beginning of the |data| audio piece. + // |capture_time| is the time at the end of the |data| audio piece. + base::TimeTicks capture_time = base::TimeTicks() + data->timestamp() + + media::AudioTimestampHelper::FramesToTime( + audio_bus.frames(), sample_rate); + + DeliverDataToTracks(audio_bus, capture_time); } bool PushableMediaStreamAudioSource::EnsureSourceIsStarted() {
diff --git a/third_party/blink/renderer/modules/mediastream/pushable_media_stream_audio_source_test.cc b/third_party/blink/renderer/modules/mediastream/pushable_media_stream_audio_source_test.cc index 7c4f45e4..f95874f1 100644 --- a/third_party/blink/renderer/modules/mediastream/pushable_media_stream_audio_source_test.cc +++ b/third_party/blink/renderer/modules/mediastream/pushable_media_stream_audio_source_test.cc
@@ -138,12 +138,15 @@ } base::RunLoop run_loop; - base::TimeTicks reference_time = base::TimeTicks::Now(); - fake_sink->SetDataTimeExpectation(reference_time, run_loop.QuitClosure()); + base::TimeTicks timestamp = base::TimeTicks::Now(); + base::TimeDelta duration = + base::TimeDelta::FromSeconds(1) * frames / sample_rate; + base::TimeTicks capture_time = timestamp + duration; + fake_sink->SetDataTimeExpectation(capture_time, run_loop.QuitClosure()); pushable_audio_source_->PushAudioData(AudioFrameSerializationData::Wrap( media::AudioBus::Create(channels, frames), sample_rate, - reference_time - base::TimeTicks())); + timestamp - base::TimeTicks())); run_loop.Run(); EXPECT_EQ(fake_sink->did_receive_format_change(), expect_format_change);
diff --git a/third_party/blink/renderer/modules/scheduler/dom_scheduler.cc b/third_party/blink/renderer/modules/scheduler/dom_scheduler.cc index e24b63e9..cdcdd0e 100644 --- a/third_party/blink/renderer/modules/scheduler/dom_scheduler.cc +++ b/third_party/blink/renderer/modules/scheduler/dom_scheduler.cc
@@ -63,11 +63,11 @@ Supplement<LocalDOMWindow>::Trace(visitor); } -ScriptPromise DOMScheduler::postTask(ScriptState* script_state, - V8Function* callback_function, - SchedulerPostTaskOptions* options, - const HeapVector<ScriptValue>& args, - ExceptionState& exception_state) { +ScriptPromise DOMScheduler::postTask( + ScriptState* script_state, + V8SchedulerPostTaskCallback* callback_function, + SchedulerPostTaskOptions* options, + ExceptionState& exception_state) { if (!GetExecutionContext() || GetExecutionContext()->IsContextDestroyed()) return RejectPromiseImmediately(exception_state); if (options->signal() && options->signal()->aborted()) @@ -112,8 +112,8 @@ base::TimeDelta::FromMilliseconds(std::max(0, options->delay())); auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state); - MakeGarbageCollected<DOMTask>(this, resolver, callback_function, args, - task_signal, delay); + MakeGarbageCollected<DOMTask>(this, resolver, callback_function, task_signal, + delay); return resolver->Promise(); }
diff --git a/third_party/blink/renderer/modules/scheduler/dom_scheduler.h b/third_party/blink/renderer/modules/scheduler/dom_scheduler.h index 1cec218..3014dff 100644 --- a/third_party/blink/renderer/modules/scheduler/dom_scheduler.h +++ b/third_party/blink/renderer/modules/scheduler/dom_scheduler.h
@@ -21,8 +21,7 @@ class DOMTaskSignal; class ExceptionState; class SchedulerPostTaskOptions; -class ScriptValue; -class V8Function; +class V8SchedulerPostTaskCallback; class WebSchedulingTaskQueue; class MODULES_EXPORT DOMScheduler : public ScriptWrappable, @@ -44,9 +43,8 @@ // underlying context is destroyed, e.g. for detached windows, this will // return a rejected promise. ScriptPromise postTask(ScriptState*, - V8Function*, + V8SchedulerPostTaskCallback*, SchedulerPostTaskOptions*, - const HeapVector<ScriptValue>& args, ExceptionState&); // Returns a TaskSignal representing the state when the current task was
diff --git a/third_party/blink/renderer/modules/scheduler/dom_task.cc b/third_party/blink/renderer/modules/scheduler/dom_task.cc index b3174c6..856c465 100644 --- a/third_party/blink/renderer/modules/scheduler/dom_task.cc +++ b/third_party/blink/renderer/modules/scheduler/dom_task.cc
@@ -9,7 +9,7 @@ #include "base/check_op.h" #include "base/metrics/histogram_macros.h" #include "third_party/blink/renderer/bindings/core/v8/script_value.h" -#include "third_party/blink/renderer/bindings/core/v8/v8_function.h" +#include "third_party/blink/renderer/bindings/modules/v8/v8_scheduler_post_task_callback.h" #include "third_party/blink/renderer/core/dom/dom_exception.h" #include "third_party/blink/renderer/core/probe/core_probes.h" #include "third_party/blink/renderer/modules/scheduler/dom_scheduler.h" @@ -33,13 +33,11 @@ DOMTask::DOMTask(DOMScheduler* scheduler, ScriptPromiseResolver* resolver, - V8Function* callback, - const HeapVector<ScriptValue>& args, + V8SchedulerPostTaskCallback* callback, DOMTaskSignal* signal, base::TimeDelta delay) : scheduler_(scheduler), callback_(callback), - arguments_(args), resolver_(resolver), signal_(signal), // TODO(kdillon): Expose queuing time from base::sequence_manager so we @@ -65,7 +63,6 @@ void DOMTask::Trace(Visitor* visitor) const { visitor->Trace(scheduler_); visitor->Trace(callback_); - visitor->Trace(arguments_); visitor->Trace(resolver_); visitor->Trace(signal_); } @@ -97,7 +94,7 @@ v8_context->SetContinuationPreservedEmbedderData( ToV8(signal_.Get(), v8_context->Global(), isolate)); ScriptValue result; - if (callback_->Invoke(nullptr, arguments_).To(&result)) + if (callback_->Invoke(nullptr).To(&result)) resolver_->Resolve(result.V8Value()); else if (try_catch.HasCaught()) resolver_->Reject(try_catch.Exception());
diff --git a/third_party/blink/renderer/modules/scheduler/dom_task.h b/third_party/blink/renderer/modules/scheduler/dom_task.h index 7c490b2..76c408e 100644 --- a/third_party/blink/renderer/modules/scheduler/dom_task.h +++ b/third_party/blink/renderer/modules/scheduler/dom_task.h
@@ -15,8 +15,7 @@ class DOMScheduler; class DOMTaskSignal; class ScriptState; -class ScriptValue; -class V8Function; +class V8SchedulerPostTaskCallback; // DOMTask represents a task scheduled via the web scheduling API. It will // keep itself alive until DOMTask::Invoke is called, which may be after the @@ -25,8 +24,7 @@ public: DOMTask(DOMScheduler*, ScriptPromiseResolver*, - V8Function*, - const HeapVector<ScriptValue>& args, + V8SchedulerPostTaskCallback*, DOMTaskSignal*, base::TimeDelta delay); @@ -44,8 +42,7 @@ Member<DOMScheduler> scheduler_; TaskHandle task_handle_; - Member<V8Function> callback_; - HeapVector<ScriptValue> arguments_; + Member<V8SchedulerPostTaskCallback> callback_; Member<ScriptPromiseResolver> resolver_; probe::AsyncTaskId async_task_id_; Member<DOMTaskSignal> signal_;
diff --git a/third_party/blink/renderer/modules/scheduler/scheduler.idl b/third_party/blink/renderer/modules/scheduler/scheduler.idl index 54791a0e..a06f1bc 100644 --- a/third_party/blink/renderer/modules/scheduler/scheduler.idl +++ b/third_party/blink/renderer/modules/scheduler/scheduler.idl
@@ -9,6 +9,6 @@ ImplementedAs=DOMScheduler, RuntimeEnabled=WebScheduler ] interface Scheduler { - [CallWith=ScriptState, MeasureAs=SchedulerPostTask, RaisesException] Promise<any> postTask(Function callback, optional SchedulerPostTaskOptions options = {}, any... arguments); + [CallWith=ScriptState, MeasureAs=SchedulerPostTask, RaisesException] Promise<any> postTask(SchedulerPostTaskCallback callback, optional SchedulerPostTaskOptions options = {}); [CallWith=ScriptState, MeasureAs=SchedulerCurrentTaskSignal] readonly attribute TaskSignal currentTaskSignal; };
diff --git a/third_party/blink/renderer/modules/scheduler/scheduler_post_task_callback.idl b/third_party/blink/renderer/modules/scheduler/scheduler_post_task_callback.idl new file mode 100644 index 0000000..7dc1b251 --- /dev/null +++ b/third_party/blink/renderer/modules/scheduler/scheduler_post_task_callback.idl
@@ -0,0 +1,7 @@ +// Copyright 2021 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. + +// Experimental Scheduling API Proposal: +// https://docs.google.com/document/d/1Apz-SD-pOagGeyWxIpgOi0ARNkrCrELhPdm18eeu9tw +callback SchedulerPostTaskCallback = any ();
diff --git a/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc b/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc index ea7be1b94..2ad0ae8 100644 --- a/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc +++ b/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc
@@ -218,11 +218,9 @@ /*reporting_observer_receiver=*/mojo::NullReceiver()); // To make the other side callable. - mojo::AssociateWithDisconnectedPipe(host_receiver.PassHandle()); - mojo::AssociateWithDisconnectedPipe( - registration_object_host_receiver.PassHandle()); - mojo::AssociateWithDisconnectedPipe( - service_worker_object_host_receiver.PassHandle()); + host_receiver.EnableUnassociatedUsage(); + registration_object_host_receiver.EnableUnassociatedUsage(); + service_worker_object_host_receiver.EnableUnassociatedUsage(); } void FailedToFetchClassicScript() override {
diff --git a/third_party/blink/renderer/modules/speech/OWNERS b/third_party/blink/renderer/modules/speech/OWNERS index e807354..5ecb2f4d 100644 --- a/third_party/blink/renderer/modules/speech/OWNERS +++ b/third_party/blink/renderer/modules/speech/OWNERS
@@ -3,4 +3,3 @@ # Speech recognition - send reviews here first, then to dmazzoni for approval. tommi@chromium.org -gshires@chromium.org
diff --git a/third_party/blink/renderer/modules/webcodecs/video_frame.cc b/third_party/blink/renderer/modules/webcodecs/video_frame.cc index 19fd47e..60d4353 100644 --- a/third_party/blink/renderer/modules/webcodecs/video_frame.cc +++ b/third_party/blink/renderer/modules/webcodecs/video_frame.cc
@@ -41,23 +41,6 @@ namespace { -bool IsValidSkColorSpace(sk_sp<SkColorSpace> sk_color_space) { - // Refer to CanvasColorSpaceToGfxColorSpace in CanvasColorParams. - sk_sp<SkColorSpace> valid_sk_color_spaces[] = { - gfx::ColorSpace::CreateSRGB().ToSkColorSpace(), - gfx::ColorSpace::CreateDisplayP3D65().ToSkColorSpace(), - gfx::ColorSpace(gfx::ColorSpace::PrimaryID::BT2020, - gfx::ColorSpace::TransferID::GAMMA24) - .ToSkColorSpace()}; - for (auto& valid_sk_color_space : valid_sk_color_spaces) { - if (SkColorSpace::Equals(sk_color_space.get(), - valid_sk_color_space.get())) { - return true; - } - } - return false; -} - struct YUVReadbackContext { gfx::Size coded_size; gfx::Rect visible_rect; @@ -189,18 +172,224 @@ const base::TimeDelta CachedVideoFramePool::kIdleTimeout = base::TimeDelta::FromSeconds(10); +scoped_refptr<viz::RasterContextProvider> GetRasterContextProvider() { + auto wrapper = SharedGpuContext::ContextProviderWrapper(); + if (!wrapper) + return nullptr; + + if (auto* provider = wrapper->ContextProvider()) + return base::WrapRefCounted(provider->RasterContextProvider()); + + return nullptr; +} + +bool CanUseZeroCopyImages(const media::VideoFrame& frame) { + // SharedImage optimization: create AcceleratedStaticBitmapImage directly. + // Disabled on Android because the hardware decode implementation may neuter + // frames, which would violate ImageBitmap requirements. + // TODO(sandersd): Handle YUV pixel formats. + // TODO(sandersd): Handle high bit depth formats. +#if defined(OS_ANDROID) + return false; +#else + return frame.NumTextures() == 1 && + frame.mailbox_holder(0).mailbox.IsSharedImage() && + (frame.format() == media::PIXEL_FORMAT_ARGB || + frame.format() == media::PIXEL_FORMAT_XRGB || + frame.format() == media::PIXEL_FORMAT_ABGR || + frame.format() == media::PIXEL_FORMAT_XBGR || + frame.format() == media::PIXEL_FORMAT_BGRA); +#endif +} + +bool PreferAcceleratedImages(const media::VideoFrame& frame) { + if (frame.format() == media::PIXEL_FORMAT_I420A) + return false; + + if (frame.HasTextures()) + return true; + + if (frame.format() == media::PIXEL_FORMAT_ARGB || + frame.format() == media::PIXEL_FORMAT_XRGB || + frame.format() == media::PIXEL_FORMAT_ABGR || + frame.format() == media::PIXEL_FORMAT_XBGR) { + return false; + } + + constexpr int kCpuEfficientFrameSize = 320u * 240u; + return frame.visible_rect().size().GetArea() > kCpuEfficientFrameSize; +} + +scoped_refptr<StaticBitmapImage> CreateImage( + scoped_refptr<media::VideoFrame> frame) { + // TODO(sandersd): Do we need to be able to handle limited-range RGB? It + // may never happen, and SkColorSpace doesn't know about it. + auto sk_color_space = + frame->ColorSpace().GetAsFullRangeRGB().ToSkColorSpace(); + if (!sk_color_space) + sk_color_space = SkColorSpace::MakeSRGB(); + + if (CanUseZeroCopyImages(*frame)) { + const SkImageInfo sk_image_info = SkImageInfo::Make( + frame->coded_size().width(), frame->coded_size().height(), + kN32_SkColorType, kUnpremul_SkAlphaType, std::move(sk_color_space)); + + // Hold a ref by storing it in the release callback. + auto release_callback = viz::SingleReleaseCallback::Create( + WTF::Bind([](scoped_refptr<media::VideoFrame> frame, + const gpu::SyncToken& sync_token, bool is_lost) {}, + frame)); + + return AcceleratedStaticBitmapImage::CreateFromCanvasMailbox( + frame->mailbox_holder(0).mailbox, frame->mailbox_holder(0).sync_token, + 0u, sk_image_info, frame->mailbox_holder(0).texture_target, true, + // Pass nullptr for |context_provider_wrapper|, because we don't + // know which context the mailbox came from. It is used only to + // detect when the mailbox is invalid due to context loss, and is + // ignored when |is_cross_thread|. + base::WeakPtr<WebGraphicsContext3DProviderWrapper>(), + // Pass null |context_thread_ref|, again because we don't know + // which context the mailbox came from. This should always trigger + // |is_cross_thread|. + base::PlatformThreadRef(), + // The task runner is only used for |release_callback|. + Thread::Current()->GetTaskRunner(), std::move(release_callback)); + } + + const bool is_mappable = + frame->IsMappable() && (frame->format() == media::PIXEL_FORMAT_I420 || + frame->format() == media::PIXEL_FORMAT_I420A); + const bool is_texturable = + frame->HasTextures() && (frame->format() == media::PIXEL_FORMAT_I420 || + frame->format() == media::PIXEL_FORMAT_I420A || + frame->format() == media::PIXEL_FORMAT_NV12); + const bool is_rgb = frame->format() == media::PIXEL_FORMAT_ARGB || + frame->format() == media::PIXEL_FORMAT_XRGB || + frame->format() == media::PIXEL_FORMAT_ABGR || + frame->format() == media::PIXEL_FORMAT_XBGR; + + if (!is_mappable && !is_texturable && !is_rgb) { + DLOG(ERROR) << "Unsupported VideoFrame: " << frame->AsHumanReadableString(); + return nullptr; + } + + if (!PreferAcceleratedImages(*frame)) { + auto info = SkImageInfo::Make( + frame->visible_rect().width(), frame->visible_rect().height(), + kN32_SkColorType, kUnpremul_SkAlphaType, std::move(sk_color_space)); + + sk_sp<SkData> image_pixels = TryAllocateSkData(info.computeMinByteSize()); + if (!image_pixels) + return nullptr; + + media::PaintCanvasVideoRenderer::ConvertVideoFrameToRGBPixels( + frame.get(), image_pixels->writable_data(), info.minRowBytes()); + return UnacceleratedStaticBitmapImage::Create(SkImage::MakeRasterData( + info, std::move(image_pixels), info.minRowBytes())); + } + + auto raster_context_provider = GetRasterContextProvider(); + if (!raster_context_provider) { + DLOG(ERROR) << "Graphics context unavailable."; + return nullptr; + } + + auto* ri = raster_context_provider->RasterInterface(); + auto* shared_image_interface = + raster_context_provider->SharedImageInterface(); + uint32_t usage = + gpu::SHARED_IMAGE_USAGE_GLES2 | gpu::SHARED_IMAGE_USAGE_DISPLAY; + if (raster_context_provider->ContextCapabilities().supports_oop_raster) { + usage |= gpu::SHARED_IMAGE_USAGE_RASTER | + gpu::SHARED_IMAGE_USAGE_OOP_RASTERIZATION; + } + + gpu::MailboxHolder dest_holder; + // Use coded_size() to comply with media::ConvertFromVideoFrameYUV. + dest_holder.mailbox = shared_image_interface->CreateSharedImage( + viz::ResourceFormat::RGBA_8888, frame->coded_size(), gfx::ColorSpace(), + kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, usage, + gpu::kNullSurfaceHandle); + dest_holder.sync_token = shared_image_interface->GenUnverifiedSyncToken(); + dest_holder.texture_target = GL_TEXTURE_2D; + + if (frame->NumTextures() == 1) { + ri->WaitSyncTokenCHROMIUM(dest_holder.sync_token.GetConstData()); + ri->CopySubTexture(frame->mailbox_holder(0).mailbox, dest_holder.mailbox, + GL_TEXTURE_2D, 0, 0, 0, 0, frame->coded_size().width(), + frame->coded_size().height(), GL_FALSE, GL_FALSE); + } else { + media::VideoFrameYUVConverter::ConvertYUVVideoFrameNoCaching( + frame.get(), raster_context_provider.get(), dest_holder); + } + + gpu::SyncToken sync_token; + ri->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData()); + + auto release_callback = viz::SingleReleaseCallback::Create(base::BindOnce( + [](scoped_refptr<viz::RasterContextProvider> provider, + gpu::Mailbox mailbox, const gpu::SyncToken& sync_token, bool is_lost) { + provider->SharedImageInterface()->DestroySharedImage(sync_token, + mailbox); + }, + raster_context_provider, dest_holder.mailbox)); + + const auto sk_image_info = SkImageInfo::Make( + frame->coded_size().width(), frame->coded_size().height(), + kN32_SkColorType, kUnpremul_SkAlphaType, std::move(sk_color_space)); + + auto image = AcceleratedStaticBitmapImage::CreateFromCanvasMailbox( + dest_holder.mailbox, sync_token, 0u, sk_image_info, + dest_holder.texture_target, true, + SharedGpuContext::ContextProviderWrapper(), + base::PlatformThread::CurrentRef(), Thread::Current()->GetTaskRunner(), + std::move(release_callback)); + + if (frame->HasTextures()) { + // Attach a new sync token to |frame|, so it's not destroyed + // before |image| is fully created. + media::WaitAndReplaceSyncTokenClient client(ri); + frame->UpdateReleaseSyncToken(&client); + } + return image; +} + +bool IsSupportedPlanarFormat(const media::VideoFrame& frame) { + if (!frame.IsMappable() && !frame.HasGpuMemoryBuffer()) + return false; + + const size_t num_planes = frame.layout().num_planes(); + switch (frame.format()) { + case media::PIXEL_FORMAT_I420: + return num_planes == 3; + case media::PIXEL_FORMAT_I420A: + return num_planes == 4; + case media::PIXEL_FORMAT_NV12: + return num_planes == 2; + case media::PIXEL_FORMAT_XBGR: + case media::PIXEL_FORMAT_XRGB: + case media::PIXEL_FORMAT_ABGR: + case media::PIXEL_FORMAT_ARGB: + return num_planes == 1; + default: + return false; + } +} + } // namespace VideoFrame::VideoFrame(scoped_refptr<media::VideoFrame> frame, - ExecutionContext* context) - : handle_( - base::MakeRefCounted<VideoFrameHandle>(std::move(frame), context)) { - DCHECK(handle_->frame()); + ExecutionContext* context) { + DCHECK(frame); + handle_ = base::MakeRefCounted<VideoFrameHandle>(std::move(frame), context); } VideoFrame::VideoFrame(scoped_refptr<VideoFrameHandle> handle) : handle_(std::move(handle)) { DCHECK(handle_); + + // Note: The provided |handle| may be invalid if close() has been called while + // a frame is in transit to another thread. } // static @@ -234,7 +423,9 @@ auto sk_color_space = sk_image_info.refColorSpace(); if (!sk_color_space) sk_color_space = SkColorSpace::MakeSRGB(); - if (!IsValidSkColorSpace(sk_color_space)) { + + const auto gfx_color_space = gfx::ColorSpace(*sk_color_space); + if (!gfx_color_space.IsValid()) { exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, "Invalid color space"); return nullptr; @@ -274,6 +465,7 @@ } frame = std::move(result.frame); + frame->set_color_space(gfx_color_space); return MakeGarbageCollected<VideoFrame>( std::move(frame), ExecutionContext::From(script_state)); } @@ -285,7 +477,7 @@ "Failed to create video frame"); return nullptr; } - frame->set_color_space(gfx::ColorSpace(*sk_color_space)); + frame->set_color_space(gfx_color_space); return MakeGarbageCollected<VideoFrame>( base::MakeRefCounted<VideoFrameHandle>( std::move(frame), std::move(sk_image), @@ -463,35 +655,9 @@ ExecutionContext::From(script_state)); } -// static -bool VideoFrame::IsSupportedPlanarFormat(media::VideoFrame* frame) { - if (!frame) - return false; - - if (!frame->IsMappable() && !frame->HasGpuMemoryBuffer()) - return false; - - const size_t num_planes = frame->layout().num_planes(); - switch (frame->format()) { - case media::PIXEL_FORMAT_I420: - return num_planes == 3; - case media::PIXEL_FORMAT_I420A: - return num_planes == 4; - case media::PIXEL_FORMAT_NV12: - return num_planes == 2; - case media::PIXEL_FORMAT_XBGR: - case media::PIXEL_FORMAT_XRGB: - case media::PIXEL_FORMAT_ABGR: - case media::PIXEL_FORMAT_ARGB: - return num_planes == 1; - default: - return false; - } -} - String VideoFrame::format() const { auto local_frame = handle_->frame(); - if (!local_frame || !IsSupportedPlanarFormat(local_frame.get())) + if (!local_frame || !IsSupportedPlanarFormat(*local_frame)) return String(); switch (local_frame->format()) { @@ -518,7 +684,7 @@ // Verify that |this| has not been invalidated, and that the format is // supported. auto local_frame = handle_->frame(); - if (!local_frame || !IsSupportedPlanarFormat(local_frame.get())) + if (!local_frame || !IsSupportedPlanarFormat(*local_frame)) return base::nullopt; // Create a Plane for each VideoFrame plane, but only the first time. @@ -604,7 +770,6 @@ } void VideoFrame::close() { - // TODO(tguilbert): Add a warning when closing already closed frames? handle_->Invalidate(); } @@ -635,23 +800,10 @@ return handle ? MakeGarbageCollected<VideoFrame>(std::move(handle)) : nullptr; } -scoped_refptr<VideoFrameHandle> VideoFrame::handle() { - return handle_; -} - -scoped_refptr<media::VideoFrame> VideoFrame::frame() { - return handle_->frame(); -} - -scoped_refptr<const media::VideoFrame> VideoFrame::frame() const { - return handle_->frame(); -} - ScriptPromise VideoFrame::createImageBitmap(ScriptState* script_state, const ImageBitmapOptions* options, ExceptionState& exception_state) { base::Optional<IntRect> crop_rect; - if (auto local_frame = handle_->frame()) crop_rect = IntRect(local_frame->visible_rect()); @@ -661,13 +813,23 @@ IntSize VideoFrame::BitmapSourceSize() const { // TODO(crbug.com/1096724): Should be scaled to display size. - return IntSize(cropWidth(), cropHeight()); + if (auto local_frame = handle_->frame()) + return IntSize(local_frame->visible_rect().size()); + return IntSize(); } ScriptPromise VideoFrame::CreateImageBitmap(ScriptState* script_state, base::Optional<IntRect> crop_rect, const ImageBitmapOptions* options, ExceptionState& exception_state) { + const auto& frame = handle_->frame(); + if (!frame) { + exception_state.ThrowDOMException( + DOMExceptionCode::kInvalidStateError, + "Cannot create ImageBitmap from destroyed VideoFrame."); + return ScriptPromise(); + } + if (auto sk_img = handle_->sk_image()) { auto* image_bitmap = MakeGarbageCollected<ImageBitmap>( UnacceleratedStaticBitmapImage::Create(std::move(sk_img)), crop_rect, @@ -676,199 +838,19 @@ exception_state); } - auto local_frame = frame(); - if (!local_frame) { + const auto image = CreateImage(frame); + if (!image) { exception_state.ThrowDOMException( - DOMExceptionCode::kInvalidStateError, - "Cannot create ImageBitmap from destroyed VideoFrame."); + DOMExceptionCode::kNotSupportedError, + String(("Unsupported VideoFrame: " + frame->AsHumanReadableString()) + .c_str())); return ScriptPromise(); } - // SharedImage optimization: create AcceleratedStaticBitmapImage directly. - // Disabled on Android because the hardware decode implementation may neuter - // frames, which would violate ImageBitmap requirements. - // TODO(sandersd): Handle YUV pixel formats. - // TODO(sandersd): Handle high bit depth formats. -#if !defined(OS_ANDROID) - if (local_frame->NumTextures() == 1 && - local_frame->mailbox_holder(0).mailbox.IsSharedImage() && - (local_frame->format() == media::PIXEL_FORMAT_ARGB || - local_frame->format() == media::PIXEL_FORMAT_XRGB || - local_frame->format() == media::PIXEL_FORMAT_ABGR || - local_frame->format() == media::PIXEL_FORMAT_XBGR || - local_frame->format() == media::PIXEL_FORMAT_BGRA)) { - // TODO(sandersd): Do we need to be able to handle limited-range RGB? It - // may never happen, and SkColorSpace doesn't know about it. - auto sk_color_space = - local_frame->ColorSpace().GetAsFullRangeRGB().ToSkColorSpace(); - if (!sk_color_space) - sk_color_space = SkColorSpace::MakeSRGB(); - - const SkImageInfo sk_image_info = SkImageInfo::Make( - local_frame->coded_size().width(), local_frame->coded_size().height(), - kN32_SkColorType, kUnpremul_SkAlphaType, std::move(sk_color_space)); - - // Hold a ref by storing it in the release callback. - auto release_callback = viz::SingleReleaseCallback::Create( - WTF::Bind([](scoped_refptr<media::VideoFrame> frame, - const gpu::SyncToken& sync_token, bool is_lost) {}, - local_frame)); - - scoped_refptr<StaticBitmapImage> image = - AcceleratedStaticBitmapImage::CreateFromCanvasMailbox( - local_frame->mailbox_holder(0).mailbox, - local_frame->mailbox_holder(0).sync_token, 0u, sk_image_info, - local_frame->mailbox_holder(0).texture_target, true, - // Pass nullptr for |context_provider_wrapper|, because we don't - // know which context the mailbox came from. It is used only to - // detect when the mailbox is invalid due to context loss, and is - // ignored when |is_cross_thread|. - base::WeakPtr<WebGraphicsContext3DProviderWrapper>(), - // Pass null |context_thread_ref|, again because we don't know - // which context the mailbox came from. This should always trigger - // |is_cross_thread|. - base::PlatformThreadRef(), - // The task runner is only used for |release_callback|. - Thread::Current()->GetTaskRunner(), std::move(release_callback)); - ImageBitmap* image_bitmap = - MakeGarbageCollected<ImageBitmap>(image, crop_rect, options); - return ImageBitmapSource::FulfillImageBitmap(script_state, image_bitmap, - exception_state); - } -#endif // !defined(OS_ANDROID) - - const bool is_rgb = local_frame->format() == media::PIXEL_FORMAT_ARGB || - local_frame->format() == media::PIXEL_FORMAT_XRGB || - local_frame->format() == media::PIXEL_FORMAT_ABGR || - local_frame->format() == media::PIXEL_FORMAT_XBGR; - - if ((local_frame->IsMappable() && - (local_frame->format() == media::PIXEL_FORMAT_I420 || - local_frame->format() == media::PIXEL_FORMAT_I420A)) || - (local_frame->HasTextures() && - (local_frame->format() == media::PIXEL_FORMAT_I420 || - local_frame->format() == media::PIXEL_FORMAT_I420A || - local_frame->format() == media::PIXEL_FORMAT_NV12)) || - is_rgb) { - scoped_refptr<StaticBitmapImage> image; - gfx::ColorSpace gfx_color_space = local_frame->ColorSpace(); - gfx_color_space = gfx_color_space.GetWithMatrixAndRange( - gfx::ColorSpace::MatrixID::RGB, gfx::ColorSpace::RangeID::FULL); - auto sk_color_space = gfx_color_space.ToSkColorSpace(); - if (!sk_color_space) - sk_color_space = SkColorSpace::MakeSRGB(); - - const bool prefer_accelerated_image_bitmap = - local_frame->format() != media::PIXEL_FORMAT_I420A && - (BitmapSourceSize().Area() > kCpuEfficientFrameSize || - local_frame->HasTextures()) && - (!is_rgb || local_frame->HasTextures()); - - if (!prefer_accelerated_image_bitmap) { - size_t bytes_per_row = sizeof(SkColor) * cropWidth(); - size_t image_pixels_size = bytes_per_row * cropHeight(); - - sk_sp<SkData> image_pixels = TryAllocateSkData(image_pixels_size); - if (!image_pixels) { - exception_state.ThrowDOMException(DOMExceptionCode::kBufferOverrunError, - "Out of memory."); - return ScriptPromise(); - } - media::PaintCanvasVideoRenderer::ConvertVideoFrameToRGBPixels( - local_frame.get(), image_pixels->writable_data(), bytes_per_row); - - SkImageInfo info = - SkImageInfo::Make(cropWidth(), cropHeight(), kN32_SkColorType, - kUnpremul_SkAlphaType, std::move(sk_color_space)); - sk_sp<SkImage> skImage = - SkImage::MakeRasterData(info, image_pixels, bytes_per_row); - image = UnacceleratedStaticBitmapImage::Create(std::move(skImage)); - } else { - scoped_refptr<viz::RasterContextProvider> raster_context_provider; - base::WeakPtr<WebGraphicsContext3DProviderWrapper> wrapper = - SharedGpuContext::ContextProviderWrapper(); - if (wrapper && wrapper->ContextProvider()) { - raster_context_provider = base::WrapRefCounted( - wrapper->ContextProvider()->RasterContextProvider()); - } - if (!raster_context_provider) { - exception_state.ThrowDOMException(DOMExceptionCode::kOperationError, - "Graphics context unavailable."); - return ScriptPromise(); - } - - auto* ri = raster_context_provider->RasterInterface(); - gpu::SharedImageInterface* shared_image_interface = - raster_context_provider->SharedImageInterface(); - uint32_t usage = - gpu::SHARED_IMAGE_USAGE_GLES2 | gpu::SHARED_IMAGE_USAGE_DISPLAY; - if (raster_context_provider->ContextCapabilities().supports_oop_raster) { - usage |= gpu::SHARED_IMAGE_USAGE_RASTER | - gpu::SHARED_IMAGE_USAGE_OOP_RASTERIZATION; - } - - gpu::MailboxHolder dest_holder; - // Use coded_size() to comply with media::ConvertFromVideoFrameYUV. - dest_holder.mailbox = shared_image_interface->CreateSharedImage( - viz::ResourceFormat::RGBA_8888, local_frame->coded_size(), - gfx::ColorSpace(), kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, - usage, gpu::kNullSurfaceHandle); - dest_holder.sync_token = shared_image_interface->GenUnverifiedSyncToken(); - dest_holder.texture_target = GL_TEXTURE_2D; - - if (local_frame->NumTextures() == 1) { - ri->WaitSyncTokenCHROMIUM(dest_holder.sync_token.GetConstData()); - ri->CopySubTexture( - local_frame->mailbox_holder(0).mailbox, dest_holder.mailbox, - GL_TEXTURE_2D, 0, 0, 0, 0, local_frame->coded_size().width(), - local_frame->coded_size().height(), GL_FALSE, GL_FALSE); - } else { - media::VideoFrameYUVConverter::ConvertYUVVideoFrameNoCaching( - local_frame.get(), raster_context_provider.get(), dest_holder); - } - - gpu::SyncToken sync_token; - ri->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData()); - - auto release_callback = viz::SingleReleaseCallback::Create(base::BindOnce( - [](scoped_refptr<viz::RasterContextProvider> provider, - gpu::Mailbox mailbox, const gpu::SyncToken& sync_token, - bool is_lost) { - provider->SharedImageInterface()->DestroySharedImage(sync_token, - mailbox); - }, - raster_context_provider, dest_holder.mailbox)); - - const SkImageInfo sk_image_info = - SkImageInfo::Make(codedWidth(), codedHeight(), kN32_SkColorType, - kUnpremul_SkAlphaType, std::move(sk_color_space)); - - image = AcceleratedStaticBitmapImage::CreateFromCanvasMailbox( - dest_holder.mailbox, sync_token, 0u, sk_image_info, - dest_holder.texture_target, true, - SharedGpuContext::ContextProviderWrapper(), - base::PlatformThread::CurrentRef(), - Thread::Current()->GetTaskRunner(), std::move(release_callback)); - - if (local_frame->HasTextures()) { - // Attach a new sync token to |local_frame|, so it's not destroyed - // before |image| is fully created. - media::WaitAndReplaceSyncTokenClient client(ri); - local_frame->UpdateReleaseSyncToken(&client); - } - } - - ImageBitmap* image_bitmap = - MakeGarbageCollected<ImageBitmap>(image, crop_rect, options); - return ImageBitmapSource::FulfillImageBitmap(script_state, image_bitmap, - exception_state); - } - - exception_state.ThrowDOMException( - DOMExceptionCode::kNotSupportedError, - String(("Unsupported VideoFrame: " + local_frame->AsHumanReadableString()) - .c_str())); - return ScriptPromise(); + auto* image_bitmap = + MakeGarbageCollected<ImageBitmap>(image, crop_rect, options); + return ImageBitmapSource::FulfillImageBitmap(script_state, image_bitmap, + exception_state); } void VideoFrame::Trace(Visitor* visitor) const {
diff --git a/third_party/blink/renderer/modules/webcodecs/video_frame.h b/third_party/blink/renderer/modules/webcodecs/video_frame.h index b8421b9..b3eb3d6 100644 --- a/third_party/blink/renderer/modules/webcodecs/video_frame.h +++ b/third_party/blink/renderer/modules/webcodecs/video_frame.h
@@ -8,7 +8,6 @@ #include <stdint.h> #include "base/optional.h" -#include "media/base/video_frame.h" #include "third_party/blink/renderer/core/imagebitmap/image_bitmap_source.h" #include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/modules/webcodecs/plane.h" @@ -18,6 +17,13 @@ #include "third_party/blink/renderer/platform/heap/member.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" +// Note: Don't include "media/base/video_frame.h" here without good reason, +// since it includes a lot of non-blink types which can pollute the namespace. + +namespace media { +class VideoFrame; +} + namespace blink { class ImageBitmap; @@ -86,18 +92,14 @@ const ImageBitmapOptions*, ExceptionState&); - scoped_refptr<VideoFrameHandle> handle(); - // Convenience functions - scoped_refptr<media::VideoFrame> frame(); - scoped_refptr<const media::VideoFrame> frame() const; + scoped_refptr<VideoFrameHandle> handle() const { return handle_; } + scoped_refptr<media::VideoFrame> frame() const { return handle_->frame(); } // GarbageCollected override void Trace(Visitor*) const override; private: - static bool IsSupportedPlanarFormat(media::VideoFrame*); - // ImageBitmapSource implementation static constexpr uint64_t kCpuEfficientFrameSize = 320u * 240u; IntSize BitmapSourceSize() const override;
diff --git a/third_party/blink/renderer/modules/webcodecs/video_frame_handle.cc b/third_party/blink/renderer/modules/webcodecs/video_frame_handle.cc index 9126f803..3d0cb3c 100644 --- a/third_party/blink/renderer/modules/webcodecs/video_frame_handle.cc +++ b/third_party/blink/renderer/modules/webcodecs/video_frame_handle.cc
@@ -4,6 +4,7 @@ #include "third_party/blink/renderer/modules/webcodecs/video_frame_handle.h" +#include "media/base/video_frame.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/skia/include/core/SkImage.h"
diff --git a/third_party/blink/renderer/modules/webcodecs/video_frame_handle.h b/third_party/blink/renderer/modules/webcodecs/video_frame_handle.h index bbbb120..a5b1130 100644 --- a/third_party/blink/renderer/modules/webcodecs/video_frame_handle.h +++ b/third_party/blink/renderer/modules/webcodecs/video_frame_handle.h
@@ -6,15 +6,21 @@ #define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_VIDEO_FRAME_HANDLE_H_ #include "base/memory/scoped_refptr.h" -#include "media/base/video_frame.h" #include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/modules/webcodecs/video_frame_logger.h" #include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h" #include "third_party/blink/renderer/platform/wtf/threading_primitives.h" #include "third_party/skia/include/core/SkRefCnt.h" +// Note: Don't include "media/base/video_frame.h" here without good reason, +// since it includes a lot of non-blink types which can pollute the namespace. + class SkImage; +namespace media { +class VideoFrame; +} + namespace blink { class ExecutionContext;
diff --git a/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc b/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc index 3dd420f9..8302820 100644 --- a/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc +++ b/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc
@@ -833,7 +833,8 @@ } WGPUExtent3D AsDawnType( - const UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict* webgpu_extent) { + const UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict* webgpu_extent, + GPUDevice* device) { DCHECK(webgpu_extent); WGPUExtent3D dawn_extent = {1, 1, 1}; @@ -863,7 +864,14 @@ webgpu_extent->GetAsGPUExtent3DDict(); dawn_extent.width = webgpu_extent_3d_dict->width(); dawn_extent.height = webgpu_extent_3d_dict->height(); - dawn_extent.depth = webgpu_extent_3d_dict->depth(); + + if (webgpu_extent_3d_dict->hasDepth()) { + device->AddConsoleWarning( + "Specifying an extent depth is deprecated. Use depthOrArrayLayers."); + dawn_extent.depth = webgpu_extent_3d_dict->depth(); + } else { + dawn_extent.depth = webgpu_extent_3d_dict->depthOrArrayLayers(); + } } else { NOTREACHED();
diff --git a/third_party/blink/renderer/modules/webgpu/dawn_conversions.h b/third_party/blink/renderer/modules/webgpu/dawn_conversions.h index b4a688f53..56dddcb2 100644 --- a/third_party/blink/renderer/modules/webgpu/dawn_conversions.h +++ b/third_party/blink/renderer/modules/webgpu/dawn_conversions.h
@@ -46,7 +46,8 @@ WGPUColor AsDawnType(const GPUColorDict*); WGPUColor AsDawnType(const DoubleSequenceOrGPUColorDict*); WGPUExtent3D AsDawnType( - const UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict*); + const UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict*, + GPUDevice* device); WGPUOrigin3D AsDawnType( const UnsignedLongEnforceRangeSequenceOrGPUOrigin3DDict*); WGPUTextureCopyView AsDawnType(const GPUTextureCopyView* webgpu_view,
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.cc b/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.cc index f2df593..283a725 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.cc +++ b/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.cc
@@ -246,7 +246,7 @@ GPUBufferCopyView* source, GPUTextureCopyView* destination, UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict& copy_size) { - WGPUExtent3D dawn_copy_size = AsDawnType(©_size); + WGPUExtent3D dawn_copy_size = AsDawnType(©_size, device_); WGPUTextureCopyView dawn_destination = AsDawnType(destination, device_); const char* error = nullptr; @@ -265,7 +265,7 @@ GPUTextureCopyView* source, GPUBufferCopyView* destination, UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict& copy_size) { - WGPUExtent3D dawn_copy_size = AsDawnType(©_size); + WGPUExtent3D dawn_copy_size = AsDawnType(©_size, device_); WGPUTextureCopyView dawn_source = AsDawnType(source, device_); const char* error = nullptr; @@ -286,7 +286,7 @@ UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict& copy_size) { WGPUTextureCopyView dawn_source = AsDawnType(source, device_); WGPUTextureCopyView dawn_destination = AsDawnType(destination, device_); - WGPUExtent3D dawn_copy_size = AsDawnType(©_size); + WGPUExtent3D dawn_copy_size = AsDawnType(©_size, device_); GetProcs().commandEncoderCopyTextureToTexture( GetHandle(), &dawn_source, &dawn_destination, &dawn_copy_size);
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_extent_3d_dict.idl b/third_party/blink/renderer/modules/webgpu/gpu_extent_3d_dict.idl index 6fc1fe24..7c67936 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_extent_3d_dict.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_extent_3d_dict.idl
@@ -7,5 +7,7 @@ dictionary GPUExtent3DDict { GPUIntegerCoordinate width = 1; GPUIntegerCoordinate height = 1; - GPUIntegerCoordinate depth = 1; + GPUIntegerCoordinate depthOrArrayLayers = 1; + // Deprecated + GPUIntegerCoordinate depth; };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_queue.cc b/third_party/blink/renderer/modules/webgpu/gpu_queue.cc index 5b4e02e4..b42abb8 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_queue.cc +++ b/third_party/blink/renderer/modules/webgpu/gpu_queue.cc
@@ -292,7 +292,7 @@ GPUTextureDataLayout* data_layout, UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict& write_size, ExceptionState& exception_state) { - WGPUExtent3D dawn_write_size = AsDawnType(&write_size); + WGPUExtent3D dawn_write_size = AsDawnType(&write_size, device_); WGPUTextureCopyView dawn_destination = AsDawnType(destination, device_); WGPUTextureDataLayout dawn_data_layout = {}; @@ -335,7 +335,7 @@ // appropriate format. Now only support texture format exactly the same. The // compatible formats need to be defined in WebGPU spec. - WGPUExtent3D dawn_copy_size = AsDawnType(©_size); + WGPUExtent3D dawn_copy_size = AsDawnType(©_size, device_); // Extract imageBitmap attributes WGPUOrigin3D origin_in_image_bitmap =
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_texture.cc b/third_party/blink/renderer/modules/webgpu/gpu_texture.cc index 2ab5110..b2590bcb 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_texture.cc +++ b/third_party/blink/renderer/modules/webgpu/gpu_texture.cc
@@ -42,7 +42,7 @@ dawn_desc.usage = static_cast<WGPUTextureUsage>(webgpu_desc->usage()); dawn_desc.dimension = AsDawnEnum<WGPUTextureDimension>(webgpu_desc->dimension()); - dawn_desc.size = AsDawnType(&webgpu_desc->size()); + dawn_desc.size = AsDawnType(&webgpu_desc->size(), device); dawn_desc.format = AsDawnEnum<WGPUTextureFormat>(webgpu_desc->format()); dawn_desc.mipLevelCount = webgpu_desc->mipLevelCount(); dawn_desc.sampleCount = webgpu_desc->sampleCount();
diff --git a/third_party/blink/renderer/modules/xr/xr_cpu_depth_information.cc b/third_party/blink/renderer/modules/xr/xr_cpu_depth_information.cc index c02306c..c12edb7 100644 --- a/third_party/blink/renderer/modules/xr/xr_cpu_depth_information.cc +++ b/third_party/blink/renderer/modules/xr/xr_cpu_depth_information.cc
@@ -4,11 +4,14 @@ #include "third_party/blink/renderer/modules/xr/xr_cpu_depth_information.h" +#include <cmath> #include <cstdlib> #include "base/numerics/checked_math.h" +#include "base/numerics/ranges.h" #include "third_party/blink/renderer/core/dom/dom_exception.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" +#include "ui/gfx/geometry/point3_f.h" namespace { constexpr char kOutOfBoundsAccess[] = @@ -44,35 +47,52 @@ } float XRCPUDepthInformation::getDepthInMeters( - uint32_t column, - uint32_t row, + float x, + float y, ExceptionState& exception_state) const { - DVLOG(3) << __func__ << ": column=" << column << ", row=" << row; + DVLOG(3) << __func__ << ": x=" << x << ", y=" << y; if (!ValidateFrame(exception_state)) { return 0.0; } - if (column >= static_cast<size_t>(size_.width())) { - exception_state.ThrowDOMException(DOMExceptionCode::kNotAllowedError, - kOutOfBoundsAccess); + if (x > 1.0 || x < 0.0) { + exception_state.ThrowRangeError(kOutOfBoundsAccess); return 0.0; } - if (row >= static_cast<size_t>(size_.height())) { - exception_state.ThrowDOMException(DOMExceptionCode::kNotAllowedError, - kOutOfBoundsAccess); + if (y > 1.0 || y < 0.0) { + exception_state.ThrowRangeError(kOutOfBoundsAccess); return 0.0; } + // Those coordinates are actually `norm_view_coordinates` before a series of + // transforms is applied, but they are modified in-place, so the name's in + // anticipation of those transforms. + gfx::Point3F depth_coordinates(x, y, 0.0); + + // `norm_view_coordinates` becomes `norm_depth_coordinates`: + norm_depth_buffer_from_norm_view_.TransformPoint(&depth_coordinates); + + // `norm_depth_coordinates` becomes `depth_coordinates`: + depth_coordinates.Scale(size_.width(), size_.height(), 1.0); + + uint32_t column = base::ClampToRange<uint32_t>( + static_cast<uint32_t>(std::round(depth_coordinates.x())), 0, + size_.width() - 1); + uint32_t row = base::ClampToRange<uint32_t>( + static_cast<uint32_t>(std::round(depth_coordinates.y())), 0, + size_.height() - 1); + auto checked_index = base::CheckAdd(column, base::CheckMul(row, size_.width())); size_t index = checked_index.ValueOrDie(); // Convert from data's native units to meters when accessing: - float result = data_->Item(index) * rawValueToMeters_; + float result = data_->Item(index) * raw_value_to_meters_; - DVLOG(3) << __func__ << ": index=" << index << ", result=" << result; + DVLOG(3) << __func__ << ": x=" << x << ", y=" << y << ", column=" << column + << ", row=" << row << ", index=" << index << ", result=" << result; return result; }
diff --git a/third_party/blink/renderer/modules/xr/xr_cpu_depth_information.h b/third_party/blink/renderer/modules/xr/xr_cpu_depth_information.h index 790918c..312311e 100644 --- a/third_party/blink/renderer/modules/xr/xr_cpu_depth_information.h +++ b/third_party/blink/renderer/modules/xr/xr_cpu_depth_information.h
@@ -31,8 +31,8 @@ DOMUint16Array* data(ExceptionState& exception_state) const; - float getDepthInMeters(uint32_t column, - uint32_t row, + float getDepthInMeters(float x, + float y, ExceptionState& exception_state) const; void Trace(Visitor* visitor) const override;
diff --git a/third_party/blink/renderer/modules/xr/xr_cpu_depth_information.idl b/third_party/blink/renderer/modules/xr/xr_cpu_depth_information.idl index b2a98d2..84dccdd7e4 100644 --- a/third_party/blink/renderer/modules/xr/xr_cpu_depth_information.idl +++ b/third_party/blink/renderer/modules/xr/xr_cpu_depth_information.idl
@@ -7,10 +7,14 @@ Exposed=Window, RuntimeEnabled=WebXRDepth ] interface XRCPUDepthInformation : XRDepthInformation { - [RaisesException, SameObject, MeasureAs=XRCPUDepthInformationDataAttribute] - readonly attribute DataView data; + [ + RaisesException, + SameObject, + SaveSameObject, + MeasureAs=XRCPUDepthInformationDataAttribute + ] readonly attribute DataView data; [RaisesException, MeasureAs=XRCPUDepthInformationGetDepth] - float getDepthInMeters(unsigned long column, unsigned long row); + float getDepthInMeters(float x, float y); };
diff --git a/third_party/blink/renderer/modules/xr/xr_depth_information.cc b/third_party/blink/renderer/modules/xr/xr_depth_information.cc index e55237c..053b030 100644 --- a/third_party/blink/renderer/modules/xr/xr_depth_information.cc +++ b/third_party/blink/renderer/modules/xr/xr_depth_information.cc
@@ -27,51 +27,33 @@ XRDepthInformation::XRDepthInformation( const XRFrame* xr_frame, const gfx::Size& size, - const gfx::Transform& norm_texture_from_norm_view, + const gfx::Transform& norm_depth_buffer_from_norm_view, float raw_value_to_meters) : xr_frame_(xr_frame), size_(size), - norm_texture_from_norm_view_(norm_texture_from_norm_view), - rawValueToMeters_(raw_value_to_meters) { + norm_depth_buffer_from_norm_view_(norm_depth_buffer_from_norm_view), + raw_value_to_meters_(raw_value_to_meters) { DVLOG(3) << __func__ << ": size_=" << size_.ToString() - << ", norm_texture_from_norm_view_=" - << norm_texture_from_norm_view_.ToString() - << ", raw_value_to_meters=" << raw_value_to_meters; + << ", norm_depth_buffer_from_norm_view_=" + << norm_depth_buffer_from_norm_view_.ToString() + << ", raw_value_to_meters_=" << raw_value_to_meters_; } -uint32_t XRDepthInformation::width(ExceptionState& exception_state) const { - if (!ValidateFrame(exception_state)) { - return 0; - } - +uint32_t XRDepthInformation::width() const { return size_.width(); } -uint32_t XRDepthInformation::height(ExceptionState& exception_state) const { - if (!ValidateFrame(exception_state)) { - return 0; - } - +uint32_t XRDepthInformation::height() const { return size_.height(); } -float XRDepthInformation::rawValueToMeters( - ExceptionState& exception_state) const { - if (!ValidateFrame(exception_state)) { - return 0.0; - } - - return rawValueToMeters_; +float XRDepthInformation::rawValueToMeters() const { + return raw_value_to_meters_; } -XRRigidTransform* XRDepthInformation::normTextureFromNormView( - ExceptionState& exception_state) const { - if (!ValidateFrame(exception_state)) { - return nullptr; - } - +XRRigidTransform* XRDepthInformation::normDepthBufferFromNormView() const { return MakeGarbageCollected<XRRigidTransform>( - TransformationMatrix(norm_texture_from_norm_view_.matrix())); + TransformationMatrix(norm_depth_buffer_from_norm_view_.matrix())); } bool XRDepthInformation::ValidateFrame(ExceptionState& exception_state) const {
diff --git a/third_party/blink/renderer/modules/xr/xr_depth_information.h b/third_party/blink/renderer/modules/xr/xr_depth_information.h index 37388c2..e371581 100644 --- a/third_party/blink/renderer/modules/xr/xr_depth_information.h +++ b/third_party/blink/renderer/modules/xr/xr_depth_information.h
@@ -20,10 +20,11 @@ DEFINE_WRAPPERTYPEINFO(); protected: - explicit XRDepthInformation(const XRFrame* xr_frame, - const gfx::Size& size, - const gfx::Transform& norm_texture_from_norm_view, - float raw_value_to_meters); + explicit XRDepthInformation( + const XRFrame* xr_frame, + const gfx::Size& size, + const gfx::Transform& norm_depth_buffer_from_norm_view, + float raw_value_to_meters); // Helper to validate whether a frame is in a correct state. Should be invoked // before every member access. If the validation returns `false`, it means the @@ -32,14 +33,13 @@ bool ValidateFrame(ExceptionState& exception_state) const; public: - uint32_t width(ExceptionState& exception_state) const; + uint32_t width() const; - uint32_t height(ExceptionState& exception_state) const; + uint32_t height() const; - XRRigidTransform* normTextureFromNormView( - ExceptionState& exception_state) const; + XRRigidTransform* normDepthBufferFromNormView() const; - float rawValueToMeters(ExceptionState& exception_state) const; + float rawValueToMeters() const; void Trace(Visitor* visitor) const override; @@ -48,8 +48,8 @@ const gfx::Size size_; - const gfx::Transform norm_texture_from_norm_view_; - const float rawValueToMeters_; + const gfx::Transform norm_depth_buffer_from_norm_view_; + const float raw_value_to_meters_; }; } // namespace blink
diff --git a/third_party/blink/renderer/modules/xr/xr_depth_information.idl b/third_party/blink/renderer/modules/xr/xr_depth_information.idl index dea2323..bdcf6184 100644 --- a/third_party/blink/renderer/modules/xr/xr_depth_information.idl +++ b/third_party/blink/renderer/modules/xr/xr_depth_information.idl
@@ -7,11 +7,10 @@ Exposed=Window, RuntimeEnabled=WebXRDepth ] interface XRDepthInformation { - [RaisesException] readonly attribute unsigned long width; - [RaisesException] readonly attribute unsigned long height; + readonly attribute unsigned long width; + readonly attribute unsigned long height; - [RaisesException, SameObject] - readonly attribute XRRigidTransform normTextureFromNormView; - [RaisesException] + [SameObject, SaveSameObject] + readonly attribute XRRigidTransform normDepthBufferFromNormView; readonly attribute float rawValueToMeters; };
diff --git a/third_party/blink/renderer/modules/xr/xr_depth_manager.cc b/third_party/blink/renderer/modules/xr/xr_depth_manager.cc index 2b8d314..30bc4f0 100644 --- a/third_party/blink/renderer/modules/xr/xr_depth_manager.cc +++ b/third_party/blink/renderer/modules/xr/xr_depth_manager.cc
@@ -10,6 +10,9 @@ namespace { +constexpr char kInvalidUsageMode[] = + "Unable to obtain XRCPUDepthInformation in \"gpu-optimized\" usage mode."; + String UsageToString(device::mojom::XRDepthUsage usage) { switch (usage) { case device::mojom::XRDepthUsage::kCPUOptimized: @@ -76,8 +79,15 @@ } } -XRCPUDepthInformation* XRDepthManager::GetDepthInformation( - const XRFrame* xr_frame) { +XRCPUDepthInformation* XRDepthManager::GetCpuDepthInformation( + const XRFrame* xr_frame, + ExceptionState& exception_state) { + if (usage_ != device::mojom::XRDepthUsage::kCPUOptimized) { + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, + kInvalidUsageMode); + return nullptr; + } + if (!depth_data_) { return nullptr; } @@ -89,6 +99,19 @@ depth_data_->raw_value_to_meters, data_); } +XRWebGLDepthInformation* XRDepthManager::GetWebGLDepthInformation( + const XRFrame* xr_frame, + ExceptionState& exception_state) { + if (usage_ != device::mojom::XRDepthUsage::kGPUOptimized) { + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, + kInvalidUsageMode); + return nullptr; + } + + NOTREACHED(); + return nullptr; +} + void XRDepthManager::EnsureData() { DCHECK(depth_data_);
diff --git a/third_party/blink/renderer/modules/xr/xr_depth_manager.h b/third_party/blink/renderer/modules/xr/xr_depth_manager.h index 9fb6168f..beff7e48 100644 --- a/third_party/blink/renderer/modules/xr/xr_depth_manager.h +++ b/third_party/blink/renderer/modules/xr/xr_depth_manager.h
@@ -12,7 +12,9 @@ namespace blink { +class ExceptionState; class XRCPUDepthInformation; +class XRWebGLDepthInformation; class XRFrame; class XRSession; @@ -31,7 +33,13 @@ const String& depthUsage() const { return usage_str_; } const String& depthDataFormat() const { return data_format_str_; } - XRCPUDepthInformation* GetDepthInformation(const XRFrame* xr_frame); + XRCPUDepthInformation* GetCpuDepthInformation( + const XRFrame* xr_frame, + ExceptionState& exception_state); + + XRWebGLDepthInformation* GetWebGLDepthInformation( + const XRFrame* xr_frame, + ExceptionState& exception_state); void Trace(Visitor* visitor) const;
diff --git a/third_party/blink/renderer/modules/xr/xr_frame.cc b/third_party/blink/renderer/modules/xr/xr_frame.cc index 9dec672..ec4b2ffe 100644 --- a/third_party/blink/renderer/modules/xr/xr_frame.cc +++ b/third_party/blink/renderer/modules/xr/xr_frame.cc
@@ -22,16 +22,9 @@ namespace { -const char kInactiveFrame[] = - "XRFrame access outside the callback that produced it is invalid."; - const char kInvalidView[] = "XRView passed in to the method did not originate from current XRFrame."; -const char kNonAnimationFrame[] = - "getViewerPose can only be called on XRFrame objects passed to " - "XRSession.requestAnimationFrame callbacks."; - const char kSessionMismatch[] = "XRSpace and XRFrame sessions do not match."; const char kCannotReportPoses[] = @@ -52,6 +45,9 @@ } // namespace +constexpr char XRFrame::kInactiveFrame[]; +constexpr char XRFrame::kNonAnimationFrame[]; + XRFrame::XRFrame(XRSession* session, bool is_animation_frame) : session_(session), is_animation_frame_(is_animation_frame) {} @@ -165,6 +161,12 @@ ExceptionState& exception_state) const { DVLOG(2) << __func__; + if (!session_->IsFeatureEnabled(device::mojom::XRSessionFeature::DEPTH)) { + exception_state.ThrowDOMException( + DOMExceptionCode::kNotSupportedError, + XRSession::kDepthSensingFeatureNotSupported); + } + if (!is_active_) { exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, kInactiveFrame); @@ -183,7 +185,7 @@ return nullptr; } - return session_->GetDepthInformation(this, exception_state); + return session_->GetCpuDepthInformation(this, exception_state); } // Return an XRPose that has a transform of basespace_from_space, while
diff --git a/third_party/blink/renderer/modules/xr/xr_frame.h b/third_party/blink/renderer/modules/xr/xr_frame.h index da1a8c6..3e32442 100644 --- a/third_party/blink/renderer/modules/xr/xr_frame.h +++ b/third_party/blink/renderer/modules/xr/xr_frame.h
@@ -45,6 +45,12 @@ DEFINE_WRAPPERTYPEINFO(); public: + static constexpr char kInactiveFrame[] = + "XRFrame access outside the callback that produced it is invalid."; + static constexpr char kNonAnimationFrame[] = + "This method can only be called on XRFrame objects passed to " + "XRSession.requestAnimationFrame callbacks."; + explicit XRFrame(XRSession* session, bool is_animation_frame = false); XRSession* session() const { return session_; }
diff --git a/third_party/blink/renderer/modules/xr/xr_session.cc b/third_party/blink/renderer/modules/xr/xr_session.cc index 1ca67a4..83e853d 100644 --- a/third_party/blink/renderer/modules/xr/xr_session.cc +++ b/third_party/blink/renderer/modules/xr/xr_session.cc
@@ -105,9 +105,6 @@ const char kEntityTypesNotSpecified[] = "No entityTypes specified: the array cannot be empty!"; -const char kDepthSensingFeatureNotSupported[] = - "Depth sensing feature is not supported by the session."; - const double kDegToRad = M_PI / 180.0; const float kMinDefaultFramebufferScale = 0.1f; @@ -246,6 +243,7 @@ constexpr char XRSession::kNoSpaceSpecified[]; constexpr char XRSession::kAnchorsFeatureNotSupported[]; constexpr char XRSession::kPlanesFeatureNotSupported[]; +constexpr char XRSession::kDepthSensingFeatureNotSupported[]; class XRSession::XRSessionResizeObserverDelegate final : public ResizeObserver::Delegate { @@ -1248,7 +1246,7 @@ } } -XRCPUDepthInformation* XRSession::GetDepthInformation( +XRCPUDepthInformation* XRSession::GetCpuDepthInformation( const XRFrame* xr_frame, ExceptionState& exception_state) const { if (!depth_manager_) { @@ -1257,7 +1255,19 @@ return nullptr; } - return depth_manager_->GetDepthInformation(xr_frame); + return depth_manager_->GetCpuDepthInformation(xr_frame, exception_state); +} + +XRWebGLDepthInformation* XRSession::GetWebGLDepthInformation( + const XRFrame* xr_frame, + ExceptionState& exception_state) const { + if (!depth_manager_) { + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, + kDepthSensingFeatureNotSupported); + return nullptr; + } + + return depth_manager_->GetWebGLDepthInformation(xr_frame, exception_state); } ScriptPromise XRSession::requestLightProbe(ScriptState* script_state,
diff --git a/third_party/blink/renderer/modules/xr/xr_session.h b/third_party/blink/renderer/modules/xr/xr_session.h index b9e2a5fc..7483905 100644 --- a/third_party/blink/renderer/modules/xr/xr_session.h +++ b/third_party/blink/renderer/modules/xr/xr_session.h
@@ -60,6 +60,7 @@ class XRTransientInputHitTestOptionsInit; class XRTransientInputHitTestSource; class XRViewData; +class XRWebGLDepthInformation; class XRWebGLLayer; using XRSessionFeatureSet = HashSet<device::mojom::XRSessionFeature>; @@ -83,7 +84,8 @@ "Anchors feature is not supported by the session."; static constexpr char kPlanesFeatureNotSupported[] = "Plane detection feature is not supported by the session."; - + static constexpr char kDepthSensingFeatureNotSupported[] = + "Depth sensing feature is not supported by the session."; // Runs all the video.requestVideoFrameCallback() callbacks associated with // one HTMLVideoElement. |double| is the |high_res_now_ms|, derived from // MonotonicTimeToZeroBasedDocumentTime(|current_frame_time|), to be passed as @@ -341,7 +343,11 @@ base::Optional<TransformationMatrix> GetMojoFrom( device::mojom::blink::XRReferenceSpaceType space_type) const; - XRCPUDepthInformation* GetDepthInformation( + XRCPUDepthInformation* GetCpuDepthInformation( + const XRFrame* xr_frame, + ExceptionState& exception_state) const; + + XRWebGLDepthInformation* GetWebGLDepthInformation( const XRFrame* xr_frame, ExceptionState& exception_state) const;
diff --git a/third_party/blink/renderer/modules/xr/xr_webgl_binding.cc b/third_party/blink/renderer/modules/xr/xr_webgl_binding.cc index 56d987b..4277ea8 100644 --- a/third_party/blink/renderer/modules/xr/xr_webgl_binding.cc +++ b/third_party/blink/renderer/modules/xr/xr_webgl_binding.cc
@@ -77,10 +77,27 @@ return nullptr; } + if (session_->ended()) { + exception_state.ThrowDOMException( + DOMExceptionCode::kInvalidStateError, + "Cannot get a reflection cube map for a session which has ended."); + return nullptr; + } + + if (session_ != light_probe->session()) { + exception_state.ThrowDOMException( + DOMExceptionCode::kInvalidStateError, + "LightProbe comes from a different session than this binding"); + return nullptr; + } + // Determine the internal_format, format, and type that will be passed to // glTexImage2D for each possible light probe reflection format. The formats // will differ depending on whether we're using WebGL 2 or WebGL 1 with // extensions. + // Note that at this point, since we know we have a valid lightProbe, we also + // know that we support whatever reflectionFormat it was created with, as it + // would not have been created otherwise. switch (light_probe->ReflectionFormat()) { case XRLightProbe::kReflectionFormatRGBA16F: if (!webgl2_ && !webgl_context_->ExtensionsUtil()->IsExtensionEnabled( @@ -160,7 +177,27 @@ XRWebGLDepthInformation* XRWebGLBinding::getDepthInformation( XRView* view, ExceptionState& exception_state) { - return nullptr; + if (!session_->IsFeatureEnabled(device::mojom::XRSessionFeature::DEPTH)) { + exception_state.ThrowDOMException( + DOMExceptionCode::kNotSupportedError, + XRSession::kDepthSensingFeatureNotSupported); + } + + XRFrame* frame = view->frame(); + + if (!frame->IsActive()) { + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, + XRFrame::kInactiveFrame); + return nullptr; + } + + if (!frame->IsAnimationFrame()) { + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, + XRFrame::kNonAnimationFrame); + return nullptr; + } + + return view->session()->GetWebGLDepthInformation(frame, exception_state); } void XRWebGLBinding::Trace(Visitor* visitor) const {
diff --git a/third_party/blink/renderer/platform/fonts/font_matching_metrics.cc b/third_party/blink/renderer/platform/fonts/font_matching_metrics.cc index 06524fe..bfefbaa 100644 --- a/third_party/blink/renderer/platform/fonts/font_matching_metrics.cc +++ b/third_party/blink/renderer/platform/fonts/font_matching_metrics.cc
@@ -321,6 +321,9 @@ .Record(ukm_recorder_); UMA_HISTOGRAM_COUNTS_10000("Blink.Fonts.FontFamilyMatchAttempts.System", system_font_families_.size()); + UMA_HISTOGRAM_COUNTS_10000( + "Blink.Fonts.FontMatchAttempts.System", + local_fonts_failed_.size() + local_fonts_succeeded_.size()); } void FontMatchingMetrics::OnFontLookup() {
diff --git a/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc b/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc index 0b9a9227..4535a22 100644 --- a/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc +++ b/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc
@@ -46,7 +46,9 @@ if (!provider || !provider->IsAccelerated()) return nullptr; - provider->Canvas()->drawImage(paint_image, 0, 0); + cc::PaintFlags paint; + paint.setBlendMode(SkBlendMode::kSrc); + provider->Canvas()->drawImage(paint_image, 0, 0, SkSamplingOptions(), &paint); return provider->Snapshot(); }
diff --git a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py index 3de5118..9b0a580 100755 --- a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py +++ b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
@@ -1022,12 +1022,18 @@ 'third_party/blink/renderer/modules/webcodecs/', ], 'allowed': [ + 'base::PlatformThreadRef', + 'base::WrapRefCounted', 'gpu::kNullSurfaceHandle', 'gpu::SHARED_IMAGE_.+', 'gpu::raster::RasterInterface', 'gpu::Mailbox', 'gpu::MailboxHolder', - "viz::RasterContextProvider", + 'gpu::SharedImageInterface', + 'gpu::SyncToken', + 'viz::RasterContextProvider', + 'viz::ResourceFormat', + 'viz::SingleReleaseCallback', 'media::.+', 'libyuv::.+', ]
diff --git a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng index ff23e48..ae78aa2 100644 --- a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng +++ b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
@@ -760,7 +760,6 @@ ### Pass in Legacy, fail in NG crbug.com/958381 external/wpt/css/css-tables/visibility-collapse-rowspan-005.html [ Pass ] -crbug.com/958381 fast/table/large-col-span-crash.html [ Pass ] crbug.com/958381 fast/table/table-all-rowspans-height-distribution-in-rows-except-overlapped.html [ Pass ] crbug.com/958381 fast/table/table-all-rowspans-height-distribution-in-rows.html [ Pass ] crbug.com/958381 fast/table/table-rowspan-height-distribution-in-rows-1.html [ Pass ] @@ -888,6 +887,13 @@ crbug.com/958381 fast/css/empty-cell-baseline.html [ Failure ] crbug.com/958381 fast/css/inline-table-first-row-empty-cell-non-auto.html [ Failure ] +# New failures after TablesNG landed, most likely rebaselined tests +crbug.com/958381 accessibility/table-column-track-merging.html [ Failure ] +crbug.com/958381 fast/table/colspanMinWidth.html [ Failure ] +crbug.com/958381 fast/table/colspanMinWidth-vertical.html [ Failure ] +crbug.com/958381 fast/table/large-col-span-crash.html [ Failure ] +crbug.com/958381 external/wpt/css/css-tables/column-track-merging.html [ Failure ] + # TablesNG end ### compositing/filters/
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index fd94ae9..0f91324 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -160,7 +160,6 @@ crbug.com/1081534 [ Win ] virtual/oopr-canvas2d/fast/canvas/canvas-path-context-fill.html [ Failure ] crbug.com/1081534 [ Win ] virtual/oopr-canvas2d/fast/canvas/canvas-state-persistence-no-dirty.html [ Pass Failure ] crbug.com/1081534 [ Win ] virtual/oopr-canvas2d/fast/canvas/canvas-transform-skewed.html [ Failure ] -crbug.com/1081534 [ Win ] virtual/oopr-canvas2d/fast/canvas/OffscreenCanvas-Bitmaprenderer-TransferToImageBitmapResetsToBlack.html [ Pass Failure ] crbug.com/1081534 [ Win ] virtual/oopr-canvas2d/fast/canvas/OffscreenCanvas-text-FontFace.html [ Pass Failure ] # Flakey tests @@ -1064,9 +1063,6 @@ ### TablesNG # crbug.com/958381 -# fails because TablesNG does not coalesce columns -crbug.com/958381 accessibility/table-cells-with-colspan.html [ Failure ] -crbug.com/958381 fast/table/large-col-span-crash.html [ Failure ] # TODO fails because cell size with only input element is 18px, not 15. line-height: 0px fixes it. crbug.com/1171616 external/wpt/css/css-tables/height-distribution/percentage-sizing-of-table-cell-children.html [ Failure ] @@ -1103,9 +1099,6 @@ crbug.com/958381 [ Mac ] virtual/layout_ng_block_frag/fragmentation/fragmented-table-cell.html [ Failure ] crbug.com/958381 [ Mac ] fragmentation/single-line-cells-paginated-with-text.html [ Failure ] -# Asan underinvalidation failure. Skip while investigating -crbug.com/958381 paint/tables/huge-table-composited-scroll-collapsed-borders.html [ Skip ] - # TablesNG ends # ====== LayoutNG-only failures until here ====== @@ -2006,8 +1999,8 @@ crbug.com/1015331 external/wpt/css/css-text/white-space/eol-spaces-bidi-001.html [ Failure ] # needs implementation of test_driver_internal.action_sequence -crbug.com/893480 external/wpt/editing/run/caretnavigation.html [ Timeout ] -crbug.com/893480 external/wpt/input-events/input-events-typing.html [ Timeout ] +crbug.com/893480 external/wpt/editing/run/caretnavigation.html [ Failure Timeout ] +crbug.com/893480 external/wpt/input-events/input-events-typing.html [ Failure Timeout ] crbug.com/893480 external/wpt/infrastructure/testdriver/actions/eventOrder.html [ Timeout ] crbug.com/893480 external/wpt/infrastructure/testdriver/actions/elementTiming.html [ Timeout ] crbug.com/893480 external/wpt/infrastructure/testdriver/actions/multiDevice.html [ Failure Timeout ] @@ -2019,7 +2012,7 @@ crbug.com/893480 external/wpt/infrastructure/testdriver/actions/textEditCommands.html [ Failure Timeout ] crbug.com/893480 external/wpt/input-events/input-events-get-target-ranges.html [ Failure Timeout ] crbug.com/893480 external/wpt/input-events/input-events-cut-paste.html [ Failure Timeout ] -crbug.com/893480 external/wpt/html/semantics/forms/the-input-element/checkable-active-onblur.html [ Timeout ] +crbug.com/893480 external/wpt/html/semantics/forms/the-input-element/checkable-active-onblur.html [ Failure Timeout ] # isInputPending requires threaded compositing and layerized iframes crbug.com/910421 external/wpt/is-input-pending/* [ Skip ] @@ -2440,6 +2433,7 @@ crbug.com/958381 [ Mac ] external/wpt/css/CSS2/tables/table-anonymous-objects-206.xht [ Failure ] # ====== New tests from wpt-importer added here ====== +crbug.com/626703 external/wpt/uievents/keyboard/modifier-keys-combinations.html [ Timeout ] crbug.com/626703 external/wpt/css/css-flexbox/percentage-descendant-of-anonymous-flex-item.html [ Failure ] crbug.com/626703 external/wpt/uievents/keyboard/modifier-keys.html [ Timeout ] crbug.com/626703 external/wpt/css/css-backgrounds/background-repeat-space-1b.html [ Failure ] @@ -2597,16 +2591,16 @@ crbug.com/626703 [ Mac10.13 ] external/wpt/html/canvas/offscreen/text/2d.text.draw.fill.maxWidth.zero.worker.html [ Timeout ] crbug.com/626703 external/wpt/css/css-scroll-snap/snap-after-initial-layout/scroll-snap-writing-mode-000.html [ Failure ] crbug.com/626703 [ Mac10.13 ] virtual/threaded/external/wpt/web-animations/timing-model/animations/updating-the-finished-state.html [ Timeout ] -crbug.com/626703 external/wpt/editing/other/typing-around-link-element-at-non-collapsed-selection.tentative.html?target=ContentEditable&parent=b [ Timeout ] -crbug.com/626703 external/wpt/editing/other/typing-around-link-element-at-collapsed-selection.tentative.html?target=ContentEditable [ Timeout ] -crbug.com/626703 external/wpt/editing/other/typing-around-link-element-at-collapsed-selection.tentative.html?target=ContentEditable&parent=b [ Timeout ] +crbug.com/626703 external/wpt/editing/other/typing-around-link-element-at-non-collapsed-selection.tentative.html?target=ContentEditable&parent=b [ Failure Timeout ] +crbug.com/626703 external/wpt/editing/other/typing-around-link-element-at-collapsed-selection.tentative.html?target=ContentEditable [ Failure Timeout ] +crbug.com/626703 external/wpt/editing/other/typing-around-link-element-at-collapsed-selection.tentative.html?target=ContentEditable&parent=b [ Failure Timeout ] crbug.com/626703 virtual/threaded/external/wpt/css/css-scroll-snap/snap-after-initial-layout/scroll-snap-writing-mode-000.html [ Failure ] -crbug.com/626703 external/wpt/editing/other/typing-around-link-element-at-non-collapsed-selection.tentative.html?target=ContentEditable&child=b [ Timeout ] -crbug.com/626703 external/wpt/editing/other/typing-around-link-element-at-non-collapsed-selection.tentative.html?target=ContentEditable&parent=b&child=i [ Timeout ] -crbug.com/626703 external/wpt/editing/other/typing-around-link-element-at-collapsed-selection.tentative.html?target=ContentEditable&child=b [ Timeout ] +crbug.com/626703 external/wpt/editing/other/typing-around-link-element-at-non-collapsed-selection.tentative.html?target=ContentEditable&child=b [ Failure Timeout ] +crbug.com/626703 external/wpt/editing/other/typing-around-link-element-at-non-collapsed-selection.tentative.html?target=ContentEditable&parent=b&child=i [ Failure Timeout ] +crbug.com/626703 external/wpt/editing/other/typing-around-link-element-at-collapsed-selection.tentative.html?target=ContentEditable&child=b [ Failure Timeout ] crbug.com/626703 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-abspos-staticpos-align-self-safe-001.html [ Failure ] -crbug.com/626703 external/wpt/editing/other/typing-around-link-element-at-non-collapsed-selection.tentative.html?target=ContentEditable [ Timeout ] -crbug.com/626703 external/wpt/editing/other/typing-around-link-element-at-collapsed-selection.tentative.html?target=ContentEditable&parent=b&child=i [ Timeout ] +crbug.com/626703 external/wpt/editing/other/typing-around-link-element-at-non-collapsed-selection.tentative.html?target=ContentEditable [ Failure Timeout ] +crbug.com/626703 external/wpt/editing/other/typing-around-link-element-at-collapsed-selection.tentative.html?target=ContentEditable&parent=b&child=i [ Failure Timeout ] crbug.com/626703 external/wpt/css/css-scroll-snap/snap-after-initial-layout/scroll-snap-initial-layout-000.html [ Failure ] crbug.com/626703 virtual/threaded/external/wpt/css/css-scroll-snap/snap-after-initial-layout/scroll-snap-initial-layout-000.html [ Failure ] crbug.com/626703 [ Mac10.13 ] external/wpt/x-frame-options/multiple.html [ Timeout ] @@ -2621,14 +2615,14 @@ crbug.com/626703 external/wpt/mediacapture-record/MediaRecorder-peerconnection-no-sink.https.html [ Timeout ] crbug.com/626703 external/wpt/mediacapture-record/MediaRecorder-peerconnection.https.html [ Timeout ] crbug.com/626703 [ Win7 ] virtual/plz-dedicated-worker/external/wpt/service-workers/service-worker/update-bytecheck.https.html [ Timeout ] -crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-joining-dl-element-and-another-list.tentative.html?Backspace [ Timeout ] -crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-deleting-in-list-items.tentative.html?Backspace,ul [ Timeout ] -crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-joining-dl-elements.tentative.html?Backspace [ Timeout ] -crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-deleting-in-list-items.tentative.html?Delete,ul [ Timeout ] -crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-joining-dl-elements.tentative.html?Delete [ Timeout ] -crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-joining-dl-element-and-another-list.tentative.html?Delete [ Timeout ] -crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-deleting-in-list-items.tentative.html?Backspace,ol [ Timeout ] -crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-deleting-in-list-items.tentative.html?Delete,ol [ Timeout ] +crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-joining-dl-element-and-another-list.tentative.html?Backspace [ Failure Timeout ] +crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-deleting-in-list-items.tentative.html?Backspace,ul [ Failure Timeout ] +crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-joining-dl-elements.tentative.html?Backspace [ Failure Timeout ] +crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-deleting-in-list-items.tentative.html?Delete,ul [ Failure Timeout ] +crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-joining-dl-elements.tentative.html?Delete [ Failure Timeout ] +crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-joining-dl-element-and-another-list.tentative.html?Delete [ Failure Timeout ] +crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-deleting-in-list-items.tentative.html?Backspace,ol [ Failure Timeout ] +crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-deleting-in-list-items.tentative.html?Delete,ol [ Failure Timeout ] crbug.com/626703 external/wpt/mediacapture-record/MediaRecorder-stop.html [ Timeout ] crbug.com/626703 [ Mac11.0 ] external/wpt/fetch/api/response/response-clone.any.worker.html [ Failure Timeout ] crbug.com/626703 [ Mac11.0 ] virtual/plz-dedicated-worker/external/wpt/fetch/api/response/response-clone.any.sharedworker.html [ Failure Timeout ] @@ -2638,7 +2632,7 @@ crbug.com/626703 [ Mac11.0 ] external/wpt/fetch/api/response/response-clone.any.html [ Failure Timeout ] crbug.com/626703 [ Mac11.0 ] virtual/plz-dedicated-worker/external/wpt/fetch/api/response/response-clone.any.html [ Failure Timeout ] crbug.com/626703 [ Mac ] external/wpt/webxr/xr_viewport_scale.https.html [ Timeout ] -crbug.com/626703 external/wpt/editing/other/select-all-and-delete-in-html-element-having-contenteditable.html [ Timeout ] +crbug.com/626703 external/wpt/editing/other/select-all-and-delete-in-html-element-having-contenteditable.html [ Failure Timeout ] crbug.com/626703 external/wpt/paint-timing/with-first-paint/first-contentful-image.html [ Timeout ] crbug.com/626703 external/wpt/paint-timing/with-first-paint/mask-image.html [ Timeout ] crbug.com/626703 external/wpt/paint-timing/with-first-paint/first-contentful-paint.html [ Timeout ] @@ -2646,14 +2640,14 @@ crbug.com/626703 external/wpt/paint-timing/with-first-paint/sibling-painting-first-image.html [ Timeout ] crbug.com/626703 external/wpt/paint-timing/with-first-paint/border-image.html [ Timeout ] crbug.com/626703 [ Mac10.15 ] virtual/threaded/external/wpt/animation-worklet/worklet-animation-local-time-null-2.https.html [ Failure ] -crbug.com/626703 external/wpt/infrastructure/testdriver/actions/iframe.html [ Timeout ] +crbug.com/626703 external/wpt/infrastructure/testdriver/actions/iframe.html [ Failure Timeout ] crbug.com/626703 external/wpt/infrastructure/testdriver/actions/crossOrigin.sub.html [ Timeout ] crbug.com/626703 [ Mac11.0 ] external/wpt/html/semantics/embedded-content/media-elements/preserves-pitch.html [ Timeout ] -crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-during-and-after-dispatch.tentative.html [ Timeout ] +crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-during-and-after-dispatch.tentative.html [ Failure Timeout ] crbug.com/626703 [ Mac11.0 ] external/wpt/scroll-to-text-fragment/redirects.html [ Timeout ] -crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-non-collapsed-selection.tentative.html?Backspace [ Timeout ] -crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-non-collapsed-selection.tentative.html?TypingA [ Timeout ] -crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-non-collapsed-selection.tentative.html?Delete [ Timeout ] +crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-non-collapsed-selection.tentative.html?Backspace [ Failure Timeout ] +crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-non-collapsed-selection.tentative.html?TypingA [ Failure Timeout ] +crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-non-collapsed-selection.tentative.html?Delete [ Failure Timeout ] crbug.com/626703 external/wpt/screen-capture/feature-policy.https.html [ Timeout ] crbug.com/626703 [ Fuchsia ] virtual/threaded/external/wpt/animation-worklet/worklet-animation-pause-immediately.https.html [ Failure ] crbug.com/626703 [ Mac11.0 ] virtual/threaded/external/wpt/animation-worklet/worklet-animation-pause-immediately.https.html [ Failure ] @@ -2665,8 +2659,8 @@ crbug.com/626703 [ Mac10.15 ] virtual/threaded/external/wpt/animation-worklet/worklet-animation-with-scroll-timeline-root-scroller.https.html [ Failure ] crbug.com/626703 [ Mac10.14 ] virtual/off-main-thread-css-paint/external/wpt/css/css-paint-api/valid-image-before-load.https.html [ Failure ] crbug.com/626703 [ Win7 ] external/wpt/html/cross-origin-embedder-policy/reporting-subresource-corp.https.html [ Failure Timeout ] -crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-backspace.tentative.html [ Timeout ] -crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-forwarddelete.tentative.html [ Timeout ] +crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-backspace.tentative.html [ Failure Timeout ] +crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-forwarddelete.tentative.html [ Failure Timeout ] crbug.com/626703 external/wpt/streams/transform-streams/patched-global.any.serviceworker.html [ Timeout ] crbug.com/626703 external/wpt/streams/transform-streams/patched-global.any.worker.html [ Timeout ] crbug.com/626703 external/wpt/streams/transform-streams/patched-global.any.sharedworker.html [ Timeout ] @@ -2981,10 +2975,8 @@ crbug.com/626703 external/wpt/css/selectors/old-tests/css3-modsel-65.xml [ Skip ] crbug.com/626703 external/wpt/css/selectors/old-tests/css3-modsel-18b.xml [ Skip ] crbug.com/626703 external/wpt/css/selectors/old-tests/css3-modsel-159.xml [ Skip ] -crbug.com/626703 external/wpt/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/reload.window.html [ Timeout ] crbug.com/626703 external/wpt/quirks/text-decoration-doesnt-propagate-into-tables/quirks.html [ Failure ] crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-painting-order.html [ Failure ] -crbug.com/626703 external/wpt/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/tasks.window.html [ Timeout ] crbug.com/875411 external/wpt/svg/text/reftests/text-complex-002.svg [ Failure ] crbug.com/875411 external/wpt/svg/text/reftests/text-shape-inside-001.svg [ Failure ] crbug.com/875411 external/wpt/svg/text/reftests/text-complex-001.svg [ Failure ]
diff --git a/third_party/blink/web_tests/accessibility/table-column-track-merging.html b/third_party/blink/web_tests/accessibility/table-column-track-merging.html new file mode 100644 index 0000000..08e43f3e --- /dev/null +++ b/third_party/blink/web_tests/accessibility/table-column-track-merging.html
@@ -0,0 +1,124 @@ +<!doctype html> +<title>Column track merging accesibilty tests</title> +<script src='../resources/testharness.js'></script> +<script src='../resources/testharnessreport.js'></script> +<link rel="author" title="Aleks Totic" href="atotic@chromium.org" /> +<link rel="help" href="https://www.w3.org/TR/css-tables-3/#dimensioning-the-row-column-grid--step2" /> +<style> + +main table { + border: 10px solid gray; + border-spacing: 20px; +} + +main td { + width: 50px; + height:50px; + padding: 0; + background:linear-gradient(to right, yellow, orange); +} +main caption { + background: #EEE; +} +main .desc { + margin-top: 20px; + color: rgb(50,0,0); +} +main pre { + white-space: pre-wrap; + +} +</style> +<main> +<p>Checks accessibility table properties when tracks are merged. a11y part of wpt/css/css-tables/column-track-merging.html</p> + +<table id="td_auto"> +<caption>auto</caption> +<tr> + <td colspan=10></td> + <td></td> +</tr> +<tr> + <td colspan=10></td> + <td></td> +</tr> +</table> + +<table id="td_auto_width" style="width:400px"> +<caption>auto 400px</caption> +<tr> + <td colspan=10></td> + <td></td> +</tr> +<tr> + <td colspan=10></td> + <td></td> +</tr> +</table> + +<table id="td_fixed" style="table-layout:fixed; width: 400px"> +<caption>fixed 400px</caption> +<tr> + <td colspan=10></td> + <td></td> +</tr> +<tr> + <td colspan=10></td> + <td></td> +</tr> +</table> + +<table id="col_fixed_130" style="table-layout:fixed; width: 130px"> +<col span=10> +<caption>col fixed 130px</caption> +<tr> + <td></td> + <td></td> +</tr> +<tr> + <td></td> + <td></td> +</tr> +</table> + +</main> +<script> + + test(function() { + assert_true(!!window.accessibilityController, "accessibilityController exists"); + }, "accessibilityController exists"); + + // a11y tests + + test(function() { + let table = accessibilityController.accessibleElementById("td_auto"); + assert_equals(table.columnCount, 2, "has merged td columns"); + let cell = table.cellForColumnAndRow(0,0); + assert_equals(cell.columnIndexRange(), "{0, 1}", "cell.columnIndexRange"); + }, "td_auto table props"); + + test(function() { + let table = accessibilityController.accessibleElementById("td_auto_width"); + assert_equals(table.columnCount, 2, "has merged td columns"); + let cell = table.cellForColumnAndRow(0,0); + assert_equals(cell.columnIndexRange(), "{0, 1}", "cell.columnIndexRange"); + }, "td_auto_width table props"); + + test(function() { + let table = accessibilityController.accessibleElementById("td_fixed"); + assert_equals(table.columnCount, 11, "has not merged td columns"); + let cell = table.cellForColumnAndRow(0,0); + assert_equals(cell.columnIndexRange(), "{0, 10}", "cell.columnIndexRange"); + }, "td_fixed table props"); + + test(function() { + let table = accessibilityController.accessibleElementById("col_fixed_130"); + assert_equals(table.columnCount, 10, "has not merged td columns"); + let cell = table.cellForColumnAndRow(0,0); + assert_equals(cell.columnIndexRange(), "{0, 1}", "cell.columnIndexRange"); + }, "col_fixed table props"); + + </script> + +</body> +</html>
diff --git a/third_party/blink/web_tests/android/ChromiumWPTExpectations b/third_party/blink/web_tests/android/ChromiumWPTExpectations index d4c7a82..f2494341 100644 --- a/third_party/blink/web_tests/android/ChromiumWPTExpectations +++ b/third_party/blink/web_tests/android/ChromiumWPTExpectations
@@ -2861,8 +2861,6 @@ crbug.com/1050754 external/wpt/html/webappapis/dynamic-markup-insertion/document-write/write-active-document.html [ Failure Pass ] crbug.com/1050754 external/wpt/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-side-effects-ignore-opens-during-unload.window.html [ Failure Pass ] crbug.com/1050754 external/wpt/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/location-set-and-document-open.html [ Timeout ] -crbug.com/1050754 external/wpt/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/reload.window.html [ Timeout ] -crbug.com/1050754 external/wpt/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/tasks.window.html [ Timeout ] crbug.com/1050754 external/wpt/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/url.window.html [ Failure Pass ] crbug.com/1050754 external/wpt/html/webappapis/microtask-queuing/queue-microtask-exceptions.any.sharedworker.html [ Failure ] crbug.com/1050754 external/wpt/html/webappapis/microtask-queuing/queue-microtask-exceptions.any.worker.html [ Failure Pass ]
diff --git a/third_party/blink/web_tests/android/WeblayerWPTExpectations b/third_party/blink/web_tests/android/WeblayerWPTExpectations index f8d427b..c82d5a2f 100644 --- a/third_party/blink/web_tests/android/WeblayerWPTExpectations +++ b/third_party/blink/web_tests/android/WeblayerWPTExpectations
@@ -1245,7 +1245,6 @@ crbug.com/1050754 external/wpt/html/user-activation/propagation-crossorigin.sub.tentative.html [ Failure ] crbug.com/1050754 external/wpt/html/user-activation/propagation-sameorigin.tentative.html [ Failure ] crbug.com/1050754 external/wpt/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/location-set-and-document-open.html [ Timeout ] -crbug.com/1050754 external/wpt/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/reload.window.html [ Timeout ] crbug.com/1050754 external/wpt/html/webappapis/microtask-queuing/queue-microtask-exceptions.any.sharedworker.html [ Failure ] crbug.com/1050754 external/wpt/html/webappapis/microtask-queuing/queue-microtask-exceptions.any.worker.html [ Failure Pass ] crbug.com/1050754 external/wpt/html/webappapis/microtask-queuing/queue-microtask.any.sharedworker.html [ Failure ]
diff --git a/third_party/blink/web_tests/android/WebviewWPTExpectations b/third_party/blink/web_tests/android/WebviewWPTExpectations index 105ca2d..bce4643 100644 --- a/third_party/blink/web_tests/android/WebviewWPTExpectations +++ b/third_party/blink/web_tests/android/WebviewWPTExpectations
@@ -3058,8 +3058,6 @@ crbug.com/1050754 external/wpt/html/webappapis/dynamic-markup-insertion/document-write/write-active-document.html [ Failure Pass ] crbug.com/1050754 external/wpt/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-side-effects-ignore-opens-during-unload.window.html [ Failure Pass ] crbug.com/1050754 external/wpt/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/location-set-and-document-open.html [ Timeout ] -crbug.com/1050754 external/wpt/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/reload.window.html [ Timeout ] -crbug.com/1050754 external/wpt/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/tasks.window.html [ Timeout ] crbug.com/1050754 external/wpt/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/url.window.html [ Failure Pass ] crbug.com/1050754 external/wpt/html/webappapis/microtask-queuing/queue-microtask-exceptions.any.sharedworker.html [ Failure ] crbug.com/1050754 external/wpt/html/webappapis/microtask-queuing/queue-microtask-exceptions.any.worker.html [ Failure Pass ]
diff --git a/third_party/blink/web_tests/animations/interpolation/min-height-interpolation.html b/third_party/blink/web_tests/animations/interpolation/min-height-interpolation.html new file mode 100644 index 0000000..608af6b --- /dev/null +++ b/third_party/blink/web_tests/animations/interpolation/min-height-interpolation.html
@@ -0,0 +1,26 @@ +<!DOCTYPE html> +<meta charset="UTF-8"> +<style> +.parent { + min-height: 30px; +} +.target { + width: 10px; + height: 10px; + background-color: black; +} +.expected { + background-color: green; +} +</style> +<body> +<script src="resources/interpolation-test.js"></script> +<script> +// Regression test for crbug.com/1175628. +assertNoInterpolation({ + property: 'min-height', + from: 'calc(25631651542881545922376008592752624554174702806001571610784437629701274% - 7px)', + to: 'calc(25631651542881545922376008592752624554174702806001571610784437629701274% - 7px)', +}); +</script> +</body>
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json index 2ba81e37..635bf72 100644 --- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json +++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -1261,6 +1261,15 @@ ] } }, + "styling": { + "font-size-number-calc-crash.svg": [ + "6b56d9df2b426e2376f87668a98f5e21ee56e37b", + [ + null, + {} + ] + ] + }, "svg-in-svg": { "svg-in-svg-circular-filter-reference-crash.html": [ "51303171f09d28e3958ab74ecdce7f9cf120bd12", @@ -244263,7 +244272,7 @@ [] ], "cors-rfc1918.idl": [ - "083b6c3d630bb8179c1376d49bd13d48235bf6f8", + "d392a679ff2cca25dae7ad406d6e57fd3ac25cef", [] ], "credential-management.idl": [ @@ -244479,7 +244488,7 @@ [] ], "js-self-profiling.idl": [ - "2c51c1cfe8eed10c8bd92bae1fdf3bf4a9216995", + "a2199999eada84ff43f1a237380685c5833c4791", [] ], "keyboard-lock.idl": [ @@ -245005,6 +245014,10 @@ "__dir__.headers": [ "35b10bd2ccdbfa99feb96079fafab61346d025ed", [] + ], + "idlharness.https-expected.txt": [ + "c1b7bf964b840d03301ce8719f251300ad1f0d76", + [] ] }, "keyboard-lock": { @@ -251942,6 +251955,10 @@ "d5d199068c5b0465f96ed643af8d7d20a889312e", [] ], + "modify.tentative-expected.txt": [ + "e13dca3d44115cda61741720b76a3030067fb40a", + [] + ], "removeRange-expected.txt": [ "51df0f5d4525db516faab89c10424d95d307804f", [] @@ -414382,7 +414399,7 @@ ] ], "modify.tentative.html": [ - "c4436fcafeb5e43ea43948183d3e64842abb8be6", + "37231571eddac45a9cce78cddff52b69b2af9ff6", [ null, {} @@ -428318,6 +428335,15 @@ ] }, "keyboard": { + "modifier-keys-combinations.html": [ + "1b364ff72ce539b31ef86f4a1bcf75aed6868845", + [ + null, + { + "testdriver": true + } + ] + ], "modifier-keys.html": [ "635e5d3b7797e1fcde058f81dda1b3b2132ee375", [
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-fallback-setter-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-fallback-setter-invalid.html new file mode 100644 index 0000000..c5c43a3 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-fallback-setter-invalid.html
@@ -0,0 +1,30 @@ +<!DOCTYPE html> +<title>CSSCounterStyleRule fallback setter with invalid values</title> +<link rel="help" href="https://www.w3.org/TR/css-counter-styles-3/#the-csscounterstylerule-interface"> +<link rel="author" href="mailto:xiaochengh@chromium.org"> +<link rel="match" href="cssom-fallback-setter-ref.html"> +<style id="sheet"> +@counter-style foo { + system: fixed; + symbols: A B; + fallback: lower-roman; +} +</style> + +<ol style="list-style-type: foo; list-style-position: inside"> + <li></li> + <li></li> + <li></li> +</ol> + +<script> +// Force layout update before changing the rule +document.body.offsetWidth; + +const sheet = document.getElementById('sheet'); +const foo_rule = sheet.sheet.rules[0]; + +// Invalid values should be ignored +foo_rule.fallback = 'none'; +foo_rule.fallback = 'lower-roman upper-roman' +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-fallback-setter-ref.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-fallback-setter-ref.html new file mode 100644 index 0000000..da4bb59 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-fallback-setter-ref.html
@@ -0,0 +1,9 @@ +<!DOCTYPE html> +<title>CSSCounterStyleRule fallback setter</title> + +<ol> + <div>A.</div> + <div>B.</div> + <div>iii.</div> +</ol> +
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-fallback-setter.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-fallback-setter.html new file mode 100644 index 0000000..399463f3 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-fallback-setter.html
@@ -0,0 +1,26 @@ +<!DOCTYPE html> +<title>CSSCounterStyleRule fallback setter</title> +<link rel="help" href="https://www.w3.org/TR/css-counter-styles-3/#the-csscounterstylerule-interface"> +<link rel="author" href="mailto:xiaochengh@chromium.org"> +<link rel="match" href="cssom-fallback-setter-ref.html"> +<style id="sheet"> +@counter-style foo { + system: fixed; + symbols: A B; +} +</style> + +<ol style="list-style-type: foo; list-style-position: inside"> + <li></li> + <li></li> + <li></li> +</ol> + +<script> +// Force layout update before changing the rule +document.body.offsetWidth; + +const sheet = document.getElementById('sheet'); +const foo_rule = sheet.sheet.rules[0]; +foo_rule.fallback = 'lower-roman'; +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-negative-setter-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-negative-setter-invalid.html new file mode 100644 index 0000000..e15447b --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-negative-setter-invalid.html
@@ -0,0 +1,29 @@ +<!DOCTYPE html> +<title>CSSCounterStyleRule negative setter with invalid values</title> +<link rel="help" href="https://www.w3.org/TR/css-counter-styles-3/#the-csscounterstylerule-interface"> +<link rel="author" href="mailto:xiaochengh@chromium.org"> +<link rel="match" href="cssom-negative-setter-ref.html"> +<style id="sheet"> +@counter-style foo { + system: extends decimal; + negative: '(' ')'; +} +</style> + +<ol style="list-style-type: foo; list-style-position: inside" start="-3"> + <li></li> + <li></li> + <li></li> +</ol> + +<script> +// Force layout update before changing the rule +document.body.offsetWidth; + +const sheet = document.getElementById('sheet'); +const foo_rule = sheet.sheet.rules[0]; + +// Invalid values should be ignored +foo_rule.negative = 'X Y Z'; +foo_rule.negative = '"X" "Y" "Z"'; +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-negative-setter-ref.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-negative-setter-ref.html new file mode 100644 index 0000000..7d465a3 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-negative-setter-ref.html
@@ -0,0 +1,9 @@ +<!DOCTYPE html> +<title>CSSCounterStyleRule negative setter</title> + +<ol> + <div>(3).</div> + <div>(2).</div> + <div>(1).</div> +</ol> +
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-negative-setter.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-negative-setter.html new file mode 100644 index 0000000..06238841 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-negative-setter.html
@@ -0,0 +1,25 @@ +<!DOCTYPE html> +<title>CSSCounterStyleRule negative setter</title> +<link rel="help" href="https://www.w3.org/TR/css-counter-styles-3/#the-csscounterstylerule-interface"> +<link rel="author" href="mailto:xiaochengh@chromium.org"> +<link rel="match" href="cssom-negative-setter-ref.html"> +<style id="sheet"> +@counter-style foo { + system: extends decimal; +} +</style> + +<ol style="list-style-type: foo; list-style-position: inside" start="-3"> + <li></li> + <li></li> + <li></li> +</ol> + +<script> +// Force layout update before changing the rule +document.body.offsetWidth; + +const sheet = document.getElementById('sheet'); +const foo_rule = sheet.sheet.rules[0]; +foo_rule.negative = '"(" ")"'; +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-pad-setter-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-pad-setter-invalid.html new file mode 100644 index 0000000..c263a1bb --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-pad-setter-invalid.html
@@ -0,0 +1,30 @@ +<!DOCTYPE html> +<title>CSSCounterStyleRule pad setter with invalid values</title> +<link rel="help" href="https://www.w3.org/TR/css-counter-styles-3/#the-csscounterstylerule-interface"> +<link rel="author" href="mailto:xiaochengh@chromium.org"> +<link rel="match" href="cssom-pad-setter-ref.html"> +<style id="sheet"> +@counter-style foo { + system: extends decimal; + pad: 3 '0'; +} +</style> + +<ol style="list-style-type: foo; list-style-position: inside"> + <li></li> + <li></li> + <li></li> +</ol> + +<script> +// Force layout update before changing the rule +document.body.offsetWidth; + +const sheet = document.getElementById('sheet'); +const foo_rule = sheet.sheet.rules[0]; + +// Invalid values should be ignored +foo_rule.pad = '-1 "0"'; +foo_rule.pad = '3'; +foo_rule.pad = '3 "X" "Y"'; +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-pad-setter-ref.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-pad-setter-ref.html new file mode 100644 index 0000000..6184686 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-pad-setter-ref.html
@@ -0,0 +1,9 @@ +<!DOCTYPE html> +<title>CSSCounterStyleRule pad setter</title> + +<ol> + <div>001.</div> + <div>002.</div> + <div>003.</div> +</ol> +
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-pad-setter.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-pad-setter.html new file mode 100644 index 0000000..df1732d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-pad-setter.html
@@ -0,0 +1,25 @@ +<!DOCTYPE html> +<title>CSSCounterStyleRule pad setter</title> +<link rel="help" href="https://www.w3.org/TR/css-counter-styles-3/#the-csscounterstylerule-interface"> +<link rel="author" href="mailto:xiaochengh@chromium.org"> +<link rel="match" href="cssom-pad-setter-ref.html"> +<style id="sheet"> +@counter-style foo { + system: extends decimal; +} +</style> + +<ol style="list-style-type: foo; list-style-position: inside"> + <li></li> + <li></li> + <li></li> +</ol> + +<script> +// Force layout update before changing the rule +document.body.offsetWidth; + +const sheet = document.getElementById('sheet'); +const foo_rule = sheet.sheet.rules[0]; +foo_rule.pad = '3 "0"'; +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-prefix-suffix-setter-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-prefix-suffix-setter-invalid.html new file mode 100644 index 0000000..7aba3a0 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-prefix-suffix-setter-invalid.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<title>CSSCounterStyleRule prefix and suffix setters with invalid values</title> +<link rel="help" href="https://www.w3.org/TR/css-counter-styles-3/#the-csscounterstylerule-interface"> +<link rel="author" href="mailto:xiaochengh@chromium.org"> +<link rel="match" href="cssom-prefix-suffix-setter-ref.html"> +<style id="sheet"> +@counter-style foo { + system: cyclic; + symbols: A B C; + prefix: '('; + suffix: ')'; +} +</style> + +<ol style="list-style-type: foo; list-style-position: inside"> + <li></li> + <li></li> + <li></li> +</ol> + +<script> +// Force layout update before changing the rule +document.body.offsetWidth; + +const sheet = document.getElementById('sheet'); +const foo_rule = sheet.sheet.rules[0]; + +// Invalid values should be ignored +foo_rule.prefix = '"(" "("'; +foo_rule.prefix = ')'; +foo_rule.prefix = '123'; + +foo_rule.suffix = '")" ")"'; +foo_rule.suffix = '('; +foo_rule.suffix = '456'; +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-prefix-suffix-setter-ref.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-prefix-suffix-setter-ref.html new file mode 100644 index 0000000..bf52d54a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-prefix-suffix-setter-ref.html
@@ -0,0 +1,9 @@ +<!DOCTYPE html> +<title>CSSCounterStyleRule prefix and suffix setters</title> + +<ol> + <div>(A)</div> + <div>(B)</div> + <div>(C)</div> +</ol> +
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-prefix-suffix-setter.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-prefix-suffix-setter.html new file mode 100644 index 0000000..899caa2 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-prefix-suffix-setter.html
@@ -0,0 +1,27 @@ +<!DOCTYPE html> +<title>CSSCounterStyleRule prefix and suffix setters</title> +<link rel="help" href="https://www.w3.org/TR/css-counter-styles-3/#the-csscounterstylerule-interface"> +<link rel="author" href="mailto:xiaochengh@chromium.org"> +<link rel="match" href="cssom-prefix-suffix-setter-ref.html"> +<style id="sheet"> +@counter-style foo { + system: cyclic; + symbols: A B C; +} +</style> + +<ol style="list-style-type: foo; list-style-position: inside"> + <li></li> + <li></li> + <li></li> +</ol> + +<script> +// Force layout update before changing the rule +document.body.offsetWidth; + +const sheet = document.getElementById('sheet'); +const foo_rule = sheet.sheet.rules[0]; +foo_rule.prefix = '"("'; +foo_rule.suffix = '")"'; +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-range-setter-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-range-setter-invalid.html new file mode 100644 index 0000000..2fc45955 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-range-setter-invalid.html
@@ -0,0 +1,31 @@ +<!DOCTYPE html> +<title>CSSCounterStyleRule range setter with invalid values</title> +<link rel="help" href="https://www.w3.org/TR/css-counter-styles-3/#the-csscounterstylerule-interface"> +<link rel="author" href="mailto:xiaochengh@chromium.org"> +<link rel="match" href="cssom-range-setter-ref.html"> +<style id="sheet"> +@counter-style foo { + system: cyclic; + symbols: A B C; + range: 1 2; +} +</style> + +<ol style="list-style-type: foo; list-style-position: inside"> + <li></li> + <li></li> + <li></li> +</ol> + +<script> +// Force layout update before changing the rule +document.body.offsetWidth; + +const sheet = document.getElementById('sheet'); +const foo_rule = sheet.sheet.rules[0]; + +// Invalid values should be ignored +foo_rule.range = "1 2 3"; +foo_rule.range = "3 1" +foo_rule.range = "1 infinity" +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-range-setter-ref.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-range-setter-ref.html new file mode 100644 index 0000000..0129b46 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-range-setter-ref.html
@@ -0,0 +1,9 @@ +<!DOCTYPE html> +<title>CSSCounterStyleRule range setter</title> + +<ol> + <div>A.</div> + <div>B.</div> + <div>3.</div> +</ol> +
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-range-setter.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-range-setter.html new file mode 100644 index 0000000..10d94f0cdb --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/cssom/cssom-range-setter.html
@@ -0,0 +1,26 @@ +<!DOCTYPE html> +<title>CSSCounterStyleRule range setter</title> +<link rel="help" href="https://www.w3.org/TR/css-counter-styles-3/#the-csscounterstylerule-interface"> +<link rel="author" href="mailto:xiaochengh@chromium.org"> +<link rel="match" href="cssom-range-setter-ref.html"> +<style id="sheet"> +@counter-style foo { + system: cyclic; + symbols: A B C; +} +</style> + +<ol style="list-style-type: foo; list-style-position: inside"> + <li></li> + <li></li> + <li></li> +</ol> + +<script> +// Force layout update before changing the rule +document.body.offsetWidth; + +const sheet = document.getElementById('sheet'); +const foo_rule = sheet.sheet.rules[0]; +foo_rule.range = "1 2"; +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-tables/column-track-merging.html b/third_party/blink/web_tests/external/wpt/css/css-tables/column-track-merging.html new file mode 100644 index 0000000..6dba9e6 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-tables/column-track-merging.html
@@ -0,0 +1,278 @@ +<!doctype html> +<title>Column track merging</title> +<script src='/resources/testharness.js'></script> +<script src='/resources/testharnessreport.js'></script> +<script src="/resources/check-layout-th.js"></script> +<link rel="author" title="Aleks Totic" href="atotic@chromium.org" /> +<link rel="help" href="https://www.w3.org/TR/css-tables-3/#dimensioning-the-row-column-grid--step2" /> +<style> + +main table { + border: 10px solid gray; + border-spacing: 20px; +} + +main td { + width: 50px; + height:50px; + padding: 0; + background:linear-gradient(to right, yellow, orange); +} +main caption { + background: #EEE; +} +main .desc { + margin-top: 20px; + color: rgb(50,0,0); +} +main pre { + white-space: pre-wrap; + +} +</style> +<h3>Column merging investigation</h3> +<o>Empty columns is a column that has no originating cells</o> +<p><a href="https://www.w3.org/TR/css-tables-3/#dimensioning-the-row-column-grid--step2">Table standard</a> discusses this under "track merging".</p> +<ul> + <li>Do empty columns get coalesced?</li> + <li>How does this interact with table-layout:fixed, table width</li> + <li>Is there a difference between columns defined by COL, vs TD.colspan? Yes!</li> + <li>Do COLs with specified width get merged?</li> +</ul> +<p>Compatibility</p> +<li>Edge17 has a bug where width of a colspanned cell always includes cell width + width of border spacing. It should be max(cell width, border spacing)</li> +<li>Safari matches Chrome Legacy. TD-originated columns are always merged.</li> +<li>Firefox follows the standard, but has a few bugs.</li> +<main> + +<h3>TD merging</h3> + +<pre class="desc">Auto table, and TD.colspan=10 + FF/Chrome Legacy/Safari: Standard. Tracks merge. + Edge17: Tracks do not merge. Wide cell is 180px (9 * border spacing) +</pre> +<table id="td_auto" data-expected-width=180> +<caption>auto</caption> +<tr> + <td colspan=10 data-expected-width=50></td> + <td></td> +</tr> +<tr> + <td colspan=10></td> + <td></td> +</tr> +</table> + +<pre class="desc">Auto table(400px), and TD.colspan=10 + FF/Chrome Legacy/Safari/Edge17: Standard. Tracks merge. Colspan cell grows because it is unconstrained. +</pre> +<table id="td_auto_width" style="width:400px" data-expected-width=400> +<caption>auto 400px</caption> +<tr> + <td colspan=10 data-expected-width=270></td> + <td></td> +</tr> +<tr> + <td colspan=10></td> + <td></td> +</tr> +</table> + +<pre class="desc">Auto table(130px), and TD.colspan=10 + FF/Chrome Legacy/Safari: Standard. Tracks merge. Colspan cell shrinks to min width becuase it is unconstrained. + Edge17: Non-compliant, buggy. Wide cell too wide, narrow cell disappears. +</pre> +<table id="td_auto_width_130" style="width:130px" data-expected-width=130> +<caption>auto 130px</caption> +<tr> + <td colspan=10 data-expected-width=10><div style="width:10px"></div></td> + <td></td> +</tr> +<tr> + <td colspan=10></td> + <td></td> +</tr> +</table> + +<pre class="td_fixed">Fixed(400px) table, and TD.colspan=10 + Chrome/Safari: Non-compliant. Tracks merge. Cells are the same size, fixed algo distributes extra width evenly. + Firefox: Standard. + Edge17: Standard, buggy. Wide cell too wide. Edge's bug is that it computes max width as (width + border_spacing) instead of max(width, border_spacing). +</pre> +<table id="td_fixed" style="table-layout:fixed; width: 400px" data-expected-width=400> +<caption>fixed 400px</caption> +<tr> + <td colspan=10 data-expected-width=180></td> + <td></td> +</tr> +<tr> + <td colspan=10></td> + <td></td> +</tr> +</table> + +<pre class="td_fixed">Fixed(130px) table, and TD.colspan=10 + Chrome/Safari: Non-compliant.Tracks merge, cells same size. + Firefox: Standard + buggy. Table does not grow. + Edge17: Standard + buggy. Wide cell too wide. +</pre> +<table id="td_fixed" style="table-layout:fixed; width: 130px" data-expected-width=310> +<caption>fixed 130px</caption> +<tr> + <td colspan=10 data-expected-width=180></td> + <td></td> +</tr> +<tr> + <td colspan=10></td> + <td></td> +</tr> +</table> + +<h3>COL merging. Same tests with COL span=10 replacing TD</h3> + +<pre class="desc">Auto table + FF/Chrome Legacy/Safari, Edge17: Standard. wide cell is 50px, tracks do merge. +</pre> +<table id="col_auto" data-expected-width=180> +<caption>auto</caption> +<col span=10> +<tr> + <td data-expected-width=50></td> + <td></td> +</tr> +<tr> + <td></td> + <td></td> +</tr> +</table> + +<pre class="desc">Auto table(400px) + FF/Chrome Legacy/Safari, Edge17: Standard. Both cells grow the same because unconstrained. +</pre> +<table id="col_auto_width" style="width:400px" data-expected-width=400> +<caption>auto 400px</caption> +<col span=10> +<tr> + <td data-expected-width=160></td> + <td></td> +</tr> +<tr> + <td ></td> + <td></td> +</tr> +</table> + +<pre class="desc">Auto table(130px) + FF/Chrome Legacy/Safari, Edge17: Standard. Both cells shrink. +</pre> +<table id="col_auto_width_130" style="width:130px" data-expected-width=130> +<caption>auto 130px</caption> +<col span=10> +<tr> + <td data-expected-width=28><div style="width:10px"></div></td> + <td></td> +</tr> +<tr> + <td></td> + <td></td> +</tr> +</table> + +<pre class="desc">Fixed(400px) table + Chrome/Safari,Firefox: Standard. + Edge17: Buggy. Fixed cells grow to fill table. +</pre> +<table id="col_fixed" style="table-layout:fixed; width: 400px" data-expected-width=400> +<caption>fixed 400px</caption> +<col span=10> +<tr> + <td data-expected-width=50></td> + <td></td> +</tr> +<tr> + <td></td> + <td></td> +</tr> +</table> + +<pre class="td_fixed">Fixed(130px) table + Chrome/Safari: Standard, very buggy. Non-collapsed columns shrink to single border spacing. + Firefox: Standard. + Edge17: Non-compliant, collapses columns. +</pre> +<table id="col_fixed_130" style="table-layout:fixed; width: 130px" data-expected-width=340> +<col span=10> +<caption>fixed 130px</caption> +<tr> + <td data-expected-width=50></td> + <td></td> +</tr> +<tr> + <td></td> + <td></td> +</tr> +</table> + +<h3>COL merging when COL has specified width.</h3> + +<ul><li>Chrome Legacy/Edge17/Safari: non-compliant, merge COLs with specified widths. + <li>Firefox: Standard, unless COL width is 0px. Buggy, does not include border-spacing around columns.</ul> +<pre class="desc">Auto table, COL width 30px. + Chrome Legacy/Edge17/Safari: non-compliant, merge. + Firefox: Standard, buggy. does not include border-spacing around columns. +</pre> +<table id="col_auto" data-expected-width=580> +<caption>auto col 30px</caption> +<col span=10 style="width:30px"> +<tr> + <td data-expected-width=50></td> + <td></td> +</tr> +<tr> + <td></td> + <td></td> +</tr> +</table> + +<pre class="desc">Auto table, COL width 5%. + Chrome Legacy/Edge17/Safari: non-compliant, merge. + Firefox: Standard, buggy. does not include border-spacing around columns. +</pre> +<table id="col_auto" data-expected-width=640> +<caption>auto col 10%</caption> +<col span=5 style="width:10%"> +<tr> + <td data-expected-width=100></td> + <td></td> +</tr> +<tr> + <td></td> + <td></td> +</tr> +</table> + +<pre class="desc">Auto table, COL width 0px. + Everyone: merges COL +</pre> +<table id="col_auto" data-expected-width=180> +<caption>auto col 0px</caption> +<col span=10 style="width:0px"> +<tr> + <td data-expected-width=50></td> + <td></td> +</tr> +<tr> + <td></td> + <td></td> +</tr> +</table> + + +</main> +<script> + checkLayout("main table"); +</script> + + +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/editing/other/typing-around-link-element-at-collapsed-selection.tentative_target=DesignMode-expected.txt b/third_party/blink/web_tests/external/wpt/editing/other/typing-around-link-element-at-collapsed-selection.tentative_target=DesignMode-expected.txt index a6b2d0a..c5eb341 100644 --- a/third_party/blink/web_tests/external/wpt/editing/other/typing-around-link-element-at-collapsed-selection.tentative_target=DesignMode-expected.txt +++ b/third_party/blink/web_tests/external/wpt/editing/other/typing-around-link-element-at-collapsed-selection.tentative_target=DesignMode-expected.txt
@@ -1,32 +1,32 @@ This is a testharness.js-based test. PASS Testing inserting content around link element -FAIL Replacing text in a link with "XY" in <p>[abc]</p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after making a link (following Selection.collapseToEnd) in <p>[abc]</p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after making a link (following ArrowRight key press) in <p>[abc]</p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after making a link (following End key press) in <p>[abc]</p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after making a link (following Selection.collapseToStart) in <p>[abc]</p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after making a link (following ArrowLeft key press) in <p>[abc]</p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after making a link (following Home key press) in <p>[abc]</p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after setting caret position to middle of a link (Selection.collapse) in <p><a href="about:blank">[]abc</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after setting caret position to middle of a link (Selection.addRange) in <p><a href="about:blank">[]abc</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after setting caret position to start of a link (Selection.collapse) in <p><a href="about:blank">ab[]c</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after setting caret position to start of a link (Selection.addRange) in <p><a href="about:blank">ab[]c</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after setting caret position to end of a link (Selection.collapse) in <p><a href="about:blank">ab[]c</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after setting caret position to end of a link (Selection.addRange) in <p><a href="about:blank">ab[]c</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after modifying caret position to middle of a link in <p><a href="about:blank">[]abc</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after modifying caret position to start of a link in <p><a href="about:blank">ab[]c</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after modifying caret position to end of a link in <p><a href="about:blank">ab[]c</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting following character of a link (Backspace) in <p><a href="about:blank">abc</a>d[]</p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting following character of a link (execCommand("delete")) in <p><a href="about:blank">abc</a>d[]</p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting a previous character of a link (Delete) in <p>[]z<a href="about:blank">abc</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting a previous character of a link (execCommand("forwarddelete")) in <p>[]z<a href="about:blank">abc</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting last character of a link (Backspace) in <p><a href="about:blank">abcd[]</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting last character of a link (execCommand("delete")) in <p><a href="about:blank">abcd[]</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting last character of a link (Delete) in <p><a href="about:blank">abc[]d</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting last character of a link (execCommand("forwarddelete")) in <p><a href="about:blank">abc[]d</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting first character of a link (Backspace) in <p><a href="about:blank">z[]abc</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting first character of a link (execCommand("delete")) in <p><a href="about:blank">z[]abc</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting first character of a link (Delete) in <p><a href="about:blank">[]zabc</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting first character of a link (execCommand("forwarddelete")) in <p><a href="about:blank">[]zabc</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" +FAIL Replacing text in a link with "XY" in <p>[abc]</p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after making a link (following Selection.collapseToEnd) in <p>[abc]</p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after making a link (following ArrowRight key press) in <p>[abc]</p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after making a link (following End key press) in <p>[abc]</p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after making a link (following Selection.collapseToStart) in <p>[abc]</p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after making a link (following ArrowLeft key press) in <p>[abc]</p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after making a link (following Home key press) in <p>[abc]</p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after setting caret position to middle of a link (Selection.collapse) in <p><a href="about:blank">[]abc</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after setting caret position to middle of a link (Selection.addRange) in <p><a href="about:blank">[]abc</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after setting caret position to start of a link (Selection.collapse) in <p><a href="about:blank">ab[]c</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after setting caret position to start of a link (Selection.addRange) in <p><a href="about:blank">ab[]c</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after setting caret position to end of a link (Selection.collapse) in <p><a href="about:blank">ab[]c</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after setting caret position to end of a link (Selection.addRange) in <p><a href="about:blank">ab[]c</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after modifying caret position to middle of a link in <p><a href="about:blank">[]abc</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after modifying caret position to start of a link in <p><a href="about:blank">ab[]c</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after modifying caret position to end of a link in <p><a href="about:blank">ab[]c</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting following character of a link (Backspace) in <p><a href="about:blank">abc</a>d[]</p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting following character of a link (execCommand("delete")) in <p><a href="about:blank">abc</a>d[]</p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting a previous character of a link (Delete) in <p>[]z<a href="about:blank">abc</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting a previous character of a link (execCommand("forwarddelete")) in <p>[]z<a href="about:blank">abc</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting last character of a link (Backspace) in <p><a href="about:blank">abcd[]</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting last character of a link (execCommand("delete")) in <p><a href="about:blank">abcd[]</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting last character of a link (Delete) in <p><a href="about:blank">abc[]d</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting last character of a link (execCommand("forwarddelete")) in <p><a href="about:blank">abc[]d</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting first character of a link (Backspace) in <p><a href="about:blank">z[]abc</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting first character of a link (execCommand("delete")) in <p><a href="about:blank">z[]abc</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting first character of a link (Delete) in <p><a href="about:blank">[]zabc</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting first character of a link (execCommand("forwarddelete")) in <p><a href="about:blank">[]zabc</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/editing/other/typing-around-link-element-at-collapsed-selection.tentative_target=DesignMode_child=b-expected.txt b/third_party/blink/web_tests/external/wpt/editing/other/typing-around-link-element-at-collapsed-selection.tentative_target=DesignMode_child=b-expected.txt index 6af2bc6..3506214 100644 --- a/third_party/blink/web_tests/external/wpt/editing/other/typing-around-link-element-at-collapsed-selection.tentative_target=DesignMode_child=b-expected.txt +++ b/third_party/blink/web_tests/external/wpt/editing/other/typing-around-link-element-at-collapsed-selection.tentative_target=DesignMode_child=b-expected.txt
@@ -1,25 +1,25 @@ This is a testharness.js-based test. PASS Testing inserting content around link element -FAIL Inserting "XY" after setting caret position to middle of a link containing <b> (Selection.collapse) in <p><a href="about:blank"><b>[]abc</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after setting caret position to middle of a link containing <b> (Selection.addRange) in <p><a href="about:blank"><b>[]abc</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after setting caret position to start of a link containing <b> (Selection.collapse) in <p><a href="about:blank"><b>ab[]c</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after setting caret position to start of a link containing <b> (Selection.addRange) in <p><a href="about:blank"><b>ab[]c</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after setting caret position to end of a link containing <b> (Selection.collapse) in <p><a href="about:blank"><b>ab[]c</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after setting caret position to end of a link containing <b> (Selection.addRange) in <p><a href="about:blank"><b>ab[]c</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after modifying caret position to middle of a link containing <b> in <p><a href="about:blank"><b>[]abc</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after modifying caret position to start of a link containing <b> in <p><a href="about:blank"><b>ab[]c</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after modifying caret position to end of a link containing <b> in <p><a href="about:blank"><b>ab[]c</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting following character of a link containing <b> (Backspace) in <p><a href="about:blank"><b>abc</b></a>d[]</p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting following character of a link containing <b> (execCommand("delete")) in <p><a href="about:blank"><b>abc</b></a>d[]</p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting a previous character of a link containing <b> (Delete) in <p>[]z<a href="about:blank"><b>abc</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting a previous character of a link containing <b> (execCommand("forwarddelete")) in <p>[]z<a href="about:blank"><b>abc</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting last character of a link containing <b> (Backspace) in <p><a href="about:blank"><b>abcd[]</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting last character of a link containing <b> (execCommand("delete")) in <p><a href="about:blank"><b>abcd[]</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting last character of a link containing <b> (Delete) in <p><a href="about:blank"><b>abc[]d</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting last character of a link containing <b> (execCommand("forwarddelete")) in <p><a href="about:blank"><b>abc[]d</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting first character of a link containing <b> (Backspace) in <p><a href="about:blank"><b>z[]abc</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting first character of a link containing <b> (execCommand("delete")) in <p><a href="about:blank"><b>z[]abc</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting first character of a link containing <b> (Delete) in <p><a href="about:blank"><b>[]zabc</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting first character of a link containing <b> (execCommand("forwarddelete")) in <p><a href="about:blank"><b>[]zabc</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" +FAIL Inserting "XY" after setting caret position to middle of a link containing <b> (Selection.collapse) in <p><a href="about:blank"><b>[]abc</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after setting caret position to middle of a link containing <b> (Selection.addRange) in <p><a href="about:blank"><b>[]abc</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after setting caret position to start of a link containing <b> (Selection.collapse) in <p><a href="about:blank"><b>ab[]c</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after setting caret position to start of a link containing <b> (Selection.addRange) in <p><a href="about:blank"><b>ab[]c</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after setting caret position to end of a link containing <b> (Selection.collapse) in <p><a href="about:blank"><b>ab[]c</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after setting caret position to end of a link containing <b> (Selection.addRange) in <p><a href="about:blank"><b>ab[]c</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after modifying caret position to middle of a link containing <b> in <p><a href="about:blank"><b>[]abc</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after modifying caret position to start of a link containing <b> in <p><a href="about:blank"><b>ab[]c</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after modifying caret position to end of a link containing <b> in <p><a href="about:blank"><b>ab[]c</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting following character of a link containing <b> (Backspace) in <p><a href="about:blank"><b>abc</b></a>d[]</p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting following character of a link containing <b> (execCommand("delete")) in <p><a href="about:blank"><b>abc</b></a>d[]</p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting a previous character of a link containing <b> (Delete) in <p>[]z<a href="about:blank"><b>abc</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting a previous character of a link containing <b> (execCommand("forwarddelete")) in <p>[]z<a href="about:blank"><b>abc</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting last character of a link containing <b> (Backspace) in <p><a href="about:blank"><b>abcd[]</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting last character of a link containing <b> (execCommand("delete")) in <p><a href="about:blank"><b>abcd[]</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting last character of a link containing <b> (Delete) in <p><a href="about:blank"><b>abc[]d</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting last character of a link containing <b> (execCommand("forwarddelete")) in <p><a href="about:blank"><b>abc[]d</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting first character of a link containing <b> (Backspace) in <p><a href="about:blank"><b>z[]abc</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting first character of a link containing <b> (execCommand("delete")) in <p><a href="about:blank"><b>z[]abc</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting first character of a link containing <b> (Delete) in <p><a href="about:blank"><b>[]zabc</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting first character of a link containing <b> (execCommand("forwarddelete")) in <p><a href="about:blank"><b>[]zabc</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/editing/other/typing-around-link-element-at-collapsed-selection.tentative_target=DesignMode_parent=b-expected.txt b/third_party/blink/web_tests/external/wpt/editing/other/typing-around-link-element-at-collapsed-selection.tentative_target=DesignMode_parent=b-expected.txt index f51ea12..4075ee2 100644 --- a/third_party/blink/web_tests/external/wpt/editing/other/typing-around-link-element-at-collapsed-selection.tentative_target=DesignMode_parent=b-expected.txt +++ b/third_party/blink/web_tests/external/wpt/editing/other/typing-around-link-element-at-collapsed-selection.tentative_target=DesignMode_parent=b-expected.txt
@@ -1,32 +1,32 @@ This is a testharness.js-based test. PASS Testing inserting content around link element -FAIL Replacing text in a link in <b> with "XY" in <p><b>[abc]</b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after making a link in <b> (following Selection.collapseToEnd) in <p><b>[abc]</b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after making a link in <b> (following ArrowRight key press) in <p><b>[abc]</b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after making a link in <b> (following End key press) in <p><b>[abc]</b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after making a link in <b> (following Selection.collapseToStart) in <p><b>[abc]</b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after making a link in <b> (following ArrowLeft key press) in <p><b>[abc]</b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after making a link in <b> (following Home key press) in <p><b>[abc]</b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after setting caret position to middle of a link in <b> (Selection.collapse) in <p><b><a href="about:blank">[]abc</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after setting caret position to middle of a link in <b> (Selection.addRange) in <p><b><a href="about:blank">[]abc</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after setting caret position to start of a link in <b> (Selection.collapse) in <p><b><a href="about:blank">ab[]c</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after setting caret position to start of a link in <b> (Selection.addRange) in <p><b><a href="about:blank">ab[]c</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after setting caret position to end of a link in <b> (Selection.collapse) in <p><b><a href="about:blank">ab[]c</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after setting caret position to end of a link in <b> (Selection.addRange) in <p><b><a href="about:blank">ab[]c</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after modifying caret position to middle of a link in <b> in <p><b><a href="about:blank">[]abc</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after modifying caret position to start of a link in <b> in <p><b><a href="about:blank">ab[]c</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after modifying caret position to end of a link in <b> in <p><b><a href="about:blank">ab[]c</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting following character of a link in <b> (Backspace) in <p><b><a href="about:blank">abc</a>d[]</b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting following character of a link in <b> (execCommand("delete")) in <p><b><a href="about:blank">abc</a>d[]</b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting a previous character of a link in <b> (Delete) in <p><b>[]z<a href="about:blank">abc</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting a previous character of a link in <b> (execCommand("forwarddelete")) in <p><b>[]z<a href="about:blank">abc</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting last character of a link in <b> (Backspace) in <p><b><a href="about:blank">abcd[]</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting last character of a link in <b> (execCommand("delete")) in <p><b><a href="about:blank">abcd[]</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting last character of a link in <b> (Delete) in <p><b><a href="about:blank">abc[]d</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting last character of a link in <b> (execCommand("forwarddelete")) in <p><b><a href="about:blank">abc[]d</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting first character of a link in <b> (Backspace) in <p><b><a href="about:blank">z[]abc</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting first character of a link in <b> (execCommand("delete")) in <p><b><a href="about:blank">z[]abc</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting first character of a link in <b> (Delete) in <p><b><a href="about:blank">[]zabc</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting first character of a link in <b> (execCommand("forwarddelete")) in <p><b><a href="about:blank">[]zabc</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" +FAIL Replacing text in a link in <b> with "XY" in <p><b>[abc]</b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after making a link in <b> (following Selection.collapseToEnd) in <p><b>[abc]</b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after making a link in <b> (following ArrowRight key press) in <p><b>[abc]</b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after making a link in <b> (following End key press) in <p><b>[abc]</b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after making a link in <b> (following Selection.collapseToStart) in <p><b>[abc]</b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after making a link in <b> (following ArrowLeft key press) in <p><b>[abc]</b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after making a link in <b> (following Home key press) in <p><b>[abc]</b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after setting caret position to middle of a link in <b> (Selection.collapse) in <p><b><a href="about:blank">[]abc</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after setting caret position to middle of a link in <b> (Selection.addRange) in <p><b><a href="about:blank">[]abc</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after setting caret position to start of a link in <b> (Selection.collapse) in <p><b><a href="about:blank">ab[]c</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after setting caret position to start of a link in <b> (Selection.addRange) in <p><b><a href="about:blank">ab[]c</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after setting caret position to end of a link in <b> (Selection.collapse) in <p><b><a href="about:blank">ab[]c</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after setting caret position to end of a link in <b> (Selection.addRange) in <p><b><a href="about:blank">ab[]c</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after modifying caret position to middle of a link in <b> in <p><b><a href="about:blank">[]abc</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after modifying caret position to start of a link in <b> in <p><b><a href="about:blank">ab[]c</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after modifying caret position to end of a link in <b> in <p><b><a href="about:blank">ab[]c</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting following character of a link in <b> (Backspace) in <p><b><a href="about:blank">abc</a>d[]</b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting following character of a link in <b> (execCommand("delete")) in <p><b><a href="about:blank">abc</a>d[]</b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting a previous character of a link in <b> (Delete) in <p><b>[]z<a href="about:blank">abc</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting a previous character of a link in <b> (execCommand("forwarddelete")) in <p><b>[]z<a href="about:blank">abc</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting last character of a link in <b> (Backspace) in <p><b><a href="about:blank">abcd[]</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting last character of a link in <b> (execCommand("delete")) in <p><b><a href="about:blank">abcd[]</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting last character of a link in <b> (Delete) in <p><b><a href="about:blank">abc[]d</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting last character of a link in <b> (execCommand("forwarddelete")) in <p><b><a href="about:blank">abc[]d</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting first character of a link in <b> (Backspace) in <p><b><a href="about:blank">z[]abc</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting first character of a link in <b> (execCommand("delete")) in <p><b><a href="about:blank">z[]abc</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting first character of a link in <b> (Delete) in <p><b><a href="about:blank">[]zabc</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting first character of a link in <b> (execCommand("forwarddelete")) in <p><b><a href="about:blank">[]zabc</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/editing/other/typing-around-link-element-at-collapsed-selection.tentative_target=DesignMode_parent=b_child=i-expected.txt b/third_party/blink/web_tests/external/wpt/editing/other/typing-around-link-element-at-collapsed-selection.tentative_target=DesignMode_parent=b_child=i-expected.txt index e8d3431..f717a62 100644 --- a/third_party/blink/web_tests/external/wpt/editing/other/typing-around-link-element-at-collapsed-selection.tentative_target=DesignMode_parent=b_child=i-expected.txt +++ b/third_party/blink/web_tests/external/wpt/editing/other/typing-around-link-element-at-collapsed-selection.tentative_target=DesignMode_parent=b_child=i-expected.txt
@@ -1,25 +1,25 @@ This is a testharness.js-based test. PASS Testing inserting content around link element -FAIL Inserting "XY" after setting caret position to middle of a link in <b> and containing <i> (Selection.collapse) in <p><b><a href="about:blank"><i>[]abc</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after setting caret position to middle of a link in <b> and containing <i> (Selection.addRange) in <p><b><a href="about:blank"><i>[]abc</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after setting caret position to start of a link in <b> and containing <i> (Selection.collapse) in <p><b><a href="about:blank"><i>ab[]c</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after setting caret position to start of a link in <b> and containing <i> (Selection.addRange) in <p><b><a href="about:blank"><i>ab[]c</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after setting caret position to end of a link in <b> and containing <i> (Selection.collapse) in <p><b><a href="about:blank"><i>ab[]c</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after setting caret position to end of a link in <b> and containing <i> (Selection.addRange) in <p><b><a href="about:blank"><i>ab[]c</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after modifying caret position to middle of a link in <b> and containing <i> in <p><b><a href="about:blank"><i>[]abc</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after modifying caret position to start of a link in <b> and containing <i> in <p><b><a href="about:blank"><i>ab[]c</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after modifying caret position to end of a link in <b> and containing <i> in <p><b><a href="about:blank"><i>ab[]c</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting following character of a link in <b> and containing <i> (Backspace) in <p><b><a href="about:blank"><i>abc</i></a>d[]</b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting following character of a link in <b> and containing <i> (execCommand("delete")) in <p><b><a href="about:blank"><i>abc</i></a>d[]</b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting a previous character of a link in <b> and containing <i> (Delete) in <p><b>[]z<a href="about:blank"><i>abc</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting a previous character of a link in <b> and containing <i> (execCommand("forwarddelete")) in <p><b>[]z<a href="about:blank"><i>abc</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting last character of a link in <b> and containing <i> (Backspace) in <p><b><a href="about:blank"><i>abcd[]</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting last character of a link in <b> and containing <i> (execCommand("delete")) in <p><b><a href="about:blank"><i>abcd[]</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting last character of a link in <b> and containing <i> (Delete) in <p><b><a href="about:blank"><i>abc[]d</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting last character of a link in <b> and containing <i> (execCommand("forwarddelete")) in <p><b><a href="about:blank"><i>abc[]d</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting first character of a link in <b> and containing <i> (Backspace) in <p><b><a href="about:blank"><i>z[]abc</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting first character of a link in <b> and containing <i> (execCommand("delete")) in <p><b><a href="about:blank"><i>z[]abc</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting first character of a link in <b> and containing <i> (Delete) in <p><b><a href="about:blank"><i>[]zabc</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting first character of a link in <b> and containing <i> (execCommand("forwarddelete")) in <p><b><a href="about:blank"><i>[]zabc</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" +FAIL Inserting "XY" after setting caret position to middle of a link in <b> and containing <i> (Selection.collapse) in <p><b><a href="about:blank"><i>[]abc</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after setting caret position to middle of a link in <b> and containing <i> (Selection.addRange) in <p><b><a href="about:blank"><i>[]abc</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after setting caret position to start of a link in <b> and containing <i> (Selection.collapse) in <p><b><a href="about:blank"><i>ab[]c</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after setting caret position to start of a link in <b> and containing <i> (Selection.addRange) in <p><b><a href="about:blank"><i>ab[]c</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after setting caret position to end of a link in <b> and containing <i> (Selection.collapse) in <p><b><a href="about:blank"><i>ab[]c</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after setting caret position to end of a link in <b> and containing <i> (Selection.addRange) in <p><b><a href="about:blank"><i>ab[]c</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after modifying caret position to middle of a link in <b> and containing <i> in <p><b><a href="about:blank"><i>[]abc</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after modifying caret position to start of a link in <b> and containing <i> in <p><b><a href="about:blank"><i>ab[]c</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after modifying caret position to end of a link in <b> and containing <i> in <p><b><a href="about:blank"><i>ab[]c</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting following character of a link in <b> and containing <i> (Backspace) in <p><b><a href="about:blank"><i>abc</i></a>d[]</b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting following character of a link in <b> and containing <i> (execCommand("delete")) in <p><b><a href="about:blank"><i>abc</i></a>d[]</b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting a previous character of a link in <b> and containing <i> (Delete) in <p><b>[]z<a href="about:blank"><i>abc</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting a previous character of a link in <b> and containing <i> (execCommand("forwarddelete")) in <p><b>[]z<a href="about:blank"><i>abc</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting last character of a link in <b> and containing <i> (Backspace) in <p><b><a href="about:blank"><i>abcd[]</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting last character of a link in <b> and containing <i> (execCommand("delete")) in <p><b><a href="about:blank"><i>abcd[]</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting last character of a link in <b> and containing <i> (Delete) in <p><b><a href="about:blank"><i>abc[]d</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting last character of a link in <b> and containing <i> (execCommand("forwarddelete")) in <p><b><a href="about:blank"><i>abc[]d</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting first character of a link in <b> and containing <i> (Backspace) in <p><b><a href="about:blank"><i>z[]abc</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting first character of a link in <b> and containing <i> (execCommand("delete")) in <p><b><a href="about:blank"><i>z[]abc</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting first character of a link in <b> and containing <i> (Delete) in <p><b><a href="about:blank"><i>[]zabc</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting first character of a link in <b> and containing <i> (execCommand("forwarddelete")) in <p><b><a href="about:blank"><i>[]zabc</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/editing/other/typing-around-link-element-at-non-collapsed-selection.tentative_target=DesignMode-expected.txt b/third_party/blink/web_tests/external/wpt/editing/other/typing-around-link-element-at-non-collapsed-selection.tentative_target=DesignMode-expected.txt index fb4c861..2774722 100644 --- a/third_party/blink/web_tests/external/wpt/editing/other/typing-around-link-element-at-non-collapsed-selection.tentative_target=DesignMode-expected.txt +++ b/third_party/blink/web_tests/external/wpt/editing/other/typing-around-link-element-at-non-collapsed-selection.tentative_target=DesignMode-expected.txt
@@ -1,34 +1,34 @@ This is a testharness.js-based test. PASS Testing inserting content at non-collapsed selection around link element -FAIL Inserting "XY" after deleting first character of a link (Direct typing) in <p><a href="about:blank">[z]abc</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link (Direct typing) in <p><a href="about:blank">abc[d]</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text after middle of a link (Direct typing) in <p><a href="about:blank">ab[cd</a>de]f</p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text before middle of a link (Direct typing) in <p>a[bc<a href="about:blank">de]f</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text between 2 same links (Direct typing) in <p><a href="about:blank">a[bc</a><a href="about:blank">de]f</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text between 2 different links (Direct typing) in <p><a href="about:blank">a[bc</a><a href="http://example.com/">de]f</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting first character of a link (Backspace) in <p><a href="about:blank">[z]abc</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link (Backspace) in <p><a href="about:blank">abc[d]</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text after middle of a link (Backspace) in <p><a href="about:blank">ab[cd</a>de]f</p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text before middle of a link (Backspace) in <p>a[bc<a href="about:blank">de]f</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text between 2 same links (Backspace) in <p><a href="about:blank">a[bc</a><a href="about:blank">de]f</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text between 2 different links (Backspace) in <p><a href="about:blank">a[bc</a><a href="http://example.com/">de]f</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting first character of a link (Delete) in <p><a href="about:blank">[z]abc</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link (Delete) in <p><a href="about:blank">abc[d]</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text after middle of a link (Delete) in <p><a href="about:blank">ab[cd</a>de]f</p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text before middle of a link (Delete) in <p>a[bc<a href="about:blank">de]f</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text between 2 same links (Delete) in <p><a href="about:blank">a[bc</a><a href="about:blank">de]f</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text between 2 different links (Delete) in <p><a href="about:blank">a[bc</a><a href="http://example.com/">de]f</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting first character of a link (execCommand("delete")) in <p><a href="about:blank">[z]abc</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link (execCommand("delete")) in <p><a href="about:blank">abc[d]</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text after middle of a link (execCommand("delete")) in <p><a href="about:blank">ab[cd</a>de]f</p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text before middle of a link (execCommand("delete")) in <p>a[bc<a href="about:blank">de]f</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text between 2 same links (execCommand("delete")) in <p><a href="about:blank">a[bc</a><a href="about:blank">de]f</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text between 2 different links (execCommand("delete")) in <p><a href="about:blank">a[bc</a><a href="http://example.com/">de]f</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting first character of a link (execCommand("forwarddelete")) in <p><a href="about:blank">[z]abc</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link (execCommand("forwarddelete")) in <p><a href="about:blank">abc[d]</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text after middle of a link (execCommand("forwarddelete")) in <p><a href="about:blank">ab[cd</a>de]f</p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text before middle of a link (execCommand("forwarddelete")) in <p>a[bc<a href="about:blank">de]f</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text between 2 same links (execCommand("forwarddelete")) in <p><a href="about:blank">a[bc</a><a href="about:blank">de]f</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text between 2 different links (execCommand("forwarddelete")) in <p><a href="about:blank">a[bc</a><a href="http://example.com/">de]f</a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" +FAIL Inserting "XY" after deleting first character of a link (Direct typing) in <p><a href="about:blank">[z]abc</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link (Direct typing) in <p><a href="about:blank">abc[d]</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text after middle of a link (Direct typing) in <p><a href="about:blank">ab[cd</a>de]f</p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text before middle of a link (Direct typing) in <p>a[bc<a href="about:blank">de]f</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text between 2 same links (Direct typing) in <p><a href="about:blank">a[bc</a><a href="about:blank">de]f</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text between 2 different links (Direct typing) in <p><a href="about:blank">a[bc</a><a href="http://example.com/">de]f</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting first character of a link (Backspace) in <p><a href="about:blank">[z]abc</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link (Backspace) in <p><a href="about:blank">abc[d]</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text after middle of a link (Backspace) in <p><a href="about:blank">ab[cd</a>de]f</p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text before middle of a link (Backspace) in <p>a[bc<a href="about:blank">de]f</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text between 2 same links (Backspace) in <p><a href="about:blank">a[bc</a><a href="about:blank">de]f</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text between 2 different links (Backspace) in <p><a href="about:blank">a[bc</a><a href="http://example.com/">de]f</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting first character of a link (Delete) in <p><a href="about:blank">[z]abc</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link (Delete) in <p><a href="about:blank">abc[d]</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text after middle of a link (Delete) in <p><a href="about:blank">ab[cd</a>de]f</p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text before middle of a link (Delete) in <p>a[bc<a href="about:blank">de]f</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text between 2 same links (Delete) in <p><a href="about:blank">a[bc</a><a href="about:blank">de]f</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text between 2 different links (Delete) in <p><a href="about:blank">a[bc</a><a href="http://example.com/">de]f</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting first character of a link (execCommand("delete")) in <p><a href="about:blank">[z]abc</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link (execCommand("delete")) in <p><a href="about:blank">abc[d]</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text after middle of a link (execCommand("delete")) in <p><a href="about:blank">ab[cd</a>de]f</p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text before middle of a link (execCommand("delete")) in <p>a[bc<a href="about:blank">de]f</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text between 2 same links (execCommand("delete")) in <p><a href="about:blank">a[bc</a><a href="about:blank">de]f</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text between 2 different links (execCommand("delete")) in <p><a href="about:blank">a[bc</a><a href="http://example.com/">de]f</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting first character of a link (execCommand("forwarddelete")) in <p><a href="about:blank">[z]abc</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link (execCommand("forwarddelete")) in <p><a href="about:blank">abc[d]</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text after middle of a link (execCommand("forwarddelete")) in <p><a href="about:blank">ab[cd</a>de]f</p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text before middle of a link (execCommand("forwarddelete")) in <p>a[bc<a href="about:blank">de]f</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text between 2 same links (execCommand("forwarddelete")) in <p><a href="about:blank">a[bc</a><a href="about:blank">de]f</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text between 2 different links (execCommand("forwarddelete")) in <p><a href="about:blank">a[bc</a><a href="http://example.com/">de]f</a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/editing/other/typing-around-link-element-at-non-collapsed-selection.tentative_target=DesignMode_child=b-expected.txt b/third_party/blink/web_tests/external/wpt/editing/other/typing-around-link-element-at-non-collapsed-selection.tentative_target=DesignMode_child=b-expected.txt index 2584e79..7a6fc54 100644 --- a/third_party/blink/web_tests/external/wpt/editing/other/typing-around-link-element-at-non-collapsed-selection.tentative_target=DesignMode_child=b-expected.txt +++ b/third_party/blink/web_tests/external/wpt/editing/other/typing-around-link-element-at-non-collapsed-selection.tentative_target=DesignMode_child=b-expected.txt
@@ -1,24 +1,24 @@ This is a testharness.js-based test. PASS Testing inserting content at non-collapsed selection around link element -FAIL Inserting "XY" after deleting first character of a link containing <b> (Direct typing) in <p><a href="about:blank"><b>[z]abc</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link containing <b> (Direct typing) in <p><a href="about:blank"><b>abc[d]</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text after middle of a link containing <b> (Direct typing) in <p><a href="about:blank"><b>ab[cd</b></a>de]f</p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text before middle of a link containing <b> (Direct typing) in <p>a[bc<a href="about:blank"><b>de]f</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting first character of a link containing <b> (Backspace) in <p><a href="about:blank"><b>[z]abc</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link containing <b> (Backspace) in <p><a href="about:blank"><b>abc[d]</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text after middle of a link containing <b> (Backspace) in <p><a href="about:blank"><b>ab[cd</b></a>de]f</p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text before middle of a link containing <b> (Backspace) in <p>a[bc<a href="about:blank"><b>de]f</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting first character of a link containing <b> (Delete) in <p><a href="about:blank"><b>[z]abc</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link containing <b> (Delete) in <p><a href="about:blank"><b>abc[d]</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text after middle of a link containing <b> (Delete) in <p><a href="about:blank"><b>ab[cd</b></a>de]f</p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text before middle of a link containing <b> (Delete) in <p>a[bc<a href="about:blank"><b>de]f</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting first character of a link containing <b> (execCommand("delete")) in <p><a href="about:blank"><b>[z]abc</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link containing <b> (execCommand("delete")) in <p><a href="about:blank"><b>abc[d]</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text after middle of a link containing <b> (execCommand("delete")) in <p><a href="about:blank"><b>ab[cd</b></a>de]f</p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text before middle of a link containing <b> (execCommand("delete")) in <p>a[bc<a href="about:blank"><b>de]f</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting first character of a link containing <b> (execCommand("forwarddelete")) in <p><a href="about:blank"><b>[z]abc</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link containing <b> (execCommand("forwarddelete")) in <p><a href="about:blank"><b>abc[d]</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text after middle of a link containing <b> (execCommand("forwarddelete")) in <p><a href="about:blank"><b>ab[cd</b></a>de]f</p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text before middle of a link containing <b> (execCommand("forwarddelete")) in <p>a[bc<a href="about:blank"><b>de]f</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" +FAIL Inserting "XY" after deleting first character of a link containing <b> (Direct typing) in <p><a href="about:blank"><b>[z]abc</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link containing <b> (Direct typing) in <p><a href="about:blank"><b>abc[d]</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text after middle of a link containing <b> (Direct typing) in <p><a href="about:blank"><b>ab[cd</b></a>de]f</p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text before middle of a link containing <b> (Direct typing) in <p>a[bc<a href="about:blank"><b>de]f</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting first character of a link containing <b> (Backspace) in <p><a href="about:blank"><b>[z]abc</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link containing <b> (Backspace) in <p><a href="about:blank"><b>abc[d]</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text after middle of a link containing <b> (Backspace) in <p><a href="about:blank"><b>ab[cd</b></a>de]f</p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text before middle of a link containing <b> (Backspace) in <p>a[bc<a href="about:blank"><b>de]f</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting first character of a link containing <b> (Delete) in <p><a href="about:blank"><b>[z]abc</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link containing <b> (Delete) in <p><a href="about:blank"><b>abc[d]</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text after middle of a link containing <b> (Delete) in <p><a href="about:blank"><b>ab[cd</b></a>de]f</p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text before middle of a link containing <b> (Delete) in <p>a[bc<a href="about:blank"><b>de]f</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting first character of a link containing <b> (execCommand("delete")) in <p><a href="about:blank"><b>[z]abc</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link containing <b> (execCommand("delete")) in <p><a href="about:blank"><b>abc[d]</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text after middle of a link containing <b> (execCommand("delete")) in <p><a href="about:blank"><b>ab[cd</b></a>de]f</p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text before middle of a link containing <b> (execCommand("delete")) in <p>a[bc<a href="about:blank"><b>de]f</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting first character of a link containing <b> (execCommand("forwarddelete")) in <p><a href="about:blank"><b>[z]abc</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link containing <b> (execCommand("forwarddelete")) in <p><a href="about:blank"><b>abc[d]</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text after middle of a link containing <b> (execCommand("forwarddelete")) in <p><a href="about:blank"><b>ab[cd</b></a>de]f</p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text before middle of a link containing <b> (execCommand("forwarddelete")) in <p>a[bc<a href="about:blank"><b>de]f</b></a></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/editing/other/typing-around-link-element-at-non-collapsed-selection.tentative_target=DesignMode_parent=b-expected.txt b/third_party/blink/web_tests/external/wpt/editing/other/typing-around-link-element-at-non-collapsed-selection.tentative_target=DesignMode_parent=b-expected.txt index 739ba50..9b425c4 100644 --- a/third_party/blink/web_tests/external/wpt/editing/other/typing-around-link-element-at-non-collapsed-selection.tentative_target=DesignMode_parent=b-expected.txt +++ b/third_party/blink/web_tests/external/wpt/editing/other/typing-around-link-element-at-non-collapsed-selection.tentative_target=DesignMode_parent=b-expected.txt
@@ -1,24 +1,24 @@ This is a testharness.js-based test. PASS Testing inserting content at non-collapsed selection around link element -FAIL Inserting "XY" after deleting first character of a link in <b> (Direct typing) in <p><b><a href="about:blank">[z]abc</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link in <b> (Direct typing) in <p><b><a href="about:blank">abc[d]</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text after middle of a link in <b> (Direct typing) in <p><b><a href="about:blank">ab[cd</a>de]f</b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text before middle of a link in <b> (Direct typing) in <p><b>a[bc<a href="about:blank">de]f</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting first character of a link in <b> (Backspace) in <p><b><a href="about:blank">[z]abc</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link in <b> (Backspace) in <p><b><a href="about:blank">abc[d]</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text after middle of a link in <b> (Backspace) in <p><b><a href="about:blank">ab[cd</a>de]f</b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text before middle of a link in <b> (Backspace) in <p><b>a[bc<a href="about:blank">de]f</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting first character of a link in <b> (Delete) in <p><b><a href="about:blank">[z]abc</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link in <b> (Delete) in <p><b><a href="about:blank">abc[d]</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text after middle of a link in <b> (Delete) in <p><b><a href="about:blank">ab[cd</a>de]f</b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text before middle of a link in <b> (Delete) in <p><b>a[bc<a href="about:blank">de]f</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting first character of a link in <b> (execCommand("delete")) in <p><b><a href="about:blank">[z]abc</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link in <b> (execCommand("delete")) in <p><b><a href="about:blank">abc[d]</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text after middle of a link in <b> (execCommand("delete")) in <p><b><a href="about:blank">ab[cd</a>de]f</b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text before middle of a link in <b> (execCommand("delete")) in <p><b>a[bc<a href="about:blank">de]f</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting first character of a link in <b> (execCommand("forwarddelete")) in <p><b><a href="about:blank">[z]abc</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link in <b> (execCommand("forwarddelete")) in <p><b><a href="about:blank">abc[d]</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text after middle of a link in <b> (execCommand("forwarddelete")) in <p><b><a href="about:blank">ab[cd</a>de]f</b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text before middle of a link in <b> (execCommand("forwarddelete")) in <p><b>a[bc<a href="about:blank">de]f</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" +FAIL Inserting "XY" after deleting first character of a link in <b> (Direct typing) in <p><b><a href="about:blank">[z]abc</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link in <b> (Direct typing) in <p><b><a href="about:blank">abc[d]</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text after middle of a link in <b> (Direct typing) in <p><b><a href="about:blank">ab[cd</a>de]f</b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text before middle of a link in <b> (Direct typing) in <p><b>a[bc<a href="about:blank">de]f</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting first character of a link in <b> (Backspace) in <p><b><a href="about:blank">[z]abc</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link in <b> (Backspace) in <p><b><a href="about:blank">abc[d]</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text after middle of a link in <b> (Backspace) in <p><b><a href="about:blank">ab[cd</a>de]f</b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text before middle of a link in <b> (Backspace) in <p><b>a[bc<a href="about:blank">de]f</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting first character of a link in <b> (Delete) in <p><b><a href="about:blank">[z]abc</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link in <b> (Delete) in <p><b><a href="about:blank">abc[d]</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text after middle of a link in <b> (Delete) in <p><b><a href="about:blank">ab[cd</a>de]f</b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text before middle of a link in <b> (Delete) in <p><b>a[bc<a href="about:blank">de]f</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting first character of a link in <b> (execCommand("delete")) in <p><b><a href="about:blank">[z]abc</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link in <b> (execCommand("delete")) in <p><b><a href="about:blank">abc[d]</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text after middle of a link in <b> (execCommand("delete")) in <p><b><a href="about:blank">ab[cd</a>de]f</b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text before middle of a link in <b> (execCommand("delete")) in <p><b>a[bc<a href="about:blank">de]f</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting first character of a link in <b> (execCommand("forwarddelete")) in <p><b><a href="about:blank">[z]abc</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link in <b> (execCommand("forwarddelete")) in <p><b><a href="about:blank">abc[d]</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text after middle of a link in <b> (execCommand("forwarddelete")) in <p><b><a href="about:blank">ab[cd</a>de]f</b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text before middle of a link in <b> (execCommand("forwarddelete")) in <p><b>a[bc<a href="about:blank">de]f</a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/editing/other/typing-around-link-element-at-non-collapsed-selection.tentative_target=DesignMode_parent=b_child=i-expected.txt b/third_party/blink/web_tests/external/wpt/editing/other/typing-around-link-element-at-non-collapsed-selection.tentative_target=DesignMode_parent=b_child=i-expected.txt index 9d0b49b..2cd75e3 100644 --- a/third_party/blink/web_tests/external/wpt/editing/other/typing-around-link-element-at-non-collapsed-selection.tentative_target=DesignMode_parent=b_child=i-expected.txt +++ b/third_party/blink/web_tests/external/wpt/editing/other/typing-around-link-element-at-non-collapsed-selection.tentative_target=DesignMode_parent=b_child=i-expected.txt
@@ -1,24 +1,24 @@ This is a testharness.js-based test. PASS Testing inserting content at non-collapsed selection around link element -FAIL Inserting "XY" after deleting first character of a link in <b> and containing <i> (Direct typing) in <p><b><a href="about:blank"><i>[z]abc</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link in <b> and containing <i> (Direct typing) in <p><b><a href="about:blank"><i>abc[d]</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text after middle of a link in <b> and containing <i> (Direct typing) in <p><b><a href="about:blank"><i>ab[cd</i></a>de]f</b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text before middle of a link in <b> and containing <i> (Direct typing) in <p><b>a[bc<a href="about:blank"><i>de]f</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting first character of a link in <b> and containing <i> (Backspace) in <p><b><a href="about:blank"><i>[z]abc</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link in <b> and containing <i> (Backspace) in <p><b><a href="about:blank"><i>abc[d]</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text after middle of a link in <b> and containing <i> (Backspace) in <p><b><a href="about:blank"><i>ab[cd</i></a>de]f</b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text before middle of a link in <b> and containing <i> (Backspace) in <p><b>a[bc<a href="about:blank"><i>de]f</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting first character of a link in <b> and containing <i> (Delete) in <p><b><a href="about:blank"><i>[z]abc</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link in <b> and containing <i> (Delete) in <p><b><a href="about:blank"><i>abc[d]</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text after middle of a link in <b> and containing <i> (Delete) in <p><b><a href="about:blank"><i>ab[cd</i></a>de]f</b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text before middle of a link in <b> and containing <i> (Delete) in <p><b>a[bc<a href="about:blank"><i>de]f</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting first character of a link in <b> and containing <i> (execCommand("delete")) in <p><b><a href="about:blank"><i>[z]abc</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link in <b> and containing <i> (execCommand("delete")) in <p><b><a href="about:blank"><i>abc[d]</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text after middle of a link in <b> and containing <i> (execCommand("delete")) in <p><b><a href="about:blank"><i>ab[cd</i></a>de]f</b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text before middle of a link in <b> and containing <i> (execCommand("delete")) in <p><b>a[bc<a href="about:blank"><i>de]f</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting first character of a link in <b> and containing <i> (execCommand("forwarddelete")) in <p><b><a href="about:blank"><i>[z]abc</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link in <b> and containing <i> (execCommand("forwarddelete")) in <p><b><a href="about:blank"><i>abc[d]</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text after middle of a link in <b> and containing <i> (execCommand("forwarddelete")) in <p><b><a href="about:blank"><i>ab[cd</i></a>de]f</b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" -FAIL Inserting "XY" after deleting text before middle of a link in <b> and containing <i> (execCommand("forwarddelete")) in <p><b>a[bc<a href="about:blank"><i>de]f</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send keys in top-level window" +FAIL Inserting "XY" after deleting first character of a link in <b> and containing <i> (Direct typing) in <p><b><a href="about:blank"><i>[z]abc</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link in <b> and containing <i> (Direct typing) in <p><b><a href="about:blank"><i>abc[d]</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text after middle of a link in <b> and containing <i> (Direct typing) in <p><b><a href="about:blank"><i>ab[cd</i></a>de]f</b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text before middle of a link in <b> and containing <i> (Direct typing) in <p><b>a[bc<a href="about:blank"><i>de]f</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting first character of a link in <b> and containing <i> (Backspace) in <p><b><a href="about:blank"><i>[z]abc</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link in <b> and containing <i> (Backspace) in <p><b><a href="about:blank"><i>abc[d]</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text after middle of a link in <b> and containing <i> (Backspace) in <p><b><a href="about:blank"><i>ab[cd</i></a>de]f</b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text before middle of a link in <b> and containing <i> (Backspace) in <p><b>a[bc<a href="about:blank"><i>de]f</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting first character of a link in <b> and containing <i> (Delete) in <p><b><a href="about:blank"><i>[z]abc</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link in <b> and containing <i> (Delete) in <p><b><a href="about:blank"><i>abc[d]</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text after middle of a link in <b> and containing <i> (Delete) in <p><b><a href="about:blank"><i>ab[cd</i></a>de]f</b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text before middle of a link in <b> and containing <i> (Delete) in <p><b>a[bc<a href="about:blank"><i>de]f</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting first character of a link in <b> and containing <i> (execCommand("delete")) in <p><b><a href="about:blank"><i>[z]abc</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link in <b> and containing <i> (execCommand("delete")) in <p><b><a href="about:blank"><i>abc[d]</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text after middle of a link in <b> and containing <i> (execCommand("delete")) in <p><b><a href="about:blank"><i>ab[cd</i></a>de]f</b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text before middle of a link in <b> and containing <i> (execCommand("delete")) in <p><b>a[bc<a href="about:blank"><i>de]f</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting first character of a link in <b> and containing <i> (execCommand("forwarddelete")) in <p><b><a href="about:blank"><i>[z]abc</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting last character in a non-collapsed range of a link in <b> and containing <i> (execCommand("forwarddelete")) in <p><b><a href="about:blank"><i>abc[d]</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text after middle of a link in <b> and containing <i> (execCommand("forwarddelete")) in <p><b><a href="about:blank"><i>ab[cd</i></a>de]f</b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" +FAIL Inserting "XY" after deleting text before middle of a link in <b> and containing <i> (execCommand("forwarddelete")) in <p><b>a[bc<a href="about:blank"><i>de]f</i></a></b></p> promise_test: Unhandled rejection with value: object "Error: can only send actions in top-level window" Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/transformations/2d.transformation.perspective.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/transformations/2d.transformation.perspective.html new file mode 100644 index 0000000..6aa4a224 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/canvas/element/transformations/2d.transformation.perspective.html
@@ -0,0 +1,34 @@ +<!DOCTYPE html> +<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. --> +<title>Canvas test: 2d.transformation.perspective</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/html/canvas/resources/canvas-tests.js"></script> +<link rel="stylesheet" href="/html/canvas/resources/canvas-tests.css"> +<body class="show_output"> + +<h1>2d.transformation.perspective</h1> +<p class="desc">perspective() results in the correct transformation matrix</p> + + +<p class="output">Actual output:</p> +<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas> + +<ul id="d"></ul> +<script> +var t = async_test("perspective() results in the correct transformation matrix"); +_addTest(function(canvas, ctx) { + +const length = 100; +ctx.perspective(length); +const domMatrix = new DOMMatrix(); +domMatrix.m34 = -1/length; +_assertMatricesApproxEqual(domMatrix, ctx.getTransform()); +ctx.rotateAxis(1, 2, 3, 4); +domMatrix.rotateAxisAngleSelf(1, 2, 3, rad2deg(4)); +_assertMatricesApproxEqual(domMatrix, ctx.getTransform()); + + +}); +</script> +
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/transformations/2d.transformation.rotate3d.X.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/transformations/2d.transformation.rotate3d.X.html index c55a9bf..42a4e3c 100644 --- a/third_party/blink/web_tests/external/wpt/html/canvas/element/transformations/2d.transformation.rotate3d.X.html +++ b/third_party/blink/web_tests/external/wpt/html/canvas/element/transformations/2d.transformation.rotate3d.X.html
@@ -24,12 +24,10 @@ const domMatrix = new DOMMatrix(); ctx.rotate3d(angle, 0, 0); domMatrix.rotateAxisAngleSelf(1, 0, 0, rad2deg(angle)); -let canvasMatrix = ctx.getTransform(); -_assertMatricesApproxEqual(domMatrix, canvasMatrix) +_assertMatricesApproxEqual(domMatrix, ctx.getTransform()) ctx.rotate3d(angle, 0, 0); domMatrix.rotateAxisAngleSelf(1, 0, 0, rad2deg(angle)); -canvasMatrix = ctx.getTransform(); -_assertMatricesApproxEqual(domMatrix, canvasMatrix) +_assertMatricesApproxEqual(domMatrix, ctx.getTransform()) });
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/transformations/2d.transformation.rotate3d.Y.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/transformations/2d.transformation.rotate3d.Y.html index 12bf507..5006769 100644 --- a/third_party/blink/web_tests/external/wpt/html/canvas/element/transformations/2d.transformation.rotate3d.Y.html +++ b/third_party/blink/web_tests/external/wpt/html/canvas/element/transformations/2d.transformation.rotate3d.Y.html
@@ -24,12 +24,10 @@ const domMatrix = new DOMMatrix(); ctx.rotate3d(0, angle, 0); domMatrix.rotateAxisAngleSelf(0, 1, 0, rad2deg(angle)); -let canvasMatrix = ctx.getTransform(); -_assertMatricesApproxEqual(domMatrix, canvasMatrix) +_assertMatricesApproxEqual(domMatrix, ctx.getTransform()) ctx.rotate3d(0, angle, 0); domMatrix.rotateAxisAngleSelf(0, 1, 0, rad2deg(angle)); -canvasMatrix = ctx.getTransform(); -_assertMatricesApproxEqual(domMatrix, canvasMatrix) +_assertMatricesApproxEqual(domMatrix, ctx.getTransform()) });
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/transformations/2d.transformation.rotate3d.Z.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/transformations/2d.transformation.rotate3d.Z.html index 8a26466..71e113d 100644 --- a/third_party/blink/web_tests/external/wpt/html/canvas/element/transformations/2d.transformation.rotate3d.Z.html +++ b/third_party/blink/web_tests/external/wpt/html/canvas/element/transformations/2d.transformation.rotate3d.Z.html
@@ -24,12 +24,10 @@ const domMatrix = new DOMMatrix(); ctx.rotate3d(0, 0, angle); domMatrix.rotateAxisAngleSelf(0, 0, 1, rad2deg(angle)); -let canvasMatrix = ctx.getTransform(); -_assertMatricesApproxEqual(domMatrix, canvasMatrix) +_assertMatricesApproxEqual(domMatrix, ctx.getTransform()) ctx.rotate3d(0, 0, angle); domMatrix.rotateAxisAngleSelf(0, 0, 1, rad2deg(angle)); -canvasMatrix = ctx.getTransform(); -_assertMatricesApproxEqual(domMatrix, canvasMatrix) +_assertMatricesApproxEqual(domMatrix, ctx.getTransform()) });
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/transformations/2d.transformation.rotate3d.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/transformations/2d.transformation.rotate3d.html index 80812bd..104e0870 100644 --- a/third_party/blink/web_tests/external/wpt/html/canvas/element/transformations/2d.transformation.rotate3d.html +++ b/third_party/blink/web_tests/external/wpt/html/canvas/element/transformations/2d.transformation.rotate3d.html
@@ -26,12 +26,10 @@ const domMatrix = new DOMMatrix(); ctx.rotate3d(angleX, angleY, angleZ); domMatrix.rotateSelf(rad2deg(angleX), rad2deg(angleY), rad2deg(angleZ)); -let canvasMatrix = ctx.getTransform(); -_assertMatricesApproxEqual(domMatrix, canvasMatrix); +_assertMatricesApproxEqual(domMatrix, ctx.getTransform()); ctx.rotate3d(angleX, angleY, angleZ); domMatrix.rotateSelf(rad2deg(angleX), rad2deg(angleY), rad2deg(angleZ)); -canvasMatrix = ctx.getTransform(); -_assertMatricesApproxEqual(domMatrix, canvasMatrix); +_assertMatricesApproxEqual(domMatrix, ctx.getTransform()); });
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/transformations/2d.transformation.rotateAxis.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/transformations/2d.transformation.rotateAxis.html index 47258df..be0785a 100644 --- a/third_party/blink/web_tests/external/wpt/html/canvas/element/transformations/2d.transformation.rotateAxis.html +++ b/third_party/blink/web_tests/external/wpt/html/canvas/element/transformations/2d.transformation.rotateAxis.html
@@ -25,12 +25,10 @@ const domMatrix = new DOMMatrix(); ctx.rotateAxis(axis.x, axis.y, axis.z, angle); domMatrix.rotateAxisAngleSelf(axis.x, axis.y, axis.z, rad2deg(angle)); -let canvasMatrix = ctx.getTransform(); -_assertMatricesApproxEqual(domMatrix, canvasMatrix); +_assertMatricesApproxEqual(domMatrix, ctx.getTransform()); ctx.rotateAxis(axis.x, axis.y, axis.z, angle); domMatrix.rotateAxisAngleSelf(axis.x, axis.y, axis.z, rad2deg(angle)); -canvasMatrix = ctx.getTransform(); -_assertMatricesApproxEqual(domMatrix, canvasMatrix); +_assertMatricesApproxEqual(domMatrix, ctx.getTransform()); });
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/element/transformations.yaml b/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/element/transformations.yaml index aa56c85..65346ca 100644 --- a/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/element/transformations.yaml +++ b/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/element/transformations.yaml
@@ -473,12 +473,10 @@ const domMatrix = new DOMMatrix(); ctx.rotate3d(angle, 0, 0); domMatrix.rotateAxisAngleSelf(1, 0, 0, rad2deg(angle)); - let canvasMatrix = ctx.getTransform(); - _assertMatricesApproxEqual(domMatrix, canvasMatrix) + _assertMatricesApproxEqual(domMatrix, ctx.getTransform()) ctx.rotate3d(angle, 0, 0); domMatrix.rotateAxisAngleSelf(1, 0, 0, rad2deg(angle)); - canvasMatrix = ctx.getTransform(); - _assertMatricesApproxEqual(domMatrix, canvasMatrix) + _assertMatricesApproxEqual(domMatrix, ctx.getTransform()) - name: 2d.transformation.rotate3d.Y desc: rotate3d() around the y axis results in the correct transformation matrix @@ -490,12 +488,10 @@ const domMatrix = new DOMMatrix(); ctx.rotate3d(0, angle, 0); domMatrix.rotateAxisAngleSelf(0, 1, 0, rad2deg(angle)); - let canvasMatrix = ctx.getTransform(); - _assertMatricesApproxEqual(domMatrix, canvasMatrix) + _assertMatricesApproxEqual(domMatrix, ctx.getTransform()) ctx.rotate3d(0, angle, 0); domMatrix.rotateAxisAngleSelf(0, 1, 0, rad2deg(angle)); - canvasMatrix = ctx.getTransform(); - _assertMatricesApproxEqual(domMatrix, canvasMatrix) + _assertMatricesApproxEqual(domMatrix, ctx.getTransform()) - name: 2d.transformation.rotate3d.Z desc: rotate3d() around the z axis results in the correct transformation matrix @@ -507,12 +503,10 @@ const domMatrix = new DOMMatrix(); ctx.rotate3d(0, 0, angle); domMatrix.rotateAxisAngleSelf(0, 0, 1, rad2deg(angle)); - let canvasMatrix = ctx.getTransform(); - _assertMatricesApproxEqual(domMatrix, canvasMatrix) + _assertMatricesApproxEqual(domMatrix, ctx.getTransform()) ctx.rotate3d(0, 0, angle); domMatrix.rotateAxisAngleSelf(0, 0, 1, rad2deg(angle)); - canvasMatrix = ctx.getTransform(); - _assertMatricesApproxEqual(domMatrix, canvasMatrix) + _assertMatricesApproxEqual(domMatrix, ctx.getTransform()) - name: 2d.transformation.rotate3d desc: rotate3d() results in the correct transformation matrix @@ -526,12 +520,10 @@ const domMatrix = new DOMMatrix(); ctx.rotate3d(angleX, angleY, angleZ); domMatrix.rotateSelf(rad2deg(angleX), rad2deg(angleY), rad2deg(angleZ)); - let canvasMatrix = ctx.getTransform(); - _assertMatricesApproxEqual(domMatrix, canvasMatrix); + _assertMatricesApproxEqual(domMatrix, ctx.getTransform()); ctx.rotate3d(angleX, angleY, angleZ); domMatrix.rotateSelf(rad2deg(angleX), rad2deg(angleY), rad2deg(angleZ)); - canvasMatrix = ctx.getTransform(); - _assertMatricesApproxEqual(domMatrix, canvasMatrix); + _assertMatricesApproxEqual(domMatrix, ctx.getTransform()); - name: 2d.transformation.rotateAxis desc: rotateAxis() results in the correct transformation matrix @@ -544,9 +536,21 @@ const domMatrix = new DOMMatrix(); ctx.rotateAxis(axis.x, axis.y, axis.z, angle); domMatrix.rotateAxisAngleSelf(axis.x, axis.y, axis.z, rad2deg(angle)); - let canvasMatrix = ctx.getTransform(); - _assertMatricesApproxEqual(domMatrix, canvasMatrix); + _assertMatricesApproxEqual(domMatrix, ctx.getTransform()); ctx.rotateAxis(axis.x, axis.y, axis.z, angle); domMatrix.rotateAxisAngleSelf(axis.x, axis.y, axis.z, rad2deg(angle)); - canvasMatrix = ctx.getTransform(); - _assertMatricesApproxEqual(domMatrix, canvasMatrix); + _assertMatricesApproxEqual(domMatrix, ctx.getTransform()); + +- name: 2d.transformation.perspective + desc: perspective() results in the correct transformation matrix + testing: + - 2d.transformation.perspective + code: | + const length = 100; + ctx.perspective(length); + const domMatrix = new DOMMatrix(); + domMatrix.m34 = -1/length; + _assertMatricesApproxEqual(domMatrix, ctx.getTransform()); + ctx.rotateAxis(1, 2, 3, 4); + domMatrix.rotateAxisAngleSelf(1, 2, 3, rad2deg(4)); + _assertMatricesApproxEqual(domMatrix, ctx.getTransform());
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-popup-element/popup-light-dismiss.tentative.html b/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-popup-element/popup-light-dismiss.tentative.html new file mode 100644 index 0000000..1781afb --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-popup-element/popup-light-dismiss.tentative.html
@@ -0,0 +1,97 @@ +<!DOCTYPE html> +<meta charset="utf-8" /> +<title>Popup light dismiss behavior</title> +<link rel="author" title="Mason Freed" href="mailto:masonfreed@chromium.org"> +<link rel=help href="https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/Popup/explainer.md"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/popup-utils.js"></script> + +<body> + + +<button id=b1 onclick='p1.show()'>Popup 1</button> +<span id=outside>Outside all popups</span> +<popup id=p1 anchor=b1> + <span id=inside1>Inside popup 1</span> + <button id=b2 onclick='p2.show()'>Popup 2</button> +</popup> +<popup id=p2 anchor=b2> + <span id=inside2>Inside popup 2</span> +</popup> + +<style> + #p1 { top:50px; } + #p2 { top:50px; left:250px; } + popup { border: 5px solid red; } +</style> + + +<script> + function clickOn(element) { + const actions = new test_driver.Actions(); + actions.pointerMove(0, 0, {origin: element}); + actions.pointerDown({button: actions.ButtonType.LEFT}); + actions.pointerUp({button: actions.ButtonType.LEFT}); + return actions.send(); + } + + function pressKey(key) { + const actions = new test_driver.Actions(); + actions.keyDown(key); + actions.keyUp(key); + return actions.send(); + } + + (async function() { + setup({ explicit_done: true }); + + const popup1 = document.querySelector('#p1'); + const popup2 = document.querySelector('#p2'); + const outside = document.querySelector('#outside'); + const inside1 = document.querySelector('#inside1'); + const inside2 = document.querySelector('#inside2'); + + assert_false(popup1.open); + popup1.show(); + assert_true(popup1.open); + await clickOn(outside); + test(t => { + assert_false(popup1.open); + },'Clicking outside a popup will dismiss the popup'); + + assert_false(popup1.open); + popup1.show(); + await clickOn(inside1); + test(t => { + assert_true(popup1.open); + popup1.hide(); + },'Clicking inside a popup does not close that popup'); + + + popup1.show(); + popup2.show(); + await clickOn(inside2); + test(t => { + assert_true(popup1.open); + assert_true(popup2.open); + popup1.hide(); + },'Clicking inside a child popup shouldn\'t close either popup'); + + assert_false(popup1.open); + assert_false(popup2.open); + popup1.show(); + popup2.show(); + await clickOn(inside1); + test(t => { + assert_true(popup1.open); + assert_false(popup2.open); + popup1.hide(); + },'Clicking inside a parent popup should close child popup'); + + done(); + })(); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/actions/actionsWithKeyPressed.html b/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/actions/actionsWithKeyPressed.html index b977f0c2..3e0795b14 100644 --- a/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/actions/actionsWithKeyPressed.html +++ b/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/actions/actionsWithKeyPressed.html
@@ -36,7 +36,7 @@ <script> let keys = []; -async_test(t => { +promise_test(async t => { let test1 = document.getElementById("test1"); let test2 = document.getElementById("test2"); document.getElementById("test1").addEventListener("click", @@ -60,8 +60,7 @@ .pointerDown() .pointerUp(); - actions.send() - .then(t.step_func_done(() => assert_array_equals(keys, [true, true, false]))) - .catch(e => t.step_func(() => assert_unreached("Actions sequence failed " + e))); + await actions.send(); + assert_array_equals(keys, [true, true, false]); }); </script>
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/cors-rfc1918.idl b/third_party/blink/web_tests/external/wpt/interfaces/cors-rfc1918.idl index 083b6c3d6..d392a679 100644 --- a/third_party/blink/web_tests/external/wpt/interfaces/cors-rfc1918.idl +++ b/third_party/blink/web_tests/external/wpt/interfaces/cors-rfc1918.idl
@@ -1,7 +1,7 @@ // GENERATED CONTENT - DO NOT EDIT // Content was automatically extracted by Reffy into webref // (https://github.com/w3c/webref) -// Source: CORS and RFC1918 (https://wicg.github.io/cors-rfc1918/) +// Source: CORS and RFC1918 (https://wicg.github.io/private-network-access/) enum AddressSpace { "local", "private", "public" };
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/js-self-profiling.idl b/third_party/blink/web_tests/external/wpt/interfaces/js-self-profiling.idl index 2c51c1c..a219999 100644 --- a/third_party/blink/web_tests/external/wpt/interfaces/js-self-profiling.idl +++ b/third_party/blink/web_tests/external/wpt/interfaces/js-self-profiling.idl
@@ -4,7 +4,7 @@ // Source: JS Self-Profiling API (https://wicg.github.io/js-self-profiling/) [Exposed=(Window,Worker)] -interface Profiler { +interface Profiler : EventTarget { readonly attribute DOMHighResTimeStamp sampleInterval; readonly attribute boolean stopped;
diff --git a/third_party/blink/web_tests/external/wpt/js-self-profiling/idlharness.https-expected.txt b/third_party/blink/web_tests/external/wpt/js-self-profiling/idlharness.https-expected.txt new file mode 100644 index 0000000..c1b7bf9 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/js-self-profiling/idlharness.https-expected.txt
@@ -0,0 +1,25 @@ +This is a testharness.js-based test. +PASS idl_test setup +PASS idl_test validation +PASS Partial interface Performance: original interface defined +PASS Partial interface Performance: valid exposure set +PASS Partial interface Performance: member names are unique +FAIL Profiler interface: existence and properties of interface object assert_equals: prototype of Profiler is not EventTarget expected function "function EventTarget() { [native code] }" but got function "function () { [native code] }" +PASS Profiler interface object length +PASS Profiler interface object name +FAIL Profiler interface: existence and properties of interface prototype object assert_equals: prototype of Profiler.prototype is not EventTarget.prototype expected object "[object EventTarget]" but got object "[object Object]" +PASS Profiler interface: existence and properties of interface prototype object's "constructor" property +PASS Profiler interface: existence and properties of interface prototype object's @@unscopables property +PASS Profiler interface: attribute sampleInterval +PASS Profiler interface: attribute stopped +PASS Profiler interface: operation stop() +PASS Profiler must be primary interface of profiler +PASS Stringification of profiler +PASS Profiler interface: profiler must inherit property "sampleInterval" with the proper type +PASS Profiler interface: profiler must inherit property "stopped" with the proper type +PASS Profiler interface: profiler must inherit property "stop()" with the proper type +PASS Performance interface: operation profile(ProfilerInitOptions) +PASS Performance interface: performance must inherit property "profile(ProfilerInitOptions)" with the proper type +PASS Performance interface: calling profile(ProfilerInitOptions) on performance with too few arguments must throw TypeError +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/compat/pointerevent_mouseevent_key_pressed-expected.txt b/third_party/blink/web_tests/external/wpt/pointerevents/compat/pointerevent_mouseevent_key_pressed-expected.txt index 3be14d3..3d8bfb8 100644 --- a/third_party/blink/web_tests/external/wpt/pointerevents/compat/pointerevent_mouseevent_key_pressed-expected.txt +++ b/third_party/blink/web_tests/external/wpt/pointerevents/compat/pointerevent_mouseevent_key_pressed-expected.txt
@@ -1,4 +1,5 @@ This is a testharness.js-based test. +Harness Error. harness_status.status = 1 , harness_status.message = Unhandled rejection: we do not support keydown and keyup actions, please use test_driver.send_keys FAIL Tests that the mouse events with some keys pressed. assert_true: Timed out waiting for pointermove expected true got false Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/idlharness.window-expected.txt b/third_party/blink/web_tests/external/wpt/pointerevents/idlharness.window-expected.txt deleted file mode 100644 index 22bb34a..0000000 --- a/third_party/blink/web_tests/external/wpt/pointerevents/idlharness.window-expected.txt +++ /dev/null
@@ -1,145 +0,0 @@ -This is a testharness.js-based test. -Found 141 tests; 135 PASS, 6 FAIL, 0 TIMEOUT, 0 NOTRUN. -PASS idl_test setup -PASS idl_test validation -PASS Partial interface Element: original interface defined -PASS Partial interface Element: member names are unique -PASS Partial interface mixin GlobalEventHandlers: original interface mixin defined -PASS Partial interface mixin GlobalEventHandlers: member names are unique -PASS Partial interface Navigator: original interface defined -PASS Partial interface Navigator: member names are unique -PASS Partial interface UIEvent: member names are unique -PASS Partial interface Document: member names are unique -PASS Partial interface mixin NavigatorID: member names are unique -PASS Partial interface Document[2]: member names are unique -PASS Partial interface Window: member names are unique -PASS Document includes GlobalEventHandlers: member names are unique -PASS Document includes DocumentAndElementEventHandlers: member names are unique -PASS Document includes NonElementParentNode: member names are unique -PASS Document includes ParentNode: member names are unique -PASS Document includes XPathEvaluatorBase: member names are unique -PASS HTMLElement includes GlobalEventHandlers: member names are unique -PASS HTMLElement includes DocumentAndElementEventHandlers: member names are unique -PASS HTMLElement includes ElementContentEditable: member names are unique -PASS HTMLElement includes HTMLOrSVGElement: member names are unique -PASS Window includes GlobalEventHandlers: member names are unique -PASS Window includes WindowEventHandlers: member names are unique -PASS Window includes WindowOrWorkerGlobalScope: member names are unique -PASS Window includes AnimationFrameProvider: member names are unique -PASS Window includes WindowSessionStorage: member names are unique -PASS Window includes WindowLocalStorage: member names are unique -PASS Navigator includes NavigatorID: member names are unique -PASS Navigator includes NavigatorLanguage: member names are unique -PASS Navigator includes NavigatorOnLine: member names are unique -PASS Navigator includes NavigatorContentUtils: member names are unique -PASS Navigator includes NavigatorCookies: member names are unique -PASS Navigator includes NavigatorPlugins: member names are unique -PASS Navigator includes NavigatorConcurrentHardware: member names are unique -PASS Element includes ParentNode: member names are unique -PASS Element includes NonDocumentTypeChildNode: member names are unique -PASS Element includes ChildNode: member names are unique -PASS Element includes Slottable: member names are unique -PASS PointerEvent interface: existence and properties of interface object -PASS PointerEvent interface object length -PASS PointerEvent interface object name -PASS PointerEvent interface: existence and properties of interface prototype object -PASS PointerEvent interface: existence and properties of interface prototype object's "constructor" property -PASS PointerEvent interface: existence and properties of interface prototype object's @@unscopables property -PASS PointerEvent interface: attribute pointerId -PASS PointerEvent interface: attribute width -PASS PointerEvent interface: attribute height -PASS PointerEvent interface: attribute pressure -PASS PointerEvent interface: attribute tangentialPressure -PASS PointerEvent interface: attribute tiltX -PASS PointerEvent interface: attribute tiltY -PASS PointerEvent interface: attribute twist -PASS PointerEvent interface: attribute altitudeAngle -PASS PointerEvent interface: attribute azimuthAngle -PASS PointerEvent interface: attribute pointerType -PASS PointerEvent interface: attribute isPrimary -PASS PointerEvent interface: operation getCoalescedEvents() -PASS PointerEvent interface: operation getPredictedEvents() -PASS PointerEvent must be primary interface of new PointerEvent("type") -PASS Stringification of new PointerEvent("type") -PASS PointerEvent interface: new PointerEvent("type") must inherit property "pointerId" with the proper type -PASS PointerEvent interface: new PointerEvent("type") must inherit property "width" with the proper type -PASS PointerEvent interface: new PointerEvent("type") must inherit property "height" with the proper type -PASS PointerEvent interface: new PointerEvent("type") must inherit property "pressure" with the proper type -PASS PointerEvent interface: new PointerEvent("type") must inherit property "tangentialPressure" with the proper type -PASS PointerEvent interface: new PointerEvent("type") must inherit property "tiltX" with the proper type -PASS PointerEvent interface: new PointerEvent("type") must inherit property "tiltY" with the proper type -PASS PointerEvent interface: new PointerEvent("type") must inherit property "twist" with the proper type -PASS PointerEvent interface: new PointerEvent("type") must inherit property "altitudeAngle" with the proper type -PASS PointerEvent interface: new PointerEvent("type") must inherit property "azimuthAngle" with the proper type -PASS PointerEvent interface: new PointerEvent("type") must inherit property "pointerType" with the proper type -PASS PointerEvent interface: new PointerEvent("type") must inherit property "isPrimary" with the proper type -PASS PointerEvent interface: new PointerEvent("type") must inherit property "getCoalescedEvents()" with the proper type -PASS PointerEvent interface: new PointerEvent("type") must inherit property "getPredictedEvents()" with the proper type -PASS HTMLElement interface: attribute ongotpointercapture -PASS HTMLElement interface: attribute onlostpointercapture -PASS HTMLElement interface: attribute onpointerdown -PASS HTMLElement interface: attribute onpointermove -PASS HTMLElement interface: attribute onpointerrawupdate -PASS HTMLElement interface: attribute onpointerup -PASS HTMLElement interface: attribute onpointercancel -PASS HTMLElement interface: attribute onpointerover -PASS HTMLElement interface: attribute onpointerout -PASS HTMLElement interface: attribute onpointerenter -PASS HTMLElement interface: attribute onpointerleave -PASS Window interface: attribute ongotpointercapture -PASS Window interface: attribute onlostpointercapture -PASS Window interface: attribute onpointerdown -PASS Window interface: attribute onpointermove -PASS Window interface: attribute onpointerrawupdate -PASS Window interface: attribute onpointerup -PASS Window interface: attribute onpointercancel -PASS Window interface: attribute onpointerover -PASS Window interface: attribute onpointerout -PASS Window interface: attribute onpointerenter -PASS Window interface: attribute onpointerleave -PASS Window interface: window must inherit property "ongotpointercapture" with the proper type -PASS Window interface: window must inherit property "onlostpointercapture" with the proper type -PASS Window interface: window must inherit property "onpointerdown" with the proper type -PASS Window interface: window must inherit property "onpointermove" with the proper type -PASS Window interface: window must inherit property "onpointerrawupdate" with the proper type -PASS Window interface: window must inherit property "onpointerup" with the proper type -PASS Window interface: window must inherit property "onpointercancel" with the proper type -PASS Window interface: window must inherit property "onpointerover" with the proper type -PASS Window interface: window must inherit property "onpointerout" with the proper type -PASS Window interface: window must inherit property "onpointerenter" with the proper type -PASS Window interface: window must inherit property "onpointerleave" with the proper type -PASS Navigator interface: attribute maxTouchPoints -PASS Navigator interface: navigator must inherit property "maxTouchPoints" with the proper type -PASS Document interface: attribute ongotpointercapture -PASS Document interface: attribute onlostpointercapture -PASS Document interface: attribute onpointerdown -PASS Document interface: attribute onpointermove -PASS Document interface: attribute onpointerrawupdate -PASS Document interface: attribute onpointerup -PASS Document interface: attribute onpointercancel -PASS Document interface: attribute onpointerover -PASS Document interface: attribute onpointerout -PASS Document interface: attribute onpointerenter -PASS Document interface: attribute onpointerleave -PASS Document interface: document must inherit property "ongotpointercapture" with the proper type -PASS Document interface: document must inherit property "onlostpointercapture" with the proper type -PASS Document interface: document must inherit property "onpointerdown" with the proper type -PASS Document interface: document must inherit property "onpointermove" with the proper type -PASS Document interface: document must inherit property "onpointerrawupdate" with the proper type -PASS Document interface: document must inherit property "onpointerup" with the proper type -PASS Document interface: document must inherit property "onpointercancel" with the proper type -PASS Document interface: document must inherit property "onpointerover" with the proper type -PASS Document interface: document must inherit property "onpointerout" with the proper type -PASS Document interface: document must inherit property "onpointerenter" with the proper type -PASS Document interface: document must inherit property "onpointerleave" with the proper type -PASS Element interface: operation setPointerCapture(long) -PASS Element interface: operation releasePointerCapture(long) -PASS Element interface: operation hasPointerCapture(long) -FAIL Element interface: document must inherit property "setPointerCapture(long)" with the proper type assert_inherits: property "setPointerCapture" not found in prototype chain -FAIL Element interface: calling setPointerCapture(long) on document with too few arguments must throw TypeError assert_inherits: property "setPointerCapture" not found in prototype chain -FAIL Element interface: document must inherit property "releasePointerCapture(long)" with the proper type assert_inherits: property "releasePointerCapture" not found in prototype chain -FAIL Element interface: calling releasePointerCapture(long) on document with too few arguments must throw TypeError assert_inherits: property "releasePointerCapture" not found in prototype chain -FAIL Element interface: document must inherit property "hasPointerCapture(long)" with the proper type assert_inherits: property "hasPointerCapture" not found in prototype chain -FAIL Element interface: calling hasPointerCapture(long) on document with too few arguments must throw TypeError assert_inherits: property "hasPointerCapture" not found in prototype chain -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/idlharness.window.js b/third_party/blink/web_tests/external/wpt/pointerevents/idlharness.window.js index b41a65f3..e6e84fa 100644 --- a/third_party/blink/web_tests/external/wpt/pointerevents/idlharness.window.js +++ b/third_party/blink/web_tests/external/wpt/pointerevents/idlharness.window.js
@@ -12,7 +12,7 @@ idl_array => { idl_array.add_objects({ Document: ['document'], - Element: ['document'], + Element: ['document.body'], Window: ['window'], Navigator: ['navigator'], PointerEvent: ['new PointerEvent("type")']
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/idlharness.window.js.ini b/third_party/blink/web_tests/external/wpt/pointerevents/idlharness.window.js.ini deleted file mode 100644 index 2c8f437..0000000 --- a/third_party/blink/web_tests/external/wpt/pointerevents/idlharness.window.js.ini +++ /dev/null
@@ -1,19 +0,0 @@ -[idlharness.window.html] - [Element interface: document must inherit property "setPointerCapture(long)" with the proper type] - expected: FAIL - - [Element interface: calling setPointerCapture(long) on document with too few arguments must throw TypeError] - expected: FAIL - - [Element interface: document must inherit property "releasePointerCapture(long)" with the proper type] - expected: FAIL - - [Element interface: calling releasePointerCapture(long) on document with too few arguments must throw TypeError] - expected: FAIL - - [Element interface: document must inherit property "hasPointerCapture(long)" with the proper type] - expected: FAIL - - [Element interface: calling hasPointerCapture(long) on document with too few arguments must throw TypeError] - expected: FAIL -
diff --git a/third_party/blink/web_tests/external/wpt/resources/chromium/webxr-test.js b/third_party/blink/web_tests/external/wpt/resources/chromium/webxr-test.js index e3b21fb..fe9dc3f9 100644 --- a/third_party/blink/web_tests/external/wpt/resources/chromium/webxr-test.js +++ b/third_party/blink/web_tests/external/wpt/resources/chromium/webxr-test.js
@@ -613,6 +613,68 @@ this.hit_test_source_creation_callback_ = callback; } + setLightEstimate(fakeXrLightEstimateInit) { + if (!fakeXrLightEstimateInit.sphericalHarmonicsCoefficients) { + throw new TypeError("sphericalHarmonicsCoefficients must be set"); + } + + if (fakeXrLightEstimateInit.sphericalHarmonicsCoefficients.length != 27) { + throw new TypeError("Must supply all 27 sphericalHarmonicsCoefficients"); + } + + if (fakeXrLightEstimateInit.primaryLightDirection && fakeXrLightEstimateInit.primaryLightDirection.w != 0) { + throw new TypeError("W component of primaryLightDirection must be 0"); + } + + if (fakeXrLightEstimateInit.primaryLightIntensity && fakeXrLightEstimateInit.primaryLightIntensity.w != 1) { + throw new TypeError("W component of primaryLightIntensity must be 1"); + } + + // If the primaryLightDirection or primaryLightIntensity aren't set, we need to set them + // to the defaults that the spec expects. ArCore will either give us everything or nothing, + // so these aren't nullable on the mojom. + if (!fakeXrLightEstimateInit.primaryLightDirection) { + fakeXrLightEstimateInit.primaryLightDirection = { x: 0.0, y: 1.0, z: 0.0, w: 0.0 }; + } + + if (!fakeXrLightEstimateInit.primaryLightIntensity) { + fakeXrLightEstimateInit.primaryLightIntensity = { x: 0.0, y: 0.0, z: 0.0, w: 1.0 }; + } + + let c = fakeXrLightEstimateInit.sphericalHarmonicsCoefficients; + + this.light_estimate_ = { + lightProbe: { + // XRSphereicalHarmonics + sphericalHarmonics: { + coefficients: [ + { red: c[0], green: c[1], blue: c[2] }, + { red: c[3], green: c[4], blue: c[5] }, + { red: c[6], green: c[7], blue: c[8] }, + { red: c[9], green: c[10], blue: c[11] }, + { red: c[12], green: c[13], blue: c[14] }, + { red: c[15], green: c[16], blue: c[17] }, + { red: c[18], green: c[19], blue: c[20] }, + { red: c[21], green: c[22], blue: c[23] }, + { red: c[24], green: c[25], blue: c[26] } + ] + }, + // Vector3dF + mainLightDirection: { + x: fakeXrLightEstimateInit.primaryLightDirection.x, + y: fakeXrLightEstimateInit.primaryLightDirection.y, + z: fakeXrLightEstimateInit.primaryLightDirection.z + }, + // RgbTupleF32 + mainLightIntensity: { + red: fakeXrLightEstimateInit.primaryLightIntensity.x, + green: fakeXrLightEstimateInit.primaryLightIntensity.y, + blue: fakeXrLightEstimateInit.primaryLightIntensity.z + } + } + } + } + // Helper methods getNonImmersiveDisplayInfo() { const displayInfo = this.getImmersiveDisplayInfo(); @@ -786,6 +848,7 @@ renderingTimeRatio: 0, stageParameters: this.stageParameters_, stageParametersId: this.stageParametersId_, + lightEstimationData: this.light_estimate_ }; this.next_frame_id_++;
diff --git a/third_party/blink/web_tests/external/wpt/selection/modify.tentative-expected.txt b/third_party/blink/web_tests/external/wpt/selection/modify.tentative-expected.txt new file mode 100644 index 0000000..e13dca3 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/selection/modify.tentative-expected.txt
@@ -0,0 +1,14 @@ +This is a testharness.js-based test. +PASS Stop at previous word boundary when whitespaces are trimmed +PASS Jump linefeed forward +PASS Jump linefeed backward +PASS Jump <br> forward +PASS Jump <br> backward +PASS Jump <br> forward which follows a linefeed +FAIL Jump <br> backward which follows a linefeed assert_equals: expected Text node "foo +" but got Element node <pre id="preLinefeedBr">foo +<br> +bar +</pre> +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/selection/modify.tentative.html b/third_party/blink/web_tests/external/wpt/selection/modify.tentative.html index c4436fca..37231571 100644 --- a/third_party/blink/web_tests/external/wpt/selection/modify.tentative.html +++ b/third_party/blink/web_tests/external/wpt/selection/modify.tentative.html
@@ -6,6 +6,21 @@ <div>Test, these are <strong id="strong"> strong </strong> <em id="em"> italic </em> normal.</div> +<pre id="preLinefeed"> +foo +bar +</pre> + +<pre id="preBr"> +foo<br>bar +</pre> + +<pre id="preLinefeedBr"> +foo +<br> +bar +</pre> + <script> const selection = getSelection(); test(() => { @@ -18,4 +33,58 @@ assert_equals(selection.focusNode, em.childNodes[0]); assert_equals(selection.focusOffset, 1); }, "Stop at previous word boundary when whitespaces are trimmed"); + +test(() => { + const preLinefeed = document.getElementById("preLinefeed"); + const textChild = preLinefeed.childNodes[0]; + selection.collapse(textChild, 3); + selection.modify("move", "forward", "character"); + assert_equals(selection.focusNode, textChild); + assert_equals(selection.focusOffset, 4); +}, "Jump linefeed forward"); + +test(() => { + const preLinefeed = document.getElementById("preLinefeed"); + const textChild = preLinefeed.childNodes[0]; + selection.collapse(textChild, 4); + selection.modify("move", "backward", "character"); + assert_equals(selection.focusNode, textChild); + assert_equals(selection.focusOffset, 3); +}, "Jump linefeed backward"); + +test(() => { + const preBr = document.getElementById("preBr"); + const [firstTextChild, br, secondTextChild] = preBr.childNodes; + selection.collapse(firstTextChild, 3); + selection.modify("move", "forward", "character"); + assert_equals(selection.focusNode, secondTextChild); + assert_equals(selection.focusOffset, 0); +}, "Jump <br> forward"); + +test(() => { + const preBr = document.getElementById("preBr"); + const [firstTextChild, br, secondTextChild] = preBr.childNodes; + selection.collapse(secondTextChild, 0); + selection.modify("move", "backward", "character"); + assert_equals(selection.focusNode, firstTextChild); + assert_equals(selection.focusOffset, 3); +}, "Jump <br> backward"); + +test(() => { + const preLinefeedBr = document.getElementById("preLinefeedBr"); + selection.collapse(preLinefeedBr, 1); + selection.modify("move", "forward", "character"); + const secondTextChild = preLinefeedBr.childNodes[2]; + assert_equals(selection.focusNode, secondTextChild); + assert_equals(selection.focusOffset, 0); +}, "Jump <br> forward which follows a linefeed"); + +test(() => { + const preLinefeedBr = document.getElementById("preLinefeedBr"); + selection.collapse(preLinefeedBr, 2); + selection.modify("move", "backward", "character"); + const textChild = preLinefeedBr.childNodes[0]; + assert_equals(selection.focusNode, textChild); + assert_equals(selection.focusOffset, textChild.textContent.length); +}, "Jump <br> backward which follows a linefeed"); </script>
diff --git a/third_party/blink/web_tests/external/wpt/svg/animations/repeatcount-numeric-limit.tentative.svg b/third_party/blink/web_tests/external/wpt/svg/animations/repeatcount-numeric-limit.tentative.svg new file mode 100644 index 0000000..aa043255 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/svg/animations/repeatcount-numeric-limit.tentative.svg
@@ -0,0 +1,26 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:h="http://www.w3.org/1999/xhtml"> + <title>A huge 'repeatCount' (1e+309) is treated as unspecified</title> + <h:link rel="help" href="https://svgwg.org/specs/animations/#TimingAttributes"/> + <h:script src="/resources/testharness.js"/> + <h:script src="/resources/testharnessreport.js"/> + + <rect width="50" height="100" fill="blue"> + <animate attributeName="fill" from="#007f00" to="green" dur="10ms" fill="freeze" + repeatCount="1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"/> + </rect> + <rect width="50" height="100" fill="blue" x="50"> + <animate attributeName="fill" from="#007f00" to="green" dur="10ms" fill="freeze" + repeatCount="1e+309"/> + </rect> + <script> + promise_test(t => { + let watchers = Array.from(document.getElementsByTagName('animate')).map(element => { + let watcher = new EventWatcher(t, element, ['endEvent', 'repeatEvent']); + return watcher.wait_for('endEvent').then(() => { + assert_equals(getComputedStyle(element).fill, 'rgb(0, 128, 0)'); + }); + }); + return Promise.all(watchers); + }); + </script> +</svg>
diff --git a/third_party/blink/web_tests/external/wpt/uievents/keyboard/modifier-keys-combinations.html b/third_party/blink/web_tests/external/wpt/uievents/keyboard/modifier-keys-combinations.html new file mode 100644 index 0000000..1b364ff --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/uievents/keyboard/modifier-keys-combinations.html
@@ -0,0 +1,43 @@ +<!DOCTYPE html> +<meta charset="utf-8" /> +<title>UI Events Test: Modifier keys combinations</title> +<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com"> +<link rel="help" href="https://w3c.github.io/uievents/#idl-keyboardevent" /> +<meta name="assert" content="This test checks that modifier keys combinations are properly detected in 'keydown' event."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<div id="target" tabindex="0">Target</div> +<script> + const keys = { + "Shift": '\uE008' + 'y', + "Control": '\uE009' + 'y', + "Alt": '\uE00A' + 'y', + "Meta": '\uE03D' + 'y', + }; + + target.focus(); + for (const [key, code] of Object.entries(keys)) { + promise_test(() => { + return new Promise(resolve => { + target.addEventListener("keydown", (event) => { + if (event.key != key) + resolve(event); + }); + test_driver.send_keys(target, code); + }).then((event) => { + if (event.shiftKey) { + // Shift + y will send a "Y" keydown event on Chromium and Firefox, but a "y" one on WebKit. + assert_true(event.key == "y" || event.key == "Y"); + } else { + assert_equals(event.key, "y"); + } + assert_equals(event.shiftKey, key === "Shift"); + assert_equals(event.ctrlKey, key === "Control"); + assert_equals(event.altKey, key === "Alt"); + assert_equals(event.metaKey, key === "Meta"); + }); + }, `Check sending "${key} + y" key combination`); + } +</script>
diff --git a/third_party/blink/web_tests/external/wpt/webcodecs/audio-encoder.any.js b/third_party/blink/web_tests/external/wpt/webcodecs/audio-encoder.any.js index 8b918dc..9ce1d0d7 100644 --- a/third_party/blink/web_tests/external/wpt/webcodecs/audio-encoder.any.js +++ b/third_party/blink/web_tests/external/wpt/webcodecs/audio-encoder.any.js
@@ -24,6 +24,44 @@ }); } +// Merge all audio buffers into a new big one with all the data. +function join_buffers(buffers) { + assert_greater_than_equal(buffers.length, 0); + let total_length = 0; + let base_buffer = buffers[0]; + for (const buffer of buffers) { + assert_not_equals(buffer, null); + assert_equals(buffer.sampleRate, base_buffer.sampleRate); + assert_equals(buffer.numberOfChannels, base_buffer.numberOfChannels); + total_length += buffer.length; + } + + let result = new AudioBuffer({ + length: total_length, + numberOfChannels: base_buffer.numberOfChannels, + sampleRate: base_buffer.sampleRate + }); + + for (let i = 0; i < base_buffer.numberOfChannels; i++) { + let channel = result.getChannelData(i); + let position = 0; + for (const buffer of buffers) { + channel.set(buffer.getChannelData(i), position); + position += buffer.length; + } + assert_equals(position, total_length); + } + + return result; +} + +function clone_frame(frame) { + return new AudioFrame({ + timestamp: frame.timestamp, + buffer: join_buffers([frame.buffer]) + }); +} + promise_test(async t => { let sample_rate = 48000; let total_duration_s = 2; @@ -55,7 +93,7 @@ let frame_duration_s = total_duration_s / frame_count; let length = frame_duration_s * config.sampleRate; let frame = make_audio_frame(timestamp_us, config.numberOfChannels, - config.sampleRate, length); + config.sampleRate, length); encoder.encode(frame); timestamp_us += frame_duration_s * 1_000_000; } @@ -68,3 +106,82 @@ assert_greater_than(timestamp_us, chunk.timestamp); } }, 'Simple audio encoding'); + + +promise_test(async t => { + let sample_rate = 48000; + let total_duration_s = 2; + let frame_count = 20; + let input_frames = []; + let output_frames = []; + + let decoder_init = { + error: t.unreached_func("Decode error"), + output: frame => { + output_frames.push(frame); + } + }; + let decoder = new AudioDecoder(decoder_init); + + let encoder_init = { + error: t.unreached_func("Encoder error"), + output: chunk => { + decoder.decode(chunk); + } + }; + let encoder = new AudioEncoder(encoder_init); + + let config = { + codec: 'opus', + sampleRate: sample_rate, + numberOfChannels: 2, + bitrate: 256000, //256kbit + // Opus header extradata. + // TODO(https://crbug.com/1177021) Get this data from AudioEncoder + description: new Uint8Array([0x4f, 0x70, 0x75, 0x73, 0x48, 0x65, 0x61, 0x64, + 0x01, 0x02, 0x38, 0x01, 0x80, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00]) + }; + + encoder.configure(config); + decoder.configure(config); + + let timestamp_us = 0; + const frame_duration_s = total_duration_s / frame_count; + const frame_length = frame_duration_s * config.sampleRate; + for (let i = 0; i < frame_count; i++) { + let frame = make_audio_frame(timestamp_us, config.numberOfChannels, + config.sampleRate, frame_length); + input_frames.push(clone_frame(frame)); + encoder.encode(frame); + timestamp_us += frame_duration_s * 1_000_000; + } + await encoder.flush(); + encoder.close(); + await decoder.flush(); + decoder.close(); + + + let total_input = join_buffers(input_frames.map(f => f.buffer)); + let total_output = join_buffers(output_frames.map(f => f.buffer)); + assert_equals(total_output.numberOfChannels, 2); + assert_equals(total_output.sampleRate, sample_rate); + + // Output can be slightly longer that the input due to padding + assert_greater_than_equal(total_output.length, total_input.length); + assert_greater_than_equal(total_output.duration, total_duration_s); + assert_approx_equals(total_output.duration, total_duration_s, 0.1); + + // Compare waveform before and after encoding + for (let channel = 0; channel < total_input.numberOfChannels; channel++) { + let input_data = total_input.getChannelData(channel); + let output_data = total_output.getChannelData(channel); + for (let i = 0; i < total_input.length; i++) { + assert_approx_equals(input_data[i], output_data[i], 0.5, + "Difference between input and output is too large." + + " index: " + i + + " input: " + input_data[i] + + " output: " + output_data[i]); + } + } + +}, 'Encoding and decoding'); \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-helper.js b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-helper.js index 5aef0a8e..cdfe63e7 100644 --- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-helper.js +++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-helper.js
@@ -242,8 +242,7 @@ async function listenForSSRCs(t, receiver) { while (true) { const ssrcs = receiver.getSynchronizationSources(); - assert_true(Array.isArray(ssrcs)); - if (ssrcs.length > 0) { + if (Array.isArray(ssrcs) && ssrcs.length > 0) { return ssrcs; } await new Promise(r => t.step_timeout(r, 0));
diff --git a/third_party/blink/web_tests/external/wpt/webxr/light-estimation/xrFrame_getLightEstimate_oldSession.https.html b/third_party/blink/web_tests/external/wpt/webxr/light-estimation/xrFrame_getLightEstimate_oldSession.https.html new file mode 100644 index 0000000..7a896aa --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/webxr/light-estimation/xrFrame_getLightEstimate_oldSession.https.html
@@ -0,0 +1,57 @@ +<!DOCTYPE html> +<body> + <script src=/resources/testharness.js></script> + <script src=/resources/testharnessreport.js></script> + <script src="../resources/webxr_util.js"></script> + <script src="../resources/webxr_test_constants.js"></script> + + <script> + let testName = "getLightEstimate rejects if probe is from wrong session"; + let testFunction = (session, controller, t, sessionObjects) => new Promise((resolve) => { + let staleLightProbe = null; + let newSession = null; + + function onFrame(time, frame) { + t.step(() => { + // Attempting to get a lightEstimate with a probe created for a + // different session should throw an exception. + assert_throws_dom('InvalidStateError', () => frame.getLightEstimate(staleLightProbe)); + }); + + // Cleanup the new session we made and then resolve. + resolve(newSession.end()); + } + + // Request a default lightProbe + let probeInit = {reflectionFormat: session.preferredReflectionFormat }; + session.requestLightProbe(probeInit).then((probe) => { + staleLightProbe = probe; + return session.end(); + }).then(() => { + // Need to request a new session. + navigator.xr.test.simulateUserActivation( () => { + navigator.xr.requestSession('immersive-ar', {'requiredFeatures': ['light-estimation']}) + .then((session2) => { + + let glLayer = new XRWebGLLayer(session2, sessionObjects.gl); + glLayer.context = sessionObjects.gl; + // Session must have a baseLayer or frame requests will be ignored. + session2.updateRenderState({ + baseLayer: glLayer + }); + newSession = session2; + newSession.requestAnimationFrame(onFrame); + }); + }); + }); + }); + + xr_session_promise_test( + testName, + testFunction, + IMMERSIVE_AR_DEVICE, + 'immersive-ar', + {'requiredFeatures': ['light-estimation']}); + + </script> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/webxr/light-estimation/xrFrame_getLightEstimate_staleFrame.https.html b/third_party/blink/web_tests/external/wpt/webxr/light-estimation/xrFrame_getLightEstimate_staleFrame.https.html new file mode 100644 index 0000000..499a30d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/webxr/light-estimation/xrFrame_getLightEstimate_staleFrame.https.html
@@ -0,0 +1,47 @@ +<!DOCTYPE html> +<body> + <script src=/resources/testharness.js></script> + <script src=/resources/testharnessreport.js></script> + <script src="../resources/webxr_util.js"></script> + <script src="../resources/webxr_test_constants.js"></script> + + <script> + let testName = "Cannot get XrLightEstimate from stale frame"; + let testFunction = (session, controller, t) => new Promise((resolve) => { + let lightProbe = null; + let staleFrame = null; + + function onFrame(time, frame) { + // Try to get the light estimate (even if it's null), it shouldn't throw. + let estimate = frame.getLightEstimate(lightProbe); + staleFrame = frame; + + t.step_timeout(afterFrame, 10); + } + + function afterFrame() { + t.step(() => { + // Attempting to call a method on the frame outside the callback that + // originally provided it should cause it to throw an exception. + assert_throws_dom('InvalidStateError', () => staleFrame.getLightEstimate(lightProbe)); + }); + + resolve(); + } + + // Request a default lightProbe + let probeInit = {reflectionFormat: session.preferredReflectionFormat}; + session.requestLightProbe(probeInit).then((probe) => { + lightProbe = probe; + session.requestAnimationFrame(onFrame); + }); + }); + + xr_session_promise_test( + testName, + testFunction, + IMMERSIVE_AR_DEVICE, + 'immersive-ar', {'requiredFeatures': ['light-estimation']}); + + </script> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/webxr/light-estimation/xrFrame_getLightEstimate_valid.https.html b/third_party/blink/web_tests/external/wpt/webxr/light-estimation/xrFrame_getLightEstimate_valid.https.html new file mode 100644 index 0000000..68c5d84 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/webxr/light-estimation/xrFrame_getLightEstimate_valid.https.html
@@ -0,0 +1,104 @@ +<!DOCTYPE html> +<body> + <script src=/resources/testharness.js></script> + <script src=/resources/testharnessreport.js></script> + <script src="../resources/webxr_util.js"></script> + <script src="../resources/webxr_test_asserts.js"></script> + <script src="../resources/webxr_test_constants.js"></script> + + <script> + let testName = "Can get XRLightEstimates during frame"; + let fakeDeviceInitParams = IMMERSIVE_AR_DEVICE; + + let fakeEstimateCoefficients = [ + 0.01, 0.02, 0.03, + 0.04, 0.05, 0.06, + 0.07, 0.08, 0.09, + 0.10, 0.11, 0.12, + 0.13, 0.14, 0.15, + 0.16, 0.17, 0.18, + 0.19, 0.20, 0.21, + 0.22, 0.23, 0.24, + 0.25, 0.26, 0.27 + ]; + + let fakeDirectionInit = { x: 1.0, y: 0.0, z: 0.0, w: 0.0 }; + let fakeIntensityInit = { x: 0.0, y: 0.0, z: 1.0, w: 1.0 }; + + let testFunction = (session, controller, t) => new Promise((resolve) => { + let lightProbe = null; + function onFrameWithNoLightEstimation(time, frame) { + let estimate = frame.getLightEstimate(lightProbe); + t.step(() => { + assert_equals(estimate, null); + }); + + controller.setLightEstimate({ + sphericalHarmonicsCoefficients: fakeEstimateCoefficients + }); + + requestSkipAnimationFrame(session, onFrameWithCoefficients); + } + + function onFrameWithCoefficients(time, frame) { + let estimate = frame.getLightEstimate(lightProbe); + t.step(() => { + assert_not_equals(estimate, null); + assert_equals(estimate.sphericalHarmonicsCoefficients.length, 27); + assert_point_approx_equals(estimate.primaryLightDirection, { x: 0.0, y: 1.0, z: 0.0, w: 0.0 }); + assert_point_approx_equals(estimate.primaryLightIntensity, { x: 0.0, y: 0.0, z: 0.0, w: 1.0 }); + }); + + controller.setLightEstimate({ + sphericalHarmonicsCoefficients: fakeEstimateCoefficients, + primaryLightDirection: fakeDirectionInit, + }); + + requestSkipAnimationFrame(session, onFrameWithDirection); + } + + function onFrameWithDirection(time, frame) { + let estimate = frame.getLightEstimate(lightProbe); + t.step(() => { + assert_not_equals(estimate, null); + assert_equals(estimate.sphericalHarmonicsCoefficients.length, 27); + assert_point_approx_equals(estimate.primaryLightDirection, fakeDirectionInit); + assert_point_approx_equals(estimate.primaryLightIntensity, { x: 0.0, y: 0.0, z: 0.0, w: 1.0 }); + }); + + controller.setLightEstimate({ + sphericalHarmonicsCoefficients: fakeEstimateCoefficients, + primaryLightDirection: fakeDirectionInit, + primaryLightIntensity: fakeIntensityInit + }); + + requestSkipAnimationFrame(session, onFrameWithDirectionAndIntensity); + } + + function onFrameWithDirectionAndIntensity(time, frame) { + let estimate = frame.getLightEstimate(lightProbe); + t.step(() => { + assert_not_equals(estimate, null); + assert_equals(estimate.sphericalHarmonicsCoefficients.length, 27); + assert_point_approx_equals(estimate.primaryLightDirection, fakeDirectionInit); + assert_point_approx_equals(estimate.primaryLightIntensity, fakeIntensityInit); + }); + + resolve(); + } + + // Request a default lightProbe + session.requestLightProbe({reflectionFormat: session.preferredReflectionFormat }).then((probe) => { + lightProbe = probe; + session.requestAnimationFrame(onFrameWithNoLightEstimation); + }); + }); + + xr_session_promise_test( + testName, + testFunction, + IMMERSIVE_AR_DEVICE, + 'immersive-ar', {'requiredFeatures': ['light-estimation']}); + + </script> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/webxr/light-estimation/xrSession_getLightProbe_ended.https.html b/third_party/blink/web_tests/external/wpt/webxr/light-estimation/xrSession_getLightProbe_ended.https.html new file mode 100644 index 0000000..cc046499 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/webxr/light-estimation/xrSession_getLightProbe_ended.https.html
@@ -0,0 +1,21 @@ +<!DOCTYPE html> +<body> + <script src=/resources/testharness.js></script> + <script src=/resources/testharnessreport.js></script> + <script src="../resources/webxr_util.js"></script> + <script src="../resources/webxr_test_constants.js"></script> + + <script> + xr_session_promise_test( + "getLightProbe rejects on an ended session", + (session, controller, t) => { + return session.end().then(() => { + return promise_rejects_dom(t, "InvalidStateError", session.requestLightProbe()) + }) + }, + IMMERSIVE_AR_DEVICE, + 'immersive-ar', + {'requiredFeatures': ['light-estimation']}); + + </script> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/webxr/light-estimation/xrSession_getLightProbe_notEnabled.https.html b/third_party/blink/web_tests/external/wpt/webxr/light-estimation/xrSession_getLightProbe_notEnabled.https.html new file mode 100644 index 0000000..23fe1c6 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/webxr/light-estimation/xrSession_getLightProbe_notEnabled.https.html
@@ -0,0 +1,18 @@ +<!DOCTYPE html> +<body> + <script src=/resources/testharness.js></script> + <script src=/resources/testharnessreport.js></script> + <script src="../resources/webxr_util.js"></script> + <script src="../resources/webxr_test_constants.js"></script> + + <script> + let fakeDeviceInitParams = IMMERSIVE_AR_DEVICE; + + xr_session_promise_test( + "getLightProbe rejects if not enabled on session", + (session, controller, t) => promise_rejects_dom(t, "NotSupportedError", session.requestLightProbe()), + IMMERSIVE_AR_DEVICE, + 'immersive-ar'); + + </script> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/webxr/light-estimation/xrSession_getLightProbe_valid.https.html b/third_party/blink/web_tests/external/wpt/webxr/light-estimation/xrSession_getLightProbe_valid.https.html new file mode 100644 index 0000000..074c7fd --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/webxr/light-estimation/xrSession_getLightProbe_valid.https.html
@@ -0,0 +1,27 @@ +<!DOCTYPE html> +<body> + <script src=/resources/testharness.js></script> + <script src=/resources/testharnessreport.js></script> + <script src="../resources/webxr_util.js"></script> + <script src="../resources/webxr_test_constants.js"></script> + + <script> + let testName = "Can create valid XRLightProbe objects"; + + function testFunction(session, controller, t) { + // Request a default lightProbe + let defaultProbe = session.requestLightProbe(); + let srgba8Probe = session.requestLightProbe({reflectionFormat: "srgba8"}); + let preferredProbe = session.requestLightProbe({reflectionFormat: session.preferredReflectionFormat }); + + return Promise.all([defaultProbe, srgba8Probe, preferredProbe]); + } + + xr_session_promise_test( + testName, + testFunction, + IMMERSIVE_AR_DEVICE, + 'immersive-ar', {'requiredFeatures': ['light-estimation']}); + + </script> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/webxr/light-estimation/xrWebGLBinding_getReflectionCubeMap.https.html b/third_party/blink/web_tests/external/wpt/webxr/light-estimation/xrWebGLBinding_getReflectionCubeMap.https.html new file mode 100644 index 0000000..b46f448 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/webxr/light-estimation/xrWebGLBinding_getReflectionCubeMap.https.html
@@ -0,0 +1,88 @@ +<!DOCTYPE html> +<body> + <script src=/resources/testharness.js></script> + <script src=/resources/testharnessreport.js></script> + <script src="../resources/webxr_util.js"></script> + <script src="../resources/webxr_test_constants.js"></script> + + <script> + let testName = "Test that getReflectionCubeMap returns or throws appropriately without a reflection map."; + + let testFunction = (session, controller, t, sessionObjects) => new Promise((resolve) => { + let debug = xr_debug.bind(this, 'testFunction'); + let lightProbe1 = null; + let binding1 = new XRWebGLBinding(session, sessionObjects.gl); + + // Request a default lightProbe + session.requestLightProbe({reflectionFormat: session.preferredReflectionFormat }).then((probe) => { + // Stash and end session. + lightProbe1 = probe; + + debug("Querying first pair"); + t.step(() => { + assert_equals( + binding1.getReflectionCubeMap(lightProbe1), + null, + "Active binding and light probe shouldn't throw when requesting cube map"); + }); + + return session.end(); + }).then(() => { + // Need to request a new session. + navigator.xr.test.simulateUserActivation( () => { + navigator.xr.requestSession('immersive-ar', { 'requiredFeatures': ['light-estimation'] }) + .then((newSession) => { + let newBinding = new XRWebGLBinding(newSession, sessionObjects.gl); + newSession.requestLightProbe({ reflectionFormat: newSession.preferredReflectionFormat }).then((newProbe) => { + t.step(() => { + debug("Querying second pair"); + assert_equals( + newBinding.getReflectionCubeMap(newProbe), + null, + "Newly created binding and light probe shouldn't throw"); + + debug("Querying old pair"); + assert_throws_dom( + "InvalidStateError", + () => binding1.getReflectionCubeMap(lightProbe1), + "Binding created with an ended session should throw InvalidStateError"); + debug("Querying mismatched pair"); + assert_throws_dom( + "InvalidStateError", + () => newBinding.getReflectionCubeMap(lightProbe1), + "Querying binding with a probe with a different backing session should throw InvalidStateError"); + }); + debug("losing context"); + + // Trigger a context loss and verify that we are unable to get the reflectionCubeMap. + let lose_context_ext = sessionObjects.gl.getExtension('WEBGL_lose_context'); + + sessionObjects.gl.canvas.addEventListener('webglcontextlost', (ev) => { + ev.preventDefault(); + + t.step(() => { + assert_throws_dom( + "InvalidStateError", + () => newBinding.getReflectionCubeMap(newProbe), + "Querying for reflection cube map on a binding with context loss should throw InvalidStateError"); + }); + + resolve(newSession.end()); + }); + + lose_context_ext.loseContext(); + }); // Request second light probe + }); // Request second session + }); // SimulateUserActivation + }); // .then on session end + }); // testFunction + + xr_session_promise_test( + testName, + testFunction, + IMMERSIVE_AR_DEVICE, + 'immersive-ar', + {'requiredFeatures': ['light-estimation']}); + + </script> +</body>
diff --git a/third_party/blink/web_tests/fast/table/large-col-span-crash.html b/third_party/blink/web_tests/fast/table/large-col-span-crash.html index b440470..6fc7362 100644 --- a/third_party/blink/web_tests/fast/table/large-col-span-crash.html +++ b/third_party/blink/web_tests/fast/table/large-col-span-crash.html
@@ -10,7 +10,7 @@ <script src="../../resources/testharness.js"></script> <script src="../../resources/testharnessreport.js"></script> <script src="../../resources/check-layout-th.js"></script> -<table data-expected-width=100 data-expected-height=100> +<table data-expected-width=2004 data-expected-height=100> <col span="4294967295"> <col> </table>
diff --git a/third_party/blink/web_tests/http/tests/loading/window-open-onblur-reentrancy-expected.txt b/third_party/blink/web_tests/http/tests/loading/window-open-onblur-reentrancy-expected.txt index 54014cf..658f9d6 100644 --- a/third_party/blink/web_tests/http/tests/loading/window-open-onblur-reentrancy-expected.txt +++ b/third_party/blink/web_tests/http/tests/loading/window-open-onblur-reentrancy-expected.txt
@@ -9,5 +9,6 @@ frame "i" - didHandleOnloadEventsForFrame frame "i" - didFinishLoadForFrame main frame - didFinishDocumentLoadForFrame +main frame - didCommitLoadForFrame main frame - didHandleOnloadEventsForFrame main frame - didFinishLoadForFrame
diff --git a/third_party/blink/web_tests/http/tests/navigation/lockedhistory-iframe-expected.txt b/third_party/blink/web_tests/http/tests/navigation/lockedhistory-iframe-expected.txt index a1d0ffb..6def51f 100644 --- a/third_party/blink/web_tests/http/tests/navigation/lockedhistory-iframe-expected.txt +++ b/third_party/blink/web_tests/http/tests/navigation/lockedhistory-iframe-expected.txt
@@ -1,6 +1,3 @@ This test verifies that setting the iframe.src through javascript to # does not add a history item. If the test passes you'll see only one history item. -============== Back Forward List ============== -curr-> http://127.0.0.1:8000/navigation/lockedhistory-iframe.html - http://127.0.0.1:8000/navigation/lockedhistory-iframe.html# (in frame "<!--framePath //<!--frame0-->-->") -=============================================== + PASS
diff --git a/third_party/blink/web_tests/http/tests/navigation/lockedhistory-iframe.html b/third_party/blink/web_tests/http/tests/navigation/lockedhistory-iframe.html index fb4420a2..f0f5c50 100644 --- a/third_party/blink/web_tests/http/tests/navigation/lockedhistory-iframe.html +++ b/third_party/blink/web_tests/http/tests/navigation/lockedhistory-iframe.html
@@ -2,7 +2,6 @@ <head> <script src="resources/document-location.js"></script> <script type="text/javascript"> -testRunner.dumpBackForwardList(); testRunner.dumpAsText(); testRunner.waitUntilDone(); @@ -15,9 +14,14 @@ <body> <p>This test verifies that setting the iframe.src through javascript to # does not add a history item. If the test passes you'll see only one history item.</p> <script type="text/javascript"> +let historyLength = history.length; myFrame = document.createElement("iframe"); myFrame.src = "javascript:document.write('<script type=text/javascript>window.parent.myCallbackFunction();<\/script>'); document.close()"; -myFrame.onload = () => testRunner.notifyDone(); +myFrame.onload = () => { + document.body.appendChild(document.createTextNode( + historyLength == history.length ? "PASS" : "FAIL")); + testRunner.notifyDone(); +} document.body.appendChild(myFrame); </script> </body>
diff --git a/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt index 5375ce2..6bfae355 100644 --- a/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt +++ b/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -1011,6 +1011,7 @@ method lineTo method measureText method moveTo + method perspective method putImageData method quadraticCurveTo method rect
diff --git a/third_party/blink/web_tests/http/tests/wasm/resources/wasm-constants.js b/third_party/blink/web_tests/http/tests/wasm/resources/wasm-constants.js deleted file mode 100644 index 2656768e..0000000 --- a/third_party/blink/web_tests/http/tests/wasm/resources/wasm-constants.js +++ /dev/null
@@ -1,447 +0,0 @@ -// Copyright 2017 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -function bytes() { - var buffer = new ArrayBuffer(arguments.length); - var view = new Uint8Array(buffer); - for (var i = 0; i < arguments.length; i++) { - var val = arguments[i]; - if ((typeof val) == "string") val = val.charCodeAt(0); - view[i] = val | 0; - } - return buffer; -} - -// Header declaration constants -var kWasmH0 = 0; -var kWasmH1 = 0x61; -var kWasmH2 = 0x73; -var kWasmH3 = 0x6d; - -var kWasmV0 = 0x1; -var kWasmV1 = 0; -var kWasmV2 = 0; -var kWasmV3 = 0; - -var kHeaderSize = 8; -var kPageSize = 65536; -var kSpecMaxPages = 65535; - -function bytesWithHeader() { - var buffer = new ArrayBuffer(kHeaderSize + arguments.length); - var view = new Uint8Array(buffer); - view[0] = kWasmH0; - view[1] = kWasmH1; - view[2] = kWasmH2; - view[3] = kWasmH3; - view[4] = kWasmV0; - view[5] = kWasmV1; - view[6] = kWasmV2; - view[7] = kWasmV3; - for (var i = 0; i < arguments.length; i++) { - var val = arguments[i]; - if ((typeof val) == "string") val = val.charCodeAt(0); - view[kHeaderSize + i] = val | 0; - } - return buffer; -} - -let kDeclNoLocals = 0; - -// Section declaration constants -let kUnknownSectionCode = 0; -let kTypeSectionCode = 1; // Function signature declarations -let kImportSectionCode = 2; // Import declarations -let kFunctionSectionCode = 3; // Function declarations -let kTableSectionCode = 4; // Indirect function table and other tables -let kMemorySectionCode = 5; // Memory attributes -let kGlobalSectionCode = 6; // Global declarations -let kExportSectionCode = 7; // Exports -let kStartSectionCode = 8; // Start function declaration -let kElementSectionCode = 9; // Elements section -let kCodeSectionCode = 10; // Function code -let kDataSectionCode = 11; // Data segments -let kNameSectionCode = 12; // Name section (encoded as string) -let kExceptionSectionCode = 13; // Exception section (must appear before code section) - -// Name section types -let kModuleNameCode = 0; -let kFunctionNamesCode = 1; -let kLocalNamesCode = 2; - -let kWasmFunctionTypeForm = 0x60; -let kWasmAnyFunctionTypeForm = 0x70; - -let kHasMaximumFlag = 1; - -// Function declaration flags -let kDeclFunctionName = 0x01; -let kDeclFunctionImport = 0x02; -let kDeclFunctionLocals = 0x04; -let kDeclFunctionExport = 0x08; - -// Local types -let kWasmStmt = 0x40; -let kWasmI32 = 0x7f; -let kWasmI64 = 0x7e; -let kWasmF32 = 0x7d; -let kWasmF64 = 0x7c; -let kWasmS128 = 0x7b; -let kWasmAnyRef = 0x6f; - -let kExternalFunction = 0; -let kExternalTable = 1; -let kExternalMemory = 2; -let kExternalGlobal = 3; - -let kTableZero = 0; -let kMemoryZero = 0; - -// Useful signatures -let kSig_i_i = makeSig([kWasmI32], [kWasmI32]); -let kSig_l_l = makeSig([kWasmI64], [kWasmI64]); -let kSig_i_l = makeSig([kWasmI64], [kWasmI32]); -let kSig_i_ii = makeSig([kWasmI32, kWasmI32], [kWasmI32]); -let kSig_i_iii = makeSig([kWasmI32, kWasmI32, kWasmI32], [kWasmI32]); -let kSig_d_dd = makeSig([kWasmF64, kWasmF64], [kWasmF64]); -let kSig_l_ll = makeSig([kWasmI64, kWasmI64], [kWasmI64]); -let kSig_i_dd = makeSig([kWasmF64, kWasmF64], [kWasmI32]); -let kSig_v_v = makeSig([], []); -let kSig_i_v = makeSig([], [kWasmI32]); -let kSig_l_v = makeSig([], [kWasmI64]); -let kSig_f_v = makeSig([], [kWasmF32]); -let kSig_d_v = makeSig([], [kWasmF64]); -let kSig_v_i = makeSig([kWasmI32], []); -let kSig_v_ii = makeSig([kWasmI32, kWasmI32], []); -let kSig_v_iii = makeSig([kWasmI32, kWasmI32, kWasmI32], []); -let kSig_v_l = makeSig([kWasmI64], []); -let kSig_v_d = makeSig([kWasmF64], []); -let kSig_v_dd = makeSig([kWasmF64, kWasmF64], []); -let kSig_v_ddi = makeSig([kWasmF64, kWasmF64, kWasmI32], []); -let kSig_ii_v = makeSig([], [kWasmI32, kWasmI32]); -let kSig_iii_v = makeSig([], [kWasmI32, kWasmI32, kWasmI32]); -let kSig_ii_i = makeSig([kWasmI32], [kWasmI32, kWasmI32]); -let kSig_iii_i = makeSig([kWasmI32], [kWasmI32, kWasmI32, kWasmI32]); -let kSig_ii_ii = makeSig([kWasmI32, kWasmI32], [kWasmI32, kWasmI32]); -let kSig_iii_ii = makeSig([kWasmI32, kWasmI32], [kWasmI32, kWasmI32, kWasmI32]); - -let kSig_v_f = makeSig([kWasmF32], []); -let kSig_f_f = makeSig([kWasmF32], [kWasmF32]); -let kSig_d_d = makeSig([kWasmF64], [kWasmF64]); -let kSig_r_r = makeSig([kWasmAnyRef], [kWasmAnyRef]); -let kSig_i_r = makeSig([kWasmAnyRef], [kWasmI32]); -let kSig_v_r = makeSig([kWasmAnyRef], []); -let kSig_r_v = makeSig([], [kWasmAnyRef]); - -function makeSig(params, results) { - return {params: params, results: results}; -} - -function makeSig_v_x(x) { - return makeSig([x], []); -} - -function makeSig_v_xx(x) { - return makeSig([x, x], []); -} - -function makeSig_r_v(r) { - return makeSig([], [r]); -} - -function makeSig_r_x(r, x) { - return makeSig([x], [r]); -} - -function makeSig_r_xx(r, x) { - return makeSig([x, x], [r]); -} - -// Opcodes -let kExprUnreachable = 0x00; -let kExprNop = 0x01; -let kExprBlock = 0x02; -let kExprLoop = 0x03; -let kExprIf = 0x04; -let kExprElse = 0x05; -let kExprTry = 0x06; -let kExprCatch = 0x07; -let kExprThrow = 0x08; -let kExprEnd = 0x0b; -let kExprBr = 0x0c; -let kExprBrIf = 0x0d; -let kExprBrTable = 0x0e; -let kExprReturn = 0x0f; -let kExprCallFunction = 0x10; -let kExprCallIndirect = 0x11; -let kExprDrop = 0x1a; -let kExprSelect = 0x1b; -let kExprGetLocal = 0x20; -let kExprSetLocal = 0x21; -let kExprTeeLocal = 0x22; -let kExprGetGlobal = 0x23; -let kExprSetGlobal = 0x24; -let kExprI32Const = 0x41; -let kExprI64Const = 0x42; -let kExprF32Const = 0x43; -let kExprF64Const = 0x44; -let kExprRefNull = 0xd0; -let kExprI32LoadMem = 0x28; -let kExprI64LoadMem = 0x29; -let kExprF32LoadMem = 0x2a; -let kExprF64LoadMem = 0x2b; -let kExprI32LoadMem8S = 0x2c; -let kExprI32LoadMem8U = 0x2d; -let kExprI32LoadMem16S = 0x2e; -let kExprI32LoadMem16U = 0x2f; -let kExprI64LoadMem8S = 0x30; -let kExprI64LoadMem8U = 0x31; -let kExprI64LoadMem16S = 0x32; -let kExprI64LoadMem16U = 0x33; -let kExprI64LoadMem32S = 0x34; -let kExprI64LoadMem32U = 0x35; -let kExprI32StoreMem = 0x36; -let kExprI64StoreMem = 0x37; -let kExprF32StoreMem = 0x38; -let kExprF64StoreMem = 0x39; -let kExprI32StoreMem8 = 0x3a; -let kExprI32StoreMem16 = 0x3b; -let kExprI64StoreMem8 = 0x3c; -let kExprI64StoreMem16 = 0x3d; -let kExprI64StoreMem32 = 0x3e; -let kExprMemorySize = 0x3f; -let kExprGrowMemory = 0x40; -let kExprI32Eqz = 0x45; -let kExprI32Eq = 0x46; -let kExprI32Ne = 0x47; -let kExprI32LtS = 0x48; -let kExprI32LtU = 0x49; -let kExprI32GtS = 0x4a; -let kExprI32GtU = 0x4b; -let kExprI32LeS = 0x4c; -let kExprI32LeU = 0x4d; -let kExprI32GeS = 0x4e; -let kExprI32GeU = 0x4f; -let kExprI64Eqz = 0x50; -let kExprI64Eq = 0x51; -let kExprI64Ne = 0x52; -let kExprI64LtS = 0x53; -let kExprI64LtU = 0x54; -let kExprI64GtS = 0x55; -let kExprI64GtU = 0x56; -let kExprI64LeS = 0x57; -let kExprI64LeU = 0x58; -let kExprI64GeS = 0x59; -let kExprI64GeU = 0x5a; -let kExprF32Eq = 0x5b; -let kExprF32Ne = 0x5c; -let kExprF32Lt = 0x5d; -let kExprF32Gt = 0x5e; -let kExprF32Le = 0x5f; -let kExprF32Ge = 0x60; -let kExprF64Eq = 0x61; -let kExprF64Ne = 0x62; -let kExprF64Lt = 0x63; -let kExprF64Gt = 0x64; -let kExprF64Le = 0x65; -let kExprF64Ge = 0x66; -let kExprRefIsNull = 0xd1; -let kExprI32Clz = 0x67; -let kExprI32Ctz = 0x68; -let kExprI32Popcnt = 0x69; -let kExprI32Add = 0x6a; -let kExprI32Sub = 0x6b; -let kExprI32Mul = 0x6c; -let kExprI32DivS = 0x6d; -let kExprI32DivU = 0x6e; -let kExprI32RemS = 0x6f; -let kExprI32RemU = 0x70; -let kExprI32And = 0x71; -let kExprI32Ior = 0x72; -let kExprI32Xor = 0x73; -let kExprI32Shl = 0x74; -let kExprI32ShrS = 0x75; -let kExprI32ShrU = 0x76; -let kExprI32Rol = 0x77; -let kExprI32Ror = 0x78; -let kExprI64Clz = 0x79; -let kExprI64Ctz = 0x7a; -let kExprI64Popcnt = 0x7b; -let kExprI64Add = 0x7c; -let kExprI64Sub = 0x7d; -let kExprI64Mul = 0x7e; -let kExprI64DivS = 0x7f; -let kExprI64DivU = 0x80; -let kExprI64RemS = 0x81; -let kExprI64RemU = 0x82; -let kExprI64And = 0x83; -let kExprI64Ior = 0x84; -let kExprI64Xor = 0x85; -let kExprI64Shl = 0x86; -let kExprI64ShrS = 0x87; -let kExprI64ShrU = 0x88; -let kExprI64Rol = 0x89; -let kExprI64Ror = 0x8a; -let kExprF32Abs = 0x8b; -let kExprF32Neg = 0x8c; -let kExprF32Ceil = 0x8d; -let kExprF32Floor = 0x8e; -let kExprF32Trunc = 0x8f; -let kExprF32NearestInt = 0x90; -let kExprF32Sqrt = 0x91; -let kExprF32Add = 0x92; -let kExprF32Sub = 0x93; -let kExprF32Mul = 0x94; -let kExprF32Div = 0x95; -let kExprF32Min = 0x96; -let kExprF32Max = 0x97; -let kExprF32CopySign = 0x98; -let kExprF64Abs = 0x99; -let kExprF64Neg = 0x9a; -let kExprF64Ceil = 0x9b; -let kExprF64Floor = 0x9c; -let kExprF64Trunc = 0x9d; -let kExprF64NearestInt = 0x9e; -let kExprF64Sqrt = 0x9f; -let kExprF64Add = 0xa0; -let kExprF64Sub = 0xa1; -let kExprF64Mul = 0xa2; -let kExprF64Div = 0xa3; -let kExprF64Min = 0xa4; -let kExprF64Max = 0xa5; -let kExprF64CopySign = 0xa6; -let kExprI32ConvertI64 = 0xa7; -let kExprI32SConvertF32 = 0xa8; -let kExprI32UConvertF32 = 0xa9; -let kExprI32SConvertF64 = 0xaa; -let kExprI32UConvertF64 = 0xab; -let kExprI64SConvertI32 = 0xac; -let kExprI64UConvertI32 = 0xad; -let kExprI64SConvertF32 = 0xae; -let kExprI64UConvertF32 = 0xaf; -let kExprI64SConvertF64 = 0xb0; -let kExprI64UConvertF64 = 0xb1; -let kExprF32SConvertI32 = 0xb2; -let kExprF32UConvertI32 = 0xb3; -let kExprF32SConvertI64 = 0xb4; -let kExprF32UConvertI64 = 0xb5; -let kExprF32ConvertF64 = 0xb6; -let kExprF64SConvertI32 = 0xb7; -let kExprF64UConvertI32 = 0xb8; -let kExprF64SConvertI64 = 0xb9; -let kExprF64UConvertI64 = 0xba; -let kExprF64ConvertF32 = 0xbb; -let kExprI32ReinterpretF32 = 0xbc; -let kExprI64ReinterpretF64 = 0xbd; -let kExprF32ReinterpretI32 = 0xbe; -let kExprF64ReinterpretI64 = 0xbf; - -// Prefix opcodes -let kAtomicPrefix = 0xfe; - -let kExprI32AtomicLoad = 0x10; -let kExprI32AtomicLoad8U = 0x12; -let kExprI32AtomicLoad16U = 0x13; -let kExprI32AtomicStore = 0x17; -let kExprI32AtomicStore8U = 0x19; -let kExprI32AtomicStore16U = 0x1a; -let kExprI32AtomicAdd = 0x1e; -let kExprI32AtomicAdd8U = 0x20; -let kExprI32AtomicAdd16U = 0x21; -let kExprI32AtomicSub = 0x25; -let kExprI32AtomicSub8U = 0x27; -let kExprI32AtomicSub16U = 0x28; -let kExprI32AtomicAnd = 0x2c; -let kExprI32AtomicAnd8U = 0x2e; -let kExprI32AtomicAnd16U = 0x2f; -let kExprI32AtomicOr = 0x33; -let kExprI32AtomicOr8U = 0x35; -let kExprI32AtomicOr16U = 0x36; -let kExprI32AtomicXor = 0x3a; -let kExprI32AtomicXor8U = 0x3c; -let kExprI32AtomicXor16U = 0x3d; -let kExprI32AtomicExchange = 0x41; -let kExprI32AtomicExchange8U = 0x43; -let kExprI32AtomicExchange16U = 0x44; -let kExprI32AtomicCompareExchange = 0x48 -let kExprI32AtomicCompareExchange8U = 0x4a -let kExprI32AtomicCompareExchange16U = 0x4b - -let kTrapUnreachable = 0; -let kTrapMemOutOfBounds = 1; -let kTrapDivByZero = 2; -let kTrapDivUnrepresentable = 3; -let kTrapRemByZero = 4; -let kTrapFloatUnrepresentable = 5; -let kTrapFuncInvalid = 6; -let kTrapFuncSigMismatch = 7; -let kTrapTypeError = 8; - -let kTrapMsgs = [ - "unreachable", - "memory access out of bounds", - "divide by zero", - "divide result unrepresentable", - "remainder by zero", - "float unrepresentable in integer range", - "invalid index into function table", - "function signature mismatch", - "wasm function signature contains illegal type" -]; - -function assertTraps(trap, code) { - try { - if (typeof code === 'function') { - code(); - } else { - eval(code); - } - } catch (e) { - assertEquals('object', typeof e); - assertEquals(kTrapMsgs[trap], e.message); - // Success. - return; - } - throw new MjsUnitAssertionError('Did not trap, expected: ' + kTrapMsgs[trap]); -} - -function assertWasmThrows(runtime_id, values, code) { - try { - if (typeof code === 'function') { - code(); - } else { - eval(code); - } - } catch (e) { - assertTrue(e instanceof WebAssembly.RuntimeError); - var e_runtime_id = e['WasmExceptionRuntimeId']; - assertEquals(e_runtime_id, runtime_id); - assertTrue(Number.isInteger(e_runtime_id)); - var e_values = e['WasmExceptionValues']; - assertEquals(values.length, e_values.length); - for (i = 0; i < values.length; ++i) { - assertEquals(values[i], e_values[i]); - } - // Success. - return; - } - throw new MjsUnitAssertionError('Did not throw expected: ' + runtime_id + values); -} - -function wasmI32Const(val) { - let bytes = [kExprI32Const]; - for (let i = 0; i < 4; ++i) { - bytes.push(0x80 | ((val >> (7 * i)) & 0x7f)); - } - bytes.push((val >> (7 * 4)) & 0x7f); - return bytes; -} - -function wasmF32Const(f) { - return [kExprF32Const].concat(Array.from(new Uint8Array((new Float32Array([f])).buffer))); -} - -function wasmF64Const(f) { - return [kExprF64Const].concat(Array.from(new Uint8Array((new Float64Array([f])).buffer))); -}
diff --git a/third_party/blink/web_tests/http/tests/wasm/resources/wasm-module-builder.js b/third_party/blink/web_tests/http/tests/wasm/resources/wasm-module-builder.js index c787c280..95e88cac 100644 --- a/third_party/blink/web_tests/http/tests/wasm/resources/wasm-module-builder.js +++ b/third_party/blink/web_tests/http/tests/wasm/resources/wasm-module-builder.js
@@ -1,46 +1,827 @@ -// Copyright 2017 the V8 project authors. All rights reserved. +// Copyright 2021 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Used for encoding f32 and double constants to bits. -let __buffer = new ArrayBuffer(8); -let byte_view = new Int8Array(__buffer); -let f32_view = new Float32Array(__buffer); -let f64_view = new Float64Array(__buffer); +let byte_view = new Uint8Array(8); +let data_view = new DataView(byte_view.buffer); -class Binary extends Array { +// The bytes function receives one of +// - several arguments, each of which is either a number or a string of length +// 1; if it's a string, the charcode of the contained character is used. +// - a single array argument containing the actual arguments +// - a single string; the returned buffer will contain the char codes of all +// contained characters. +function bytes(...input) { + if (input.length == 1 && typeof input[0] == 'array') input = input[0]; + if (input.length == 1 && typeof input[0] == 'string') { + let len = input[0].length; + let view = new Uint8Array(len); + for (let i = 0; i < len; i++) view[i] = input[0].charCodeAt(i); + return view.buffer; + } + let view = new Uint8Array(input.length); + for (let i = 0; i < input.length; i++) { + let val = input[i]; + if (typeof val == 'string') { + assertEquals(1, val.length, 'string inputs must have length 1'); + val = val.charCodeAt(0); + } + view[i] = val | 0; + } + return view.buffer; +} + +// Header declaration constants +var kWasmH0 = 0; +var kWasmH1 = 0x61; +var kWasmH2 = 0x73; +var kWasmH3 = 0x6d; + +var kWasmV0 = 0x1; +var kWasmV1 = 0; +var kWasmV2 = 0; +var kWasmV3 = 0; + +var kHeaderSize = 8; +var kPageSize = 65536; +var kSpecMaxPages = 65536; +var kMaxVarInt32Size = 5; +var kMaxVarInt64Size = 10; + +let kDeclNoLocals = 0; + +// Section declaration constants +let kUnknownSectionCode = 0; +let kTypeSectionCode = 1; // Function signature declarations +let kImportSectionCode = 2; // Import declarations +let kFunctionSectionCode = 3; // Function declarations +let kTableSectionCode = 4; // Indirect function table and other tables +let kMemorySectionCode = 5; // Memory attributes +let kGlobalSectionCode = 6; // Global declarations +let kExportSectionCode = 7; // Exports +let kStartSectionCode = 8; // Start function declaration +let kElementSectionCode = 9; // Elements section +let kCodeSectionCode = 10; // Function code +let kDataSectionCode = 11; // Data segments +let kDataCountSectionCode = 12; // Data segment count (between Element & Code) +let kExceptionSectionCode = 13; // Exception section (between Memory & Global) + +// Name section types +let kModuleNameCode = 0; +let kFunctionNamesCode = 1; +let kLocalNamesCode = 2; + +let kWasmFunctionTypeForm = 0x60; +let kWasmStructTypeForm = 0x5f; +let kWasmArrayTypeForm = 0x5e; + +let kLimitsNoMaximum = 0x00; +let kLimitsWithMaximum = 0x01; +let kLimitsSharedNoMaximum = 0x02; +let kLimitsSharedWithMaximum = 0x03; +let kLimitsMemory64NoMaximum = 0x04; +let kLimitsMemory64WithMaximum = 0x05; + +// Segment flags +let kActiveNoIndex = 0; +let kPassive = 1; +let kActiveWithIndex = 2; +let kDeclarative = 3; +let kPassiveWithElements = 5; +let kDeclarativeWithElements = 7; + +// Function declaration flags +let kDeclFunctionName = 0x01; +let kDeclFunctionImport = 0x02; +let kDeclFunctionLocals = 0x04; +let kDeclFunctionExport = 0x08; + +// Value types and related +let kWasmStmt = 0x40; +let kWasmI32 = 0x7f; +let kWasmI64 = 0x7e; +let kWasmF32 = 0x7d; +let kWasmF64 = 0x7c; +let kWasmS128 = 0x7b; +let kWasmI8 = 0x7a; +let kWasmI16 = 0x79; +let kWasmFuncRef = 0x70; +let kWasmAnyFunc = kWasmFuncRef; // Alias named as in the JS API spec +let kWasmExternRef = 0x6f; +let kWasmAnyRef = 0x6e; +let kWasmEqRef = 0x6d; +let kWasmOptRef = 0x6c; +let kWasmRef = 0x6b; +function wasmOptRefType(index) { return {opcode: kWasmOptRef, index: index}; } +function wasmRefType(index) { return {opcode: kWasmRef, index: index}; } +let kWasmI31Ref = 0x6a; +let kWasmRtt = 0x69; +function wasmRtt(index, depth) { + return {opcode: kWasmRtt, index: index, depth: depth}; +} + +let kExternalFunction = 0; +let kExternalTable = 1; +let kExternalMemory = 2; +let kExternalGlobal = 3; +let kExternalException = 4; + +let kTableZero = 0; +let kMemoryZero = 0; +let kSegmentZero = 0; + +let kExceptionAttribute = 0; + +// Useful signatures +let kSig_i_i = makeSig([kWasmI32], [kWasmI32]); +let kSig_l_l = makeSig([kWasmI64], [kWasmI64]); +let kSig_i_l = makeSig([kWasmI64], [kWasmI32]); +let kSig_i_ii = makeSig([kWasmI32, kWasmI32], [kWasmI32]); +let kSig_i_iii = makeSig([kWasmI32, kWasmI32, kWasmI32], [kWasmI32]); +let kSig_v_iiii = makeSig([kWasmI32, kWasmI32, kWasmI32, kWasmI32], []); +let kSig_f_ff = makeSig([kWasmF32, kWasmF32], [kWasmF32]); +let kSig_d_dd = makeSig([kWasmF64, kWasmF64], [kWasmF64]); +let kSig_l_ll = makeSig([kWasmI64, kWasmI64], [kWasmI64]); +let kSig_i_dd = makeSig([kWasmF64, kWasmF64], [kWasmI32]); +let kSig_v_v = makeSig([], []); +let kSig_i_v = makeSig([], [kWasmI32]); +let kSig_l_v = makeSig([], [kWasmI64]); +let kSig_f_v = makeSig([], [kWasmF32]); +let kSig_d_v = makeSig([], [kWasmF64]); +let kSig_v_i = makeSig([kWasmI32], []); +let kSig_v_ii = makeSig([kWasmI32, kWasmI32], []); +let kSig_v_iii = makeSig([kWasmI32, kWasmI32, kWasmI32], []); +let kSig_v_l = makeSig([kWasmI64], []); +let kSig_v_d = makeSig([kWasmF64], []); +let kSig_v_dd = makeSig([kWasmF64, kWasmF64], []); +let kSig_v_ddi = makeSig([kWasmF64, kWasmF64, kWasmI32], []); +let kSig_ii_v = makeSig([], [kWasmI32, kWasmI32]); +let kSig_iii_v = makeSig([], [kWasmI32, kWasmI32, kWasmI32]); +let kSig_ii_i = makeSig([kWasmI32], [kWasmI32, kWasmI32]); +let kSig_iii_i = makeSig([kWasmI32], [kWasmI32, kWasmI32, kWasmI32]); +let kSig_ii_ii = makeSig([kWasmI32, kWasmI32], [kWasmI32, kWasmI32]); +let kSig_iii_ii = makeSig([kWasmI32, kWasmI32], [kWasmI32, kWasmI32, kWasmI32]); + +let kSig_v_f = makeSig([kWasmF32], []); +let kSig_f_f = makeSig([kWasmF32], [kWasmF32]); +let kSig_f_d = makeSig([kWasmF64], [kWasmF32]); +let kSig_d_d = makeSig([kWasmF64], [kWasmF64]); +let kSig_r_r = makeSig([kWasmExternRef], [kWasmExternRef]); +let kSig_a_a = makeSig([kWasmAnyFunc], [kWasmAnyFunc]); +let kSig_i_r = makeSig([kWasmExternRef], [kWasmI32]); +let kSig_v_r = makeSig([kWasmExternRef], []); +let kSig_v_a = makeSig([kWasmAnyFunc], []); +let kSig_v_rr = makeSig([kWasmExternRef, kWasmExternRef], []); +let kSig_v_aa = makeSig([kWasmAnyFunc, kWasmAnyFunc], []); +let kSig_r_v = makeSig([], [kWasmExternRef]); +let kSig_a_v = makeSig([], [kWasmAnyFunc]); +let kSig_a_i = makeSig([kWasmI32], [kWasmAnyFunc]); +let kSig_s_i = makeSig([kWasmI32], [kWasmS128]); +let kSig_i_s = makeSig([kWasmS128], [kWasmI32]); + +function makeSig(params, results) { + return {params: params, results: results}; +} + +function makeSig_v_x(x) { + return makeSig([x], []); +} + +function makeSig_v_xx(x) { + return makeSig([x, x], []); +} + +function makeSig_r_v(r) { + return makeSig([], [r]); +} + +function makeSig_r_x(r, x) { + return makeSig([x], [r]); +} + +function makeSig_r_xx(r, x) { + return makeSig([x, x], [r]); +} + +// Opcodes +const kWasmOpcodes = { + 'Unreachable': 0x00, + 'Nop': 0x01, + 'Block': 0x02, + 'Loop': 0x03, + 'If': 0x04, + 'Else': 0x05, + 'Try': 0x06, + 'Catch': 0x07, + 'Throw': 0x08, + 'Rethrow': 0x09, + 'Unwind': 0x0a, + 'End': 0x0b, + 'Br': 0x0c, + 'BrIf': 0x0d, + 'BrTable': 0x0e, + 'Return': 0x0f, + 'CallFunction': 0x10, + 'CallIndirect': 0x11, + 'ReturnCall': 0x12, + 'ReturnCallIndirect': 0x13, + 'CallRef': 0x14, + 'ReturnCallRef': 0x15, + 'Let': 0x17, + 'Delegate': 0x18, + 'Drop': 0x1a, + 'Select': 0x1b, + 'SelectWithType': 0x1c, + 'LocalGet': 0x20, + 'LocalSet': 0x21, + 'LocalTee': 0x22, + 'GlobalGet': 0x23, + 'GlobalSet': 0x24, + 'TableGet': 0x25, + 'TableSet': 0x26, + 'I32LoadMem': 0x28, + 'I64LoadMem': 0x29, + 'F32LoadMem': 0x2a, + 'F64LoadMem': 0x2b, + 'I32LoadMem8S': 0x2c, + 'I32LoadMem8U': 0x2d, + 'I32LoadMem16S': 0x2e, + 'I32LoadMem16U': 0x2f, + 'I64LoadMem8S': 0x30, + 'I64LoadMem8U': 0x31, + 'I64LoadMem16S': 0x32, + 'I64LoadMem16U': 0x33, + 'I64LoadMem32S': 0x34, + 'I64LoadMem32U': 0x35, + 'I32StoreMem': 0x36, + 'I64StoreMem': 0x37, + 'F32StoreMem': 0x38, + 'F64StoreMem': 0x39, + 'I32StoreMem8': 0x3a, + 'I32StoreMem16': 0x3b, + 'I64StoreMem8': 0x3c, + 'I64StoreMem16': 0x3d, + 'I64StoreMem32': 0x3e, + 'MemorySize': 0x3f, + 'MemoryGrow': 0x40, + 'I32Const': 0x41, + 'I64Const': 0x42, + 'F32Const': 0x43, + 'F64Const': 0x44, + 'I32Eqz': 0x45, + 'I32Eq': 0x46, + 'I32Ne': 0x47, + 'I32LtS': 0x48, + 'I32LtU': 0x49, + 'I32GtS': 0x4a, + 'I32GtU': 0x4b, + 'I32LeS': 0x4c, + 'I32LeU': 0x4d, + 'I32GeS': 0x4e, + 'I32GeU': 0x4f, + 'I64Eqz': 0x50, + 'I64Eq': 0x51, + 'I64Ne': 0x52, + 'I64LtS': 0x53, + 'I64LtU': 0x54, + 'I64GtS': 0x55, + 'I64GtU': 0x56, + 'I64LeS': 0x57, + 'I64LeU': 0x58, + 'I64GeS': 0x59, + 'I64GeU': 0x5a, + 'F32Eq': 0x5b, + 'F32Ne': 0x5c, + 'F32Lt': 0x5d, + 'F32Gt': 0x5e, + 'F32Le': 0x5f, + 'F32Ge': 0x60, + 'F64Eq': 0x61, + 'F64Ne': 0x62, + 'F64Lt': 0x63, + 'F64Gt': 0x64, + 'F64Le': 0x65, + 'F64Ge': 0x66, + 'I32Clz': 0x67, + 'I32Ctz': 0x68, + 'I32Popcnt': 0x69, + 'I32Add': 0x6a, + 'I32Sub': 0x6b, + 'I32Mul': 0x6c, + 'I32DivS': 0x6d, + 'I32DivU': 0x6e, + 'I32RemS': 0x6f, + 'I32RemU': 0x70, + 'I32And': 0x71, + 'I32Ior': 0x72, + 'I32Xor': 0x73, + 'I32Shl': 0x74, + 'I32ShrS': 0x75, + 'I32ShrU': 0x76, + 'I32Rol': 0x77, + 'I32Ror': 0x78, + 'I64Clz': 0x79, + 'I64Ctz': 0x7a, + 'I64Popcnt': 0x7b, + 'I64Add': 0x7c, + 'I64Sub': 0x7d, + 'I64Mul': 0x7e, + 'I64DivS': 0x7f, + 'I64DivU': 0x80, + 'I64RemS': 0x81, + 'I64RemU': 0x82, + 'I64And': 0x83, + 'I64Ior': 0x84, + 'I64Xor': 0x85, + 'I64Shl': 0x86, + 'I64ShrS': 0x87, + 'I64ShrU': 0x88, + 'I64Rol': 0x89, + 'I64Ror': 0x8a, + 'F32Abs': 0x8b, + 'F32Neg': 0x8c, + 'F32Ceil': 0x8d, + 'F32Floor': 0x8e, + 'F32Trunc': 0x8f, + 'F32NearestInt': 0x90, + 'F32Sqrt': 0x91, + 'F32Add': 0x92, + 'F32Sub': 0x93, + 'F32Mul': 0x94, + 'F32Div': 0x95, + 'F32Min': 0x96, + 'F32Max': 0x97, + 'F32CopySign': 0x98, + 'F64Abs': 0x99, + 'F64Neg': 0x9a, + 'F64Ceil': 0x9b, + 'F64Floor': 0x9c, + 'F64Trunc': 0x9d, + 'F64NearestInt': 0x9e, + 'F64Sqrt': 0x9f, + 'F64Add': 0xa0, + 'F64Sub': 0xa1, + 'F64Mul': 0xa2, + 'F64Div': 0xa3, + 'F64Min': 0xa4, + 'F64Max': 0xa5, + 'F64CopySign': 0xa6, + 'I32ConvertI64': 0xa7, + 'I32SConvertF32': 0xa8, + 'I32UConvertF32': 0xa9, + 'I32SConvertF64': 0xaa, + 'I32UConvertF64': 0xab, + 'I64SConvertI32': 0xac, + 'I64UConvertI32': 0xad, + 'I64SConvertF32': 0xae, + 'I64UConvertF32': 0xaf, + 'I64SConvertF64': 0xb0, + 'I64UConvertF64': 0xb1, + 'F32SConvertI32': 0xb2, + 'F32UConvertI32': 0xb3, + 'F32SConvertI64': 0xb4, + 'F32UConvertI64': 0xb5, + 'F32ConvertF64': 0xb6, + 'F64SConvertI32': 0xb7, + 'F64UConvertI32': 0xb8, + 'F64SConvertI64': 0xb9, + 'F64UConvertI64': 0xba, + 'F64ConvertF32': 0xbb, + 'I32ReinterpretF32': 0xbc, + 'I64ReinterpretF64': 0xbd, + 'F32ReinterpretI32': 0xbe, + 'F64ReinterpretI64': 0xbf, + 'I32SExtendI8': 0xc0, + 'I32SExtendI16': 0xc1, + 'I64SExtendI8': 0xc2, + 'I64SExtendI16': 0xc3, + 'I64SExtendI32': 0xc4, + 'RefNull': 0xd0, + 'RefIsNull': 0xd1, + 'RefFunc': 0xd2 +}; + +function defineWasmOpcode(name, value) { + if (globalThis.kWasmOpcodeNames === undefined) { + globalThis.kWasmOpcodeNames = {}; + } + Object.defineProperty(globalThis, name, {value: value}); + if (globalThis.kWasmOpcodeNames[value] !== undefined) { + throw new Error(`Duplicate wasm opcode: ${value}. Previous name: ${ + globalThis.kWasmOpcodeNames[value]}, new name: ${name}`); + } + globalThis.kWasmOpcodeNames[value] = name; +} +for (let name in kWasmOpcodes) { + defineWasmOpcode(`kExpr${name}`, kWasmOpcodes[name]); +} + +// Prefix opcodes +const kPrefixOpcodes = { + 'GC': 0xfb, + 'Numeric': 0xfc, + 'Simd': 0xfd, + 'Atomic': 0xfe +}; +for (let prefix in kPrefixOpcodes) { + defineWasmOpcode(`k${prefix}Prefix`, kPrefixOpcodes[prefix]); +} + +// GC opcodes +let kExprStructNewWithRtt = 0x01; +let kExprStructNewDefault = 0x02; +let kExprStructGet = 0x03; +let kExprStructGetS = 0x04; +let kExprStructGetU = 0x05; +let kExprStructSet = 0x06; +let kExprArrayNewWithRtt = 0x11; +let kExprArrayNewDefault = 0x12; +let kExprArrayGet = 0x13; +let kExprArrayGetS = 0x14; +let kExprArrayGetU = 0x15; +let kExprArraySet = 0x16; +let kExprArrayLen = 0x17; +let kExprI31New = 0x20; +let kExprI31GetS = 0x21; +let kExprI31GetU = 0x22; +let kExprRttCanon = 0x30; +let kExprRttSub = 0x31; +let kExprRefTest = 0x40; +let kExprRefCast = 0x41; +let kExprBrOnCast = 0x42; + +// Numeric opcodes. +let kExprI32SConvertSatF32 = 0x00; +let kExprI32UConvertSatF32 = 0x01; +let kExprI32SConvertSatF64 = 0x02; +let kExprI32UConvertSatF64 = 0x03; +let kExprI64SConvertSatF32 = 0x04; +let kExprI64UConvertSatF32 = 0x05; +let kExprI64SConvertSatF64 = 0x06; +let kExprI64UConvertSatF64 = 0x07; +let kExprMemoryInit = 0x08; +let kExprDataDrop = 0x09; +let kExprMemoryCopy = 0x0a; +let kExprMemoryFill = 0x0b; +let kExprTableInit = 0x0c; +let kExprElemDrop = 0x0d; +let kExprTableCopy = 0x0e; +let kExprTableGrow = 0x0f; +let kExprTableSize = 0x10; +let kExprTableFill = 0x11; + +// Atomic opcodes. +let kExprAtomicNotify = 0x00; +let kExprI32AtomicWait = 0x01; +let kExprI64AtomicWait = 0x02; +let kExprI32AtomicLoad = 0x10; +let kExprI32AtomicLoad8U = 0x12; +let kExprI32AtomicLoad16U = 0x13; +let kExprI32AtomicStore = 0x17; +let kExprI32AtomicStore8U = 0x19; +let kExprI32AtomicStore16U = 0x1a; +let kExprI32AtomicAdd = 0x1e; +let kExprI32AtomicAdd8U = 0x20; +let kExprI32AtomicAdd16U = 0x21; +let kExprI32AtomicSub = 0x25; +let kExprI32AtomicSub8U = 0x27; +let kExprI32AtomicSub16U = 0x28; +let kExprI32AtomicAnd = 0x2c; +let kExprI32AtomicAnd8U = 0x2e; +let kExprI32AtomicAnd16U = 0x2f; +let kExprI32AtomicOr = 0x33; +let kExprI32AtomicOr8U = 0x35; +let kExprI32AtomicOr16U = 0x36; +let kExprI32AtomicXor = 0x3a; +let kExprI32AtomicXor8U = 0x3c; +let kExprI32AtomicXor16U = 0x3d; +let kExprI32AtomicExchange = 0x41; +let kExprI32AtomicExchange8U = 0x43; +let kExprI32AtomicExchange16U = 0x44; +let kExprI32AtomicCompareExchange = 0x48; +let kExprI32AtomicCompareExchange8U = 0x4a; +let kExprI32AtomicCompareExchange16U = 0x4b; + +let kExprI64AtomicLoad = 0x11; +let kExprI64AtomicLoad8U = 0x14; +let kExprI64AtomicLoad16U = 0x15; +let kExprI64AtomicLoad32U = 0x16; +let kExprI64AtomicStore = 0x18; +let kExprI64AtomicStore8U = 0x1b; +let kExprI64AtomicStore16U = 0x1c; +let kExprI64AtomicStore32U = 0x1d; +let kExprI64AtomicAdd = 0x1f; +let kExprI64AtomicAdd8U = 0x22; +let kExprI64AtomicAdd16U = 0x23; +let kExprI64AtomicAdd32U = 0x24; +let kExprI64AtomicSub = 0x26; +let kExprI64AtomicSub8U = 0x29; +let kExprI64AtomicSub16U = 0x2a; +let kExprI64AtomicSub32U = 0x2b; +let kExprI64AtomicAnd = 0x2d; +let kExprI64AtomicAnd8U = 0x30; +let kExprI64AtomicAnd16U = 0x31; +let kExprI64AtomicAnd32U = 0x32; +let kExprI64AtomicOr = 0x34; +let kExprI64AtomicOr8U = 0x37; +let kExprI64AtomicOr16U = 0x38; +let kExprI64AtomicOr32U = 0x39; +let kExprI64AtomicXor = 0x3b; +let kExprI64AtomicXor8U = 0x3e; +let kExprI64AtomicXor16U = 0x3f; +let kExprI64AtomicXor32U = 0x40; +let kExprI64AtomicExchange = 0x42; +let kExprI64AtomicExchange8U = 0x45; +let kExprI64AtomicExchange16U = 0x46; +let kExprI64AtomicExchange32U = 0x47; +let kExprI64AtomicCompareExchange = 0x49 +let kExprI64AtomicCompareExchange8U = 0x4c; +let kExprI64AtomicCompareExchange16U = 0x4d; +let kExprI64AtomicCompareExchange32U = 0x4e; + +// Simd opcodes. +let kExprS128LoadMem = 0x00; +let kExprS128Load8x8S = 0x01; +let kExprS128Load8x8U = 0x02; +let kExprS128Load16x4S = 0x03; +let kExprS128Load16x4U = 0x04; +let kExprS128Load32x2S = 0x05; +let kExprS128Load32x2U = 0x06; +let kExprS128Load8Splat = 0x07; +let kExprS128Load16Splat = 0x08; +let kExprS128Load32Splat = 0x09; +let kExprS128Load64Splat = 0x0a; +let kExprS128StoreMem = 0x0b; + +let kExprS128Const = 0x0c; +let kExprI8x16Shuffle = 0x0d; + +let kExprI8x16Swizzle = 0x0e; +let kExprI8x16Splat = 0x0f; +let kExprI16x8Splat = 0x10; +let kExprI32x4Splat = 0x11; +let kExprI64x2Splat = 0x12; +let kExprF32x4Splat = 0x13; +let kExprF64x2Splat = 0x14; +let kExprI8x16ReplaceLane = 0x17; +let kExprI16x8ExtractLaneS = 0x18; +let kExprI16x8ReplaceLane = 0x1a; +let kExprI32x4ExtractLane = 0x1b; +let kExprI32x4ReplaceLane = 0x1c; +let kExprI64x2ReplaceLane = 0x1e; +let kExprF32x4ReplaceLane = 0x20; +let kExprF64x2ExtractLane = 0x21; +let kExprF64x2ReplaceLane = 0x22; +let kExprI8x16Eq = 0x23; +let kExprI8x16Ne = 0x24; +let kExprI8x16LtS = 0x25; +let kExprI8x16LtU = 0x26; +let kExprI8x16GtS = 0x27; +let kExprI8x16GtU = 0x28; +let kExprI8x16LeS = 0x29; +let kExprI8x16LeU = 0x2a; +let kExprI8x16GeS = 0x2b; +let kExprI8x16GeU = 0x2c; +let kExprI16x8Eq = 0x2d; +let kExprI16x8Ne = 0x2e; +let kExprI16x8LtS = 0x2f; +let kExprI16x8LtU = 0x30; +let kExprI16x8GtS = 0x31; +let kExprI16x8GtU = 0x32; +let kExprI16x8LeS = 0x33; +let kExprI16x8LeU = 0x34; +let kExprI16x8GeS = 0x35; +let kExprI16x8GeU = 0x36; +let kExprI32x4Eq = 0x37; +let kExprI32x4Ne = 0x38; +let kExprI32x4LtS = 0x39; +let kExprI32x4LtU = 0x3a; +let kExprI32x4GtS = 0x3b; +let kExprI32x4GtU = 0x3c; +let kExprI32x4LeS = 0x3d; +let kExprI32x4LeU = 0x3e; +let kExprI32x4GeS = 0x3f; +let kExprI32x4GeU = 0x40; +let kExprF32x4Eq = 0x41; +let kExprF32x4Ne = 0x42; +let kExprF32x4Lt = 0x43; +let kExprF32x4Gt = 0x44; +let kExprF32x4Le = 0x45; +let kExprF32x4Ge = 0x46; +let kExprF64x2Eq = 0x47; +let kExprF64x2Ne = 0x48; +let kExprF64x2Lt = 0x49; +let kExprF64x2Gt = 0x4a; +let kExprF64x2Le = 0x4b; +let kExprF64x2Ge = 0x4c; +let kExprS128Not = 0x4d; +let kExprS128And = 0x4e; +let kExprS128AndNot = 0x4f; +let kExprS128Or = 0x50; +let kExprS128Xor = 0x51; +let kExprS128Select = 0x52; +let kExprI8x16Abs = 0x60; +let kExprI8x16Neg = 0x61; +let kExprV128AnyTrue = 0x62; +let kExprV8x16AllTrue = 0x63; +let kExprI8x16SConvertI16x8 = 0x65; +let kExprI8x16UConvertI16x8 = 0x66; +let kExprI8x16Shl = 0x6b; +let kExprI8x16ShrS = 0x6c; +let kExprI8x16ShrU = 0x6d; +let kExprI8x16Add = 0x6e; +let kExprI8x16AddSatS = 0x6f; +let kExprI8x16AddSatU = 0x70; +let kExprI8x16Sub = 0x71; +let kExprI8x16SubSatS = 0x72; +let kExprI8x16SubSatU = 0x73; +let kExprI8x16MinS = 0x76; +let kExprI8x16MinU = 0x77; +let kExprI8x16MaxS = 0x78; +let kExprI8x16MaxU = 0x79; +let kExprI8x16RoundingAverageU = 0x7b; +let kExprI16x8Abs = 0x80; +let kExprI16x8Neg = 0x81; +let kExprV16x8AllTrue = 0x83; +let kExprI16x8SConvertI32x4 = 0x85; +let kExprI16x8UConvertI32x4 = 0x86; +let kExprI16x8SConvertI8x16Low = 0x87; +let kExprI16x8SConvertI8x16High = 0x88; +let kExprI16x8UConvertI8x16Low = 0x89; +let kExprI16x8UConvertI8x16High = 0x8a; +let kExprI16x8Shl = 0x8b; +let kExprI16x8ShrS = 0x8c; +let kExprI16x8ShrU = 0x8d; +let kExprI16x8Add = 0x8e; +let kExprI16x8AddSatS = 0x8f; +let kExprI16x8AddSatU = 0x90; +let kExprI16x8Sub = 0x91; +let kExprI16x8SubSatS = 0x92; +let kExprI16x8SubSatU = 0x93; +let kExprI16x8Mul = 0x95; +let kExprI16x8MinS = 0x96; +let kExprI16x8MinU = 0x97; +let kExprI16x8MaxS = 0x98; +let kExprI16x8MaxU = 0x99; +let kExprI16x8RoundingAverageU = 0x9b; +let kExprI32x4Abs = 0xa0; +let kExprI32x4Neg = 0xa1; +let kExprV32x4AllTrue = 0xa3; +let kExprI32x4SConvertI16x8Low = 0xa7; +let kExprI32x4SConvertI16x8High = 0xa8; +let kExprI32x4UConvertI16x8Low = 0xa9; +let kExprI32x4UConvertI16x8High = 0xaa; +let kExprI32x4Shl = 0xab; +let kExprI32x4ShrS = 0xac; +let kExprI32x4ShrU = 0xad; +let kExprI32x4Add = 0xae; +let kExprI32x4Sub = 0xb1; +let kExprI32x4Mul = 0xb5; +let kExprI32x4MinS = 0xb6; +let kExprI32x4MinU = 0xb7; +let kExprI32x4MaxS = 0xb8; +let kExprI32x4MaxU = 0xb9; +let kExprI64x2Neg = 0xc1; +let kExprI64x2Shl = 0xcb; +let kExprI64x2ShrS = 0xcc; +let kExprI64x2ShrU = 0xcd; +let kExprI64x2Add = 0xce; +let kExprI64x2Sub = 0xd1; +let kExprI64x2Mul = 0xd5; +let kExprI64x2ExtMulHighI32x4U = 0xd7; +let kExprF32x4Abs = 0xe0; +let kExprF32x4Neg = 0xe1; +let kExprF32x4Sqrt = 0xe3; +let kExprF32x4Add = 0xe4; +let kExprF32x4Sub = 0xe5; +let kExprF32x4Mul = 0xe6; +let kExprF32x4Div = 0xe7; +let kExprF32x4Min = 0xe8; +let kExprF32x4Max = 0xe9; +let kExprF64x2Abs = 0xec; +let kExprF64x2Neg = 0xed; +let kExprF64x2Sqrt = 0xef; +let kExprF64x2Add = 0xf0; +let kExprF64x2Sub = 0xf1; +let kExprF64x2Mul = 0xf2; +let kExprF64x2Div = 0xf3; +let kExprF64x2Min = 0xf4; +let kExprF64x2Max = 0xf5; +let kExprI32x4SConvertF32x4 = 0xf8; +let kExprI32x4UConvertF32x4 = 0xf9; +let kExprF32x4SConvertI32x4 = 0xfa; +let kExprF32x4UConvertI32x4 = 0xfb; + +// Compilation hint constants. +let kCompilationHintStrategyDefault = 0x00; +let kCompilationHintStrategyLazy = 0x01; +let kCompilationHintStrategyEager = 0x02; +let kCompilationHintStrategyLazyBaselineEagerTopTier = 0x03; +let kCompilationHintTierDefault = 0x00; +let kCompilationHintTierBaseline = 0x01; +let kCompilationHintTierOptimized = 0x02; + +let kTrapUnreachable = 0; +let kTrapMemOutOfBounds = 1; +let kTrapDivByZero = 2; +let kTrapDivUnrepresentable = 3; +let kTrapRemByZero = 4; +let kTrapFloatUnrepresentable = 5; +let kTrapTableOutOfBounds = 6; +let kTrapFuncSigMismatch = 7; +let kTrapUnalignedAccess = 8; +let kTrapDataSegmentDropped = 9; +let kTrapElemSegmentDropped = 10; +let kTrapRethrowNull = 11; + +let kTrapMsgs = [ + "unreachable", + "memory access out of bounds", + "divide by zero", + "divide result unrepresentable", + "remainder by zero", + "float unrepresentable in integer range", + "table index is out of bounds", + "function signature mismatch", + "operation does not support unaligned accesses", + "data segment has been dropped", + "element segment has been dropped", + "rethrowing null value" +]; + +function assertTraps(trap, code) { + assertThrows(code, WebAssembly.RuntimeError, kTrapMsgs[trap]); +} + +class Binary { + constructor() { + this.length = 0; + this.buffer = new Uint8Array(8192); + } + + ensure_space(needed) { + if (this.buffer.length - this.length >= needed) return; + let new_capacity = this.buffer.length * 2; + while (new_capacity - this.length < needed) new_capacity *= 2; + let new_buffer = new Uint8Array(new_capacity); + new_buffer.set(this.buffer); + this.buffer = new_buffer; + } + + trunc_buffer() { + return new Uint8Array(this.buffer.buffer, 0, this.length); + } + + reset() { + this.length = 0; + } + emit_u8(val) { - this.push(val); + this.ensure_space(1); + this.buffer[this.length++] = val; } emit_u16(val) { - this.push(val & 0xff); - this.push((val >> 8) & 0xff); + this.ensure_space(2); + this.buffer[this.length++] = val; + this.buffer[this.length++] = val >> 8; } emit_u32(val) { - this.push(val & 0xff); - this.push((val >> 8) & 0xff); - this.push((val >> 16) & 0xff); - this.push((val >> 24) & 0xff); + this.ensure_space(4); + this.buffer[this.length++] = val; + this.buffer[this.length++] = val >> 8; + this.buffer[this.length++] = val >> 16; + this.buffer[this.length++] = val >> 24; } - emit_u32v(val) { - while (true) { + emit_leb_u(val, max_len) { + this.ensure_space(max_len); + for (let i = 0; i < max_len; ++i) { let v = val & 0xff; val = val >>> 7; if (val == 0) { - this.push(v); - break; + this.buffer[this.length++] = v; + return; } - this.push(v | 0x80); + this.buffer[this.length++] = v | 0x80; } + throw new Error("Leb value exceeds maximum length of " + max_len); + } + + emit_u32v(val) { + this.emit_leb_u(val, kMaxVarInt32Size); + } + + emit_u64v(val) { + this.emit_leb_u(val, kMaxVarInt64Size); } emit_bytes(data) { - for (let i = 0; i < data.length; i++) { - this.push(data[i] & 0xff); - } + this.ensure_space(data.length); + this.buffer.set(data, this.length); + this.length += data.length; } emit_string(string) { @@ -60,37 +841,52 @@ } } + emit_type(type) { + if ((typeof type) == "number") this.emit_u8(type); + else { + this.emit_u8(type.opcode); + if ('depth' in type) this.emit_u8(type.depth); + this.emit_u32v(type.index); + } + } + emit_header() { - this.push(kWasmH0, kWasmH1, kWasmH2, kWasmH3, - kWasmV0, kWasmV1, kWasmV2, kWasmV3); + this.emit_bytes([ + kWasmH0, kWasmH1, kWasmH2, kWasmH3, kWasmV0, kWasmV1, kWasmV2, kWasmV3 + ]); } emit_section(section_code, content_generator) { // Emit section name. this.emit_u8(section_code); // Emit the section to a temporary buffer: its full length isn't know yet. - let section = new Binary; + const section = new Binary; content_generator(section); // Emit section length. this.emit_u32v(section.length); // Copy the temporary buffer. - for (var i = 0; i < section.length; i++) this.push(section[i]); + // Avoid spread because {section} can be huge. + this.emit_bytes(section.trunc_buffer()); } } class WasmFunctionBuilder { - constructor(module, name, type_index) { + // Encoding of local names: a string corresponds to a local name, + // a number n corresponds to n undefined names. + constructor(module, name, type_index, arg_names) { this.module = module; this.name = name; this.type_index = type_index; this.body = []; + this.locals = []; + this.local_names = arg_names; + this.body_offset = undefined; // Not valid until module is serialized. } numLocalNames() { - if (this.local_names === undefined) return 0; let num_local_names = 0; for (let loc_name of this.local_names) { - if (loc_name !== undefined) ++num_local_names; + if (typeof loc_name == "string") ++num_local_names; } return num_local_names; } @@ -105,6 +901,11 @@ return this; } + setCompilationHint(strategy, baselineTier, topTier) { + this.module.setCompilationHint(strategy, baselineTier, topTier, this.index); + return this; + } + addBody(body) { for (let b of body) { if (typeof b !== 'number' || (b & (~0xFF)) !== 0 ) @@ -123,23 +924,18 @@ getNumLocals() { let total_locals = 0; - for (let l of this.locals || []) { - for (let type of ["i32", "i64", "f32", "f64", "s128"]) { - total_locals += l[type + "_count"] || 0; - } + for (let l of this.locals) { + total_locals += l.count } return total_locals; } - addLocals(locals, names) { - const old_num_locals = this.getNumLocals(); - if (!this.locals) this.locals = [] - this.locals.push(locals); - if (names) { - if (!this.local_names) this.local_names = []; - const missing_names = old_num_locals - this.local_names.length; - this.local_names.push(...new Array(missing_names), ...names); - } + addLocals(type, count, names) { + this.locals.push({type: type, count: count}); + names = names || []; + if (names.length > count) throw new Error('too many locals names given'); + this.local_names.push(...names); + if (count > names.length) this.local_names.push(count - names.length); return this; } @@ -163,22 +959,58 @@ } } +class WasmTableBuilder { + constructor(module, type, initial_size, max_size) { + this.module = module; + this.type = type; + this.initial_size = initial_size; + this.has_max = max_size != undefined; + this.max_size = max_size; + } + + exportAs(name) { + this.module.exports.push({name: name, kind: kExternalTable, + index: this.index}); + return this; + } +} + +function makeField(type, mutability) { + assertEquals("boolean", typeof mutability, + "field mutability must be boolean"); + return {type: type, mutability: mutability}; +} + +class WasmStruct { + constructor(fields) { + assertTrue(Array.isArray(fields), "struct fields must be an array"); + this.fields = fields; + } +} + +class WasmArray { + constructor(type) { + this.type = type; + } +} + class WasmModuleBuilder { constructor() { this.types = []; this.imports = []; this.exports = []; this.globals = []; + this.tables = []; this.exceptions = []; this.functions = []; - this.function_table = []; - this.function_table_length_min = 0; - this.function_table_length_max = 0; - this.function_table_inits = []; - this.segments = []; + this.compilation_hints = []; + this.element_segments = []; + this.data_segments = []; this.explicit = []; this.num_imported_funcs = 0; this.num_imported_globals = 0; + this.num_imported_tables = 0; + this.num_imported_exceptions = 0; return this; } @@ -187,8 +1019,25 @@ return this; } - addMemory(min, max, exp, shared) { - this.memory = {min: min, max: max, exp: exp, shared: shared}; + addMemory(min, max, exported, shared) { + this.memory = { + min: min, + max: max, + exported: exported, + shared: shared || false, + is_memory64: false + }; + return this; + } + + addMemory64(min, max, exported) { + this.memory = { + min: min, + max: max, + exported: exported, + shared: false, + is_memory64: true + }; return this; } @@ -203,14 +1052,21 @@ for (var i = 0; i < name.length; i++) { result.emit_u8(name.charCodeAt(i)); } - return result; + return result.trunc_buffer() + } + + createCustomSection(name, bytes) { + name = this.stringToBytes(name); + var section = new Binary(); + section.emit_u8(0); + section.emit_u32v(name.length + bytes.length); + section.emit_bytes(name); + section.emit_bytes(bytes); + return section.trunc_buffer(); } addCustomSection(name, bytes) { - name = this.stringToBytes(name); - var length = new Binary(); - length.emit_u32v(name.length + bytes.length); - this.explicit.push([0, ...length, ...name, ...bytes]); + this.explicit.push(this.createCustomSection(name, bytes)); } addType(type) { @@ -220,53 +1076,99 @@ return this.types.length - 1; } - addGlobal(local_type, mutable) { - let glob = new WasmGlobalBuilder(this, local_type, mutable); + addStruct(fields) { + this.types.push(new WasmStruct(fields)); + return this.types.length - 1; + } + + addArray(type) { + this.types.push(new WasmArray(type)); + return this.types.length - 1; + } + + addGlobal(type, mutable) { + let glob = new WasmGlobalBuilder(this, type, mutable); glob.index = this.globals.length + this.num_imported_globals; this.globals.push(glob); return glob; } - addException(type) { - if (type.results.length != 0) - throw new Error('Invalid exception signature: ' + type); - this.exceptions.push(type); - return this.exceptions.length - 1; + addTable(type, initial_size, max_size = undefined) { + if (type == kWasmI32 || type == kWasmI64 || type == kWasmF32 || + type == kWasmF64 || type == kWasmS128 || type == kWasmStmt) { + throw new Error('Tables must be of a reference type'); + } + let table = new WasmTableBuilder(this, type, initial_size, max_size); + table.index = this.tables.length + this.num_imported_tables; + this.tables.push(table); + return table; } - addFunction(name, type) { + addException(type) { let type_index = (typeof type) == "number" ? type : this.addType(type); - let func = new WasmFunctionBuilder(this, name, type_index); + let except_index = this.exceptions.length + this.num_imported_exceptions; + this.exceptions.push(type_index); + return except_index; + } + + addFunction(name, type, arg_names) { + arg_names = arg_names || []; + let type_index = (typeof type) == "number" ? type : this.addType(type); + let num_args = this.types[type_index].params.length; + if (num_args < arg_names.length) throw new Error("too many arg names provided"); + if (num_args > arg_names.length) arg_names.push(num_args - arg_names.length); + let func = new WasmFunctionBuilder(this, name, type_index, arg_names); func.index = this.functions.length + this.num_imported_funcs; this.functions.push(func); return func; } - addImport(module = "", name, type) { + addImport(module, name, type) { + if (this.functions.length != 0) { + throw new Error('Imported functions must be declared before local ones'); + } let type_index = (typeof type) == "number" ? type : this.addType(type); this.imports.push({module: module, name: name, kind: kExternalFunction, - type: type_index}); + type_index: type_index}); return this.num_imported_funcs++; } - addImportedGlobal(module = "", name, type, mutable = false) { + addImportedGlobal(module, name, type, mutable = false) { + if (this.globals.length != 0) { + throw new Error('Imported globals must be declared before local ones'); + } let o = {module: module, name: name, kind: kExternalGlobal, type: type, mutable: mutable}; this.imports.push(o); return this.num_imported_globals++; } - addImportedMemory(module = "", name, initial = 0, maximum, shared) { + addImportedMemory(module, name, initial = 0, maximum, shared) { let o = {module: module, name: name, kind: kExternalMemory, initial: initial, maximum: maximum, shared: shared}; this.imports.push(o); return this; } - addImportedTable(module = "", name, initial, maximum) { + addImportedTable(module, name, initial, maximum, type) { + if (this.tables.length != 0) { + throw new Error('Imported tables must be declared before local ones'); + } let o = {module: module, name: name, kind: kExternalTable, initial: initial, - maximum: maximum}; + maximum: maximum, type: type || kWasmFuncRef}; this.imports.push(o); + return this.num_imported_tables++; + } + + addImportedException(module, name, type) { + if (this.exceptions.length != 0) { + throw new Error('Imported exceptions must be declared before local ones'); + } + let type_index = (typeof type) == "number" ? type : this.addType(type); + let o = {module: module, name: name, kind: kExternalException, + type_index: type_index}; + this.imports.push(o); + return this.num_imported_exceptions++; } addExport(name, index) { @@ -275,31 +1177,60 @@ } addExportOfKind(name, kind, index) { + if (index == undefined && kind != kExternalTable && + kind != kExternalMemory) { + throw new Error( + 'Index for exports other than tables/memories must be provided'); + } + if (index !== undefined && (typeof index) != 'number') { + throw new Error('Index for exports must be a number') + } this.exports.push({name: name, kind: kind, index: index}); return this; } + setCompilationHint(strategy, baselineTier, topTier, index) { + this.compilation_hints[index] = {strategy: strategy, baselineTier: + baselineTier, topTier: topTier}; + return this; + } + addDataSegment(addr, data, is_global = false) { - this.segments.push({addr: addr, data: data, is_global: is_global}); - return this.segments.length - 1; + this.data_segments.push( + {addr: addr, data: data, is_global: is_global, is_active: true}); + return this.data_segments.length - 1; + } + + addPassiveDataSegment(data) { + this.data_segments.push({data: data, is_active: false}); + return this.data_segments.length - 1; } exportMemoryAs(name) { this.exports.push({name: name, kind: kExternalMemory, index: 0}); } - addFunctionTableInit(base, is_global, array, is_import = false) { - this.function_table_inits.push({base: base, is_global: is_global, - array: array}); - if (!is_global) { - var length = base + array.length; - if (length > this.function_table_length_min && !is_import) { - this.function_table_length_min = length; - } - if (length > this.function_table_length_max && !is_import) { - this.function_table_length_max = length; - } - } + addElementSegment(table, base, is_global, array) { + this.element_segments.push({ + table: table, + base: base, + is_global: is_global, + array: array, + is_active: true, + is_declarative: false + }); + return this; + } + + addPassiveElementSegment(array) { + this.element_segments.push( + {array: array, is_active: false, is_declarative: false}); + return this; + } + + addDeclarativeElementSegment(array) { + this.element_segments.push( + {array: array, is_active: false, is_declarative: true}); return this; } @@ -308,12 +1239,25 @@ if (typeof n != 'number') throw new Error('invalid table (entries have to be numbers): ' + array); } - return this.addFunctionTableInit(this.function_table.length, false, array); + if (this.tables.length == 0) { + this.addTable(kWasmAnyFunc, 0); + } + // Adjust the table to the correct size. + let table = this.tables[0]; + const base = table.initial_size; + const table_size = base + array.length; + table.initial_size = table_size; + if (table.has_max && table_size > table.max_size) { + table.max_size = table_size; + } + return this.addElementSegment(0, base, false, array); } - setFunctionTableBounds(min, max) { - this.function_table_length_min = min; - this.function_table_length_max = max; + setTableBounds(min, max = undefined) { + if (this.tables.length != 0) { + throw new Error("The table bounds of table '0' have already been set."); + } + this.addTable(kWasmAnyFunc, min, max); return this; } @@ -322,7 +1266,7 @@ return this; } - toArray(debug = false) { + toBuffer(debug = false) { let binary = new Binary; let wasm = this; @@ -335,14 +1279,27 @@ binary.emit_section(kTypeSectionCode, section => { section.emit_u32v(wasm.types.length); for (let type of wasm.types) { - section.emit_u8(kWasmFunctionTypeForm); - section.emit_u32v(type.params.length); - for (let param of type.params) { - section.emit_u8(param); - } - section.emit_u32v(type.results.length); - for (let result of type.results) { - section.emit_u8(result); + if (type instanceof WasmStruct) { + section.emit_u8(kWasmStructTypeForm); + section.emit_u32v(type.fields.length); + for (let field of type.fields) { + section.emit_type(field.type); + section.emit_u8(field.mutability ? 1 : 0); + } + } else if (type instanceof WasmArray) { + section.emit_u8(kWasmArrayTypeForm); + section.emit_type(type.type); + section.emit_u8(1); // Only mutable arrays supported currently. + } else { + section.emit_u8(kWasmFunctionTypeForm); + section.emit_u32v(type.params.length); + for (let param of type.params) { + section.emit_type(param); + } + section.emit_u32v(type.results.length); + for (let result of type.results) { + section.emit_type(result); + } } } }); @@ -358,9 +1315,9 @@ section.emit_string(imp.name || ''); section.emit_u8(imp.kind); if (imp.kind == kExternalFunction) { - section.emit_u32v(imp.type); + section.emit_u32v(imp.type_index); } else if (imp.kind == kExternalGlobal) { - section.emit_u32v(imp.type); + section.emit_type(imp.type); section.emit_u8(imp.mutable); } else if (imp.kind == kExternalMemory) { var has_max = (typeof imp.maximum) != "undefined"; @@ -373,11 +1330,14 @@ section.emit_u32v(imp.initial); // initial if (has_max) section.emit_u32v(imp.maximum); // maximum } else if (imp.kind == kExternalTable) { - section.emit_u8(kWasmAnyFunctionTypeForm); + section.emit_type(imp.type); var has_max = (typeof imp.maximum) != "undefined"; section.emit_u8(has_max ? 1 : 0); // flags section.emit_u32v(imp.initial); // initial if (has_max) section.emit_u32v(imp.maximum); // maximum + } else if (imp.kind == kExternalException) { + section.emit_u32v(kExceptionAttribute); + section.emit_u32v(imp.type_index); } else { throw new Error("unknown/unsupported import kind " + imp.kind); } @@ -396,17 +1356,17 @@ }); } - // Add function_table. - if (wasm.function_table_length_min > 0) { - if (debug) print("emitting table @ " + binary.length); + // Add table section + if (wasm.tables.length > 0) { + if (debug) print ("emitting tables @ " + binary.length); binary.emit_section(kTableSectionCode, section => { - section.emit_u8(1); // one table entry - section.emit_u8(kWasmAnyFunctionTypeForm); - // TODO(gdeepti): Cleanup to use optional max flag, - // fix up tests to set correct initial/maximum values - section.emit_u32v(1); - section.emit_u32v(wasm.function_table_length_min); - section.emit_u32v(wasm.function_table_length_max); + section.emit_u32v(wasm.tables.length); + for (let table of wasm.tables) { + section.emit_type(table.type); + section.emit_u8(table.has_max); + section.emit_u32v(table.initial_size); + if (table.has_max) section.emit_u32v(table.max_size); + } }); } @@ -416,15 +1376,34 @@ binary.emit_section(kMemorySectionCode, section => { section.emit_u8(1); // one memory entry const has_max = wasm.memory.max !== undefined; - const is_shared = wasm.memory.shared !== undefined; - // Emit flags (bit 0: reszeable max, bit 1: shared memory) - if (is_shared) { - section.emit_u8(has_max ? 3 : 2); + if (wasm.memory.is_memory64) { + assertFalse( + wasm.memory.shared, 'sharing memory64 is not supported (yet)'); + section.emit_u8( + has_max ? kLimitsMemory64WithMaximum : kLimitsMemory64NoMaximum); + section.emit_u64v(wasm.memory.min); + if (has_max) section.emit_u64v(wasm.memory.max); } else { - section.emit_u8(has_max ? 1 : 0); + section.emit_u8( + wasm.memory.shared ? + (has_max ? kLimitsSharedWithMaximum : + kLimitsSharedNoMaximum) : + (has_max ? kLimitsWithMaximum : kLimitsNoMaximum)); + section.emit_u32v(wasm.memory.min); + if (has_max) section.emit_u32v(wasm.memory.max); } - section.emit_u32v(wasm.memory.min); - if (has_max) section.emit_u32v(wasm.memory.max); + }); + } + + // Add event section. + if (wasm.exceptions.length > 0) { + if (debug) print("emitting events @ " + binary.length); + binary.emit_section(kExceptionSectionCode, section => { + section.emit_u32v(wasm.exceptions.length); + for (let type_index of wasm.exceptions) { + section.emit_u32v(kExceptionAttribute); + section.emit_u32v(type_index); + } }); } @@ -434,7 +1413,7 @@ binary.emit_section(kGlobalSectionCode, section => { section.emit_u32v(wasm.globals.length); for (let global of wasm.globals) { - section.emit_u8(global.type); + section.emit_type(global.type); section.emit_u8(global.mutable); if ((typeof global.init_index) == "undefined") { // Emit a constant initializer. @@ -445,32 +1424,44 @@ break; case kWasmI64: section.emit_u8(kExprI64Const); - section.emit_u32v(global.init); + section.emit_u64v(global.init); break; case kWasmF32: - section.emit_u8(kExprF32Const); - f32_view[0] = global.init; - section.emit_u8(byte_view[0]); - section.emit_u8(byte_view[1]); - section.emit_u8(byte_view[2]); - section.emit_u8(byte_view[3]); + section.emit_bytes(wasmF32Const(global.init)); break; case kWasmF64: - section.emit_u8(kExprF64Const); - f64_view[0] = global.init; - section.emit_u8(byte_view[0]); - section.emit_u8(byte_view[1]); - section.emit_u8(byte_view[2]); - section.emit_u8(byte_view[3]); - section.emit_u8(byte_view[4]); - section.emit_u8(byte_view[5]); - section.emit_u8(byte_view[6]); - section.emit_u8(byte_view[7]); + section.emit_bytes(wasmF64Const(global.init)); + break; + case kWasmS128: + section.emit_bytes(wasmS128Const(global.init)); + break; + case kWasmExternRef: + section.emit_u8(kExprRefNull); + section.emit_u8(kWasmExternRef); + assertEquals(global.function_index, undefined); + break; + case kWasmAnyFunc: + if (global.function_index !== undefined) { + section.emit_u8(kExprRefFunc); + section.emit_u32v(global.function_index); + } else { + section.emit_u8(kExprRefNull); + section.emit_u8(kWasmAnyFunc); + } + break; + default: + if (global.function_index !== undefined) { + section.emit_u8(kExprRefFunc); + section.emit_u32v(global.function_index); + } else { + section.emit_u8(kExprRefNull); + section.emit_u32v(global.type.index); + } break; } } else { // Emit a global-index initializer. - section.emit_u8(kExprGetGlobal); + section.emit_u8(kExprGlobalGet); section.emit_u32v(global.init_index); } section.emit_u8(kExprEnd); // end of init expression @@ -479,7 +1470,7 @@ } // Add export table. - var mem_export = (wasm.memory !== undefined && wasm.memory.exp); + var mem_export = (wasm.memory !== undefined && wasm.memory.exported); var exports_count = wasm.exports.length + (mem_export ? 1 : 0); if (exports_count > 0) { if (debug) print("emitting exports @ " + binary.length); @@ -506,102 +1497,160 @@ }); } - // Add table elements. - if (wasm.function_table_inits.length > 0) { - if (debug) print("emitting table @ " + binary.length); + // Add element segments + if (wasm.element_segments.length > 0) { + if (debug) print("emitting element segments @ " + binary.length); binary.emit_section(kElementSectionCode, section => { - var inits = wasm.function_table_inits; + var inits = wasm.element_segments; section.emit_u32v(inits.length); for (let init of inits) { - section.emit_u8(0); // table index - if (init.is_global) { - section.emit_u8(kExprGetGlobal); + if (init.is_active) { + // Active segment. + if (init.table == 0) { + section.emit_u32v(kActiveNoIndex); + } else { + section.emit_u32v(kActiveWithIndex); + section.emit_u32v(init.table); + } + if (init.is_global) { + section.emit_u8(kExprGlobalGet); + } else { + section.emit_u8(kExprI32Const); + } + section.emit_u32v(init.base); + section.emit_u8(kExprEnd); + if (init.table != 0) { + section.emit_u8(kExternalFunction); + } + section.emit_u32v(init.array.length); + for (let index of init.array) { + section.emit_u32v(index); + } + } else if ( + init.is_declarative && + init.array.every(index => index !== null)) { + section.emit_u8(kDeclarative); + section.emit_u8(kExternalFunction); + section.emit_u32v(init.array.length); + for (let index of init.array) { + section.emit_u32v(index); + } } else { - section.emit_u8(kExprI32Const); - } - section.emit_u32v(init.base); - section.emit_u8(kExprEnd); - section.emit_u32v(init.array.length); - for (let index of init.array) { - section.emit_u32v(index); + // Passive or declarative segment with elements. + section.emit_u8( + init.is_declarative ? kDeclarativeWithElements : + kPassiveWithElements); // flags + section.emit_u8(kWasmAnyFunc); + section.emit_u32v(init.array.length); + for (let index of init.array) { + if (index === null) { + section.emit_u8(kExprRefNull); + section.emit_u8(kWasmAnyFunc); + section.emit_u8(kExprEnd); + } else { + section.emit_u8(kExprRefFunc); + section.emit_u32v(index); + section.emit_u8(kExprEnd); + } + } } } }); } - // Add exceptions. - if (wasm.exceptions.length > 0) { - if (debug) print("emitting exceptions @ " + binary.length); - binary.emit_section(kExceptionSectionCode, section => { - section.emit_u32v(wasm.exceptions.length); - for (let type of wasm.exceptions) { - section.emit_u32v(type.params.length); - for (let param of type.params) { - section.emit_u8(param); - } - } + // If there are any passive data segments, add the DataCount section. + if (wasm.data_segments.some(seg => !seg.is_active)) { + binary.emit_section(kDataCountSectionCode, section => { + section.emit_u32v(wasm.data_segments.length); }); } + // If there are compilation hints add a custom section 'compilationHints' + // after the function section and before the code section. + if (wasm.compilation_hints.length > 0) { + if (debug) print("emitting compilation hints @ " + binary.length); + // Build custom section payload. + let payloadBinary = new Binary(); + let implicit_compilation_hints_count = wasm.functions.length; + payloadBinary.emit_u32v(implicit_compilation_hints_count); + + // Defaults to the compiler's choice if no better hint was given (0x00). + let defaultHintByte = kCompilationHintStrategyDefault | + (kCompilationHintTierDefault << 2) | + (kCompilationHintTierDefault << 4); + + // Emit hint byte for every function defined in this module. + for (let i = 0; i < implicit_compilation_hints_count; i++) { + let index = wasm.num_imported_funcs + i; + var hintByte; + if(index in wasm.compilation_hints) { + let hint = wasm.compilation_hints[index]; + hintByte = hint.strategy | (hint.baselineTier << 2) | + (hint.topTier << 4); + } else{ + hintByte = defaultHintByte; + } + payloadBinary.emit_u8(hintByte); + } + + // Finalize as custom section. + let name = "compilationHints"; + let bytes = this.createCustomSection(name, payloadBinary.trunc_buffer()); + binary.emit_bytes(bytes); + } + // Add function bodies. if (wasm.functions.length > 0) { // emit function bodies if (debug) print("emitting code @ " + binary.length); + let section_length = 0; binary.emit_section(kCodeSectionCode, section => { section.emit_u32v(wasm.functions.length); + let header = new Binary; for (let func of wasm.functions) { + header.reset(); // Function body length will be patched later. - let local_decls = []; - for (let l of func.locals || []) { - if (l.i32_count > 0) { - local_decls.push({count: l.i32_count, type: kWasmI32}); - } - if (l.i64_count > 0) { - local_decls.push({count: l.i64_count, type: kWasmI64}); - } - if (l.f32_count > 0) { - local_decls.push({count: l.f32_count, type: kWasmF32}); - } - if (l.f64_count > 0) { - local_decls.push({count: l.f64_count, type: kWasmF64}); - } - if (l.s128_count > 0) { - local_decls.push({count: l.s128_count, type: kWasmS128}); - } - } - - let header = new Binary; + let local_decls = func.locals || []; header.emit_u32v(local_decls.length); for (let decl of local_decls) { header.emit_u32v(decl.count); - header.emit_u8(decl.type); + header.emit_type(decl.type); } - section.emit_u32v(header.length + func.body.length); - section.emit_bytes(header); + section.emit_bytes(header.trunc_buffer()); + // Set to section offset for now, will update. + func.body_offset = section.length; section.emit_bytes(func.body); } + section_length = section.length; }); + for (let func of wasm.functions) { + func.body_offset += binary.length - section_length; + } } // Add data segments. - if (wasm.segments.length > 0) { + if (wasm.data_segments.length > 0) { if (debug) print("emitting data segments @ " + binary.length); binary.emit_section(kDataSectionCode, section => { - section.emit_u32v(wasm.segments.length); - for (let seg of wasm.segments) { - section.emit_u8(0); // linear memory index 0 - if (seg.is_global) { - // initializer is a global variable - section.emit_u8(kExprGetGlobal); - section.emit_u32v(seg.addr); + section.emit_u32v(wasm.data_segments.length); + for (let seg of wasm.data_segments) { + if (seg.is_active) { + section.emit_u8(0); // linear memory index 0 / flags + if (seg.is_global) { + // initializer is a global variable + section.emit_u8(kExprGlobalGet); + section.emit_u32v(seg.addr); + } else { + // initializer is a constant + section.emit_u8(kExprI32Const); + section.emit_u32v(seg.addr); + } + section.emit_u8(kExprEnd); } else { - // initializer is a constant - section.emit_u8(kExprI32Const); - section.emit_u32v(seg.addr); + section.emit_u8(kPassive); // flags } - section.emit_u8(kExprEnd); section.emit_u32v(seg.data.length); section.emit_bytes(seg.data); } @@ -651,10 +1700,15 @@ if (func.numLocalNames() == 0) continue; name_section.emit_u32v(func.index); name_section.emit_u32v(func.numLocalNames()); + let name_index = 0; for (let i = 0; i < func.local_names.length; ++i) { - if (func.local_names[i] === undefined) continue; - name_section.emit_u32v(i); - name_section.emit_string(func.local_names[i]); + if (typeof func.local_names[i] == "string") { + name_section.emit_u32v(name_index); + name_section.emit_string(func.local_names[i]); + name_index++; + } else { + name_index += func.local_names[i]; + } } } }); @@ -662,23 +1716,15 @@ }); } - return binary; + return binary.trunc_buffer(); } - toBuffer(debug = false) { - let bytes = this.toArray(debug); - let buffer = new ArrayBuffer(bytes.length); - let view = new Uint8Array(buffer); - for (let i = 0; i < bytes.length; i++) { - let val = bytes[i]; - if ((typeof val) == "string") val = val.charCodeAt(0); - view[i] = val | 0; - } - return buffer; + toArray(debug = false) { + return Array.from(this.toBuffer(debug)); } instantiate(ffi) { - let module = new WebAssembly.Module(this.toBuffer()); + let module = this.toModule(); let instance = new WebAssembly.Instance(module, ffi); return instance; } @@ -692,3 +1738,49 @@ return new WebAssembly.Module(this.toBuffer(debug)); } } + +function wasmSignedLeb(val, max_len = 5) { + let res = []; + for (let i = 0; i < max_len; ++i) { + let v = val & 0x7f; + // If {v} sign-extended from 7 to 32 bits is equal to val, we are done. + if (((v << 25) >> 25) == val) { + res.push(v); + return res; + } + res.push(v | 0x80); + val = val >> 7; + } + throw new Error( + 'Leb value <' + val + '> exceeds maximum length of ' + max_len); +} + +function wasmI32Const(val) { + return [kExprI32Const, ...wasmSignedLeb(val, 5)]; +} + +function wasmF32Const(f) { + // Write in little-endian order at offset 0. + data_view.setFloat32(0, f, true); + return [ + kExprF32Const, byte_view[0], byte_view[1], byte_view[2], byte_view[3] + ]; +} + +function wasmF64Const(f) { + // Write in little-endian order at offset 0. + data_view.setFloat64(0, f, true); + return [ + kExprF64Const, byte_view[0], byte_view[1], byte_view[2], + byte_view[3], byte_view[4], byte_view[5], byte_view[6], byte_view[7] + ]; +} + +function wasmS128Const(f) { + // Write in little-endian order at offset 0. + return [kSimdPrefix, kExprS128Const, ...f]; +} + +function getOpcodeName(opcode) { + return globalThis.kWasmOpcodeNames?.[opcode] ?? 'unknown'; +}
diff --git a/third_party/blink/web_tests/http/tests/wasm/wasm_worker_termination_while_compiling.html b/third_party/blink/web_tests/http/tests/wasm/wasm_worker_termination_while_compiling.html index 8dd42d6..ca86f78 100644 --- a/third_party/blink/web_tests/http/tests/wasm/wasm_worker_termination_while_compiling.html +++ b/third_party/blink/web_tests/http/tests/wasm/wasm_worker_termination_while_compiling.html
@@ -1,7 +1,6 @@ <!DOCTYPE html> <script src="../../../resources/testharness.js"></script> <script src="../../../resources/testharnessreport.js"></script> -<script src="resources/wasm-constants.js"></script> <script src="resources/wasm-module-builder.js"></script> <script>
diff --git a/third_party/blink/web_tests/http/tests/wasm_streaming/regression860637.html b/third_party/blink/web_tests/http/tests/wasm_streaming/regression860637.html index b0c9722b..4a92c3e8 100644 --- a/third_party/blink/web_tests/http/tests/wasm_streaming/regression860637.html +++ b/third_party/blink/web_tests/http/tests/wasm_streaming/regression860637.html
@@ -2,7 +2,6 @@ <script src="../../../resources/testharness.js"></script> <script src="../../../resources/testharnessreport.js"></script> <script src="wasm_response_apis.js"></script> -<script src="../wasm/resources/wasm-constants.js"></script> <script src="../wasm/resources/wasm-module-builder.js"></script> <script> promise_test(TestRegression837417, "Regression test");
diff --git a/third_party/blink/web_tests/http/tests/wasm_streaming/wasm_response_apis.html b/third_party/blink/web_tests/http/tests/wasm_streaming/wasm_response_apis.html index 6701745..bd16cc1d 100644 --- a/third_party/blink/web_tests/http/tests/wasm_streaming/wasm_response_apis.html +++ b/third_party/blink/web_tests/http/tests/wasm_streaming/wasm_response_apis.html
@@ -2,7 +2,6 @@ <script src="../../../resources/testharness.js"></script> <script src="../../../resources/testharnessreport.js"></script> <script src="wasm_response_apis.js"></script> -<script src="../wasm/resources/wasm-constants.js"></script> <script src="../wasm/resources/wasm-module-builder.js"></script> <script> promise_test(TestStreamedCompile, "test compileStreaming");
diff --git a/third_party/blink/web_tests/http/tests/wasm_streaming/wasm_response_apis.js b/third_party/blink/web_tests/http/tests/wasm_streaming/wasm_response_apis.js index 316f37e..32d6ac6 100644 --- a/third_party/blink/web_tests/http/tests/wasm_streaming/wasm_response_apis.js +++ b/third_party/blink/web_tests/http/tests/wasm_streaming/wasm_response_apis.js
@@ -156,11 +156,11 @@ builder.addFunction("main", kSig_i_i) .addBody([ - kExprGetLocal, 0, + kExprLocalGet, 0, kExprI32LoadMem, 0, 0, kExprI32Const, 1, kExprCallIndirect, signature, kTableZero, - kExprGetLocal,0, + kExprLocalGet,0, kExprI32LoadMem,0, 0, kExprCallFunction, 0, kExprI32Add @@ -170,7 +170,7 @@ // return mem[i] + some_value(); builder.addFunction("_wrap_writer", signature) .addBody([ - kExprGetLocal, 0, + kExprLocalGet, 0, kExprCallFunction, 1]); builder.appendToTable([2, 3]);
diff --git a/third_party/blink/web_tests/platform/linux/fast/table/colspanMinWidth-expected.png b/third_party/blink/web_tests/platform/linux/fast/table/colspanMinWidth-expected.png index a4a09724..91f25c2 100644 --- a/third_party/blink/web_tests/platform/linux/fast/table/colspanMinWidth-expected.png +++ b/third_party/blink/web_tests/platform/linux/fast/table/colspanMinWidth-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/table/colspanMinWidth-vertical-expected.png b/third_party/blink/web_tests/platform/linux/fast/table/colspanMinWidth-vertical-expected.png index b5eb3d5..05f2896 100644 --- a/third_party/blink/web_tests/platform/linux/fast/table/colspanMinWidth-vertical-expected.png +++ b/third_party/blink/web_tests/platform/linux/fast/table/colspanMinWidth-vertical-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/tables/mozilla_expected_failures/bugs/bug17826-expected.png b/third_party/blink/web_tests/platform/linux/tables/mozilla_expected_failures/bugs/bug17826-expected.png index 26238bd..a47cc3cd 100644 --- a/third_party/blink/web_tests/platform/linux/tables/mozilla_expected_failures/bugs/bug17826-expected.png +++ b/third_party/blink/web_tests/platform/linux/tables/mozilla_expected_failures/bugs/bug17826-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/tables/mozilla_expected_failures/bugs/bug47163-expected.png b/third_party/blink/web_tests/platform/linux/tables/mozilla_expected_failures/bugs/bug47163-expected.png index 54aa47f..90fc151 100644 --- a/third_party/blink/web_tests/platform/linux/tables/mozilla_expected_failures/bugs/bug47163-expected.png +++ b/third_party/blink/web_tests/platform/linux/tables/mozilla_expected_failures/bugs/bug47163-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/tables/mozilla_expected_failures/bugs/bug7121-2-expected.png b/third_party/blink/web_tests/platform/linux/tables/mozilla_expected_failures/bugs/bug7121-2-expected.png index b8e6363d..2bd0151d 100644 --- a/third_party/blink/web_tests/platform/linux/tables/mozilla_expected_failures/bugs/bug7121-2-expected.png +++ b/third_party/blink/web_tests/platform/linux/tables/mozilla_expected_failures/bugs/bug7121-2-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/layout_ng_fragment_traversal/fast/table/colspanMinWidth-expected.png b/third_party/blink/web_tests/platform/linux/virtual/layout_ng_fragment_traversal/fast/table/colspanMinWidth-expected.png new file mode 100644 index 0000000..91f25c2 --- /dev/null +++ b/third_party/blink/web_tests/platform/linux/virtual/layout_ng_fragment_traversal/fast/table/colspanMinWidth-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/layout_ng_fragment_traversal/fast/table/colspanMinWidth-vertical-expected.png b/third_party/blink/web_tests/platform/linux/virtual/layout_ng_fragment_traversal/fast/table/colspanMinWidth-vertical-expected.png new file mode 100644 index 0000000..05f2896 --- /dev/null +++ b/third_party/blink/web_tests/platform/linux/virtual/layout_ng_fragment_traversal/fast/table/colspanMinWidth-vertical-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/layout_ng_fragment_traversal/fast/table/rowspan-paint-order-expected.png b/third_party/blink/web_tests/platform/linux/virtual/layout_ng_fragment_traversal/fast/table/rowspan-paint-order-expected.png new file mode 100644 index 0000000..b5353a78 --- /dev/null +++ b/third_party/blink/web_tests/platform/linux/virtual/layout_ng_fragment_traversal/fast/table/rowspan-paint-order-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/css/css-tables/html5-table-formatting-1-expected.txt b/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/css/css-tables/html5-table-formatting-1-expected.txt new file mode 100644 index 0000000..8910d66 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/css/css-tables/html5-table-formatting-1-expected.txt
@@ -0,0 +1,9 @@ +This is a testharness.js-based test. +PASS Empty tables can still get a lsyout +FAIL Empty tables do not take table-columns into account assert_equals: expected 50 but got 200 +FAIL Empty tables do not take table-rows into account assert_equals: expected 50 but got 100 +PASS Table-columns are taken into account after missing cells are generated (empty line) +PASS Table-columns are taken into account after missing cells are generated (partially empty line) +PASS Table-columns are taken into account after missing cells are generated (non-empty line) +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/mac/virtual/layout_ng_fragment_traversal/fast/table/colspanMinWidth-expected.png b/third_party/blink/web_tests/platform/mac-mac-arm11.0/fast/table/colspanMinWidth-expected.png similarity index 100% copy from third_party/blink/web_tests/platform/mac/virtual/layout_ng_fragment_traversal/fast/table/colspanMinWidth-expected.png copy to third_party/blink/web_tests/platform/mac-mac-arm11.0/fast/table/colspanMinWidth-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/layout_ng_fragment_traversal/fast/table/colspanMinWidth-vertical-expected.png b/third_party/blink/web_tests/platform/mac-mac-arm11.0/fast/table/colspanMinWidth-vertical-expected.png similarity index 100% copy from third_party/blink/web_tests/platform/mac/virtual/layout_ng_fragment_traversal/fast/table/colspanMinWidth-vertical-expected.png copy to third_party/blink/web_tests/platform/mac-mac-arm11.0/fast/table/colspanMinWidth-vertical-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac-arm11.0/tables/mozilla_expected_failures/bugs/bug47163-expected.png b/third_party/blink/web_tests/platform/mac-mac-arm11.0/tables/mozilla_expected_failures/bugs/bug47163-expected.png new file mode 100644 index 0000000..b23aafb --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac-arm11.0/tables/mozilla_expected_failures/bugs/bug47163-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/layout_ng_fragment_traversal/fast/table/colspanMinWidth-expected.png b/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/layout_ng_fragment_traversal/fast/table/colspanMinWidth-expected.png similarity index 100% rename from third_party/blink/web_tests/platform/mac/virtual/layout_ng_fragment_traversal/fast/table/colspanMinWidth-expected.png rename to third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/layout_ng_fragment_traversal/fast/table/colspanMinWidth-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/layout_ng_fragment_traversal/fast/table/colspanMinWidth-vertical-expected.png b/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/layout_ng_fragment_traversal/fast/table/colspanMinWidth-vertical-expected.png similarity index 100% rename from third_party/blink/web_tests/platform/mac/virtual/layout_ng_fragment_traversal/fast/table/colspanMinWidth-vertical-expected.png rename to third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/layout_ng_fragment_traversal/fast/table/colspanMinWidth-vertical-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/table/colspanMinWidth-expected.png b/third_party/blink/web_tests/platform/mac/fast/table/colspanMinWidth-expected.png index 2c4cd186..0aacb4b 100644 --- a/third_party/blink/web_tests/platform/mac/fast/table/colspanMinWidth-expected.png +++ b/third_party/blink/web_tests/platform/mac/fast/table/colspanMinWidth-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/table/colspanMinWidth-vertical-expected.png b/third_party/blink/web_tests/platform/mac/fast/table/colspanMinWidth-vertical-expected.png index 0518096..aabc7f20a 100644 --- a/third_party/blink/web_tests/platform/mac/fast/table/colspanMinWidth-vertical-expected.png +++ b/third_party/blink/web_tests/platform/mac/fast/table/colspanMinWidth-vertical-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/tables/mozilla/bugs/bug1302-expected.png b/third_party/blink/web_tests/platform/mac/tables/mozilla/bugs/bug1302-expected.png index efa6ca86..44cde41 100644 --- a/third_party/blink/web_tests/platform/mac/tables/mozilla/bugs/bug1302-expected.png +++ b/third_party/blink/web_tests/platform/mac/tables/mozilla/bugs/bug1302-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/tables/mozilla_expected_failures/bugs/bug17826-expected.png b/third_party/blink/web_tests/platform/mac/tables/mozilla_expected_failures/bugs/bug17826-expected.png index ed37f5f..bdbf39c 100644 --- a/third_party/blink/web_tests/platform/mac/tables/mozilla_expected_failures/bugs/bug17826-expected.png +++ b/third_party/blink/web_tests/platform/mac/tables/mozilla_expected_failures/bugs/bug17826-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/tables/mozilla_expected_failures/bugs/bug47163-expected.png b/third_party/blink/web_tests/platform/mac/tables/mozilla_expected_failures/bugs/bug47163-expected.png index b23aafb..15d23402 100644 --- a/third_party/blink/web_tests/platform/mac/tables/mozilla_expected_failures/bugs/bug47163-expected.png +++ b/third_party/blink/web_tests/platform/mac/tables/mozilla_expected_failures/bugs/bug47163-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/tables/mozilla_expected_failures/bugs/bug7121-2-expected.png b/third_party/blink/web_tests/platform/mac/tables/mozilla_expected_failures/bugs/bug7121-2-expected.png index 0d51927..bd778a6 100644 --- a/third_party/blink/web_tests/platform/mac/tables/mozilla_expected_failures/bugs/bug7121-2-expected.png +++ b/third_party/blink/web_tests/platform/mac/tables/mozilla_expected_failures/bugs/bug7121-2-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/table/colspanMinWidth-expected.png b/third_party/blink/web_tests/platform/win/fast/table/colspanMinWidth-expected.png index 6b8125f..d7b36f9 100644 --- a/third_party/blink/web_tests/platform/win/fast/table/colspanMinWidth-expected.png +++ b/third_party/blink/web_tests/platform/win/fast/table/colspanMinWidth-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/table/colspanMinWidth-vertical-expected.png b/third_party/blink/web_tests/platform/win/fast/table/colspanMinWidth-vertical-expected.png index 80e7e7e1..e1fe026 100644 --- a/third_party/blink/web_tests/platform/win/fast/table/colspanMinWidth-vertical-expected.png +++ b/third_party/blink/web_tests/platform/win/fast/table/colspanMinWidth-vertical-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/table/rowspan-paint-order-expected.png b/third_party/blink/web_tests/platform/win/fast/table/rowspan-paint-order-expected.png index c581137..2d6d7ae 100644 --- a/third_party/blink/web_tests/platform/win/fast/table/rowspan-paint-order-expected.png +++ b/third_party/blink/web_tests/platform/win/fast/table/rowspan-paint-order-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/tables/mozilla_expected_failures/bugs/bug17826-expected.png b/third_party/blink/web_tests/platform/win/tables/mozilla_expected_failures/bugs/bug17826-expected.png index 374c7a5..7e7b317 100644 --- a/third_party/blink/web_tests/platform/win/tables/mozilla_expected_failures/bugs/bug17826-expected.png +++ b/third_party/blink/web_tests/platform/win/tables/mozilla_expected_failures/bugs/bug17826-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/tables/mozilla_expected_failures/bugs/bug47163-expected.png b/third_party/blink/web_tests/platform/win/tables/mozilla_expected_failures/bugs/bug47163-expected.png index 5e3dca2..3b7028f 100644 --- a/third_party/blink/web_tests/platform/win/tables/mozilla_expected_failures/bugs/bug47163-expected.png +++ b/third_party/blink/web_tests/platform/win/tables/mozilla_expected_failures/bugs/bug47163-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/tables/mozilla_expected_failures/bugs/bug7121-2-expected.png b/third_party/blink/web_tests/platform/win/tables/mozilla_expected_failures/bugs/bug7121-2-expected.png index 8018881..7341ad8 100644 --- a/third_party/blink/web_tests/platform/win/tables/mozilla_expected_failures/bugs/bug7121-2-expected.png +++ b/third_party/blink/web_tests/platform/win/tables/mozilla_expected_failures/bugs/bug7121-2-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/external/wpt/xhr/responsexml-document-properties-expected.txt b/third_party/blink/web_tests/platform/win7/external/wpt/xhr/responsexml-document-properties-expected.txt deleted file mode 100644 index 63dbbc8c..0000000 --- a/third_party/blink/web_tests/platform/win7/external/wpt/xhr/responsexml-document-properties-expected.txt +++ /dev/null
@@ -1,27 +0,0 @@ -This is a testharness.js-based test. -PASS domain -PASS URL -PASS documentURI -PASS baseURI -PASS referrer -PASS title -PASS contentType -PASS readyState -PASS location -PASS defaultView -PASS body -PASS doctype -PASS all -PASS cookie -PASS Test document URL properties after redirect -PASS Test document URL properties of document with <base> after redirect -FAIL lastModified set to time of response if no HTTP header provided assert_less_than_equal: expected a number less than or equal to 1566177285 but got 1566180885 -FAIL lastModified set to related HTTP header if provided assert_equals: expected 1566155231000 but got 1566151631000 -PASS cookie (after setting it) -PASS styleSheets should be an object -PASS implementation should be an object -PASS images should be an object -PASS forms should be an object -PASS links should be an object -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/resources/testdriver-vendor.js b/third_party/blink/web_tests/resources/testdriver-vendor.js index a3bebdd2..6177dd4 100644 --- a/third_party/blink/web_tests/resources/testdriver-vendor.js +++ b/third_party/blink/web_tests/resources/testdriver-vendor.js
@@ -168,7 +168,7 @@ window.test_driver_internal.action_sequence = function(actions) { if (window.top !== window) { - return Promise.reject(new Error("can only send keys in top-level window")); + return Promise.reject(new Error("can only send actions in top-level window")); } var didScrollIntoView = false; @@ -177,6 +177,12 @@ var last_y_position = 0; var first_pointer_down = false; for (let j = 0; j < actions[i].actions.length; j++) { + if (actions[i].actions[j].type == "keyDown" || + actions[i].actions[j].type == "keyUp") { + return Promise.reject(new Error("we do not support keydown and keyup actions, " + + "please use test_driver.send_keys")); + } + if ('origin' in actions[i].actions[j]) { if (typeof(actions[i].actions[j].origin) === 'string') { if (actions[i].actions[j].origin == "viewport") {
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt index ea9a51e..7e6918f 100644 --- a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt +++ b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -1030,6 +1030,7 @@ [Worker] method lineTo [Worker] method measureText [Worker] method moveTo +[Worker] method perspective [Worker] method putImageData [Worker] method quadraticCurveTo [Worker] method rect
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt index 44829e1..c220371 100644 --- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt +++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -1044,6 +1044,7 @@ method lineTo method measureText method moveTo + method perspective method putImageData method quadraticCurveTo method rect @@ -5763,6 +5764,7 @@ method lineTo method measureText method moveTo + method perspective method putImageData method quadraticCurveTo method rect @@ -10562,7 +10564,7 @@ interface XRDepthInformation attribute @@toStringTag getter height - getter normTextureFromNormView + getter normDepthBufferFromNormView getter rawValueToMeters getter width method constructor
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt index 3b672a18..4dfe890 100644 --- a/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt +++ b/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -931,6 +931,7 @@ [Worker] method lineTo [Worker] method measureText [Worker] method moveTo +[Worker] method perspective [Worker] method putImageData [Worker] method quadraticCurveTo [Worker] method rect
diff --git a/third_party/blink/web_tests/wpt_internal/scheduler/task_arguments.html b/third_party/blink/web_tests/wpt_internal/scheduler/task_arguments.html deleted file mode 100644 index 2782315a..0000000 --- a/third_party/blink/web_tests/wpt_internal/scheduler/task_arguments.html +++ /dev/null
@@ -1,18 +0,0 @@ -<!doctype html> -<title>Scheduling API: Task Argument Passing</title> -<link rel="author" title="Scott Haseley" href="mailto:shaseley@chromium.org"> -<link rel="help" href="https://github.com/WICG/main-thread-scheduling"> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> - -<script> -'use strict'; - -async_test(t => { - scheduler.postTask(t.step_func_done((arg1, arg2) => { - assert_equals(arg1, 'foo'); - assert_equals(arg2, 10); - }), { priority: 'user-visible' }, 'foo', 10); -}, 'Test scheduler.postTask correctly passes arguments'); - -</script>
diff --git a/third_party/boringssl/BUILD.generated.gni b/third_party/boringssl/BUILD.generated.gni index 740267a..aee38c2 100644 --- a/third_party/boringssl/BUILD.generated.gni +++ b/third_party/boringssl/BUILD.generated.gni
@@ -49,6 +49,7 @@ "src/crypto/bio/printf.c", "src/crypto/bio/socket.c", "src/crypto/bio/socket_helper.c", + "src/crypto/blake2/blake2.c", "src/crypto/bn_extra/bn_asn1.c", "src/crypto/bn_extra/convert.c", "src/crypto/buf/buf.c", @@ -301,6 +302,7 @@ "src/include/openssl/base.h", "src/include/openssl/base64.h", "src/include/openssl/bio.h", + "src/include/openssl/blake2.h", "src/include/openssl/blowfish.h", "src/include/openssl/bn.h", "src/include/openssl/buf.h",
diff --git a/third_party/boringssl/BUILD.generated_tests.gni b/third_party/boringssl/BUILD.generated_tests.gni index d7a9f2a5..eb9ea3d 100644 --- a/third_party/boringssl/BUILD.generated_tests.gni +++ b/third_party/boringssl/BUILD.generated_tests.gni
@@ -30,6 +30,7 @@ "src/crypto/asn1/asn1_test.cc", "src/crypto/base64/base64_test.cc", "src/crypto/bio/bio_test.cc", + "src/crypto/blake2/blake2_test.cc", "src/crypto/buf/buf_test.cc", "src/crypto/bytestring/bytestring_test.cc", "src/crypto/chacha/chacha_test.cc", @@ -93,6 +94,7 @@ ] crypto_test_data = [ + "src/crypto/blake2/blake2b256_tests.txt", "src/crypto/cipher_extra/test/aes_128_cbc_sha1_tls_implicit_iv_tests.txt", "src/crypto/cipher_extra/test/aes_128_cbc_sha1_tls_tests.txt", "src/crypto/cipher_extra/test/aes_128_cbc_sha256_tls_tests.txt",
diff --git a/third_party/chromevox/OWNERS b/third_party/chromevox/OWNERS index dfab84a0..976b955 100644 --- a/third_party/chromevox/OWNERS +++ b/third_party/chromevox/OWNERS
@@ -1,4 +1 @@ -aboxhall@chromium.org -dmazzoni@chromium.org -dtseng@chromium.org -plundblad@chromium.org +file://ui/accessibility/OWNERS
diff --git a/third_party/chromevox/third_party/sre/OWNERS b/third_party/chromevox/third_party/sre/OWNERS deleted file mode 100644 index 3f3d042a..0000000 --- a/third_party/chromevox/third_party/sre/OWNERS +++ /dev/null
@@ -1,2 +0,0 @@ -dtseng@chromium.org -dmazzoni@chromium.org
diff --git a/third_party/chromevox/third_party/sre/README.md b/third_party/chromevox/third_party/sre/README.md new file mode 100644 index 0000000..eda69ab --- /dev/null +++ b/third_party/chromevox/third_party/sre/README.md
@@ -0,0 +1,9 @@ +# Speech Rule Engine + +This project generates human-friendly readings appropriate for text-to-speech +playback given Math ML. + +Chrome OS accessibility extensions e.g. ChromeVox, use it for this purpose. + +The project also contains localizations for a large number of unicode codepoints +appropriate for tts reading.
diff --git a/third_party/subresource-filter-ruleset/README.chromium b/third_party/subresource-filter-ruleset/README.chromium index d8943fab9..e1835f9d 100644 --- a/third_party/subresource-filter-ruleset/README.chromium +++ b/third_party/subresource-filter-ruleset/README.chromium
@@ -1,6 +1,6 @@ Name: EasyList URL: https://easylist.to/easylist/easylist.txt -Version: 202010221614 +Version: 202101291627 License: Creative Commons Attribution-ShareAlike 3.0 Unported License File: LICENSE Security Critical: no
diff --git a/third_party/subresource-filter-ruleset/data/UnindexedRules.sha1 b/third_party/subresource-filter-ruleset/data/UnindexedRules.sha1 index 56419e6..ea65a83 100644 --- a/third_party/subresource-filter-ruleset/data/UnindexedRules.sha1 +++ b/third_party/subresource-filter-ruleset/data/UnindexedRules.sha1
@@ -1 +1 @@ -83bced6c2676ed8d7c57a84c9a8d4f76c08f79e2 \ No newline at end of file +7dc8bceb0b3f31ff30276c543da7a62dcecd2299 \ No newline at end of file
diff --git a/third_party/tflite-support/README.chromium b/third_party/tflite-support/README.chromium index 190a4e68..397fe52 100644 --- a/third_party/tflite-support/README.chromium +++ b/third_party/tflite-support/README.chromium
@@ -23,6 +23,7 @@ - Use _Exit instead of _exit to work on all platforms (0001-use-exit.patch) - Remove external file handlers support for memory mapping files to support Windows (0001-remove-unsupported-memory-map-from-file-handler.patch) +- Fixes sign compare issues in tflite-support (0001-task-utils-sign-compare.patch) Third party dependencies: - tflite
diff --git a/third_party/tflite-support/patches/0001-task-utils-sign-compare.patch b/third_party/tflite-support/patches/0001-task-utils-sign-compare.patch new file mode 100644 index 0000000..85172c99 --- /dev/null +++ b/third_party/tflite-support/patches/0001-task-utils-sign-compare.patch
@@ -0,0 +1,34 @@ +From f84b50f175efff54ee6a6ef795703907245260cd Mon Sep 17 00:00:00 2001 +From: Sophie Chang <sophiechang@chromium.org> +Date: Wed, 10 Feb 2021 17:55:30 +0000 +Subject: [PATCH] fix sign issues + +--- + .../src/tensorflow_lite_support/cc/task/core/task_utils.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/third_party/tflite-support/src/tensorflow_lite_support/cc/task/core/task_utils.h b/third_party/tflite-support/src/tensorflow_lite_support/cc/task/core/task_utils.h +index 744dbbfb0f80..ced3dbcae9e4 100644 +--- a/third_party/tflite-support/src/tensorflow_lite_support/cc/task/core/task_utils.h ++++ b/third_party/tflite-support/src/tensorflow_lite_support/cc/task/core/task_utils.h +@@ -119,7 +119,7 @@ inline void PopulateVector(const TfLiteTensor* tensor, std::vector<T>* data) { + const T* results = GetTensorData<T>(tensor); + size_t num = tensor->bytes / sizeof(tensor->type); + data->reserve(num); +- for (int i = 0; i < num; i++) { ++ for (size_t i = 0; i < num; i++) { + data->emplace_back(results[i]); + } + } +@@ -169,7 +169,7 @@ static TensorType* FindTensorByName( + tensor_metadatas->size() != tensors.size()) { + return nullptr; + } +- for (int i = 0; i < tensor_metadatas->size(); i++) { ++ for (flatbuffers::uoffset_t i = 0; i < tensor_metadatas->size(); i++) { + if (strcmp(name.data(), tensor_metadatas->Get(i)->name()->c_str()) == 0) { + return tensors[i]; + } +-- +2.30.0.478.g8a0d178c01-goog +
diff --git a/third_party/tflite-support/src/tensorflow_lite_support/cc/task/core/task_utils.h b/third_party/tflite-support/src/tensorflow_lite_support/cc/task/core/task_utils.h index 744dbbf..ced3dbc 100644 --- a/third_party/tflite-support/src/tensorflow_lite_support/cc/task/core/task_utils.h +++ b/third_party/tflite-support/src/tensorflow_lite_support/cc/task/core/task_utils.h
@@ -119,7 +119,7 @@ const T* results = GetTensorData<T>(tensor); size_t num = tensor->bytes / sizeof(tensor->type); data->reserve(num); - for (int i = 0; i < num; i++) { + for (size_t i = 0; i < num; i++) { data->emplace_back(results[i]); } } @@ -169,7 +169,7 @@ tensor_metadatas->size() != tensors.size()) { return nullptr; } - for (int i = 0; i < tensor_metadatas->size(); i++) { + for (flatbuffers::uoffset_t i = 0; i < tensor_metadatas->size(); i++) { if (strcmp(name.data(), tensor_metadatas->Get(i)->name()->c_str()) == 0) { return tensors[i]; }
diff --git a/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar-depth-gpu.html b/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar-depth-gpu.html index 5461c61..731d12f 100644 --- a/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar-depth-gpu.html +++ b/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar-depth-gpu.html
@@ -223,11 +223,13 @@ }; // clip space coordinates + texture space coordinates + // our depth buffer has an origin in top-left corner of the screen - + // we need to adjust the texture coordinates to account for that const vertices_data = [ - -1, -1, 0, 0, // bottom left - 1, -1, 1, 0, // bottom right - -1, 1, 0, 1, // top left - 1, 1, 1, 1, // top right + -1, -1, 0, 1, // bottom left + 1, -1, 1, 1, // bottom right + -1, 1, 0, 0, // top left + 1, 1, 1, 0, // top right ]; vertexBuffer = uploadVertexData(vertices_data); @@ -366,7 +368,7 @@ gl.uniform1i(programInfo.uniformLocations.depthTexture, 0); gl.uniformMatrix4fv(programInfo.uniformLocations.uvTransform, false, - depthData.normTextureFromNormView.matrix); + depthData.normDepthBufferFromNormView.matrix); gl.uniform1f(programInfo.uniformLocations.rawValueToMeters, depthData.rawValueToMeters);
diff --git a/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar-depth.html b/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar-depth.html index a05c805..4d530ea 100644 --- a/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar-depth.html +++ b/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar-depth.html
@@ -303,57 +303,129 @@ } } - function renderDepthInformationCPU(depthData, view, viewport) { + function calculateVerticesFromDepth(depthData, viewport) { + // This function calculates vertices data going from depth buffer + // coordinates into normalized view coordinates to then fetch the + // distance using the XRCPUDepthInformation.getDepthInMeters() helper. + // The normalized view coordinates are then converted to NDC in order + // to produce the vertices data. + const RESOLUTION = 5; const depth_width = depthData.width; const depth_height = depthData.height; - const norm_tex_from_norm_view = depthData.normTextureFromNormView.matrix; - const norm_view_from_norm_tex = mat4.invert(mat4.create(), norm_tex_from_norm_view); + const X_RANGE = depth_width; + const Y_RANGE = depth_height; + + const vertices_data = []; + + const norm_depth_from_norm_view = depthData.normDepthBufferFromNormView.matrix; + const norm_view_from_norm_depth = mat4.invert(mat4.create(), norm_depth_from_norm_view); const inverse_depth_dimensions = vec3.fromValues(1.0 / depth_width, 1.0 / depth_height, 0); - const viewport_dimensions = vec3.fromValues(viewport.width, viewport.height, 0); - const depth_vec = vec3.fromValues(depth_width-1, depth_height-1, 0); - const zeroes_vec = vec3.fromValues(0, 0, 0); + for(let x = 0; x < X_RANGE; x = x + RESOLUTION) { + for(let y = 0; y < Y_RANGE; y = y + RESOLUTION) { - const vertices_data = []; + // We start with absolute depth buffer coordinates: + const depth_coords_depth_buffer = vec3.fromValues(x, y, 0); - for(let x = 0; x < depth_width; x = x + RESOLUTION) { - for(let y = 0; y < depth_height; y = y + RESOLUTION) { - const distance = depthData.getDepthInMeters(x, y); + // Normalize them by depth buffer dimensions: + const depth_cooords_norm_depth_buffer = scaleByVec(vec3.create(), + depth_coords_depth_buffer, + inverse_depth_dimensions); - const depth_coords = vec3.fromValues(x, y, 0); - - // Calculate the view coordinates that correspond to (x, y) depth coordiante: - // 1. Normalize to [0, 1] range: - const depth_coords_norm = scaleByVec(vec3.create(), - depth_coords, inverse_depth_dimensions); - // 2. Map from normalized texture coordinates to normalized view coordinates: + // Transform to normalized view coordinates: const depth_coords_view_norm = vec3.transformMat4(vec3.create(), - depth_coords_norm, - norm_view_from_norm_tex); - // 3. Denormalize by viewport dimensions: - const depth_coords_view = scaleByVec(vec3.create(), - depth_coords_view_norm, viewport_dimensions); - clamp(depth_coords_view, depth_coords_view, zeroes_vec, viewport_dimensions); + depth_cooords_norm_depth_buffer, + norm_view_from_norm_depth); - // Convert to NDC: - depth_coords_view[0] = (2.0 * depth_coords_view[0]) / viewport.width - 1; - depth_coords_view[1] = (2.0 * depth_coords_view[1]) / viewport.height - 1; - - if(depth_coords_view[0] > 1 || depth_coords_view[0] < -1 || - depth_coords_view[1] > 1 || depth_coords_view[1] < -1) { + if(depth_coords_view_norm[0] < 0 || depth_coords_view_norm[0] > 1 || + depth_coords_view_norm[1] < 0 || depth_coords_view_norm[1] > 1) { continue; } - vertices_data.push(depth_coords_view[0], depth_coords_view[1], distance); + // getDepthInMeters() accepts inputs in normalized view coordinate system + // that has origin in top left corner, X's grow to the right, and Y's grow + // downward. + const distance = depthData.getDepthInMeters(depth_coords_view_norm[0], + depth_coords_view_norm[1]); + + // We need to convert normalized view coordinates to normalized device coordinates, + // with the origin at the center of a cube with side length = 2 and Y growing upward. + const depth_coords_ndc = vec3.clone(depth_coords_view_norm); + + // First, fix up the Y axis: + depth_coords_ndc[1] = 1 - depth_coords_ndc[1]; + + // Then, convert to range [-1, 1]: + depth_coords_ndc[0] = (2.0 * depth_coords_ndc[0]) - 1; + depth_coords_ndc[1] = (2.0 * depth_coords_ndc[1]) - 1; + + if(depth_coords_ndc[0] > 1 || depth_coords_ndc[0] < -1 || + depth_coords_ndc[1] > 1 || depth_coords_ndc[1] < -1) { + continue; + } + + vertices_data.push(depth_coords_ndc[0], depth_coords_ndc[1], distance); } } + return vertices_data; + } + + function calculateVerticesFromViewCoordinates(depthData, viewport) { + // This function calculates vertices data going directly from normalized + // view coordinates & using the XRCPUDepthInformation.getDepthInMeters() + // helper. Normalized view coordinates are then converted to NDC. + + const smaller_dim = Math.min(viewport.width, viewport.height); + const larger_dim = Math.max(viewport.width, viewport.height); + const is_portrait = smaller_dim == viewport.width; + + const larger_dim_resolution = (smaller_dim * 0.1) / larger_dim; + + const X_RESOLUTION = is_portrait ? 0.1 : larger_dim_resolution; + const Y_RESOLUTION = is_portrait ? larger_dim_resolution : 0.1; + + const X_RANGE = 1.0; + const Y_RANGE = 1.0; + + const vertices_data = []; + + for(let x = 0; x <= X_RANGE; x += X_RESOLUTION) { + for(let y = 0; y <= Y_RANGE; y += Y_RESOLUTION) { + const distance = depthData.getDepthInMeters(x, y); + + // We need to convert normalized view coordinates to normalized device coordinates, + // with the origin at the center of a cube with side length = 2 and Y growing upward. + const depth_coords_ndc = vec3.fromValues(x, y, 0.0); + + // First, fix up the Y axis: + depth_coords_ndc[1] = 1 - depth_coords_ndc[1]; + + // Then, convert to range [-1, 1]: + depth_coords_ndc[0] = (2.0 * depth_coords_ndc[0]) - 1; + depth_coords_ndc[1] = (2.0 * depth_coords_ndc[1]) - 1; + + if(depth_coords_ndc[0] > 1 || depth_coords_ndc[0] < -1 || + depth_coords_ndc[1] > 1 || depth_coords_ndc[1] < -1) { + continue; + } + + vertices_data.push(depth_coords_ndc[0], depth_coords_ndc[1], distance); + } + } + + return vertices_data; + } + + function renderDepthInformationCPU(depthData, view, viewport) { + const vertices_data = calculateVerticesFromViewCoordinates(depthData, viewport); + gl.useProgram(programInfo.program); gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
diff --git a/third_party/webxr_test_pages/webxr-samples/shaders/depth-api-gpu.frag b/third_party/webxr_test_pages/webxr-samples/shaders/depth-api-gpu.frag index 3e21fb1..b265757 100644 --- a/third_party/webxr_test_pages/webxr-samples/shaders/depth-api-gpu.frag +++ b/third_party/webxr_test_pages/webxr-samples/shaders/depth-api-gpu.frag
@@ -29,10 +29,10 @@ } void main(void) { - vec2 texCoord = (uUvTransform * vec4(vTexCoord.xy, 0, 1)).xy; + vec4 texCoord = uUvTransform * vec4(vTexCoord, 0, 1); highp float normalized_depth = clamp( - DepthGetMeters(uDepthTexture, texCoord) / kMaxDepthInMeters, 0.0, 1.0); + DepthGetMeters(uDepthTexture, texCoord.xy) / kMaxDepthInMeters, 0.0, 1.0); gl_FragColor = vec4(DepthGetColorVisualization(normalized_depth), 0.75); }
diff --git a/tools/clang/scripts/apply_edits.py b/tools/clang/scripts/apply_edits.py index a49a739..abf95df 100755 --- a/tools/clang/scripts/apply_edits.py +++ b/tools/clang/scripts/apply_edits.py
@@ -164,6 +164,59 @@ ''' +_NEWLINE_CHARACTERS = [ord('\n'), ord('\r')] + + +def _FindStartOfPreviousLine(contents, index): + """ Requires that `index` points to the start of a line. + Returns an index to the start of the previous line. + """ + assert (index > 0) + assert (contents[index - 1] in _NEWLINE_CHARACTERS) + + # Go back over the newline characters associated with the *single* end of a + # line just before `index`, despite of whether end of a line is designated by + # "\r", "\n" or "\r\n". Examples: + # 1. "... \r\n <new index> \r\n <old index> ... + # 2. "... \n <new index> \n <old index> ... + index = index - 1 + if index > 0 and contents[index - 1] in _NEWLINE_CHARACTERS and \ + contents[index - 1] != contents[index]: + index = index - 1 + + # Go back until `index` points right after an end of a line (or at the + # beginning of the `contents`). + while index > 0 and contents[index - 1] not in _NEWLINE_CHARACTERS: + index = index - 1 + + return index + + +def _SkipOverPreviousComment(contents, index): + """ Returns `index`, possibly moving it earlier so that it skips over comment + lines appearing in `contents` just before the old `index. + + Example: + <returned `index` points here>// Comment + // Comment + <original `index` points here>bar + """ + # If `index` points at the start of the file, or `index` doesn't point at the + # beginning of a line, then don't skip anything and just return `index`. + if index == 0 or contents[index - 1] not in _NEWLINE_CHARACTERS: + return index + + # Is the previous line a non-comment? If so, just return `index`. + new_index = _FindStartOfPreviousLine(contents, index) + prev_text = contents[new_index:index] + _COMMENT_START_REGEX = "^ \s* ( // | \* )" + if not re.search(_COMMENT_START_REGEX, prev_text, re.VERBOSE): + return index + + # Otherwise skip over the previous line + continue skipping via recursion. + return _SkipOverPreviousComment(contents, new_index) + + def _InsertNonSystemIncludeHeader(filepath, header_line_to_add, contents): """ Mutates |contents| (contents of |filepath|) to #include the |header_to_add @@ -185,7 +238,7 @@ regex_text = _INCLUDE_INSERTION_POINT_REGEX_TEMPLATE % primary_header_basename match = re.search(regex_text, contents, re.MULTILINE | re.VERBOSE) assert (match is not None) - insertion_point = match.start() + insertion_point = _SkipOverPreviousComment(contents, match.start()) # Extra empty line is required if the addition is not adjacent to other # includes.
diff --git a/tools/clang/scripts/apply_edits_test.py b/tools/clang/scripts/apply_edits_test.py index d8edd45f..a2bc63b 100755 --- a/tools/clang/scripts/apply_edits_test.py +++ b/tools/clang/scripts/apply_edits_test.py
@@ -56,6 +56,15 @@ class InsertIncludeHeaderTest(unittest.TestCase): + def _assertEqualContents(self, expected, actual): + if expected != actual: + print("####################### EXPECTED:") + print(expected) + print("####################### ACTUAL:") + print(actual) + print("####################### END.") + self.assertEqual(expected, actual) + def testSkippingCppComments(self): old_contents = ''' // Copyright info here. @@ -69,7 +78,144 @@ #include "old/header.h" ''' new_header_line = '#include "new/header.h' - self.assertEqual(expected_new_contents, _InsertHeader(old_contents)) + self._assertEqualContents(expected_new_contents, + _InsertHeader(old_contents)) + + def testSkippingCppComments_DocCommentForStruct(self): + """ This is a regression test for https://crbug.com/1175684 """ + old_contents = ''' +// Copyright blah blah... + +#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_FILTER_H_ +#define SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_FILTER_H_ + +#include <stdint.h> + +// Doc comment for a struct. +// Multiline. +struct sock_filter { + uint16_t code; +}; + ''' + expected_new_contents = ''' +// Copyright blah blah... + +#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_FILTER_H_ +#define SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_FILTER_H_ + +#include <stdint.h> + +#include "new/header.h" + +// Doc comment for a struct. +// Multiline. +struct sock_filter { + uint16_t code; +}; + ''' + new_header_line = '#include "new/header.h' + self._assertEqualContents(expected_new_contents, + _InsertHeader(old_contents)) + + def testSkippingCppComments_DocCommentForStruct2(self): + """ This is a regression test for https://crbug.com/1175684 """ + old_contents = ''' +// Copyright blah blah... + +// Doc comment for a struct. +struct sock_filter { + uint16_t code; +}; + ''' + expected_new_contents = ''' +// Copyright blah blah... + +#include "new/header.h" + +// Doc comment for a struct. +struct sock_filter { + uint16_t code; +}; + ''' + new_header_line = '#include "new/header.h' + self._assertEqualContents(expected_new_contents, + _InsertHeader(old_contents)) + + def testSkippingCppComments_DocCommentForStruct3(self): + """ This is a regression test for https://crbug.com/1175684 """ + old_contents = ''' +// Doc comment for a struct. +struct sock_filter { + uint16_t code; +}; + ''' + expected_new_contents = ''' +#include "new/header.h" + +// Doc comment for a struct. +struct sock_filter { + uint16_t code; +}; + ''' + new_header_line = '#include "new/header.h' + self._assertEqualContents(expected_new_contents, + _InsertHeader(old_contents)) + + def testSkippingCppComments_DocCommentForInclude(self): + """ This is a regression test for https://crbug.com/1175684 """ + old_contents = ''' +// Copyright blah blah... + +// System includes. +#include <stdint.h> + +// Doc comment for a struct. +struct sock_filter { + uint16_t code; +}; + ''' + expected_new_contents = ''' +// Copyright blah blah... + +// System includes. +#include <stdint.h> + +#include "new/header.h" + +// Doc comment for a struct. +struct sock_filter { + uint16_t code; +}; + ''' + new_header_line = '#include "new/header.h' + self._assertEqualContents(expected_new_contents, + _InsertHeader(old_contents)) + + def testSkippingCppComments_DocCommentForWholeFile(self): + """ This is a regression test for https://crbug.com/1175684 """ + old_contents = ''' +// Copyright blah blah... + +// Doc comment for the whole file. + +struct sock_filter { + uint16_t code; +}; + ''' + expected_new_contents = ''' +// Copyright blah blah... + +// Doc comment for the whole file. + +#include "new/header.h" + +struct sock_filter { + uint16_t code; +}; + ''' + new_header_line = '#include "new/header.h' + self._assertEqualContents(expected_new_contents, + _InsertHeader(old_contents)) def testSkippingOldStyleComments(self): old_contents = ''' @@ -87,7 +233,8 @@ #include "new/header.h" #include "old/header.h" ''' - self.assertEqual(expected_new_contents, _InsertHeader(old_contents)) + self._assertEqualContents(expected_new_contents, + _InsertHeader(old_contents)) def testSkippingOldStyleComments_NoWhitespaceAtLineStart(self): old_contents = ''' @@ -105,7 +252,8 @@ #include "new/header.h" #include "old/header.h" ''' - self.assertEqual(expected_new_contents, _InsertHeader(old_contents)) + self._assertEqualContents(expected_new_contents, + _InsertHeader(old_contents)) def testSkippingSystemHeaders(self): old_contents = ''' @@ -121,7 +269,8 @@ #include "new/header.h" #include "old/header.h" ''' - self.assertEqual(expected_new_contents, _InsertHeader(old_contents)) + self._assertEqualContents(expected_new_contents, + _InsertHeader(old_contents)) def testSkippingPrimaryHeader(self): old_contents = ''' @@ -139,7 +288,8 @@ #include "new/header.h" #include "old/header.h" ''' - self.assertEqual(expected_new_contents, _InsertHeader(old_contents)) + self._assertEqualContents(expected_new_contents, + _InsertHeader(old_contents)) def testSimilarNonPrimaryHeader_WithPrimaryHeader(self): old_contents = ''' @@ -159,7 +309,8 @@ #include "new/header.h" #include "zzz/foo.h" ''' - self.assertEqual(expected_new_contents, _InsertHeader(old_contents)) + self._assertEqualContents(expected_new_contents, + _InsertHeader(old_contents)) def testSimilarNonPrimaryHeader_NoPrimaryHeader(self): old_contents = ''' @@ -175,7 +326,8 @@ #include "new/header.h" #include "zzz/foo.h" ''' - self.assertEqual(expected_new_contents, _InsertHeader(old_contents)) + self._assertEqualContents(expected_new_contents, + _InsertHeader(old_contents)) def testSkippingIncludeGuards(self): old_contents = ''' @@ -195,8 +347,9 @@ #endif FOO_IMPL_H_ ''' - self.assertEqual(expected_new_contents, - _InsertHeader(old_contents, 'foo/impl.h', 'new/header.h')) + self._assertEqualContents( + expected_new_contents, + _InsertHeader(old_contents, 'foo/impl.h', 'new/header.h')) def testSkippingIncludeGuards2(self): # This test is based on base/third_party/valgrind/memcheck.h @@ -217,7 +370,8 @@ #endif ''' - self.assertEqual(expected_new_contents, _InsertHeader(old_contents)) + self._assertEqualContents(expected_new_contents, + _InsertHeader(old_contents)) def testSkippingIncludeGuards3(self): # This test is based on base/third_party/xdg_mime/xdgmime.h @@ -256,7 +410,8 @@ #endif /* __cplusplus */ #endif /* __XDG_MIME_H__ */ ''' - self.assertEqual(expected_new_contents, _InsertHeader(old_contents)) + self._assertEqualContents(expected_new_contents, + _InsertHeader(old_contents)) def testSkippingIncludeGuards4(self): # This test is based on ash/first_run/desktop_cleaner.h and/or @@ -285,7 +440,8 @@ #endif // ASH_FIRST_RUN_DESKTOP_CLEANER_ ''' - self.assertEqual(expected_new_contents, _InsertHeader(old_contents)) + self._assertEqualContents(expected_new_contents, + _InsertHeader(old_contents)) def testSkippingIncludeGuards5(self): # This test is based on third_party/weston/include/GLES2/gl2.h (the |extern @@ -322,7 +478,8 @@ #endif ''' - self.assertEqual(expected_new_contents, _InsertHeader(old_contents)) + self._assertEqualContents(expected_new_contents, + _InsertHeader(old_contents)) def testSkippingIncludeGuards6(self): # This test is based on ios/third_party/blink/src/html_token.h @@ -353,7 +510,8 @@ #endif ''' - self.assertEqual(expected_new_contents, _InsertHeader(old_contents)) + self._assertEqualContents(expected_new_contents, + _InsertHeader(old_contents)) def testNoOpIfAlreadyPresent(self): # This tests that the new header won't be inserted (and duplicated) @@ -372,7 +530,8 @@ #include "new/header.h" #include "new/header2.h" ''' - self.assertEqual(expected_new_contents, _InsertHeader(old_contents)) + self._assertEqualContents(expected_new_contents, + _InsertHeader(old_contents)) def testNoOpIfAlreadyPresent_WithTrailingComment(self): # This tests that the new header won't be inserted (and duplicated) @@ -391,7 +550,8 @@ #include "new/header.h" // blah #include "new/header2.h" ''' - self.assertEqual(expected_new_contents, _InsertHeader(old_contents)) + self._assertEqualContents(expected_new_contents, + _InsertHeader(old_contents)) def testNoOldHeaders(self): # This tests that an extra new line is inserted after the new header @@ -408,7 +568,8 @@ struct S {}; ''' - self.assertEqual(expected_new_contents, _InsertHeader(old_contents)) + self._assertEqualContents(expected_new_contents, + _InsertHeader(old_contents)) def testPlatformIfDefs(self): # This test is based on @@ -454,7 +615,8 @@ namespace double_conversion { ''' - self.assertEqual(expected_new_contents, _InsertHeader(old_contents)) + self._assertEqualContents(expected_new_contents, + _InsertHeader(old_contents)) def testNoOldIncludesAndIfDefs(self): # Artificial test: no old #includes + some #ifdefs. The main focus of the @@ -476,7 +638,8 @@ void foo(); ''' - self.assertEqual(expected_new_contents, _InsertHeader(old_contents)) + self._assertEqualContents(expected_new_contents, + _InsertHeader(old_contents)) def testNoOldIncludesAndIfDefs2(self): # Artificial test: no old #includes + some #ifdefs. The main focus of the @@ -498,7 +661,8 @@ void foo(); ''' - self.assertEqual(expected_new_contents, _InsertHeader(old_contents)) + self._assertEqualContents(expected_new_contents, + _InsertHeader(old_contents)) def testUtf8BomMarker(self): # Test based on @@ -523,12 +687,12 @@ expected.extend(expected_new_contents.encode('utf-8')) # Test sanity check (i.e. not an assertion about code under test). utf8_bom = [0xef, 0xbb, 0xbf] - self.assertEqual(list(actual[0:3]), utf8_bom) - self.assertEqual(list(expected[0:3]), utf8_bom) + self._assertEqualContents(list(actual[0:3]), utf8_bom) + self._assertEqualContents(list(expected[0:3]), utf8_bom) # Actual test. edit = apply_edits.Edit('include-user-header', -1, -1, "new/header.h") apply_edits._ApplySingleEdit("foo/impl.cc", actual, edit, None) - self.assertEqual(expected, actual) + self._assertEqualContents(expected, actual) def _CreateReplacement(content_string, old_substring, new_substring):
diff --git a/tools/clang/scripts/build.py b/tools/clang/scripts/build.py index 5dafaa4..3b10d7a 100755 --- a/tools/clang/scripts/build.py +++ b/tools/clang/scripts/build.py
@@ -395,8 +395,9 @@ for d in ['asan-i386-Linux', 'asan-x86_64-Linux', 'lsan-i386-Linux', 'lsan-x86_64-Linux', 'msan-x86_64-Linux', 'tsan-x86_64-Linux', 'ubsan-i386-Linux', 'ubsan-x86_64-Linux']: - EnsureDirExists(os.path.join(sanitizer_common_tests, d)) - CopyFile(libstdcpp, os.path.join(sanitizer_common_tests, d)) + libpath = os.path.join(sanitizer_common_tests, d, 'Output', 'lib') + EnsureDirExists(libpath) + CopyFile(libstdcpp, libpath) def gn_arg(v): @@ -681,11 +682,7 @@ CopyLibstdcpp(args, LLVM_BOOTSTRAP_INSTALL_DIR) RunCommand(['ninja'], msvc_arch='x64') if args.run_tests: - test_targets = [ 'check-all' ] - if sys.platform == 'darwin': - # TODO(crbug.com/731375): Run check-all on Darwin too. - test_targets = [ 'check-llvm', 'check-clang', 'check-builtins' ] - RunCommand(['ninja'] + test_targets, msvc_arch='x64') + RunCommand(['ninja', 'check-all'], msvc_arch='x64') RunCommand(['ninja', 'install'], msvc_arch='x64') if sys.platform == 'win32':
diff --git a/tools/mb/mb.py b/tools/mb/mb.py index abdc4e42..0a93132 100755 --- a/tools/mb/mb.py +++ b/tools/mb/mb.py
@@ -1632,10 +1632,21 @@ '--logs-dir=${ISOLATED_OUTDIR}', '--', ] - cmdline += [ - '../../testing/test_env.py', - '../../' + self.ToSrcRelPath(isolate_map[target]['script']) - ] + if is_android: + extra_files.append('../../build/android/test_wrapper/logdog_wrapper.py') + cmdline += [ + '../../testing/test_env.py', + '../../build/android/test_wrapper/logdog_wrapper.py', + '--script', + '../../' + self.ToSrcRelPath(isolate_map[target]['script']), + '--logdog-bin-cmd', + '../../.task_template_packages/logdog_butler', + ] + else: + cmdline += [ + '../../testing/test_env.py', + '../../' + self.ToSrcRelPath(isolate_map[target]['script']) + ] elif test_type == 'additional_compile_target': cmdline = [ './' + str(target) + executable_suffix,
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index cadbdfe4..3b48caf3 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -14,10 +14,6 @@ # this dict to look up which config to use for a given bot. 'builder_groups': { 'chrome': { - 'chromeos-arm-generic-beta': 'official_chromeos_arm-generic', - 'chromeos-arm-generic-ltc': 'official_chromeos_arm-generic', - 'chromeos-arm-generic-lts': 'official_chromeos_arm-generic', - 'chromeos-arm-generic-stable': 'official_chromeos_arm-generic', 'chromeos-arm-generic-cfi-thin-lto-chrome': 'chromeos_arm-generic_cfi_thin_lto_official', 'chromeos-betty-pi-arc-cfi-thin-lto-chrome': 'chromeos_betty-pi-arc_cfi_thin_lto_official', 'chromeos-betty-pi-arc-chrome': 'chromeos_betty-pi-arc_include_unwind_tables_official_use_fake_dbus_clients', @@ -1976,27 +1972,27 @@ ], 'gpu_fyi_tests_debug_trybot': [ - 'gpu_fyi_tests', 'debug_bot', + 'gpu_fyi_tests', 'debug_bot', 'disable_nacl', ], 'gpu_fyi_tests_debug_trybot_x86': [ - 'gpu_fyi_tests', 'debug_bot', 'x86', + 'gpu_fyi_tests', 'debug_bot', 'x86', 'disable_nacl', ], 'gpu_fyi_tests_dx12vk_debug_trybot': [ - 'gpu_fyi_tests', 'dx12vk', 'debug_bot', + 'gpu_fyi_tests', 'dx12vk', 'debug_bot', 'disable_nacl', ], 'gpu_fyi_tests_dx12vk_release_trybot': [ - 'gpu_fyi_tests', 'dx12vk', 'release_trybot', + 'gpu_fyi_tests', 'dx12vk', 'release_trybot', 'disable_nacl', ], 'gpu_fyi_tests_release_trybot': [ - 'gpu_fyi_tests', 'release_trybot', + 'gpu_fyi_tests', 'release_trybot', 'disable_nacl', ], 'gpu_fyi_tests_release_trybot_arm64': [ - 'gpu_fyi_tests', 'release_trybot', 'arm64', + 'gpu_fyi_tests', 'release_trybot', 'arm64', 'disable_nacl', ], 'gpu_fyi_tests_release_trybot_asan': [ @@ -2004,7 +2000,7 @@ ], 'gpu_fyi_tests_release_trybot_fuchsia': [ - 'gpu_fyi_tests', 'release_trybot', 'fuchsia', + 'gpu_fyi_tests', 'release_trybot', 'fuchsia', 'disable_nacl', ], 'gpu_fyi_tests_release_trybot_tsan': [ @@ -2012,7 +2008,7 @@ ], 'gpu_fyi_tests_release_trybot_x86': [ - 'gpu_fyi_tests', 'release_trybot', 'x86', + 'gpu_fyi_tests', 'release_trybot', 'x86', 'disable_nacl', ], 'gpu_tests_android_release_bot_minimal_symbols_arm64_fastbuild': [ @@ -2337,10 +2333,6 @@ 'msan', 'release_bot_blink', ], - 'official_chromeos_arm-generic': [ - 'chromeos_device', 'arm-generic', 'goma', 'official_optimize', - ], - 'official_celab_release_bot': [ 'official', 'release_bot', 'minimal_symbols', ], @@ -2738,7 +2730,7 @@ 'angle_specific_tests': { 'mixins': ['angle_gles1_conform_tests', 'angle_deqp_tests', - 'angle_trace_perf_tests'], + 'angle_trace_perf_tests', 'disable_nacl'], }, 'angle_trace_perf_tests': {
diff --git a/tools/mb/mb_config_expectations/chrome.json b/tools/mb/mb_config_expectations/chrome.json index e0deafa5..fc45870 100644 --- a/tools/mb/mb_config_expectations/chrome.json +++ b/tools/mb/mb_config_expectations/chrome.json
@@ -1,13 +1,4 @@ { - "chromeos-arm-generic-beta": { - "args_file": "//build/args/chromeos/arm-generic.gni", - "gn_args": { - "is_chromeos_device": true, - "is_official_build": true, - "ozone_platform_headless": true, - "use_goma": true - } - }, "chromeos-arm-generic-cfi-thin-lto-chrome": { "args_file": "//build/args/chromeos/arm-generic.gni", "gn_args": { @@ -22,33 +13,6 @@ "use_thin_lto": true } }, - "chromeos-arm-generic-ltc": { - "args_file": "//build/args/chromeos/arm-generic.gni", - "gn_args": { - "is_chromeos_device": true, - "is_official_build": true, - "ozone_platform_headless": true, - "use_goma": true - } - }, - "chromeos-arm-generic-lts": { - "args_file": "//build/args/chromeos/arm-generic.gni", - "gn_args": { - "is_chromeos_device": true, - "is_official_build": true, - "ozone_platform_headless": true, - "use_goma": true - } - }, - "chromeos-arm-generic-stable": { - "args_file": "//build/args/chromeos/arm-generic.gni", - "gn_args": { - "is_chromeos_device": true, - "is_official_build": true, - "ozone_platform_headless": true, - "use_goma": true - } - }, "chromeos-betty-pi-arc-cfi-thin-lto-chrome": { "args_file": "//build/args/chromeos/betty-pi-arc.gni", "gn_args": {
diff --git a/tools/mb/mb_config_expectations/chromium.angle.json b/tools/mb/mb_config_expectations/chromium.angle.json index 402c2e3..e72935f 100644 --- a/tools/mb/mb_config_expectations/chromium.angle.json +++ b/tools/mb/mb_config_expectations/chromium.angle.json
@@ -5,6 +5,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "is_component_build": true, "is_debug": false, "symbol_level": 1, @@ -37,6 +38,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": false, + "enable_nacl": false, "is_component_build": true, "is_debug": false, "symbol_level": 1, @@ -53,6 +55,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "is_component_build": true, "is_debug": false, "symbol_level": 1, @@ -68,6 +71,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "is_component_build": true, "is_debug": false, "symbol_level": 1, @@ -82,6 +86,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "is_component_build": true, "is_debug": false, "symbol_level": 1, @@ -95,6 +100,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "enable_run_ios_unittests_with_xctest": true, "ios_set_attributes_for_xcode_project_generation": false, "is_component_build": false, @@ -112,6 +118,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "is_component_build": true, "is_debug": false, "symbol_level": 1, @@ -135,6 +142,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "is_component_build": true, "is_debug": false, "ozone_platform": "headless", @@ -153,6 +161,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "is_component_build": true, "is_debug": false, "symbol_level": 1, @@ -200,6 +209,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "is_component_build": true, "is_debug": false, "symbol_level": 1, @@ -212,6 +222,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "is_component_build": true, "is_debug": false, "symbol_level": 1,
diff --git a/tools/mb/mb_config_expectations/chromium.gpu.fyi.json b/tools/mb/mb_config_expectations/chromium.gpu.fyi.json index 0c31de3..f5b59fe 100644 --- a/tools/mb/mb_config_expectations/chromium.gpu.fyi.json +++ b/tools/mb/mb_config_expectations/chromium.gpu.fyi.json
@@ -260,6 +260,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false, @@ -273,6 +274,7 @@ "gn_args": { "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": true, @@ -317,6 +319,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false, @@ -330,6 +333,7 @@ "gn_args": { "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": true, @@ -371,6 +375,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false, @@ -385,6 +390,7 @@ "gn_args": { "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": true, @@ -411,6 +417,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false, @@ -424,6 +431,7 @@ "gn_args": { "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": true, @@ -438,6 +446,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "enable_vulkan": true, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, @@ -452,6 +461,7 @@ "gn_args": { "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, + "enable_nacl": false, "enable_vulkan": true, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, @@ -477,6 +487,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false, @@ -536,6 +547,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false,
diff --git a/tools/mb/mb_config_expectations/tryserver.chromium.angle.json b/tools/mb/mb_config_expectations/tryserver.chromium.angle.json index 814acf89..e36c6333 100644 --- a/tools/mb/mb_config_expectations/tryserver.chromium.angle.json +++ b/tools/mb/mb_config_expectations/tryserver.chromium.angle.json
@@ -96,6 +96,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false, @@ -112,6 +113,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "enable_run_ios_unittests_with_xctest": true, "ios_set_attributes_for_xcode_project_generation": false, "is_component_build": false, @@ -128,6 +130,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false, @@ -172,6 +175,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false, @@ -207,6 +211,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false, @@ -222,6 +227,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false,
diff --git a/tools/mb/mb_config_expectations/tryserver.chromium.linux.json b/tools/mb/mb_config_expectations/tryserver.chromium.linux.json index b9c5597..5060a6e4 100644 --- a/tools/mb/mb_config_expectations/tryserver.chromium.linux.json +++ b/tools/mb/mb_config_expectations/tryserver.chromium.linux.json
@@ -157,6 +157,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false, @@ -181,6 +182,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false, @@ -195,6 +197,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false, @@ -222,6 +225,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false, @@ -235,6 +239,7 @@ "gn_args": { "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": true, @@ -259,6 +264,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false, @@ -273,6 +279,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false, @@ -287,6 +294,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false, @@ -822,6 +830,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false,
diff --git a/tools/mb/mb_config_expectations/tryserver.chromium.mac.json b/tools/mb/mb_config_expectations/tryserver.chromium.mac.json index bfef7290..0dfe375d 100644 --- a/tools/mb/mb_config_expectations/tryserver.chromium.mac.json +++ b/tools/mb/mb_config_expectations/tryserver.chromium.mac.json
@@ -14,6 +14,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false, @@ -27,6 +28,7 @@ "gn_args": { "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": true, @@ -41,6 +43,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false, @@ -55,6 +58,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false, @@ -69,6 +73,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false, @@ -99,6 +104,7 @@ "gn_args": { "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": true, @@ -123,6 +129,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false, @@ -137,6 +144,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false, @@ -151,6 +159,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false, @@ -164,6 +173,7 @@ "gn_args": { "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": true, @@ -178,6 +188,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false, @@ -192,6 +203,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false, @@ -564,6 +576,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false,
diff --git a/tools/mb/mb_config_expectations/tryserver.chromium.win.json b/tools/mb/mb_config_expectations/tryserver.chromium.win.json index b0579d6..86512e7 100644 --- a/tools/mb/mb_config_expectations/tryserver.chromium.win.json +++ b/tools/mb/mb_config_expectations/tryserver.chromium.win.json
@@ -4,6 +4,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false, @@ -28,6 +29,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false, @@ -42,6 +44,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false, @@ -55,6 +58,7 @@ "gn_args": { "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": true, @@ -78,6 +82,7 @@ "gn_args": { "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, + "enable_nacl": false, "enable_vulkan": true, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, @@ -93,6 +98,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "enable_vulkan": true, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, @@ -108,6 +114,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false, @@ -122,6 +129,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false, @@ -137,6 +145,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false, @@ -163,6 +172,7 @@ "gn_args": { "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": true, @@ -189,6 +199,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false, @@ -214,6 +225,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false, @@ -229,6 +241,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false, @@ -412,6 +425,7 @@ "build_angle_gles1_conform_tests": true, "build_angle_trace_perf_tests": true, "dcheck_always_on": true, + "enable_nacl": false, "ffmpeg_branding": "Chrome", "internal_gles2_conform_tests": true, "is_component_build": false,
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml index b5e65f3..2a22107 100644 --- a/tools/metrics/actions/actions.xml +++ b/tools/metrics/actions/actions.xml
@@ -27206,6 +27206,29 @@ </description> </action> +<action name="WindowNaming_Cleared"> + <owner>ellyjones@chromium.org</owner> + <description> + Logged when the user accepts the "Name Window..." prompt to clear + a custom name for a browser window. + </description> +</action> + +<action name="WindowNaming_DialogShown"> + <owner>ellyjones@chromium.org</owner> + <description> + Logged when the user opens the "Name Window..." prompt. + </description> +</action> + +<action name="WindowNaming_Set"> + <owner>ellyjones@chromium.org</owner> + <description> + Logged when the user accepts the "Name Window..." prompt to set a + custom name for a browser window. + </description> +</action> + <action name="WindowSelector_ActiveWindowChanged"> <owner>tbuckley@chromium.org</owner> <description>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index ae3daf6..4bae998 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -12784,6 +12784,7 @@ <int value="14" label="CONTEXT_LOST_SET_DRAW_RECTANGLE_FAILED"/> <int value="15" label="CONTEXT_LOST_DIRECT_COMPOSITION_OVERLAY_FAILED"/> <int value="16" label="CONTEXT_LOST_SWAP_FAILED"/> + <int value="17" label="CONTEXT_LOST_BEGIN_PAINT_FAILED"/> </enum> <enum name="ContextMenuDelayedElementDetails"> @@ -26331,6 +26332,7 @@ <int value="1539" label="FILEMANAGERPRIVATE_ISTABLETMODEENABLED"/> <int value="1540" label="FILEMANAGERPRIVATE_NOTIFYDRIVEDIALOGRESULT"/> <int value="1541" label="ENTERPRISEREPORTINGPRIVATE_GETCONTEXTINFO"/> + <int value="1542" label="SCRIPTING_REMOVECSS"/> </enum> <enum name="ExtensionIconState"> @@ -42825,6 +42827,7 @@ <int value="-2104654357" label="GamesHub:enabled"/> <int value="-2102286055" label="WebViewVulkanIntermediateBuffer:disabled"/> <int value="-2101682955" label="EnableNotificationIndicator:enabled"/> + <int value="-2101338272" label="EnablePciguardUi:disabled"/> <int value="-2101337189" label="AutofillOffNoServerData:disabled"/> <int value="-2099486626" label="DownloadLater:enabled"/> <int value="-2099457894" label="Mash:enabled"/> @@ -43090,6 +43093,7 @@ <int value="-1880355454" label="disable-topchrome-md"/> <int value="-1879877238" label="disable-cancel-all-touches"/> <int value="-1878958319" label="ScrollableTabStripButtons:disabled"/> + <int value="-1876955850" label="EnablePciguardUi:enabled"/> <int value="-1876881908" label="disable-infobar-for-protected-media-identifier"/> <int value="-1875383510" label="UseGoogleLocalNtp:disabled"/> @@ -44558,6 +44562,7 @@ <int value="-561194974" label="AutofillExpandedPopupViews:enabled"/> <int value="-560551550" label="use-memory-pressure-chromeos"/> <int value="-560114351" label="OfflinePagesRenovations:disabled"/> + <int value="-558488712" label="PreemtiveLinkToTextGeneration:disabled"/> <int value="-558471324" label="PreviewsCoinFlipHoldback_UKMOnly:disabled"/> <int value="-557742250" label="ContentSuggestionsCategories:disabled"/> <int value="-556218705" label="SlowDCTimerInterruptsWin:enabled"/> @@ -46693,6 +46698,7 @@ label="OmniboxRemoveSuggestionsFromClipboard:disabled"/> <int value="1442798825" label="enable-quic"/> <int value="1442830837" label="MemoryAblation:disabled"/> + <int value="1446349255" label="ArcEnableUsap:disabled"/> <int value="1446946673" label="DesktopRestructuredLanguageSettings:disabled"/> <int value="1447295459" label="SyncPseudoUSSApps:enabled"/> <int value="1448684258" label="TabHoverCardImages:enabled"/> @@ -46715,6 +46721,7 @@ <int value="1460747747" label="GdiTextPrinting:enabled"/> <int value="1460958818" label="NTPForeignSessionsSuggestions:enabled"/> <int value="1461581256" label="MovablePartialScreenshot:enabled"/> + <int value="1463230871" label="ArcEnableUsap:enabled"/> <int value="1464028544" label="WinUseHybridSpellChecker:disabled"/> <int value="1464610065" label="TabbedAppOverflowMenuRegroup:disabled"/> <int value="1465624446" label="disable-zero-copy"/> @@ -46853,6 +46860,7 @@ <int value="1600926040" label="TranslateCompactUI:enabled"/> <int value="1601582484" label="enable-crash-reporter-for-testing"/> <int value="1602627012" label="OverrideSitePrefsForHrefTranslate:enabled"/> + <int value="1602791752" label="PreemtiveLinkToTextGeneration:enabled"/> <int value="1602869271" label="ChromeShareScreenshot:disabled"/> <int value="1603578716" label="CaptionSettings:disabled"/> <int value="1604893983" label="VizForWebView:disabled"/> @@ -72845,6 +72853,12 @@ <int value="2" label="Parse error"/> </enum> +<enum name="SubresourceWebBundleLoadResult"> + <int value="0" label="Success"/> + <int value="1" label="Metadata parse error"/> + <int value="2" label="Memory quota exceeded"/> +</enum> + <enum name="SuccessTimeoutStarted"> <int value="0" label="Success"/> <int value="1" label="Timeout"/>
diff --git a/tools/metrics/histograms/histograms_xml/accessibility/histograms.xml b/tools/metrics/histograms/histograms_xml/accessibility/histograms.xml index c8b73a6..0bfc33c 100644 --- a/tools/metrics/histograms/histograms_xml/accessibility/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/accessibility/histograms.xml
@@ -265,7 +265,7 @@ </histogram> <histogram name="Accessibility.CrosHighContrast" enum="BooleanEnabled" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>dmazzoni@chromium.org</owner> <owner>kenjibaheux@google.com</owner> <owner>chrome-a11y-core@google.com</owner> @@ -508,7 +508,7 @@ </histogram> <histogram name="Accessibility.ImageLabels.ModalDialogAccepted" - enum="BooleanAccepted" expires_after="2021-06-06"> + enum="BooleanAccepted" expires_after="2021-08-09"> <owner>katie@chromium.org</owner> <owner>dmazzoni@chromium.org</owner> <summary> @@ -531,7 +531,7 @@ </histogram> <histogram name="Accessibility.ImageLabels.RequestLanguage" enum="LanguageCode" - expires_after="2021-03-28"> + expires_after="2021-08-09"> <owner>katie@chromium.org</owner> <owner>dmazzoni@chromium.org</owner> <owner>chrome-a11y-core@google.com</owner> @@ -543,7 +543,7 @@ </histogram> <histogram name="Accessibility.iOS.NewLargerTextCategory" enum="BooleanHit" - expires_after="2021-05-02"> + expires_after="2021-08-09"> <owner>gambard@chromium.org</owner> <owner>rkgibson@google.com</owner> <summary> @@ -558,7 +558,7 @@ </histogram> <histogram name="Accessibility.LanguageDetection.CountDetectionAttempted" - units="count" expires_after="2021-05-23"> + units="count" expires_after="2021-08-09"> <owner>chrishall@chromium.org</owner> <owner>aboxhall@chromium.org</owner> <owner>dmazzoni@chromium.org</owner> @@ -568,7 +568,7 @@ </histogram> <histogram name="Accessibility.LanguageDetection.CountLabelled" units="count" - expires_after="2021-05-23"> + expires_after="2021-08-09"> <owner>chrishall@chromium.org</owner> <owner>aboxhall@chromium.org</owner> <owner>dmazzoni@chromium.org</owner> @@ -579,7 +579,7 @@ </histogram> <histogram name="Accessibility.LanguageDetection.LangsPerPage" units="count" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>chrishall@chromium.org</owner> <owner>aboxhall@chromium.org</owner> <owner>dmazzoni@chromium.org</owner> @@ -591,7 +591,7 @@ </histogram> <histogram name="Accessibility.LanguageDetection.PercentageLabelledWithTop" - units="%" expires_after="2021-05-23"> + units="%" expires_after="2021-08-09"> <owner>chrishall@chromium.org</owner> <owner>aboxhall@chromium.org</owner> <owner>dmazzoni@chromium.org</owner> @@ -614,7 +614,7 @@ </histogram> <histogram name="Accessibility.LanguageDetection.PercentageOverridden" - units="%" expires_after="2021-05-23"> + units="%" expires_after="2021-08-09"> <owner>chrishall@chromium.org</owner> <owner>aboxhall@chromium.org</owner> <owner>dmazzoni@chromium.org</owner> @@ -895,7 +895,7 @@ </histogram> <histogram name="Accessibility.Shortcuts.CrosDockedMagnifier" - enum="BooleanEnabled" expires_after="2021-05-23"> + enum="BooleanEnabled" expires_after="2021-08-09"> <owner>amraboelkher@chromium.org</owner> <owner>poromov@chromium.org</owner> <summary> @@ -905,7 +905,7 @@ </histogram> <histogram name="Accessibility.Shortcuts.CrosHighContrast" - enum="BooleanEnabled" expires_after="2021-05-23"> + enum="BooleanEnabled" expires_after="2021-08-09"> <owner>amraboelkher@chromium.org</owner> <owner>poromov@chromium.org</owner> <summary> @@ -915,7 +915,7 @@ </histogram> <histogram name="Accessibility.Shortcuts.CrosScreenMagnifier" - enum="BooleanEnabled" expires_after="2021-05-23"> + enum="BooleanEnabled" expires_after="2021-08-09"> <owner>amraboelkher@chromium.org</owner> <owner>poromov@chromium.org</owner> <summary> @@ -925,7 +925,7 @@ </histogram> <histogram name="Accessibility.Shortcuts.CrosSpokenFeedback" - enum="BooleanEnabled" expires_after="2021-05-23"> + enum="BooleanEnabled" expires_after="2021-08-09"> <owner>amraboelkher@chromium.org</owner> <owner>poromov@chromium.org</owner> <summary> @@ -1180,7 +1180,7 @@ </histogram> <histogram name="DomDistiller.ReaderMode.EntryPoint" - enum="ReaderModeEntryPoint" expires_after="2021-06-06"> + enum="ReaderModeEntryPoint" expires_after="2021-08-09"> <owner>katie@chromium.org</owner> <owner>gilmanmh@google.com</owner> <owner>chrome-a11y-core@google.com</owner> @@ -1188,7 +1188,7 @@ </histogram> <histogram name="DomDistiller.ReaderMode.ExitPoint" enum="ReaderModeEntryPoint" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>katie@chromium.org</owner> <owner>gilmanmh@google.com</owner> <owner>chrome-a11y-core@google.com</owner>
diff --git a/tools/metrics/histograms/histograms_xml/android/histograms.xml b/tools/metrics/histograms/histograms_xml/android/histograms.xml index 9a140cc..edae4bf 100644 --- a/tools/metrics/histograms/histograms_xml/android/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/android/histograms.xml
@@ -620,7 +620,7 @@ </histogram> <histogram name="Android.DeviceSize.LargestDisplaySize" units="dp" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>twellington@chromium.org</owner> <owner>tedchoc@chromium.org</owner> <owner>clank-app-team@google.com</owner> @@ -632,7 +632,7 @@ </histogram> <histogram name="Android.DeviceSize.SmallestDisplaySize" units="dp" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>twellington@chromium.org</owner> <owner>tedchoc@chromium.org</owner> <owner>clank-app-team@google.com</owner> @@ -683,7 +683,7 @@ </histogram> <histogram name="Android.Download.Rename.Dialog.Action" - enum="Android.Download.Rename.Dialog.Action" expires_after="2021-05-30"> + enum="Android.Download.Rename.Dialog.Action" expires_after="2021-08-09"> <owner>hesen@chromium.org</owner> <owner>clank-downloads@google.com</owner> <summary> @@ -693,7 +693,7 @@ </histogram> <histogram name="Android.Download.Rename.Result" - enum="Android.Download.Rename.Result" expires_after="2021-05-30"> + enum="Android.Download.Rename.Result" expires_after="2021-08-09"> <owner>hesen@chromium.org</owner> <owner>clank-downloads@google.com</owner> <summary> @@ -808,7 +808,7 @@ </histogram> <histogram name="Android.DownloadManager.OpenSource.Audio" - enum="AndroidDownloadOpenSource" expires_after="2021-06-06"> + enum="AndroidDownloadOpenSource" expires_after="2021-08-09"> <owner>xingliu@chromium.org</owner> <owner>clank-downloads@google.com</owner> <summary>Records how users open audio download files on Android.</summary> @@ -1519,7 +1519,7 @@ </histogram> <histogram name="Android.NTP.Impression" enum="NTPImpressionType" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>finkm@chromium.org</owner> <summary> Counts impressions of the NTP on Android. It also counts potential @@ -1830,7 +1830,7 @@ </histogram> <histogram name="Android.PhotoPicker.EnumerationTime" units="ms" - expires_after="2021-06-01"> + expires_after="2021-08-09"> <owner>finnur@chromium.org</owner> <owner>twellington@chromium.org</owner> <summary> @@ -2079,7 +2079,7 @@ </histogram> <histogram name="Android.ShouldDestroyIncognitoProfileOnStartup" - units="Boolean" expires_after="M92"> + units="Boolean" expires_after="2021-08-09"> <owner>rhalavati@chromium.org</owner> <owner>yfriedman@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/apps/histograms.xml b/tools/metrics/histograms/histograms_xml/apps/histograms.xml index b3acb55..979bbe5 100644 --- a/tools/metrics/histograms/histograms_xml/apps/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/apps/histograms.xml
@@ -411,7 +411,7 @@ </histogram> <histogram name="Apps.AppList.SearchQueryLength.Apps" units="characters" - expires_after="2021-05-16"> + expires_after="2021-08-09"> <owner>thanhdng@chromium.org</owner> <owner>tby@chromium.org</owner> <summary> @@ -740,7 +740,7 @@ </histogram> <histogram name="Apps.AppListAppMovingType" enum="AppListAppMovingType" - expires_after="M92"> + expires_after="2021-08-09"> <owner>mmourgos@chromium.org</owner> <owner>newcomer@chromium.org</owner> <summary> @@ -871,7 +871,7 @@ </histogram> <histogram name="Apps.AppListPageOpened" enum="AppListPage" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>calamity@chromium.org</owner> <owner>src/ash/app_list/OWNERS</owner> <summary> @@ -1056,7 +1056,7 @@ </histogram> <histogram name="Apps.AppListSearchQueryLength" units="characters" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <!-- Name completed by histogram_suffixes name="TabletOrClamshellMode" --> <owner>calamity@chromium.org</owner> @@ -1138,7 +1138,7 @@ </histogram> <histogram name="Apps.AppListStateTransitionSource" - enum="AppListStateTransitionSource" expires_after="2021-05-02"> + enum="AppListStateTransitionSource" expires_after="2021-08-09"> <owner>newcomer@chromium.org</owner> <owner>mmourgos@chromium.org</owner> <summary> @@ -1185,7 +1185,7 @@ </summary> </histogram> -<histogram name="Apps.AppsInFolders" units="Apps" expires_after="2021-04-04"> +<histogram name="Apps.AppsInFolders" units="Apps" expires_after="2021-08-09"> <!-- Name completed by histogram_suffixes name="AppListFolderExperiment" --> @@ -1223,7 +1223,7 @@ </histogram> <histogram base="true" name="Apps.ContextMenuShowSource" enum="MenuSourceType" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <!-- Name completed by histogram_suffixes name="AppUIComponent" --> @@ -1278,7 +1278,7 @@ </histogram> <histogram base="true" name="Apps.DefaultAppLaunch" enum="DefaultAppName" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <!-- Name completed by histogram_suffixes name="DefaultAppLaunchSource" --> <owner>dominickn@chromium.org</owner> @@ -1645,7 +1645,7 @@ </summary> </histogram> -<histogram name="Apps.NumberOfPages" units="page(s)" expires_after="M92"> +<histogram name="Apps.NumberOfPages" units="page(s)" expires_after="2021-08-09"> <owner>mmourgos@chromium.org</owner> <owner>newcomer@chromium.org</owner> <summary> @@ -1654,7 +1654,8 @@ </summary> </histogram> -<histogram name="Apps.NumberOfPagesNotFull" units="page(s)" expires_after="M92"> +<histogram name="Apps.NumberOfPagesNotFull" units="page(s)" + expires_after="2021-08-09"> <owner>mmourgos@chromium.org</owner> <owner>newcomer@chromium.org</owner> <summary> @@ -1664,7 +1665,7 @@ </histogram> <histogram name="Apps.PaginationTransition.AnimationSmoothness" units="%" - expires_after="M92"> + expires_after="2021-08-09"> <!-- Name completed by histogram_suffixes name="TabletOrClamshellMode" --> <owner>newcomer@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/arc/histograms.xml b/tools/metrics/histograms/histograms_xml/arc/histograms.xml index 5a9f340..8362e83d 100644 --- a/tools/metrics/histograms/histograms_xml/arc/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/arc/histograms.xml
@@ -138,7 +138,7 @@ </histogram> <histogram name="Arc.AppListRecommendedImp.AllImpression" units="count" - expires_after="2021-05-30"> + expires_after="2021-08-09"> <owner>robsc@chromium.org</owner> <owner>napper@chromium.org</owner> <summary> @@ -157,7 +157,8 @@ </summary> </histogram> -<histogram name="Arc.AppShortcuts.BuildMenuTime" units="ms" expires_after="M92"> +<histogram name="Arc.AppShortcuts.BuildMenuTime" units="ms" + expires_after="2021-08-09"> <owner>mmourgos@chromium.org</owner> <owner>newcomer@chromium.org</owner> <summary> @@ -445,7 +446,7 @@ </histogram> <histogram name="Arc.EngagementTime.Background" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>maajid@google.com</owner> <owner>shaochuan@google.com</owner> <owner>shihuis@google.com</owner> @@ -680,7 +681,7 @@ </histogram> <histogram name="Arc.OptInCancel" enum="ArcOptInCancel" - expires_after="2021-05-23"> + expires_after="2021-08-09"> <owner>elijahtaylor@google.com</owner> <owner>shihuis@google.com</owner> <summary>Arc OptIn cancelation reason.</summary> @@ -711,7 +712,7 @@ </histogram> <histogram name="Arc.OptInSilentAuthCode.SecondaryAccount" - enum="ArcOptInSilentAuthCode" expires_after="2021-04-04"> + enum="ArcOptInSilentAuthCode" expires_after="2021-08-09"> <owner>khmel@google.com</owner> <summary> Arc Silent Auth Code status. This status is set during the minting of an @@ -780,7 +781,7 @@ </histogram> <histogram name="Arc.PlayStoreSearch.ReturnedAppsTotal" units="apps" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>hejq@chromium.org</owner> <summary> The total number of returned apps of a Play Store app discovery query. @@ -959,7 +960,7 @@ </histogram> <histogram name="Arc.Runtime.Performance.CommitDeviation" units="microseconds" - expires_after="2021-05-16"> + expires_after="2021-08-09"> <!-- Name completed by histogram_suffixes name="ArcPerformanceAppCategories" --> <owner>khmel@google.com</owner> @@ -1017,7 +1018,7 @@ </histogram> <histogram name="Arc.SdkVersionUpgradeType" enum="ArcSdkVersionUpgradeType" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>niwa@google.com</owner> <owner>yusukes@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/ash/histograms.xml b/tools/metrics/histograms/histograms_xml/ash/histograms.xml index 16dfa409..0fe28529 100644 --- a/tools/metrics/histograms/histograms_xml/ash/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/ash/histograms.xml
@@ -634,7 +634,7 @@ </histogram> <histogram name="Ash.Desks.MoveWindowFromActiveDesk" - enum="DesksMoveWindowFromActiveDeskSource" expires_after="2021-04-25"> + enum="DesksMoveWindowFromActiveDeskSource" expires_after="2021-08-09"> <owner>afakhry@chromium.org</owner> <owner>tclaiborne@chromium.org</owner> <summary> @@ -981,7 +981,7 @@ </histogram> <histogram name="Ash.HotseatGesture" enum="HotseatInAppGesture" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>andrewxu@chromium.org</owner> <owner>tbarzic@chromium.org</owner> <summary>Gestures supported by the in-app hotseat.</summary> @@ -1112,7 +1112,7 @@ </histogram> <histogram name="Ash.Login.Lock.NbPasswordAttempts.UntilFailure" - units="attempts" expires_after="2021-05-27"> + units="attempts" expires_after="2021-08-09"> <owner>tellier@google.com</owner> <owner>cros-oac@google.com</owner> <summary> @@ -1196,7 +1196,7 @@ </histogram> <histogram name="Ash.Login.OOBE.UserClicks" enum="OobeUserClickTarget" - expires_after="2021-04-18"> + expires_after="2021-08-09"> <owner>raleksandrov@google.com</owner> <owner>cros-oac@google.com</owner> <summary>What shelf buttons or trays are clicked in the OOBE.</summary> @@ -1359,7 +1359,7 @@ </histogram> <histogram name="Ash.NumberOfVisibleWindowsInPrimaryDisplay" units="Windows" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>jamescook@chromium.org</owner> <summary> An upper bound on the number of windows visible to the user on the primary @@ -1988,7 +1988,8 @@ </summary> </histogram> -<histogram name="Ash.SplitView.TimeInSplitView" units="ms" expires_after="M92"> +<histogram name="Ash.SplitView.TimeInSplitView" units="ms" + expires_after="2021-08-09"> <owner>xdai@chromium.org</owner> <summary> The amount of time that the user spent in split view mode. The time is @@ -2073,7 +2074,7 @@ </histogram> <histogram name="Ash.SwipeHomeToOverviewGesture" - enum="SwipeHomeToOverviewResult" expires_after="2021-04-04"> + enum="SwipeHomeToOverviewResult" expires_after="2021-08-09"> <owner>andrewxu@chromium.org</owner> <owner>tbarzic@chromium.org</owner> <summary> @@ -2185,13 +2186,13 @@ </histogram> <histogram name="Ash.TouchView.TouchViewActivePercentage" units="%" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>girard@chromium.org</owner> <summary>The proportion of time spent in TouchView during a session.</summary> </histogram> <histogram name="Ash.TouchView.TouchViewActiveTotal" units="minutes" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>girard@chromium.org</owner> <summary>The total time that TouchView is active during a session.</summary> </histogram> @@ -2247,7 +2248,7 @@ </histogram> <histogram name="Ash.Wallpaper.CustomLayout" enum="WallpaperLayout" - expires_after="M92"> + expires_after="2021-08-09"> <owner>xdai@chromium.org</owner> <summary> The custom wallpaper layout type. Recorded when the user sets a new custom @@ -2255,7 +2256,8 @@ </summary> </histogram> -<histogram name="Ash.Wallpaper.Source" enum="WallpaperType" expires_after="M92"> +<histogram name="Ash.Wallpaper.Source" enum="WallpaperType" + expires_after="2021-08-09"> <owner>xdai@chromium.org</owner> <summary> Recorded when a new wallpaper is set, either by the built-in Wallpaper @@ -2264,7 +2266,8 @@ </summary> </histogram> -<histogram name="Ash.Wallpaper.Type" enum="WallpaperType" expires_after="M92"> +<histogram name="Ash.Wallpaper.Type" enum="WallpaperType" + expires_after="2021-08-09"> <owner>kuscher@google.com</owner> <summary>The wallpaper type. Recorded at user login.</summary> </histogram> @@ -2359,7 +2362,7 @@ </histogram> <histogram name="Ash.WindowCycleController.TimeBetweenTaskSwitches" - units="seconds" expires_after="2021-05-16"> + units="seconds" expires_after="2021-08-09"> <owner>sammiequon@chromium.org</owner> <owner>tclaiborne@chromium.org</owner> <owner>xdai@chromium.org</owner> @@ -2382,7 +2385,7 @@ </histogram> <histogram name="Ash.WindowCycleView.AnimationSmoothness.Show" units="%" - expires_after="2021-05-31"> + expires_after="2021-08-09"> <owner>yjliu@chromium.org</owner> <owner>chromeos-wmp@google.com</owner> <summary> @@ -2394,7 +2397,7 @@ </histogram> <histogram name="Ash.WindowDragFromShelfResult" enum="ShelfWindowDragResult" - expires_after="2021-04-04"> + expires_after="2021-08-09"> <owner>andrewxu@chromium.org</owner> <owner>tbarzic@chromium.org</owner> <summary> @@ -2555,7 +2558,7 @@ <histogram name="Ash.WorkspaceWindowResizer.TabDragging.PresentationTime.MaxLatency.ClamshellMode" - units="ms" expires_after="2021-06-06"> + units="ms" expires_after="2021-08-09"> <owner>yichenz@chromium.org</owner> <owner>chromeos-wmp@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/assistant/histograms.xml b/tools/metrics/histograms/histograms_xml/assistant/histograms.xml index 359c5c4..621e584 100644 --- a/tools/metrics/histograms/histograms_xml/assistant/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/assistant/histograms.xml
@@ -147,14 +147,14 @@ </histogram> <histogram name="Assistant.QueryResponseType" enum="AssistantQueryResponseType" - expires_after="2021-04-11"> + expires_after="2021-08-09"> <owner>xiaohuic@chromium.org</owner> <owner>meilinw@chromium.org</owner> <summary>The Assistant query response type.</summary> </histogram> <histogram name="Assistant.QuerySource" enum="AssistantQuerySource" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>xiaohuic@chromium.org</owner> <owner>meilinw@chromium.org</owner> <summary> @@ -192,7 +192,7 @@ </histogram> <histogram name="Assistant.SetDspHotwordLocale" enum="BooleanSuccess" - expires_after="2021-05-14"> + expires_after="2021-08-09"> <owner>meilinw@chromium.org</owner> <owner>xiaohuic@chromium.org</owner> <summary> @@ -272,7 +272,7 @@ </histogram> <histogram base="true" name="QuickAnswers.Consent.Duration" units="ms" - expires_after="2021-05-16"> + expires_after="2021-08-09"> <owner>llin@google.com</owner> <owner>croissant-eng@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/autofill/histograms.xml b/tools/metrics/histograms/histograms_xml/autofill/histograms.xml index a690d614..6f90860 100644 --- a/tools/metrics/histograms/histograms_xml/autofill/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/autofill/histograms.xml
@@ -22,7 +22,7 @@ <histograms> <histogram name="Autofill.Address.IsEnabled.PageLoad" enum="BooleanEnabled" - expires_after="2021-04-01"> + expires_after="2021-08-09"> <owner>jsaul@google.com</owner> <owner>chrome-autofill@google.com</owner> <summary> @@ -32,7 +32,7 @@ </histogram> <histogram name="Autofill.Address.IsEnabled.Startup" enum="BooleanEnabled" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>jsaul@google.com</owner> <owner>chrome-autofill@google.com</owner> <summary> @@ -324,7 +324,7 @@ <histogram name="Autofill.BetterAuth.UserPerceivedLatencyOnCardSelection.OptedIn.Duration" - units="ms" expires_after="2021-05-31"> + units="ms" expires_after="2021-08-09"> <owner>jsaul@google.com</owner> <owner>manasverma@google.com</owner> <owner>autofill-auth-team@google.com</owner> @@ -392,7 +392,7 @@ </histogram> <histogram name="Autofill.CardUnmask.CvcLength" units="digits" - expires_after="2021-03-31"> + expires_after="2021-08-09"> <owner>jsaul@google.com</owner> <owner>siyua@chromium.org</owner> <owner>payments-autofill-team@google.com</owner> @@ -417,7 +417,7 @@ </histogram> <histogram name="Autofill.CardUploadEnabled" enum="AutofillCardUploadEnabled" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>aneeshali@google.com</owner> <owner>jsaul@google.com</owner> <summary> @@ -428,7 +428,7 @@ </histogram> <histogram name="Autofill.CreditCard.IsEnabled.PageLoad" enum="BooleanEnabled" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>jsaul@google.com</owner> <owner>chrome-autofill@google.com</owner> <summary> @@ -438,7 +438,7 @@ </histogram> <histogram name="Autofill.CreditCard.IsEnabled.Startup" enum="BooleanEnabled" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>jsaul@google.com</owner> <owner>chrome-autofill@google.com</owner> <summary> @@ -592,7 +592,7 @@ </histogram> <histogram name="Autofill.ExpirationDateFixFlowPromptShown" enum="Boolean" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>siashah@google.com</owner> <owner>jsaul@google.com</owner> <owner>payments-autofill-team@google.com</owner> @@ -972,7 +972,7 @@ </histogram> <histogram name="Autofill.IsEnabled.Startup" enum="BooleanEnabled" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>jsaul@google.com</owner> <owner>battre@chromium.org</owner> <owner>chrome-autofill@google.com</owner> @@ -1159,7 +1159,7 @@ </histogram> <histogram name="Autofill.ManageCardsPrompt" enum="AutofillManageCardsPrompt" - expires_after="2021-06-01"> + expires_after="2021-08-09"> <owner>manasverma@google.com</owner> <owner>jsaul@google.com</owner> <summary> @@ -1497,7 +1497,7 @@ </histogram> <histogram name="Autofill.ServerCardLinkClicked" enum="AutofillSyncState" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>jsaul@google.com</owner> <owner>battre@chromium.org</owner> <owner>chrome-autofill@google.com</owner> @@ -1775,7 +1775,7 @@ </histogram> <histogram name="Autofill.UnmaskPrompt.Duration" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>jsaul@google.com</owner> <owner>siyua@chromium.org</owner> <summary> @@ -1786,7 +1786,7 @@ </histogram> <histogram name="Autofill.UnmaskPrompt.Events" enum="AutofillUnmaskPromptEvent" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>jsaul@google.com</owner> <owner>siyua@chromium.org</owner> <summary> @@ -1796,7 +1796,7 @@ </histogram> <histogram name="Autofill.UnmaskPrompt.GetRealPanDuration" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>jsaul@google.com</owner> <owner>siyua@chromium.org</owner> <summary> @@ -1807,7 +1807,7 @@ </histogram> <histogram name="Autofill.UnmaskPrompt.GetRealPanResult" - enum="AutofillGetRealPanResult" expires_after="2021-06-06"> + enum="AutofillGetRealPanResult" expires_after="2021-08-09"> <owner>jsaul@google.com</owner> <owner>siyua@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/background/histograms.xml b/tools/metrics/histograms/histograms_xml/background/histograms.xml index 307d0ca..64e4ed20 100644 --- a/tools/metrics/histograms/histograms_xml/background/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/background/histograms.xml
@@ -340,7 +340,7 @@ </histogram> <histogram name="BackgroundSync.Registration.OneShot" - enum="BackgroundSyncStatus" expires_after="2021-06-06"> + enum="BackgroundSyncStatus" expires_after="2021-08-09"> <owner>nator@chromium.org</owner> <owner>rayankans@chromium.org</owner> <summary> @@ -349,7 +349,7 @@ </histogram> <histogram name="BackgroundSync.Registration.OneShot.CouldFire" - enum="BooleanCouldFireImmediately" expires_after="2021-04-25"> + enum="BooleanCouldFireImmediately" expires_after="2021-08-09"> <owner>nator@chromium.org</owner> <owner>rayankans@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/blink/histograms.xml b/tools/metrics/histograms/histograms_xml/blink/histograms.xml index ef7309a5..412904c6 100644 --- a/tools/metrics/histograms/histograms_xml/blink/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/blink/histograms.xml
@@ -74,7 +74,7 @@ </histogram> <histogram name="Blink.Canvas.ContentChangeMode" - enum="BooleanContentChangeMode" expires_after="2021-05-09"> + enum="BooleanContentChangeMode" expires_after="2021-08-09"> <owner>yiyix@chromium.org</owner> <owner>fserb@chromium.org</owner> <summary> @@ -86,7 +86,7 @@ </histogram> <histogram name="Blink.Canvas.ContextType" enum="CanvasContextType" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>fserb@chromium.org</owner> <owner>aaronhk@chromium.org</owner> <summary> @@ -104,7 +104,7 @@ </histogram> <histogram base="true" name="Blink.Canvas.DrawImage.Duration" - units="microseconds" expires_after="2021-06-06"> + units="microseconds" expires_after="2021-08-09"> <owner>fserb@chromium.org</owner> <owner>aaronhk@chromium.org</owner> <summary> @@ -117,7 +117,7 @@ </histogram> <histogram base="true" name="Blink.Canvas.DrawImage.SqrtNumberOfPixels" - units="sqrt(pixels)" expires_after="2021-06-06"> + units="sqrt(pixels)" expires_after="2021-08-09"> <owner>fserb@chromium.org</owner> <owner>aaronhk@chromium.org</owner> <summary> @@ -186,7 +186,7 @@ </histogram> <histogram name="Blink.Canvas.MaximumInflightResources" - units="canvas resources" expires_after="2021-04-04"> + units="canvas resources" expires_after="2021-08-09"> <owner>aaronhk@chromium.org</owner> <owner>fserb@chromium.org</owner> <summary> @@ -197,7 +197,7 @@ </histogram> <histogram name="Blink.Canvas.NumCanvasesPerPage" units="canvases" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>aaronhk@chromium.org</owner> <owner>fserb@chromium.org</owner> <summary> @@ -694,7 +694,7 @@ </histogram> <histogram base="true" name="Blink.DisplayLockIntersectionObserver.UpdateTime" - units="microseconds" expires_after="2021-06-06"> + units="microseconds" expires_after="2021-08-09"> <!-- Name completed by histogram_suffixes name="BlinkUpdateTimePreFCPSuffixes" --> <!-- Name completed by histogram_suffixes name="BlinkUpdateTimePostFCPSuffixes" --> @@ -855,6 +855,16 @@ </summary> </histogram> +<histogram name="Blink.Fonts.FontMatchAttempts.System" units="attempts" + expires_after="2021-12-20"> + <owner>caraitto@chromium.org</owner> + <owner>privacy-sandbox-dev@chromium.org</owner> + <summary> + Number of system font match attempts (success + failure) made via @font-face + src:local(), from page load to page unload. Recorded on page unload. + </summary> +</histogram> + <histogram name="Blink.Fonts.ShapeCache" units="units" expires_after="2021-10-15"> <owner>drott@chromium.org</owner> @@ -1263,7 +1273,7 @@ </histogram> <histogram base="true" name="Blink.JavascriptIntersectionObserver.UpdateTime" - units="microseconds" expires_after="2021-06-06"> + units="microseconds" expires_after="2021-08-09"> <!-- Name completed by histogram_suffixes name="BlinkUpdateTimePreFCPSuffixes" --> <!-- Name completed by histogram_suffixes name="BlinkUpdateTimePostFCPSuffixes" --> @@ -1376,7 +1386,7 @@ </histogram> <histogram base="true" name="Blink.LazyLoadIntersectionObserver.UpdateTime" - units="microseconds" expires_after="2021-06-06"> + units="microseconds" expires_after="2021-08-09"> <!-- Name completed by histogram_suffixes name="BlinkUpdateTimePreFCPSuffixes" --> <!-- Name completed by histogram_suffixes name="BlinkUpdateTimePostFCPSuffixes" --> @@ -1673,7 +1683,7 @@ </histogram> <histogram base="true" name="Blink.MediaIntersectionObserver.UpdateTime" - units="microseconds" expires_after="2021-06-06"> + units="microseconds" expires_after="2021-08-09"> <!-- Name completed by histogram_suffixes name="BlinkUpdateTimePreFCPSuffixes" --> <!-- Name completed by histogram_suffixes name="BlinkUpdateTimePostFCPSuffixes" --> @@ -1865,7 +1875,7 @@ </histogram> <histogram name="Blink.Render.DisplayLockActivationReason" - enum="DisplayLockActivationReason" expires_after="2021-05-23"> + enum="DisplayLockActivationReason" expires_after="2021-08-09"> <owner>vmpstr@chromium.org</owner> <owner>chrishtr@chromium.org</owner> <summary>This indicates the reason for display-locking activation</summary> @@ -2037,7 +2047,7 @@ </histogram> <histogram name="Blink.Sms.BackendAvailability" - enum="WebOTPBackendAvailability" expires_after="M92"> + enum="WebOTPBackendAvailability" expires_after="2021-08-09"> <owner>yigu@chromium.org</owner> <owner>web-identity@google.com</owner> <summary> @@ -2047,7 +2057,7 @@ </histogram> <histogram name="Blink.Sms.PendingOriginCount" units="origins" - expires_after="M92"> + expires_after="2021-08-09"> <owner>yigu@chromium.org</owner> <owner>web-identity@google.com</owner> <summary> @@ -2058,7 +2068,7 @@ </histogram> <histogram name="Blink.Sms.Receive.DestroyedReason" - enum="WebOTPServiceDestroyedReason" expires_after="M92"> + enum="WebOTPServiceDestroyedReason" expires_after="2021-08-09"> <owner>goto@chromium.org</owner> <owner>reillyg@chromium.org</owner> <owner>yigu@chromium.org</owner> @@ -2069,7 +2079,7 @@ </histogram> <histogram name="Blink.Sms.Receive.Infobar" enum="WebOTPServiceInfobarAction" - expires_after="M92"> + expires_after="2021-08-09"> <owner>goto@chromium.org</owner> <owner>reillyg@chromium.org</owner> <owner>yigu@chromium.org</owner> @@ -2081,7 +2091,7 @@ </histogram> <histogram name="Blink.Sms.Receive.Outcome" enum="WebOTPServiceOutcome" - expires_after="M92"> + expires_after="2021-08-09"> <owner>goto@chromium.org</owner> <owner>reillyg@chromium.org</owner> <owner>yigu@chromium.org</owner> @@ -2090,7 +2100,7 @@ </histogram> <histogram name="Blink.Sms.Receive.SmsParsingStatus" enum="SmsParsingStatus" - expires_after="M92"> + expires_after="2021-08-09"> <owner>yigu@chromium.org</owner> <owner>web-identity@google.com</owner> <summary> @@ -2125,7 +2135,7 @@ </histogram> <histogram name="Blink.Sms.Receive.TimeCancelOnSuccess" units="ms" - expires_after="M92"> + expires_after="2021-08-09"> <owner>goto@chromium.org</owner> <owner>reillyg@chromium.org</owner> <owner>yigu@chromium.org</owner> @@ -2137,7 +2147,7 @@ </histogram> <histogram name="Blink.Sms.Receive.TimeContinueOnSuccess" units="ms" - expires_after="M92"> + expires_after="2021-08-09"> <owner>goto@chromium.org</owner> <owner>reillyg@chromium.org</owner> <owner>yigu@chromium.org</owner> @@ -2149,7 +2159,7 @@ </histogram> <histogram name="Blink.Sms.Receive.TimeSmsReceive" units="ms" - expires_after="M92"> + expires_after="2021-08-09"> <owner>goto@chromium.org</owner> <owner>reillyg@chromium.org</owner> <owner>yigu@chromium.org</owner> @@ -2160,7 +2170,8 @@ </summary> </histogram> -<histogram name="Blink.Sms.Receive.TimeSuccess" units="ms" expires_after="M92"> +<histogram name="Blink.Sms.Receive.TimeSuccess" units="ms" + expires_after="2021-08-09"> <owner>goto@chromium.org</owner> <owner>reillyg@chromium.org</owner> <owner>yigu@chromium.org</owner> @@ -2173,7 +2184,7 @@ </histogram> <histogram name="Blink.Sms.Receive.TimeUserCancel" units="ms" - expires_after="M92"> + expires_after="2021-08-09"> <owner>goto@chromium.org</owner> <owner>yigu@chromium.org</owner> <owner>web-identity@google.com</owner> @@ -2316,7 +2327,7 @@ </histogram> <histogram name="Blink.UseCounter.DocumentPolicy.Header" - enum="DocumentPolicyFeature" expires_after="2021-05-30"> + enum="DocumentPolicyFeature" expires_after="2021-08-09"> <owner>iclelland@chromium.org</owner> <owner>feature-control@chromium.org</owner> <summary> @@ -2345,7 +2356,7 @@ </histogram> <histogram name="Blink.UseCounter.Extensions.Features" enum="FeatureObserver" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>chasej@chromium.org</owner> <owner>feature-control@chromium.org</owner> <summary> @@ -2635,7 +2646,7 @@ </histogram> <histogram name="BlinkGC.MainThreadMarkingThroughput" units="MB/s" - expires_after="M92"> + expires_after="2021-08-09"> <owner>mlippautz@chromium.org</owner> <owner>oilpan-reviews@chromium.org</owner> <summary> @@ -2674,7 +2685,8 @@ </summary> </histogram> -<histogram name="BlinkGC.TimeForAtomicPhase" units="ms" expires_after="M92"> +<histogram name="BlinkGC.TimeForAtomicPhase" units="ms" + expires_after="2021-08-09"> <owner>mlippautz@chromium.org</owner> <owner>oilpan-reviews@chromium.org</owner> <summary> @@ -2696,7 +2708,8 @@ </summary> </histogram> -<histogram name="BlinkGC.TimeForCompleteSweep" units="ms" expires_after="M92"> +<histogram name="BlinkGC.TimeForCompleteSweep" units="ms" + expires_after="2021-08-09"> <owner>bikineev@chromium.org</owner> <owner>oilpan-reviews@chromium.org</owner> <summary> @@ -2753,7 +2766,7 @@ </summary> </histogram> -<histogram name="BlinkGC.TimeForMarking" units="ms" expires_after="M92"> +<histogram name="BlinkGC.TimeForMarking" units="ms" expires_after="2021-08-09"> <owner>omerkatz@chromium.org</owner> <owner>oilpan-reviews@chromium.org</owner> <summary> @@ -2763,7 +2776,8 @@ </summary> </histogram> -<histogram name="BlinkGC.TimeForMarkingRoots" units="ms" expires_after="M92"> +<histogram name="BlinkGC.TimeForMarkingRoots" units="ms" + expires_after="2021-08-09"> <owner>omerkatz@chromium.org</owner> <owner>oilpan-reviews@chromium.org</owner> <summary> @@ -2793,7 +2807,7 @@ </histogram> <histogram name="BlinkGC.TimeForSweepingForeground" units="ms" - expires_after="M92"> + expires_after="2021-08-09"> <owner>bikineev@chromium.org</owner> <owner>oilpan-reviews@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/browser/histograms.xml b/tools/metrics/histograms/histograms_xml/browser/histograms.xml index de8c740..fedf14e 100644 --- a/tools/metrics/histograms/histograms_xml/browser/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/browser/histograms.xml
@@ -21,6 +21,15 @@ <histograms> +<histogram name="Browser.AnyWindowHasName" enum="Boolean" + expires_after="2021-06-30"> + <owner>ellyjones@chromium.org</owner> + <summary> + Whether any browser window in the current session has a user-set name. + Logged once every histogram recording. + </summary> +</histogram> + <histogram name="Browser.BitmapFetcher.Decode" units="ms" expires_after="2021-06-27"> <owner>manukh@chromium.org</owner> @@ -290,7 +299,7 @@ </histogram> <histogram name="Browser.Responsiveness.IOJanksTotalPerMinute" units="janks" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>gab@chromium.org</owner> <owner>olivierli@chromium.org</owner> <summary> @@ -304,7 +313,7 @@ </histogram> <histogram name="Browser.Responsiveness.IOJankyIntervalsPerMinute" - units="janks" expires_after="2021-06-06"> + units="janks" expires_after="2021-08-09"> <owner>gab@chromium.org</owner> <owner>olivierli@chromium.org</owner> <summary> @@ -421,7 +430,7 @@ </histogram> <histogram base="true" name="Browser.Tabs.TotalIncompleteSwitchDuration" - units="ms" expires_after="2021-04-25"> + units="ms" expires_after="2021-08-09"> <!-- Name completed by histogram_suffixes name="TabSwitchingType" --> <owner>fdoray@chromium.org</owner> @@ -469,7 +478,7 @@ </histogram> <histogram name="BrowserDialogs.ExternalProtocol.HandleState" - enum="HandleStateType" expires_after="2021-05-30"> + enum="HandleStateType" expires_after="2021-08-09"> <owner>dominickn@chromium.org</owner> <owner>meacer@chromium.org</owner> <summary> @@ -650,7 +659,7 @@ </histogram> <histogram name="BrowserServices.VerificationResult" - enum="BrowserServicesVerificationResult" expires_after="M92"> + enum="BrowserServicesVerificationResult" expires_after="2021-08-09"> <owner>peconn@chromium.org</owner> <owner>peter@chromium.org</owner> <summary> @@ -759,7 +768,7 @@ </histogram> <histogram name="BrowserSwitcher.ExternalSitelistSize" units="rules" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>nicolaso@chromium.org</owner> <owner>pastarmovj@chromium.org</owner> <summary> @@ -830,7 +839,7 @@ </histogram> <histogram name="BrowserSwitcher.UrlListWildcard" enum="BooleanPresent" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>nicolaso@chromium.org</owner> <owner>pastarmovj@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/chrome/histograms.xml b/tools/metrics/histograms/histograms_xml/chrome/histograms.xml index 1ec29fb8a..d0b2fdda 100644 --- a/tools/metrics/histograms/histograms_xml/chrome/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/chrome/histograms.xml
@@ -145,7 +145,7 @@ </histogram> <histogram name="Chrome.Tabs.AnimationSmoothness.TabLoading" units="%" - expires_after="2021-06-04"> + expires_after="2021-08-09"> <owner>yichenz@chromium.org</owner> <owner>chromeos-wmp@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml b/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml index b297543..3bc82d6 100644 --- a/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml
@@ -81,7 +81,7 @@ </histogram> <histogram name="ChromeOS.Apps.NumberOfAppsForNotification" - enum="BooleanMultipleApps" expires_after="2021-06-06"> + enum="BooleanMultipleApps" expires_after="2021-08-09"> <owner>dominickn@chromium.org</owner> <owner>nancylingwang@chromium.org</owner> <summary> @@ -182,7 +182,7 @@ </histogram> <histogram name="ChromeOS.Camera.OpenDeviceClientType" - enum="ChromeOSCameraClientType" expires_after="2021-05-16"> + enum="ChromeOSCameraClientType" expires_after="2021-08-09"> <owner>lnishan@chromium.org</owner> <owner>chromeos-camera-eng@google.com</owner> <summary> @@ -292,7 +292,7 @@ </histogram> <histogram name="ChromeOS.CWP.ParseCPUFrequencies" - enum="ChromeOSParseCPUFrequencyStatus" expires_after="2021-04-18"> + enum="ChromeOSParseCPUFrequencyStatus" expires_after="2021-08-09"> <owner>gmx@chromium.org</owner> <owner>cwp-team@google.com</owner> <summary> @@ -499,7 +499,7 @@ </histogram> <histogram name="ChromeOS.KeyPermissionsManager.Migration" - enum="KeyPermissionsManagerMigrationStatus" expires_after="2021-06-06"> + enum="KeyPermissionsManagerMigrationStatus" expires_after="2021-08-09"> <owner>omorsi@google.com</owner> <owner>pmarko@google.com</owner> <summary> @@ -694,7 +694,7 @@ </histogram> <histogram name="ChromeOS.PrivacyScreen.Toggled" - enum="PrivacyScreenToggleUISurface" expires_after="2021-04-14"> + enum="PrivacyScreenToggleUISurface" expires_after="2021-08-09"> <owner>tengs@chromium.org</owner> <owner>gzadina@google.com</owner> <summary> @@ -991,7 +991,7 @@ </histogram> <histogram name="ChromeOS.Settings.PathVisited" enum="WebUISettingsPathHashes" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>khorimoto@chromium.org</owner> <owner>cros-customization@google.com</owner> <summary> @@ -1155,7 +1155,7 @@ </histogram> <histogram name="ChromeOS.Sync.PreferencesMigrated" enum="BooleanMigrated" - expires_after="2021-03-28"> + expires_after="2021-08-09"> <owner>jamescook@chromium.org</owner> <owner>cros-customization@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/compositing/histograms.xml b/tools/metrics/histograms/histograms_xml/compositing/histograms.xml index 8f2d429..ee94fb5f 100644 --- a/tools/metrics/histograms/histograms_xml/compositing/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/compositing/histograms.xml
@@ -83,7 +83,7 @@ </histogram> <histogram name="Compositing.Browser.NumActivePictureLayers" units="layers" - expires_after="2021-06-01"> + expires_after="2021-08-09"> <owner>schenney@chromium.org</owner> <owner>paint-dev@chromium.org</owner> <summary> @@ -154,7 +154,7 @@ </histogram> <histogram name="Compositing.DirectRenderer.PartialSwap.ExtraDamage" units="%" - expires_after="2021-04-11"> + expires_after="2021-08-09"> <owner>vasilyt@chromium.org</owner> <owner>backer@chromium.org</owner> <summary> @@ -183,7 +183,7 @@ </histogram> <histogram name="Compositing.DirectRenderer.PartialSwap.RootDamage" units="%" - expires_after="2021-04-25"> + expires_after="2021-08-09"> <owner>vasilyt@chromium.org</owner> <owner>backer@chromium.org</owner> <summary> @@ -195,7 +195,7 @@ </histogram> <histogram name="Compositing.DirectRenderer.PartialSwap.TotalDamage" units="%" - expires_after="2021-04-18"> + expires_after="2021-08-09"> <owner>vasilyt@chromium.org</owner> <owner>backer@chromium.org</owner> <summary> @@ -207,7 +207,7 @@ </histogram> <histogram name="Compositing.DirectRenderer.Software.DrawFrameUs" - units="microseconds" expires_after="2021-05-16"> + units="microseconds" expires_after="2021-08-09"> <owner>weiliangc@chromium.org</owner> <summary> Time spent drawing of composited layers by SoftwareRenderer, in @@ -456,7 +456,7 @@ </histogram> <histogram name="Compositing.Renderer.LCDTextDisallowedReasonKPixels" - enum="LCDTextDisallowedReason" expires_after="2021-06-06"> + enum="LCDTextDisallowedReason" expires_after="2021-08-09"> <owner>wangxianzhu@chromium.org</owner> <owner>paint-dev@chromium.org</owner> <summary> @@ -469,7 +469,7 @@ </histogram> <histogram name="Compositing.Renderer.LCDTextDisallowedReasonLayers" - enum="LCDTextDisallowedReason" expires_after="2021-04-01"> + enum="LCDTextDisallowedReason" expires_after="2021-08-09"> <owner>wangxianzhu@chromium.org</owner> <owner>paint-dev@chromium.org</owner> <summary> @@ -500,7 +500,7 @@ </histogram> <histogram name="Compositing.Renderer.NumRenderSurfaces" units="surfaces" - expires_after="2021-06-01"> + expires_after="2021-08-09"> <owner>schenney@chromium.org</owner> <owner>paint-dev@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/content/histograms.xml b/tools/metrics/histograms/histograms_xml/content/histograms.xml index 0590266..0b88990 100644 --- a/tools/metrics/histograms/histograms_xml/content/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/content/histograms.xml
@@ -781,7 +781,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.ImageFetchStatus" - enum="CombinedHttpResponseAndNetErrorCode" expires_after="2021-06-01"> + enum="CombinedHttpResponseAndNetErrorCode" expires_after="2021-08-09"> <owner>harringtond@chromium.org</owner> <owner>feed@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/cookie/histograms.xml b/tools/metrics/histograms/histograms_xml/cookie/histograms.xml index 84dbb6c..1676457 100644 --- a/tools/metrics/histograms/histograms_xml/cookie/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/cookie/histograms.xml
@@ -601,7 +601,7 @@ </histogram> <histogram name="Cookie.TimeBlockedOnLoad" units="ms" - expires_after="2021-04-25"> + expires_after="2021-08-09"> <owner>nharper@chromium.org</owner> <summary> The amount of time (ms) between the cookie store load starting and
diff --git a/tools/metrics/histograms/histograms_xml/cros/histograms.xml b/tools/metrics/histograms/histograms_xml/cros/histograms.xml index 09972de..050eecaa 100644 --- a/tools/metrics/histograms/histograms_xml/cros/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/cros/histograms.xml
@@ -34,7 +34,7 @@ </histogram> <histogram name="CrosDisks.ArchiveType" enum="CrosDisksArchiveType" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>fdegros@chromium.org</owner> <owner>chromeos-files-app@google.com</owner> <summary> @@ -44,7 +44,7 @@ </histogram> <histogram name="CrosDisks.DeviceMediaType" enum="CrosDisksDeviceMediaType" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>fdegros@chromium.org</owner> <owner>chromeos-files-app@google.com</owner> <summary> @@ -54,7 +54,7 @@ </histogram> <histogram name="CrosDisks.FilesystemType" enum="CrosDisksFilesystemType" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>fdegros@chromium.org</owner> <owner>chromeos-files-app@google.com</owner> <summary> @@ -74,7 +74,7 @@ </histogram> <histogram name="CrosDisks.Fuse.Rar2fs" enum="Rar2fsError" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>fdegros@chromium.org</owner> <owner>chromeos-files-app@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/crypt/histograms.xml b/tools/metrics/histograms/histograms_xml/crypt/histograms.xml index 626966ff1..b1c233a 100644 --- a/tools/metrics/histograms/histograms_xml/crypt/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/crypt/histograms.xml
@@ -43,7 +43,7 @@ </histogram> <histogram name="CryptAuth.ClientAppMetadataInstanceIdTokenFetch.Result" - enum="InstanceIDResult" expires_after="2021-06-06"> + enum="InstanceIDResult" expires_after="2021-08-09"> <owner>khorimoto@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -53,7 +53,7 @@ </histogram> <histogram name="CryptAuth.ClientAppMetadataInstanceIdTokenFetch.Retries" - units="retries" expires_after="2021-06-06"> + units="retries" expires_after="2021-08-09"> <owner>khorimoto@chromium.org</owner> <owner>nohle@chromium.org</owner> <owner>better-together-dev@google.com</owner> @@ -128,7 +128,7 @@ </histogram> <histogram name="CryptAuth.DeviceSyncSoftwareFeaturesResult" - enum="BooleanSuccess" expires_after="2021-06-06"> + enum="BooleanSuccess" expires_after="2021-08-09"> <owner>hansberry@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -264,7 +264,7 @@ <histogram name="CryptAuth.DeviceSyncV2.DeviceSyncer.IsLocalDeviceMetadataConsistent" - enum="BooleanConsistent" expires_after="2021-06-06"> + enum="BooleanConsistent" expires_after="2021-08-09"> <owner>nohle@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -275,7 +275,7 @@ </histogram> <histogram name="CryptAuth.DeviceSyncV2.DeviceSyncer.MetadataDecryptionSuccess" - enum="BooleanSuccess" expires_after="2021-06-06"> + enum="BooleanSuccess" expires_after="2021-08-09"> <owner>nohle@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -286,7 +286,7 @@ </histogram> <histogram name="CryptAuth.DeviceSyncV2.DeviceSyncer.MetadataParsingSuccess" - enum="BooleanSuccess" expires_after="2021-06-06"> + enum="BooleanSuccess" expires_after="2021-08-09"> <owner>nohle@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -299,7 +299,7 @@ <histogram name="CryptAuth.DeviceSyncV2.FeatureStatusGetter.ApiCallResult.GetFeatureStatuses" - enum="CryptAuthApiCallResult" expires_after="2021-06-06"> + enum="CryptAuthApiCallResult" expires_after="2021-08-09"> <owner>nohle@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -311,7 +311,7 @@ <histogram name="CryptAuth.DeviceSyncV2.FeatureStatusGetter.CorrectNumberOfDevicesInResponse" - enum="BooleanExpected" expires_after="2021-06-06"> + enum="BooleanExpected" expires_after="2021-08-09"> <owner>nohle@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -335,7 +335,7 @@ <histogram name="CryptAuth.DeviceSyncV2.FeatureStatusGetter.IsDuplicateDeviceId" - enum="BooleanDuplicate" expires_after="2021-06-06"> + enum="BooleanDuplicate" expires_after="2021-08-09"> <owner>nohle@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -347,7 +347,7 @@ </histogram> <histogram name="CryptAuth.DeviceSyncV2.FeatureStatusGetter.IsKnownFeatureType" - enum="BooleanKnown" expires_after="2021-06-06"> + enum="BooleanKnown" expires_after="2021-08-09"> <owner>nohle@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -361,7 +361,7 @@ <histogram name="CryptAuth.DeviceSyncV2.FeatureStatusGetter.IsUnsupportedFeatureMarkedEnabled" - enum="Boolean" expires_after="2021-06-06"> + enum="Boolean" expires_after="2021-08-09"> <owner>nohle@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -374,7 +374,7 @@ <histogram name="CryptAuth.DeviceSyncV2.FeatureStatusGetter.WasDeviceInResponseRequested" - enum="BooleanRequested" expires_after="2021-06-06"> + enum="BooleanRequested" expires_after="2021-08-09"> <owner>nohle@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -437,7 +437,7 @@ <histogram name="CryptAuth.DeviceSyncV2.GroupPrivateKeySharer.EncryptionSuccess" - enum="BooleanSuccess" expires_after="2021-06-06"> + enum="BooleanSuccess" expires_after="2021-08-09"> <owner>nohle@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -474,7 +474,7 @@ <histogram name="CryptAuth.DeviceSyncV2.GroupPrivateKeySharer.IsEncryptingKeyEmpty" - enum="Boolean" expires_after="2021-06-06"> + enum="Boolean" expires_after="2021-08-09"> <owner>nohle@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -487,7 +487,7 @@ </histogram> <histogram name="CryptAuth.DeviceSyncV2.InvocationReason" - enum="CryptAuthV2InvocationReason" expires_after="2021-06-06"> + enum="CryptAuthV2InvocationReason" expires_after="2021-08-09"> <owner>nohle@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -594,7 +594,7 @@ <histogram name="CryptAuth.DeviceSyncV2.MetadataSyncer.IsDeviceMetadataPacketValid" - enum="Boolean" expires_after="2021-06-06"> + enum="Boolean" expires_after="2021-08-09"> <owner>nohle@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -605,7 +605,7 @@ </histogram> <histogram name="CryptAuth.DeviceSyncV2.MetadataSyncer.IsDuplicateDeviceId" - enum="Boolean" expires_after="2021-06-06"> + enum="Boolean" expires_after="2021-08-09"> <owner>nohle@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -617,7 +617,7 @@ </histogram> <histogram name="CryptAuth.DeviceSyncV2.RemoteDeviceProvider.NumV1Devices" - units="count" expires_after="2021-06-06"> + units="count" expires_after="2021-08-09"> <owner>nohle@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -629,7 +629,7 @@ </histogram> <histogram name="CryptAuth.DeviceSyncV2.RemoteDeviceProvider.NumV2Devices" - units="count" expires_after="2021-06-06"> + units="count" expires_after="2021-08-09"> <owner>nohle@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -642,7 +642,7 @@ <histogram name="CryptAuth.DeviceSyncV2.RemoteDeviceProvider.PercentageOfV1DevicesReplacedByV2Devices" - units="%" expires_after="2021-06-06"> + units="%" expires_after="2021-08-09"> <owner>nohle@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -671,7 +671,7 @@ <histogram name="CryptAuth.DeviceSyncV2.RemoteDeviceProvider.RatioOfV2ToV1Devices" - units="%" expires_after="2021-06-06"> + units="%" expires_after="2021-08-09"> <owner>nohle@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -699,7 +699,7 @@ </histogram> <histogram name="CryptAuth.DeviceSyncV2.Result.ResultCode" - enum="CryptAuthV2DeviceSyncResultCode" expires_after="2021-06-06"> + enum="CryptAuthV2DeviceSyncResultCode" expires_after="2021-08-09"> <owner>nohle@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -709,7 +709,7 @@ </histogram> <histogram name="CryptAuth.DeviceSyncV2.Result.ResultType" - enum="CryptAuthV2DeviceSyncResultType" expires_after="2021-06-06"> + enum="CryptAuthV2DeviceSyncResultType" expires_after="2021-08-09"> <owner>nohle@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -794,7 +794,7 @@ </histogram> <histogram name="CryptAuth.EnrollmentV2.InvocationReason" - enum="CryptAuthV2InvocationReason" expires_after="2021-06-06"> + enum="CryptAuthV2InvocationReason" expires_after="2021-08-09"> <owner>nohle@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -804,7 +804,7 @@ </histogram> <histogram name="CryptAuth.EnrollmentV2.Result.ResultCode" - enum="CryptAuthV2EnrollmentResult" expires_after="2021-06-06"> + enum="CryptAuthV2EnrollmentResult" expires_after="2021-08-09"> <owner>nohle@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -824,7 +824,7 @@ </histogram> <histogram name="CryptAuth.EnrollmentV2.UserKeyPairState" - enum="CryptAuthV2EnrollmentUserKeyPairState" expires_after="2021-06-06"> + enum="CryptAuthV2EnrollmentUserKeyPairState" expires_after="2021-08-09"> <owner>nohle@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -908,7 +908,7 @@ </histogram> <histogram name="CryptAuth.Gcm.Registration.AttemptTimeWithRetries" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>nohle@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -940,7 +940,7 @@ </histogram> <histogram name="CryptAuth.InstanceId.DidInstanceIdChange" - enum="BooleanChanged" expires_after="2021-06-06"> + enum="BooleanChanged" expires_after="2021-08-09"> <owner>nohle@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -951,7 +951,7 @@ </histogram> <histogram name="CryptAuth.InstanceId.DidInstanceIdTokenChange" - enum="BooleanChanged" expires_after="2021-06-06"> + enum="BooleanChanged" expires_after="2021-08-09"> <owner>nohle@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/cryptohome/histograms.xml b/tools/metrics/histograms/histograms_xml/cryptohome/histograms.xml index db226c1b..d9df5cc5 100644 --- a/tools/metrics/histograms/histograms_xml/cryptohome/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/cryptohome/histograms.xml
@@ -42,7 +42,7 @@ </histogram> <histogram name="Cryptohome.ChecksumStatus" enum="CryptohomeChecksumStatus" - expires_after="2021-05-16"> + expires_after="2021-08-09"> <owner>apronin@chromium.org</owner> <owner>cros-hwsec+uma@chromium.org</owner> <summary> @@ -63,7 +63,7 @@ </histogram> <histogram name="Cryptohome.DeprecatedApiCalled" - enum="CryptohomeDeprecatedApiCalled" expires_after="2021-06-06"> + enum="CryptohomeDeprecatedApiCalled" expires_after="2021-08-09"> <owner>apronin@chromium.org</owner> <owner>louiscollard@chromium.org</owner> <owner>zuan@chromium.org</owner> @@ -371,7 +371,7 @@ </histogram> <histogram name="Cryptohome.OOPMountCleanupResult" - enum="CryptohomeOOPMountCleanupResult" expires_after="2021-06-06"> + enum="CryptohomeOOPMountCleanupResult" expires_after="2021-08-09"> <owner>betuls@chromium.org</owner> <owner>jorgelo@chromium.org</owner> <summary> @@ -381,7 +381,7 @@ </histogram> <histogram name="Cryptohome.OOPMountOperationResult" - enum="CryptohomeOOPMountOperationResult" expires_after="2021-06-06"> + enum="CryptohomeOOPMountOperationResult" expires_after="2021-08-09"> <owner>betuls@chromium.org</owner> <owner>jorgelo@chromium.org</owner> <summary> @@ -413,7 +413,7 @@ </histogram> <histogram name="Cryptohome.TimeSessionUnlock" units="ms" - expires_after="2021-04-11"> + expires_after="2021-08-09"> <owner>kerrnel@chromium.org</owner> <owner>mnissler@chromium.org</owner> <summary> @@ -456,7 +456,7 @@ </histogram> <histogram name="Cryptohome.TimeToMountEx" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>jorgelo@chromium.org</owner> <owner>cros-hwsec+uma@chromium.org</owner> <summary> @@ -476,7 +476,7 @@ </histogram> <histogram name="Cryptohome.TimeToMountGuestEx" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>jorgelo@chromium.org</owner> <owner>cros-hwsec+uma@chromium.org</owner> <summary> @@ -486,7 +486,7 @@ </histogram> <histogram name="Cryptohome.TimeToPerformEphemeralMount" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>jorgelo@chromium.org</owner> <owner>cros-hwsec+uma@chromium.org</owner> <summary> @@ -520,7 +520,7 @@ </histogram> <histogram name="Cryptohome.TimeToPerformOOPMountOperation" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>jorgelo@chromium.org</owner> <owner>betuls@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/custom_tabs/histograms.xml b/tools/metrics/histograms/histograms_xml/custom_tabs/histograms.xml index 990af8e..d462df8 100644 --- a/tools/metrics/histograms/histograms_xml/custom_tabs/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/custom_tabs/histograms.xml
@@ -64,7 +64,7 @@ </histogram> <histogram name="CustomTabs.ConnectionStatusOnReturn.GSA" - enum="CustomTabsConnection" expires_after="M92"> + enum="CustomTabsConnection" expires_after="2021-08-09"> <owner>peconn@chromium.org</owner> <owner>peter@chromium.org</owner> <summary> @@ -77,7 +77,7 @@ </histogram> <histogram name="CustomTabs.ConnectionStatusOnReturn.NonGSA" - enum="CustomTabsConnection" expires_after="M92"> + enum="CustomTabsConnection" expires_after="2021-08-09"> <owner>peconn@chromium.org</owner> <owner>peter@chromium.org</owner> <summary> @@ -165,7 +165,7 @@ </histogram> <histogram name="CustomTabs.ParallelRequestStatusOnStart" - enum="CustomTabsParallelRequestStatusOnStart" expires_after="M92"> + enum="CustomTabsParallelRequestStatusOnStart" expires_after="2021-08-09"> <owner>lizeb@chromium.org</owner> <owner>cct-team@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/data_reduction_proxy/histograms.xml b/tools/metrics/histograms/histograms_xml/data_reduction_proxy/histograms.xml index dc3ea3e..952a2a8 100644 --- a/tools/metrics/histograms/histograms_xml/data_reduction_proxy/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/data_reduction_proxy/histograms.xml
@@ -256,7 +256,7 @@ </histogram> <histogram name="DataReductionProxy.EnabledState" - enum="DataReductionProxyEnabledState" expires_after="2021-06-06"> + enum="DataReductionProxyEnabledState" expires_after="2021-08-09"> <owner>rajendrant@chromium.org</owner> <owner>tbansal@chromium.org</owner> <summary> @@ -470,7 +470,7 @@ </histogram> <histogram name="DataReductionProxy.UserViewedOriginalSize" units="KB" - expires_after="2021-05-02"> + expires_after="2021-08-09"> <owner>rajendrant@chromium.org</owner> <owner>robertogden@chromium.org</owner> <owner>src/components/data_reduction_proxy/OWNERS</owner> @@ -495,7 +495,7 @@ </histogram> <histogram name="DataReductionProxy.UserViewedSavingsSize" units="KB" - expires_after="2021-05-02"> + expires_after="2021-08-09"> <owner>rajendrant@chromium.org</owner> <owner>robertogden@chromium.org</owner> <owner>src/components/data_reduction_proxy/OWNERS</owner>
diff --git a/tools/metrics/histograms/histograms_xml/dev/histograms.xml b/tools/metrics/histograms/histograms_xml/dev/histograms.xml index 80b39c37..9b568375 100644 --- a/tools/metrics/histograms/histograms_xml/dev/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/dev/histograms.xml
@@ -65,7 +65,7 @@ </histogram> <histogram name="DevTools.BackgroundService.StartRecording" - enum="DevToolsBackgroundService" expires_after="M92"> + enum="DevToolsBackgroundService" expires_after="2021-08-09"> <owner>yangguo@chromium.org</owner> <owner>bmeurer@chromium.org</owner> <owner>rayankans@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/download/histograms.xml b/tools/metrics/histograms/histograms_xml/download/histograms.xml index 84b2d9b..1d14c21 100644 --- a/tools/metrics/histograms/histograms_xml/download/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/download/histograms.xml
@@ -48,7 +48,7 @@ </histogram> <histogram name="Download.CancelReason" enum="DownloadCancelReason" - expires_after="2021-04-01"> + expires_after="2021-08-09"> <owner>xingliu@chromium.org</owner> <owner>clank-downloads@google.com</owner> <summary>Records why the download is canceled.</summary> @@ -563,7 +563,7 @@ </histogram> <histogram name="Download.Parallelizable.FileSize" units="KB" - expires_after="2021-05-02"> + expires_after="2021-08-09"> <owner>xingliu@chromium.org</owner> <owner>clank-downloads@google.com</owner> <summary>The download size of a parallelizable download.</summary>
diff --git a/tools/metrics/histograms/histograms_xml/enterprise/histograms.xml b/tools/metrics/histograms/histograms_xml/enterprise/histograms.xml index 732eb02..91c8b7f2 100644 --- a/tools/metrics/histograms/histograms_xml/enterprise/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/enterprise/histograms.xml
@@ -42,7 +42,7 @@ </histogram> <histogram name="Enterprise.AppRestrictionLoadTime2.EmptyBundle" units="ms" - expires_after="2021-04-04"> + expires_after="2021-08-09"> <owner>twellington@google.com</owner> <owner>tedchcoc@chromium.org</owner> <summary> @@ -52,7 +52,7 @@ </histogram> <histogram name="Enterprise.AppRestrictionLoadTime2.NonEmptyBundle" units="ms" - expires_after="2021-05-16"> + expires_after="2021-08-09"> <owner>twellington@google.com</owner> <owner>tedchcoc@chromium.org</owner> <summary> @@ -162,7 +162,7 @@ </histogram> <histogram base="true" name="Enterprise.AutoEnrollmentRequestStatus" - enum="EnterpriseDeviceManagementStatus" expires_after="2021-05-02"> + enum="EnterpriseDeviceManagementStatus" expires_after="2021-08-09"> <!-- Name completed by histogram_suffixes name="EnterpriseAutoEnrollmentType". --> <owner>pmarko@chromium.org</owner> @@ -170,6 +170,29 @@ <summary>URL fetcher status for auto-enrollment requests.</summary> </histogram> +<histogram base="true" name="Enterprise.BrowserSigninIOS.SignedOutByPolicy" + enum="BooleanHit" expires_after="2021-06-30"> + <owner>gujen@google.com</owner> + <owner>goanuj@google.com</owner> + <summary> + Recorded when a signed-in user is automatically signed out of the browser + due to the BrowserSignin policy being set to 0 (sign-in disabled) by their + organization. The sample is always recorded as true. + </summary> +</histogram> + +<histogram base="true" + name="Enterprise.BrowserSigninIOS.SignInInterruptedByPolicy" + enum="BooleanHit" expires_after="2021-06-30"> + <owner>gujen@google.com</owner> + <owner>goanuj@google.com</owner> + <summary> + Recorded when a user is in the process of signing in to the browser, but is + interrupted due to the BrowserSignin policy being set to 0 (sign-in + disabled) by their organization. The sample is always recorded as true. + </summary> +</histogram> + <histogram base="true" name="Enterprise.CachedDevicePolicyDeviceIdValidity" enum="EnterprisePolicyDeviceIdValidity" expires_after="M95"> <owner>emaxx@chromium.org</owner> @@ -494,7 +517,7 @@ </histogram> <histogram name="Enterprise.DMServerRequestSuccess" - enum="EnterpriseDMServerRequestSuccess" expires_after="2021-06-06"> + enum="EnterpriseDMServerRequestSuccess" expires_after="2021-08-09"> <owner>poromov@chromium.org</owner> <owner>managed-devices@google.com</owner> <summary> @@ -641,7 +664,7 @@ </histogram> <histogram name="Enterprise.EnrollmentTime.Success" units="ms" - expires_after="2021-05-16"> + expires_after="2021-08-09"> <owner>raleksandrov@google.com</owner> <owner>cros-oac@google.com</owner> <summary> @@ -885,7 +908,7 @@ <histogram name="Enterprise.MachineLevelUserCloudPolicyEnrollment.RequestFailureTime" - units="ms" expires_after="2021-06-01"> + units="ms" expires_after="2021-08-09"> <owner>rogerta@chromium.org</owner> <owner>zmin@chromium.org</owner> <summary> @@ -965,7 +988,7 @@ </histogram> <histogram name="Enterprise.Policies" enum="EnterprisePolicies" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>mnissler@chromium.org</owner> <summary> A set of enterprise policy rules that are in use. This is recorded every 24 @@ -1136,7 +1159,7 @@ </histogram> <histogram name="Enterprise.RegularUserSession.SessionLength" units="minutes" - expires_after="2021-05-16"> + expires_after="2021-08-09"> <owner>marcgrimme@chromium.org</owner> <owner>managed-devices@google.com</owner> <summary> @@ -1194,7 +1217,7 @@ </histogram> <histogram name="Enterprise.StorePolicy.Duration" units="ms" - expires_after="2021-05-20"> + expires_after="2021-08-09"> <owner>mpolzer@google.com</owner> <owner>managed-platforms@google.com</owner> <summary> @@ -1580,7 +1603,7 @@ </histogram> <histogram name="EnterpriseCheck.InvalidPolicies" enum="EnterprisePolicies" - expires_after="2021-05-09"> + expires_after="2021-08-09"> <owner>pastarmovj@chromium.org</owner> <summary> A set of policy rules that were ignored due to integrity violations while @@ -1590,7 +1613,7 @@ </histogram> <histogram name="EnterpriseCheck.InvalidPoliciesDetected" - units="disabled policies" expires_after="2021-05-05"> + units="disabled policies" expires_after="2021-08-09"> <owner>pastarmovj@chromium.org</owner> <owner>zmin@chomium.org</owner> <summary> @@ -1624,7 +1647,7 @@ </histogram> <histogram name="EnterpriseCheck.IsFullyManaged2" enum="IsFullyManagedBoolean" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>twellington@google.com</owner> <owner>tedchcoc@chromium.org</owner> <summary> @@ -1681,7 +1704,7 @@ </histogram> <histogram name="EnterpriseCheck.Mac.IsCurrentUserDomainUser" enum="Boolean" - expires_after="2021-05-23"> + expires_after="2021-08-09"> <owner>avi@chromium.org</owner> <owner>pastarmovj@chromium.org</owner> <summary> @@ -1701,7 +1724,7 @@ </histogram> <histogram name="EnterpriseCheck.Mac.IsDeviceMDMEnrolledNew" - enum="EnterpriseMacMDMStatusNew" expires_after="2021-05-23"> + enum="EnterpriseMacMDMStatusNew" expires_after="2021-08-09"> <owner>avi@chromium.org</owner> <owner>pastarmovj@chromium.org</owner> <summary> @@ -1712,7 +1735,7 @@ </histogram> <histogram name="EnterpriseCheck.Mac.IsDeviceMDMEnrolledOld" - enum="EnterpriseMacMDMStatusOld" expires_after="2021-05-23"> + enum="EnterpriseMacMDMStatusOld" expires_after="2021-08-09"> <owner>avi@chromium.org</owner> <owner>pastarmovj@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/event/histograms.xml b/tools/metrics/histograms/histograms_xml/event/histograms.xml index 03b2487e..3f43da0 100644 --- a/tools/metrics/histograms/histograms_xml/event/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/event/histograms.xml
@@ -22,7 +22,7 @@ <histograms> <histogram name="Event.AggregatedLatency.Renderer2" units="microseconds" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>flackr@chromium.org</owner> <summary> Time between initiation of any input event and the renderer receiving and @@ -55,7 +55,7 @@ </histogram> <histogram name="Event.AsyncTargeting.AsyncClientDepth" units="clients" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>sadrul@chromium.org</owner> <owner>event-targeting@chromium.org</owner> <summary> @@ -65,7 +65,7 @@ </histogram> <histogram name="Event.AsyncTargeting.ResponseTime" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>sadrul@chromium.org</owner> <owner>event-targeting@chromium.org</owner> <summary> @@ -397,7 +397,7 @@ </histogram> <histogram name="Event.Latency.OS_NO_VALIDATION.POSITIVE" units="ms" - expires_after="2021-05-09"> + expires_after="2021-08-09"> <owner>sullivan@chromium.org</owner> <owner>input-dev@chromium.org</owner> <summary> @@ -553,7 +553,7 @@ <histogram name="Event.Latency.ScrollBegin.Scrollbar.TimeToScrollUpdateSwapBegin4" - units="microseconds" expires_after="2021-06-06"> + units="microseconds" expires_after="2021-08-09"> <owner>nzolghadr@chromium.org</owner> <owner>dlibby@microsoft.com</owner> <owner>input-dev@chromium.org</owner> @@ -657,7 +657,7 @@ </histogram> <histogram name="Event.Latency.ScrollBegin.Touch.GpuSwap2" units="microseconds" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>flackr@chromium.org</owner> <summary> Time between gpu starts to swap the first ScrollUpdate gesture event in a @@ -1053,7 +1053,7 @@ </histogram> <histogram name="Event.Latency.ScrollUpdate.TimeToScrollUpdateSwapBegin2" - units="microseconds" expires_after="2021-06-06"> + units="microseconds" expires_after="2021-08-09"> <owner>nzolghadr@chromium.org</owner> <summary> Time between initial creation of a wheel/touch event and start of the frame @@ -1224,7 +1224,7 @@ </histogram> <histogram name="Event.Latency.ScrollUpdate.Touch.GpuSwap2" - units="microseconds" expires_after="2021-06-06"> + units="microseconds" expires_after="2021-08-09"> <owner>flackr@chromium.org</owner> <owner>input-dev@chromium.org</owner> <summary> @@ -1437,7 +1437,7 @@ </histogram> <histogram name="Event.PassiveListeners" enum="EventResultType" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>dtapuska@chromium.org</owner> <summary> The result of handling of MouseWheel, TouchStart, TouchMove, TouchEnd events @@ -1637,7 +1637,7 @@ </histogram> <histogram name="Event.VizHitTest.AsyncHitTestReasons" - enum="AsyncHitTestReasons" expires_after="2021-06-06"> + enum="AsyncHitTestReasons" expires_after="2021-08-09"> <owner>sadrul@chromium.org</owner> <owner>event-targeting@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/extension/histograms.xml b/tools/metrics/histograms/histograms_xml/extension/histograms.xml index 36f8293..e31cda2 100644 --- a/tools/metrics/histograms/histograms_xml/extension/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/extension/histograms.xml
@@ -177,7 +177,7 @@ </histogram> <histogram name="ExtensionOverrideBubble.SettingsApiUserSelectionHomePage" - enum="ExtensionBubbleAction" expires_after="2021-04-01"> + enum="ExtensionBubbleAction" expires_after="2021-08-09"> <owner>rdevlin.cronin@chromium.org</owner> <owner>extensions-core@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/extensions/histograms.xml b/tools/metrics/histograms/histograms_xml/extensions/histograms.xml index b949a206..a884b34 100644 --- a/tools/metrics/histograms/histograms_xml/extensions/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/extensions/histograms.xml
@@ -264,7 +264,7 @@ </histogram> <histogram name="Extensions.BookmarkAppLaunchSource" enum="AppLaunchSource" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>benwells@chromium.org</owner> <owner>dominickn@chromium.org</owner> <owner>mgiuca@chromium.org</owner> @@ -359,7 +359,7 @@ </histogram> <histogram name="Extensions.ContentVerification.ComputeHashesOnInstallResult" - enum="BooleanSuccess" expires_after="2021-05-02"> + enum="BooleanSuccess" expires_after="2021-08-09"> <owner>burunduk@chromium.org</owner> <owner>lazyboy@chromium.org</owner> <owner>rdevlin.cronin@chromium.org</owner> @@ -375,7 +375,7 @@ </histogram> <histogram name="Extensions.ContentVerification.ComputeHashesOnInstallTime" - units="ms" expires_after="2021-05-02"> + units="ms" expires_after="2021-08-09"> <owner>burunduk@chromium.org</owner> <owner>lazyboy@chromium.org</owner> <owner>rdevlin.cronin@chromium.org</owner> @@ -403,7 +403,7 @@ </histogram> <histogram name="Extensions.ContentVerification.FetchResult" - enum="BooleanSuccess" expires_after="2021-05-30"> + enum="BooleanSuccess" expires_after="2021-08-09"> <owner>lazyboy@chromium.org</owner> <owner>rdevlin.cronin@chromium.org</owner> <owner>extensions-core@chromium.org</owner> @@ -521,7 +521,7 @@ </histogram> <histogram name="Extensions.CorruptPolicyExtensionResolved" units="ms" - expires_after="2021-03-28"> + expires_after="2021-08-09"> <owner>burunduk@chromium.org</owner> <owner>lazyboy@chromium.org</owner> <owner>extensions-core@chromium.org</owner> @@ -595,7 +595,7 @@ <histogram name="Extensions.DeclarativeNetRequest.EvaluateBeforeRequestTime.SingleExtension2" - units="microseconds" expires_after="2021-06-06"> + units="microseconds" expires_after="2021-08-09"> <owner>karandeepb@chromium.org</owner> <owner>extensions-core@chromium.org</owner> <summary> @@ -608,7 +608,7 @@ <histogram name="Extensions.DeclarativeNetRequest.EvaluateRequestTime.AllExtensions3" - units="microseconds" expires_after="2021-06-06"> + units="microseconds" expires_after="2021-08-09"> <owner>karandeepb@chromium.org</owner> <owner>extensions-core@chromium.org</owner> <summary> @@ -961,7 +961,7 @@ </histogram> <histogram name="Extensions.DisableReason" enum="ExtensionDisableReason" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>rdevlin.cronin@chromium.org</owner> <owner>extensions-core@chromium.org</owner> <summary> @@ -1127,7 +1127,7 @@ </histogram> <histogram name="Extensions.ExtensionAddDisabledRemotelyReason" - enum="ExtensionUpdateCheckDataKey" expires_after="2021-06-06"> + enum="ExtensionUpdateCheckDataKey" expires_after="2021-08-09"> <owner>bdea@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <summary> @@ -1160,7 +1160,7 @@ </histogram> <histogram name="Extensions.ExtensionDisabledRemotely" - enum="ExtensionUpdateCheckDataKey" expires_after="2021-06-06"> + enum="ExtensionUpdateCheckDataKey" expires_after="2021-08-09"> <owner>bdea@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <summary> @@ -1429,7 +1429,7 @@ </histogram> <histogram name="Extensions.ForceInstalledFailureNoUpdatesInfo" - enum="ExtensionNoUpdatesInfo" expires_after="2021-06-06"> + enum="ExtensionNoUpdatesInfo" expires_after="2021-08-09"> <owner>snijhara@google.com</owner> <owner>swapnilgupta@google.com</owner> <owner>burunduk@chromium.org</owner> @@ -1801,7 +1801,7 @@ </histogram> <histogram name="Extensions.Functions.ExtensionServiceWorkerCalls" - enum="ExtensionFunctions" expires_after="2021-04-11"> + enum="ExtensionFunctions" expires_after="2021-08-09"> <owner>lazyboy@chromium.org</owner> <owner>dbertoni@chromium.org</owner> <owner>rdevlin.cronin@chromium.org</owner> @@ -2295,7 +2295,7 @@ </histogram> <histogram name="Extensions.InstallPrompt.Type2" - enum="ExtensionInstallPromptType" expires_after="2021-06-01"> + enum="ExtensionInstallPromptType" expires_after="2021-08-09"> <owner>meacer@chromium.org</owner> <owner>rdevlin.cronin@chromium.org</owner> <summary> @@ -2823,7 +2823,7 @@ </histogram> <histogram name="Extensions.NotAllowlistedEnabled" units="extensions" - expires_after="2021-06-01"> + expires_after="2021-08-09"> <owner>jeffcyr@google.com</owner> <owner>lucferron@chromium.org</owner> <summary> @@ -2859,7 +2859,7 @@ </histogram> <histogram name="Extensions.Permissions_Install3" enum="ExtensionPermission3" - expires_after="2021-05-09"> + expires_after="2021-08-09"> <owner>rdevlin.cronin@chromium.org</owner> <owner>extensions-core@chromium.org</owner> <summary> @@ -3278,7 +3278,7 @@ </histogram> <histogram name="Extensions.StartupPagesOverrides" units="units" - expires_after="2021-06-01"> + expires_after="2021-08-09"> <owner>rdevlin.cronin@chromium.org</owner> <owner>kelvinjiang@chromium.org</owner> <summary> @@ -3659,7 +3659,7 @@ </histogram> <histogram name="Extensions.WebRequestCount" units="extensions" - expires_after="2021-05-09"> + expires_after="2021-08-09"> <owner>karandeepb@chromium.org</owner> <owner>rdevlin.cronin@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/file/histograms.xml b/tools/metrics/histograms/histograms_xml/file/histograms.xml index 0a04f794b..6ea11159 100644 --- a/tools/metrics/histograms/histograms_xml/file/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/file/histograms.xml
@@ -133,14 +133,14 @@ </histogram> <histogram name="FileBrowser.DriveHostedFilePinSuccess" enum="BooleanSuccess" - expires_after="M92"> + expires_after="2021-08-09"> <owner>austinct@chromium.org</owner> <owner>dats@chromium.org</owner> <summary>Tracks success rate of pinning hosted files in Drive.</summary> </histogram> <histogram name="FileBrowser.DrivePinSuccess" enum="BooleanSuccess" - expires_after="M92"> + expires_after="2021-08-09"> <owner>austinct@chromium.org</owner> <owner>dats@chromium.org</owner> <summary>Tracks success rate of pinning files in Drive.</summary> @@ -197,7 +197,7 @@ </histogram> <histogram name="FileBrowser.FormatFileSystemType" - enum="FileManagerFormatFileSystemType" expires_after="2021-05-02"> + enum="FileManagerFormatFileSystemType" expires_after="2021-08-09"> <owner>austinct@chromium.org</owner> <summary> Chrome OS File Browser: this records the filesystem selected when formatting @@ -490,7 +490,7 @@ </histogram> <histogram name="FileBrowser.PhotoEditor.LoadTime" units="ms" - expires_after="M92"> + expires_after="2021-08-09"> <owner>simmonsjosh@google.com</owner> <owner>src/ui/file_manager/OWNERS</owner> <summary>Chrome OS Photo Editor: time to load an image from a file.</summary> @@ -661,7 +661,7 @@ </histogram> <histogram name="FileBrowser.SuggestApps.Install" - enum="SuggestAppsDialogInstall" expires_after="M92"> + enum="SuggestAppsDialogInstall" expires_after="2021-08-09"> <owner>simmonsjosh@google.com</owner> <owner>src/ui/file_manager/OWNERS</owner> <summary> @@ -671,7 +671,7 @@ </histogram> <histogram name="FileBrowser.SuggestApps.Load" enum="SuggestAppsDialogLoad" - expires_after="M92"> + expires_after="2021-08-09"> <owner>simmonsjosh@google.com</owner> <owner>src/ui/file_manager/OWNERS</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/fingerprint/histograms.xml b/tools/metrics/histograms/histograms_xml/fingerprint/histograms.xml index adcb052..2c8b172a 100644 --- a/tools/metrics/histograms/histograms_xml/fingerprint/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/fingerprint/histograms.xml
@@ -48,7 +48,7 @@ </histogram> <histogram name="Fingerprint.Reset.ResetContextMode" - enum="FingerprintSensorMode" expires_after="2021-06-06"> + enum="FingerprintSensorMode" expires_after="2021-08-09"> <owner>tomhughes@chromium.org</owner> <owner>chromeos-fingerprint@google.com</owner> <summary>The mode FPMCU was in when we reset context.</summary>
diff --git a/tools/metrics/histograms/histograms_xml/gcm/histograms.xml b/tools/metrics/histograms/histograms_xml/gcm/histograms.xml index 8bd3813..b165913c 100644 --- a/tools/metrics/histograms/histograms_xml/gcm/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/gcm/histograms.xml
@@ -391,7 +391,7 @@ </histogram> <histogram name="GCM.SendWebPushMessageResult" enum="SendWebPushMessageResult" - expires_after="M92"> + expires_after="2021-08-09"> <owner>knollr@chromium.org</owner> <owner>peter@chromium.org</owner> <summary> @@ -401,7 +401,7 @@ </histogram> <histogram name="GCM.SendWebPushMessageStatusCode" - enum="CombinedHttpResponseAndNetErrorCode" expires_after="M92"> + enum="CombinedHttpResponseAndNetErrorCode" expires_after="2021-08-09"> <owner>knollr@chromium.org</owner> <owner>peter@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/geolocation/histograms.xml b/tools/metrics/histograms/histograms_xml/geolocation/histograms.xml index fe6519c..f00054a 100644 --- a/tools/metrics/histograms/histograms_xml/geolocation/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/geolocation/histograms.xml
@@ -22,7 +22,7 @@ <histograms> <histogram name="Geolocation.AuthorizationActionExistingUser" - enum="GeolocationAuthorizationAction" expires_after="2021-06-06"> + enum="GeolocationAuthorizationAction" expires_after="2021-08-09"> <owner>mattreynolds@chromium.org</owner> <owner>device-dev@chromium.org</owner> <summary> @@ -32,7 +32,7 @@ </histogram> <histogram name="Geolocation.AuthorizationActionNewUser" - enum="GeolocationAuthorizationAction" expires_after="2021-06-06"> + enum="GeolocationAuthorizationAction" expires_after="2021-08-09"> <owner>mattreynolds@chromium.org</owner> <owner>device-dev@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/gpu/histograms.xml b/tools/metrics/histograms/histograms_xml/gpu/histograms.xml index 6f033a0b7..44a238b7 100644 --- a/tools/metrics/histograms/histograms_xml/gpu/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/gpu/histograms.xml
@@ -785,7 +785,7 @@ </histogram> <histogram name="GPU.GPUProcessTerminationStatus2" enum="GpuTerminationStatus" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>vmiura@chromium.org</owner> <summary> Counts for each time the GPU Process Host detects the process dies. @@ -823,7 +823,7 @@ </histogram> <histogram name="GPU.IntelGpuGeneration" enum="IntelGpuGeneration" - expires_after="2021-05-02"> + expires_after="2021-08-09"> <owner>sadrul@chromium.org</owner> <owner>zmo@chromium.org</owner> <summary> @@ -1060,7 +1060,7 @@ </histogram> <histogram name="GPU.Scheduler.RunTaskTime" units="microseconds" - expires_after="2021-05-16"> + expires_after="2021-08-09"> <owner>kylechar@chromium.org</owner> <owner>chrome-gpu-metrics@google.com</owner> <summary> @@ -1090,7 +1090,7 @@ </histogram> <histogram name="GPU.SharedImage.ContentConsumed" enum="BooleanMatched" - expires_after="2021-05-23"> + expires_after="2021-08-09"> <owner>penghuang@chromium.org</owner> <owner>backer@chromium.org</owner> <summary> @@ -1152,7 +1152,7 @@ </histogram> <histogram name="GPU.SwapTimeUs" units="microseconds" - expires_after="2021-05-23"> + expires_after="2021-08-09"> <owner>vasilyt@chromium.org</owner> <owner>backer@chromium.org</owner> <summary> @@ -1172,7 +1172,7 @@ </histogram> <histogram name="GPU.Vulkan.CreateExternalVkSemaphore" units="microseconds" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>backer@chromium.org</owner> <owner>penghuang@chromium.org</owner> <owner>vasilyt@chromium.org</owner> @@ -1194,7 +1194,7 @@ </histogram> <histogram name="GPU.Vulkan.ImportSemaphoreGLPerSwapBuffers" units="units" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>backer@chromium.org</owner> <owner>penghuang@chromium.org</owner> <owner>vasilyt@chromium.org</owner> @@ -1202,7 +1202,7 @@ </histogram> <histogram name="GPU.Vulkan.ImportVkSemaphoreHandle" units="microseconds" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>backer@chromium.org</owner> <owner>penghuang@chromium.org</owner> <owner>vasilyt@chromium.org</owner> @@ -1213,7 +1213,7 @@ </histogram> <histogram name="GPU.Vulkan.ImportVkSemaphoreIntoGL" units="microseconds" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>backer@chromium.org</owner> <owner>penghuang@chromium.org</owner> <owner>vasilyt@chromium.org</owner> @@ -1283,7 +1283,7 @@ </histogram> <histogram name="GPU.Vulkan.QueueSubmitPerSwapBuffers" units="units" - expires_after="2021-04-04"> + expires_after="2021-08-09"> <owner>backer@chromium.org</owner> <owner>penghuang@chromium.org</owner> <owner>vasilyt@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml b/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml index 219625f..ca07314b 100644 --- a/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml +++ b/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
@@ -6512,6 +6512,7 @@ <histogram_suffixes name="FeedNetworkRequestType" separator="."> <suffix name="FeedQuery" label="Requests to fetch new feed content"/> + <suffix name="NextPage" label="Requests to fetch the next page of the feed"/> <suffix name="UploadActions" label="Requests to upload user action data"/> <affected-histogram name="ContentSuggestions.Feed.Network.ResponseStatus"/> </histogram_suffixes> @@ -18241,7 +18242,11 @@ <affected-histogram name="Startup.BrowserMessageLoopStartTimeFromMainEntry3"/> <affected-histogram name="Startup.BrowserOpenTabs"/> <affected-histogram name="Startup.BrowserWindow.FirstPaint"/> - <affected-histogram name="Startup.BrowserWindow.FirstPaint.CompositingEnded"/> + <affected-histogram name="Startup.BrowserWindow.FirstPaint.CompositingEnded"> + <obsolete> + Obsolete as of Feb 2021. + </obsolete> + </affected-histogram> <affected-histogram name="Startup.BrowserWindowDisplay"/> <affected-histogram name="Startup.FirstWebContents.MainFrameLoad"/> <affected-histogram name="Startup.FirstWebContents.MainFrameLoad2"/>
diff --git a/tools/metrics/histograms/histograms_xml/history/histograms.xml b/tools/metrics/histograms/histograms_xml/history/histograms.xml index 8f75e4f..9f8713e 100644 --- a/tools/metrics/histograms/histograms_xml/history/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/history/histograms.xml
@@ -487,7 +487,7 @@ </histogram> <histogram name="History.DomainCountQueryTime" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>mpearson@chromium.org</owner> <owner>mjzhang@chromium.org</owner> <owner>chrome-analysis-team@google.com</owner> @@ -690,7 +690,7 @@ </histogram> <histogram name="History.MonthlyHostCount" units="hosts" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>mpearson@chromium.org</owner> <owner>sky@chromium.org</owner> <summary> @@ -857,7 +857,7 @@ </histogram> <histogram name="History.WeeklyHostCount" units="units" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>mpearson@chromium.org</owner> <owner>sky@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/image/histograms.xml b/tools/metrics/histograms/histograms_xml/image/histograms.xml index c96f2dfe..7a451cacda 100644 --- a/tools/metrics/histograms/histograms_xml/image/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/image/histograms.xml
@@ -42,7 +42,7 @@ </histogram> <histogram name="ImageAnnotationService.AccessibilityV1.ClientResult" - enum="ImageAnnotationServiceClientResult" expires_after="2021-05-30"> + enum="ImageAnnotationServiceClientResult" expires_after="2021-08-09"> <owner>dmazzoni@chromium.org</owner> <owner>amoylan@chromium.org</owner> <owner>martis@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/input/histograms.xml b/tools/metrics/histograms/histograms_xml/input/histograms.xml index 923320ca..eaf2d38 100644 --- a/tools/metrics/histograms/histograms_xml/input/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/input/histograms.xml
@@ -230,14 +230,14 @@ </histogram> <histogram name="InputMethod.AutoCorrectLevel" enum="IMECorrectionLevel" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>shend@chromium.org</owner> <owner>essential-inputs-team@google.com</owner> <summary>The auto-correction level for suggestion engine.</summary> </histogram> <histogram name="InputMethod.Category" enum="InputMethodCategory" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>shend@chromium.org</owner> <owner>essential-inputs-team@google.com</owner> <summary> @@ -247,7 +247,7 @@ </histogram> <histogram name="InputMethod.Commit.Index" units="units" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>shend@chromium.org</owner> <owner>essential-inputs-team@google.com</owner> <summary> @@ -337,7 +337,7 @@ </histogram> <histogram name="InputMethod.Handwriting.CharsEdited5s" units="chars" - expires_after="2021-05-02"> + expires_after="2021-08-09"> <owner>shend@chromium.org</owner> <owner>essential-inputs-team@google.com</owner> <summary> @@ -401,7 +401,7 @@ </histogram> <histogram name="InputMethod.KeyEventLatency" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>shend@chromium.org</owner> <owner>essential-inputs-team@google.com</owner> <summary>Time taken by the engine to handle a key event.</summary> @@ -521,7 +521,7 @@ </histogram> <histogram name="InputMethod.PkCommit.Index" units="units" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>shend@chromium.org</owner> <owner>essential-inputs-team@google.com</owner> <summary> @@ -649,7 +649,7 @@ </histogram> <histogram name="InputMethod.VirtualKeyboard.ErrorType" - enum="VirtualKeyboardErrorTypeHashes" expires_after="2021-06-06"> + enum="VirtualKeyboardErrorTypeHashes" expires_after="2021-08-09"> <owner>shend@chromium.org</owner> <owner>essential-inputs-team@google.com</owner> <summary>Errors from the virtual keyboard extension</summary>
diff --git a/tools/metrics/histograms/histograms_xml/interstitial/histograms.xml b/tools/metrics/histograms/histograms_xml/interstitial/histograms.xml index cc1f4ba..00162b17 100644 --- a/tools/metrics/histograms/histograms_xml/interstitial/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/interstitial/histograms.xml
@@ -263,7 +263,7 @@ </histogram> <histogram name="TypedNavigationUpgradeThrottle.Event" - enum="TypedNavigationUpgradeThrottleEvent" expires_after="M92"> + enum="TypedNavigationUpgradeThrottleEvent" expires_after="2021-08-09"> <owner>meacer@chromium.org</owner> <owner>security-enamel@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/ios/histograms.xml b/tools/metrics/histograms/histograms_xml/ios/histograms.xml index a8a21ea..a2fbbfa 100644 --- a/tools/metrics/histograms/histograms_xml/ios/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/ios/histograms.xml
@@ -882,7 +882,7 @@ </histogram> <histogram name="IOS.Spotlight.Origin" enum="IOSSpotlightOrigin" - expires_after="2021-05-02"> + expires_after="2021-08-09"> <owner>olivierrobin@chromium.org</owner> <owner>rohitrao@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/login/histograms.xml b/tools/metrics/histograms/histograms_xml/login/histograms.xml index 81efc4d..ccb3597f 100644 --- a/tools/metrics/histograms/histograms_xml/login/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/login/histograms.xml
@@ -42,7 +42,7 @@ </histogram> <histogram name="Login.BrowserShutdownTime" units="ms" - expires_after="2021-05-16"> + expires_after="2021-08-09"> <owner>xiyuan@chromium.org</owner> <summary> Tracks the browser process shutdown time from when SIGTERM is sent to the @@ -92,7 +92,7 @@ </histogram> <histogram name="Login.MountNamespaceCreationSuccess" enum="Boolean" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>betuls@chromium.org</owner> <owner>jorgelo@chromium.org</owner> <owner>chromeos-security-core@google.com</owner> @@ -158,7 +158,7 @@ </histogram> <histogram name="Login.PasswordChangeFlow" enum="LoginPasswordChangeFlow" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>xiyuan@chromium.org</owner> <owner>omrilio@chromium.org</owner> <summary> @@ -238,7 +238,7 @@ </histogram> <histogram name="Login.TokenCheckResponseTime" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>rsorokin@chromium.org</owner> <owner>cros-oac@google.com</owner> <summary> @@ -280,7 +280,7 @@ </histogram> <histogram name="Login.UsersActiveWeekly" units="users" - expires_after="2021-04-04"> + expires_after="2021-08-09"> <owner>alemate@chromium.org</owner> <owner>achuith@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/media/histograms.xml b/tools/metrics/histograms/histograms_xml/media/histograms.xml index 1403f90..1db38861 100644 --- a/tools/metrics/histograms/histograms_xml/media/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/media/histograms.xml
@@ -296,7 +296,7 @@ </histogram> <histogram name="Media.Audio.Capture.StreamCallbackError2" - enum="AudioCaptureDeviceError" expires_after="2021-04-25"> + enum="AudioCaptureDeviceError" expires_after="2021-08-09"> <owner>guidou@chromium.org</owner> <owner>olka@chromium.org</owner> <summary> @@ -493,7 +493,7 @@ </histogram> <histogram name="Media.Audio.Processing.TotalDelayMs" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>armax@chromium.org</owner> <owner>guidou@chromium.org</owner> <summary> @@ -677,7 +677,7 @@ </histogram> <histogram name="Media.Audio.Render.SinkCache.UsedForSinkCreation" - enum="BooleanUsage" expires_after="2021-04-05"> + enum="BooleanUsage" expires_after="2021-08-09"> <owner>guidou@chromium.org</owner> <owner>olka@chromium.org</owner> <summary> @@ -865,7 +865,7 @@ </histogram> <histogram name="Media.AudioOutputController.CallbackError" enum="BooleanError" - expires_after="2021-04-05"> + expires_after="2021-08-09"> <owner>guidou@chromium.org</owner> <owner>olka@chromium.org</owner> <summary> @@ -938,7 +938,7 @@ <histogram name="Media.AudioOutputResampler.OpenLowLatencyStream" enum="AudioOutputResamplerLowLatencyOpenStreamResult" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>armax@chromium.org</owner> <owner>guidou@chromium.org</owner> <owner>olka@chromium.org</owner> @@ -1041,7 +1041,7 @@ </histogram> <histogram name="Media.AudioRendererImpl.SinkStatus" enum="OutputDeviceStatus" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>armax@chromium.org</owner> <owner>dalecurtis@chromium.org</owner> <owner>guidou@chromium.org</owner> @@ -1148,7 +1148,7 @@ </histogram> <histogram name="Media.Capabilities.DecodingInfo.Time.Video.Clear" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>chcunningham@chromium.org</owner> <owner>mlamouri@google.com</owner> <owner>media-dev@chromium.org</owner> @@ -1606,7 +1606,7 @@ </histogram> <histogram name="Media.EME.EncryptedMediaEnabled" enum="BooleanEnabled" - expires_after="2021-05-07"> + expires_after="2021-08-09"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -1907,7 +1907,7 @@ </histogram> <histogram name="Media.Feeds.AggregateWatchtime" units="ms" - expires_after="2021-06-07"> + expires_after="2021-08-09"> <owner>beccahughes@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -1918,7 +1918,7 @@ </histogram> <histogram name="Media.Feeds.Feed.ReadResult" enum="MediaFeedReadResult" - expires_after="2021-05-09"> + expires_after="2021-08-09"> <owner>beccahughes@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2133,7 +2133,7 @@ </histogram> <histogram name="Media.History.DatabaseSize" units="KB" - expires_after="2021-05-09"> + expires_after="2021-08-09"> <owner>beccahughes@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2142,7 +2142,7 @@ </histogram> <histogram name="Media.History.Init.Result" enum="MediaHistoryInitResult" - expires_after="2021-05-09"> + expires_after="2021-08-09"> <owner>beccahughes@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2153,7 +2153,7 @@ </histogram> <histogram name="Media.History.Init.ResultAfterDelete" - enum="MediaHistoryInitResult" expires_after="2021-05-09"> + enum="MediaHistoryInitResult" expires_after="2021-08-09"> <owner>beccahughes@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2943,7 +2943,7 @@ </histogram> <histogram name="Media.PipelineStatus.Start" enum="PipelineStatus" - expires_after="2021-05-07"> + expires_after="2021-08-09"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -3186,7 +3186,7 @@ </histogram> <histogram name="Media.RtcLowLatencyVideoRenderer.AverageQueueLengthX10" - units="frames" expires_after="2021-05-31"> + units="frames" expires_after="2021-08-09"> <owner>kron@chromium.org</owner> <owner>webrtc-video@google.com</owner> <summary> @@ -3197,7 +3197,7 @@ </histogram> <histogram name="Media.RtcLowLatencyVideoRenderer.DrainedFramesPermille" - units="permille" expires_after="2021-05-31"> + units="permille" expires_after="2021-08-09"> <owner>kron@chromium.org</owner> <owner>webrtc-video@google.com</owner> <summary> @@ -3208,7 +3208,7 @@ </histogram> <histogram name="Media.RtcLowLatencyVideoRenderer.DroppedFramesPermille" - units="permille" expires_after="2021-05-31"> + units="permille" expires_after="2021-08-09"> <owner>kron@chromium.org</owner> <owner>webrtc-video@google.com</owner> <summary> @@ -3219,7 +3219,7 @@ </histogram> <histogram name="Media.RtcLowLatencyVideoRenderer.EnterDrainModeCount" - units="count" expires_after="2021-05-31"> + units="count" expires_after="2021-08-09"> <owner>kron@chromium.org</owner> <owner>webrtc-video@google.com</owner> <summary> @@ -3240,7 +3240,7 @@ </histogram> <histogram name="Media.RtcLowLatencyVideoRenderer.NoNewFrameToRenderPermille" - units="permille" expires_after="2021-05-31"> + units="permille" expires_after="2021-08-09"> <owner>kron@chromium.org</owner> <owner>webrtc-video@google.com</owner> <summary> @@ -3251,7 +3251,7 @@ </histogram> <histogram name="Media.RtcLowLatencyVideoRenderer.ReduceSteadyStateCount" - units="count" expires_after="2021-05-31"> + units="count" expires_after="2021-08-09"> <owner>kron@chromium.org</owner> <owner>webrtc-video@google.com</owner> <summary> @@ -3262,7 +3262,7 @@ </histogram> <histogram name="Media.RtcLowLatencyVideoRenderer.TotalFrames" units="frames" - expires_after="2021-05-31"> + expires_after="2021-08-09"> <owner>kron@chromium.org</owner> <owner>webrtc-video@google.com</owner> <summary> @@ -3273,7 +3273,7 @@ </histogram> <histogram name="Media.RtcLowLatencyVideoRenderer.TryToRenderFrameCount" - units="count" expires_after="2021-05-31"> + units="count" expires_after="2021-08-09"> <owner>kron@chromium.org</owner> <owner>webrtc-video@google.com</owner> <summary> @@ -3845,7 +3845,7 @@ </histogram> <histogram name="Media.VideoCapture.DelayUntilFirstFrame" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>guidou@chromium.org</owner> <owner>armax@chromium.org</owner> <summary> @@ -3856,7 +3856,7 @@ </histogram> <histogram name="Media.VideoCapture.Device.SupportedPixelFormat" - enum="VideoPixelFormatUnion" expires_after="M92"> + enum="VideoPixelFormatUnion" expires_after="2021-08-09"> <owner>eshr@google.com</owner> <owner>handellm@google.com</owner> <summary> @@ -3868,7 +3868,7 @@ </histogram> <histogram name="Media.VideoCapture.Device.SupportedResolution" - enum="VideoResolutionDesignation" expires_after="M92"> + enum="VideoResolutionDesignation" expires_after="2021-08-09"> <owner>eshr@google.com</owner> <owner>handellm@google.com</owner> <summary> @@ -3934,7 +3934,7 @@ </histogram> <histogram name="Media.VideoCapture.Mac.Device.CapturedIOSurface" - enum="Boolean" expires_after="M92"> + enum="Boolean" expires_after="2021-08-09"> <owner>eshr@google.com</owner> <owner>handellm@google.com</owner> <summary> @@ -3946,7 +3946,7 @@ <histogram name="Media.VideoCapture.Mac.Device.CapturedWithRequestedPixelFormat" - enum="Boolean" expires_after="M92"> + enum="Boolean" expires_after="2021-08-09"> <owner>eshr@google.com</owner> <owner>handellm@google.com</owner> <summary> @@ -3957,7 +3957,7 @@ </histogram> <histogram name="Media.VideoCapture.Mac.Device.CapturedWithRequestedResolution" - enum="ResolutionComparison" expires_after="M92"> + enum="ResolutionComparison" expires_after="2021-08-09"> <owner>eshr@google.com</owner> <owner>handellm@google.com</owner> <summary> @@ -3969,7 +3969,7 @@ </histogram> <histogram name="Media.VideoCapture.Mac.Device.RequestedPixelFormat" - enum="VideoPixelFormatUnion" expires_after="M92"> + enum="VideoPixelFormatUnion" expires_after="2021-08-09"> <owner>eshr@google.com</owner> <owner>handellm@google.com</owner> <summary> @@ -4683,7 +4683,7 @@ </histogram> <histogram name="MediaRouter.Cast.LaunchSessionResponse.AppType" - enum="MediaRouterResponseReceiverAppType" expires_after="2021-06-08"> + enum="MediaRouterResponseReceiverAppType" expires_after="2021-08-09"> <owner>muyaoxu@google.com</owner> <owner>openscreen-eng@google.com</owner> <summary> @@ -4775,7 +4775,7 @@ </histogram> <histogram name="MediaRouter.CastStreaming.Start.Failure" - enum="MirrorFailureType" expires_after="2021-06-06"> + enum="MirrorFailureType" expires_after="2021-08-09"> <owner>takumif@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/memory/histograms.xml b/tools/metrics/histograms/histograms_xml/memory/histograms.xml index 87db055..7c5677ab 100644 --- a/tools/metrics/histograms/histograms_xml/memory/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/memory/histograms.xml
@@ -1038,7 +1038,7 @@ <histogram name="Memory.Experimental.Renderer.PeakResidentSet.AtHighestPrivateMemoryFootprint" - units="MB" expires_after="2021-06-06"> + units="MB" expires_after="2021-08-09"> <owner>tasak@google.com</owner> <owner>bartekn@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/mobile/histograms.xml b/tools/metrics/histograms/histograms_xml/mobile/histograms.xml index f16e046..33e840e0 100644 --- a/tools/metrics/histograms/histograms_xml/mobile/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/mobile/histograms.xml
@@ -173,7 +173,7 @@ </histogram> <histogram base="true" name="Mobile.Messages.Badge.Tapped" - enum="MobileMessagesBadgeState" expires_after="2021-05-23"> + enum="MobileMessagesBadgeState" expires_after="2021-08-09"> <!-- Name completed by histogram_suffixes name="Mobile.Messages.Type" --> <owner>sczs@chromium.org</owner> @@ -182,7 +182,7 @@ </histogram> <histogram base="true" name="Mobile.Messages.Banner.Dismiss" - enum="MobileMessagesBannerDismissType" expires_after="2021-05-23"> + enum="MobileMessagesBannerDismissType" expires_after="2021-08-09"> <!-- Name completed by histogram_suffixes name="Mobile.Messages.Type" --> <owner>sczs@chromium.org</owner> @@ -590,7 +590,7 @@ </histogram> <histogram name="MobileDownload.Location.Dialog.Result" - enum="DownloadLocationDialogResult" expires_after="2021-06-06"> + enum="DownloadLocationDialogResult" expires_after="2021-08-09"> <owner>xingliu@chromium.org</owner> <owner>clank-downloads@google.com</owner> <summary> @@ -624,7 +624,7 @@ </histogram> <histogram name="MobileDownload.Location.DirectoryType" - enum="DownloadLocationDirectoryType" expires_after="2021-05-02"> + enum="DownloadLocationDirectoryType" expires_after="2021-08-09"> <owner>xingliu@chromium.org</owner> <owner>dtrainor@chromium.org</owner> <owner>qinmin@chromium.org</owner> @@ -636,14 +636,14 @@ </histogram> <histogram name="MobileDownload.Location.Download.DirectoryType" - enum="DownloadLocationDirectoryType" expires_after="2021-05-02"> + enum="DownloadLocationDirectoryType" expires_after="2021-08-09"> <owner>xingliu@chromium.org</owner> <owner>clank-downloads@google.com</owner> <summary>Records the directory type when download is completed.</summary> </histogram> <histogram name="MobileDownload.Location.Setting.DirectoryType" - enum="DownloadLocationDirectoryType" expires_after="2021-05-02"> + enum="DownloadLocationDirectoryType" expires_after="2021-08-09"> <owner>xingliu@chromium.org</owner> <owner>clank-downloads@google.com</owner> <summary> @@ -1045,7 +1045,7 @@ </histogram> <histogram name="MobileSignInPromo.BookmarkManager.ImpressionsTilXButton" - units="impressions" expires_after="2021-04-20"> + units="impressions" expires_after="2021-08-09"> <owner>jlebel@chromium.org</owner> <owner>chrome-signin-team@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/multi_device/histograms.xml b/tools/metrics/histograms/histograms_xml/multi_device/histograms.xml index 9eb1aa0..6c3c5ee3 100644 --- a/tools/metrics/histograms/histograms_xml/multi_device/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/multi_device/histograms.xml
@@ -42,7 +42,7 @@ <histogram name="MultiDevice.DeviceSyncService.FindEligibleDevices.Result.FailureReason" enum="MultiDevice_DeviceSyncService_DeviceSyncRequestFailureReason" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>vecore@google.com</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -61,7 +61,7 @@ <histogram name="MultiDevice.DeviceSyncService.ForceSyncNow.Result" enum="MultiDevice_DeviceSyncService_ForceCryptAuthOperationResult" - expires_after="2021-04-04"> + expires_after="2021-08-09"> <owner>vecore@google.com</owner> <owner>better-together-dev@google.com</owner> <summary>Result for when ForceSyncNow is called.</summary> @@ -69,7 +69,7 @@ <histogram name="MultiDevice.DeviceSyncService.SetSoftwareFeatureState.Disable.FailedFeature" - enum="MultiDevice_DeviceSyncService_Features" expires_after="2021-04-04"> + enum="MultiDevice_DeviceSyncService_Features" expires_after="2021-08-09"> <owner>vecore@google.com</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -79,7 +79,7 @@ <histogram name="MultiDevice.DeviceSyncService.SetSoftwareFeatureState.Enable.FailedFeature" - enum="MultiDevice_DeviceSyncService_Features" expires_after="2021-04-04"> + enum="MultiDevice_DeviceSyncService_Features" expires_after="2021-08-09"> <owner>vecore@google.com</owner> <owner>better-together-dev@google.com</owner> <summary>Breaks down which features failed when attempted to enable.</summary> @@ -95,7 +95,7 @@ <histogram name="MultiDevice.DeviceSyncService.SetSoftwareFeatureState.Result.FailureReason" enum="MultiDevice_DeviceSyncService_DeviceSyncRequestFailureReason" - expires_after="2021-04-04"> + expires_after="2021-08-09"> <owner>vecore@google.com</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -106,7 +106,7 @@ <histogram name="MultiDevice.ForgetHostConfirmed" enum="MultiDevice_VerifyAndForgetHostConfirmationState" - expires_after="2021-04-04"> + expires_after="2021-08-09"> <owner>vecore@google.com</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -115,7 +115,7 @@ </histogram> <histogram name="MultiDevice.PostOOBESetupFlow.PageShown" - enum="MultiDevice_PostOOBESetupFlow_Page" expires_after="2021-06-06"> + enum="MultiDevice_PostOOBESetupFlow_Page" expires_after="2021-08-09"> <owner>vecore@google.com</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -132,7 +132,7 @@ <histogram name="MultiDevice.SecureChannel.BLE.GattConnectionToAuthentication.EffectiveSuccessRateWithRetries" - enum="BooleanSuccess" expires_after="2021-04-04"> + enum="BooleanSuccess" expires_after="2021-08-09"> <owner>vecore@google.com</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -161,7 +161,7 @@ <histogram name="MultiDevice.SecureChannel.BLE.Performance.ReceiveAdvertisementToConnectionDuration.Background" - units="ms" expires_after="2021-06-06"> + units="ms" expires_after="2021-08-09"> <owner>vecore@google.com</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -194,7 +194,7 @@ <histogram name="MultiDevice.SecureChannel.BLE.Performance.StartScanToConnectionDuration.Background" - units="ms" expires_after="2021-04-04"> + units="ms" expires_after="2021-08-09"> <owner>vecore@google.com</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -238,7 +238,7 @@ <histogram name="MultiDevice.SecureChannel.BLE.ReceiveAdvertisementToGattConnection.EffectiveSuccessRateWithRetries" - enum="BooleanSuccess" expires_after="2021-04-04"> + enum="BooleanSuccess" expires_after="2021-08-09"> <owner>vecore@google.com</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -386,7 +386,7 @@ </histogram> <histogram name="MultiDevice.Setup.HostVerifier.DoesHostHaveCryptoData" - enum="Boolean" expires_after="2021-06-06"> + enum="Boolean" expires_after="2021-08-09"> <owner>nohle@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -401,7 +401,7 @@ <histogram name="MultiDevice.VerifyButtonClicked" enum="MultiDevice_VerifyAndForgetHostConfirmationState" - expires_after="2021-04-04"> + expires_after="2021-08-09"> <owner>vecore@google.com</owner> <owner>better-together-dev@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/navigation/histograms.xml b/tools/metrics/histograms/histograms_xml/navigation/histograms.xml index 7404937e..14f8ebe 100644 --- a/tools/metrics/histograms/histograms_xml/navigation/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/navigation/histograms.xml
@@ -422,7 +422,7 @@ <histogram name="BackForwardCache.UnexpectedRendererToBrowserMessage.InterfaceName" - enum="MojoInterfaceName" expires_after="2021-05-09"> + enum="MojoInterfaceName" expires_after="2021-08-09"> <owner>carlscab@google.com</owner> <owner>bfcache-dev@chromium.org</owner> <summary> @@ -717,7 +717,7 @@ </histogram> <histogram name="Navigation.IsSameBrowsingInstance" - enum="NavigationIsSameBrowsingInstance" expires_after="2021-05-09"> + enum="NavigationIsSameBrowsingInstance" expires_after="2021-08-09"> <owner>arthursonzogni@chromium.org</owner> <owner>clamy@chromium.org</owner> <owner>nasko@chromium.org</owner> @@ -783,7 +783,7 @@ </histogram> <histogram name="Navigation.MainFrame.SiteEngagementLevel" - enum="SiteEngagementLevel" expires_after="2021-06-06"> + enum="SiteEngagementLevel" expires_after="2021-08-09"> <owner>meacer@chromium.org</owner> <owner>security-enamel@chromium.org</owner> <summary> @@ -813,7 +813,7 @@ </histogram> <histogram name="Navigation.MainFrameHasRTLDomainDifferentPage2" enum="Boolean" - expires_after="M92"> + expires_after="2021-08-09"> <owner>cthomp@chromium.org</owner> <owner>security-enamel@chromium.org</owner> <summary> @@ -858,7 +858,7 @@ </histogram> <histogram name="Navigation.MainFrameSchemeDifferentPageOTR2" - enum="NavigationScheme" expires_after="2021-06-01"> + enum="NavigationScheme" expires_after="2021-08-09"> <owner>elawrence@chromium.org</owner> <owner>estark@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/net/histograms.xml b/tools/metrics/histograms/histograms_xml/net/histograms.xml index 603f931..a425fe7 100644 --- a/tools/metrics/histograms/histograms_xml/net/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/net/histograms.xml
@@ -51,7 +51,7 @@ </histogram> <histogram name="Net.AlternateServiceFailed" enum="NetErrorCodes" - expires_after="2021-05-11"> + expires_after="2021-08-09"> <owner>tbansal@chromium.org</owner> <owner>dschinazi@chromium.org</owner> <owner>src/net/OWNERS</owner> @@ -299,7 +299,7 @@ </histogram> <histogram base="true" name="Net.CertVerifier.NameNormalizationPrivateRoots" - enum="NetCertificateNameNormalization" expires_after="2021-04-26"> + enum="NetCertificateNameNormalization" expires_after="2021-08-09"> <owner>mattm@chromium.org</owner> <owner>rsleevi@chromium.org</owner> <summary> @@ -374,7 +374,7 @@ </histogram> <histogram name="Net.ConnectionInfo.SubResource" enum="ConnectionInfo" - expires_after="2021-05-11"> + expires_after="2021-08-09"> <owner>dschinazi@chromium.org</owner> <owner>src/net/OWNERS</owner> <summary> @@ -445,7 +445,7 @@ </histogram> <histogram name="Net.CountOfBrokenAlternativeServices" units="services" - expires_after="2021-05-11"> + expires_after="2021-08-09"> <owner>dschinazi@chromium.org</owner> <owner>src/net/OWNERS</owner> <summary> @@ -469,7 +469,7 @@ </histogram> <histogram name="Net.CountOfRecentlyBrokenAlternativeServices" units="services" - expires_after="2021-05-11"> + expires_after="2021-08-09"> <owner>dschinazi@chromium.org</owner> <owner>src/net/OWNERS</owner> <summary> @@ -590,7 +590,7 @@ </histogram> <histogram name="Net.DNS.DnsTask.SuccessTime" units="ms" - expires_after="2021-06-04"> + expires_after="2021-08-09"> <owner>ericorth@chromium.org</owner> <owner>src/net/OWNERS</owner> <summary> @@ -1205,7 +1205,7 @@ </histogram> <histogram name="Net.DNS.SecureDnsMode.Off.ResolveTime" units="ms" - expires_after="2021-05-09"> + expires_after="2021-08-09"> <owner>ericorth@chromium.org</owner> <owner>doh-core@google.com</owner> <summary> @@ -1240,7 +1240,7 @@ </histogram> <histogram name="Net.DNS.SecureDnsTask.DnsModeSecure.FailureTime" units="ms" - expires_after="2021-05-02"> + expires_after="2021-08-09"> <owner>ericorth@chromium.org</owner> <owner>doh-core@google.com</owner> <summary> @@ -1290,7 +1290,7 @@ </histogram> <histogram name="Net.DNS.UI.ProbeAttemptSuccess" enum="Boolean" - expires_after="2021-05-02"> + expires_after="2021-08-09"> <owner>ericorth@chromium.org</owner> <owner>doh-core@google.com</owner> <summary> @@ -1300,7 +1300,7 @@ </histogram> <histogram name="Net.DNS.UI.ValidationAttemptSuccess" enum="Boolean" - expires_after="2021-05-02"> + expires_after="2021-08-09"> <owner>ericorth@chromium.org</owner> <owner>doh-core@google.com</owner> <summary> @@ -1585,7 +1585,7 @@ </histogram> <histogram name="Net.HttpAuthCount" enum="HttpAuthCount" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>asanka@chromium.org</owner> <owner>mmenke@chromium.org</owner> <summary> @@ -1614,7 +1614,7 @@ </histogram> <histogram name="Net.HttpAuthTarget" enum="HttpAuthTarget" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>asanka@chromium.org</owner> <owner>mmenke@chromium.org</owner> <summary> @@ -2418,7 +2418,7 @@ </histogram> <histogram name="Net.QuicSession.AbortedPendingStreamRequests" - units="stream requests" expires_after="2021-05-11"> + units="stream requests" expires_after="2021-08-09"> <owner>dschinazi@chromium.org</owner> <owner>src/net/quic/OWNERS</owner> <summary> @@ -2469,7 +2469,7 @@ </histogram> <histogram name="Net.QuicSession.CertVerificationResult" enum="NetErrorCodes" - expires_after="2021-05-11"> + expires_after="2021-08-09"> <owner>dschinazi@chromium.org</owner> <owner>src/net/quic/OWNERS</owner> <summary> @@ -2540,7 +2540,7 @@ </histogram> <histogram name="Net.QuicSession.ClosedDuringInitializeSession" enum="Boolean" - expires_after="2021-05-11"> + expires_after="2021-08-09"> <owner>dschinazi@chromium.org</owner> <owner>src/net/quic/OWNERS</owner> <summary> @@ -2715,7 +2715,7 @@ <histogram name="Net.QuicSession.ConnectionCloseErrorCodeServerIetfApplicationGQuicErrorMissing" - enum="QuicHttp3ErrorCodes" expires_after="2021-05-11"> + enum="QuicHttp3ErrorCodes" expires_after="2021-08-09"> <owner>dschinazi@chromium.org</owner> <owner>src/net/quic/OWNERS</owner> <summary> @@ -2758,7 +2758,7 @@ <histogram name="Net.QuicSession.ConnectionCloseErrorCodeServerIetfTransportGQuicErrorMissing" - enum="QuicTransportErrorCodes" expires_after="2021-05-11"> + enum="QuicTransportErrorCodes" expires_after="2021-08-09"> <owner>dschinazi@chromium.org</owner> <owner>src/net/quic/OWNERS</owner> <summary> @@ -2796,7 +2796,7 @@ </histogram> <histogram name="Net.QuicSession.ConnectionFlowControlBlocked" - enum="BooleanBlocked" expires_after="2021-05-11"> + enum="BooleanBlocked" expires_after="2021-08-09"> <owner>dschinazi@chromium.org</owner> <owner>src/net/quic/OWNERS</owner> <summary> @@ -2929,7 +2929,7 @@ </histogram> <histogram name="Net.QuicSession.EncryptionEstablishedTime" - units="Milliseconds" expires_after="2021-05-11"> + units="Milliseconds" expires_after="2021-08-09"> <owner>fayang@chromium.org</owner> <owner>src/net/quic/OWNERS</owner> <summary> @@ -3042,7 +3042,7 @@ </histogram> <histogram name="Net.QuicSession.HeaderCompressionRatioHpackReceived" units="%" - expires_after="2021-05-11"> + expires_after="2021-08-09"> <owner>dschinazi@chromium.org</owner> <owner>src/net/quic/OWNERS</owner> <summary> @@ -3051,7 +3051,7 @@ </histogram> <histogram name="Net.QuicSession.HeaderCompressionRatioHpackSent" units="%" - expires_after="2021-05-11"> + expires_after="2021-08-09"> <owner>dschinazi@chromium.org</owner> <owner>src/net/quic/OWNERS</owner> <summary> @@ -3060,7 +3060,7 @@ </histogram> <histogram name="Net.QuicSession.HeaderCompressionRatioQpackReceived" units="%" - expires_after="2021-05-11"> + expires_after="2021-08-09"> <owner>dschinazi@chromium.org</owner> <owner>src/net/quic/OWNERS</owner> <summary> @@ -3182,7 +3182,7 @@ <histogram name="Net.QuicSession.LastInFlightPacketSentTimeFromHandshakeCompletionWithPublicReset" - units="ms" expires_after="2021-05-11"> + units="ms" expires_after="2021-08-09"> <owner>fayang@chromium.org</owner> <owner>src/net/quic/OWNERS</owner> <summary> @@ -3192,7 +3192,7 @@ </histogram> <histogram name="Net.QuicSession.LastSentPacketContentBeforePublicReset" - units="bitfield value" expires_after="2021-05-11"> + units="bitfield value" expires_after="2021-08-09"> <owner>fayang@chromium.org</owner> <owner>src/net/quic/OWNERS</owner> <summary> @@ -3222,7 +3222,7 @@ </histogram> <histogram name="Net.QuicSession.MaxReordering" units="units" - expires_after="2021-05-11"> + expires_after="2021-08-09"> <owner>dschinazi@chromium.org</owner> <owner>src/net/quic/OWNERS</owner> <summary> @@ -3325,7 +3325,7 @@ </histogram> <histogram name="Net.QuicSession.NumPingsSent" units="pings" - expires_after="2021-05-11"> + expires_after="2021-08-09"> <owner>renjietang@chromium.org</owner> <owner>src/net/quic/OWNERS</owner> <summary> @@ -3344,7 +3344,7 @@ </histogram> <histogram name="Net.QuicSession.NumTotalStreams" units="units" - expires_after="2021-05-11"> + expires_after="2021-08-09"> <owner>dschinazi@chromium.org</owner> <owner>src/net/quic/OWNERS</owner> <summary> @@ -3458,7 +3458,7 @@ </histogram> <histogram name="Net.QuicSession.PendingStreamsWaitTime" units="ms" - expires_after="2021-05-11"> + expires_after="2021-08-09"> <owner>dschinazi@chromium.org</owner> <owner>src/net/quic/OWNERS</owner> <summary> @@ -3632,7 +3632,7 @@ </histogram> <histogram name="Net.QuicSession.ReceivedSettings.BlockedStreams" units="units" - expires_after="2021-05-11"> + expires_after="2021-08-09"> <owner>dschinazi@chromium.org</owner> <owner>src/net/quic/OWNERS</owner> <summary> @@ -3642,7 +3642,7 @@ </histogram> <histogram name="Net.QuicSession.ReceivedSettings.CountPlusOne" units="units" - expires_after="2021-05-11"> + expires_after="2021-08-09"> <owner>dschinazi@chromium.org</owner> <owner>src/net/quic/OWNERS</owner> <summary> @@ -3652,7 +3652,7 @@ </histogram> <histogram name="Net.QuicSession.ReceivedSettings.MaxHeaderListSize2" - units="bytes" expires_after="2021-05-11"> + units="bytes" expires_after="2021-08-09"> <owner>dschinazi@chromium.org</owner> <owner>src/net/quic/OWNERS</owner> <summary> @@ -3662,7 +3662,7 @@ </histogram> <histogram name="Net.QuicSession.ReceivedSettings.MaxTableCapacity2" - units="bytes" expires_after="2021-05-11"> + units="bytes" expires_after="2021-08-09"> <owner>dschinazi@chromium.org</owner> <owner>src/net/quic/OWNERS</owner> <summary> @@ -3672,7 +3672,7 @@ </histogram> <histogram name="Net.QuicSession.ReceivedSettings.ReservedCountPlusOne" - units="units" expires_after="2021-05-11"> + units="units" expires_after="2021-08-09"> <owner>dschinazi@chromium.org</owner> <owner>src/net/quic/OWNERS</owner> <summary> @@ -3726,7 +3726,7 @@ </histogram> <histogram name="Net.QuicSession.RstStreamErrorCodeServer" - enum="QuicRstStreamErrorCodes" expires_after="2021-05-11"> + enum="QuicRstStreamErrorCodes" expires_after="2021-08-09"> <owner>dschinazi@chromium.org</owner> <owner>src/net/quic/OWNERS</owner> <summary> @@ -3757,7 +3757,7 @@ </histogram> <histogram name="Net.QuicSession.SendPacketSize" units="bytes" - expires_after="2021-05-11"> + expires_after="2021-08-09"> <owner>zhongyi@chromium.org</owner> <owner>src/net/quic/OWNERS</owner> <summary> @@ -3832,7 +3832,7 @@ </histogram> <histogram name="Net.QuicSession.StreamCloseErrorCodeClient.HandshakeConfirmed" - enum="QuicErrorCodes" expires_after="2021-05-11"> + enum="QuicErrorCodes" expires_after="2021-08-09"> <owner>dschinazi@chromium.org</owner> <owner>src/net/quic/OWNERS</owner> <summary> @@ -3852,7 +3852,7 @@ </histogram> <histogram name="Net.QuicSession.StreamFlowControlBlocked" - enum="BooleanBlocked" expires_after="2021-05-11"> + enum="BooleanBlocked" expires_after="2021-08-09"> <owner>dschinazi@chromium.org</owner> <owner>src/net/quic/OWNERS</owner> <summary> @@ -3974,7 +3974,7 @@ </histogram> <histogram name="Net.QuicSession.UndecryptablePacketsReceived" units="units" - expires_after="2021-05-11"> + expires_after="2021-08-09"> <owner>dschinazi@chromium.org</owner> <owner>src/net/quic/OWNERS</owner> <summary> @@ -4302,7 +4302,7 @@ </histogram> <histogram name="Net.QuicTransportClient.ConnectionError" enum="NetErrorCodes" - expires_after="2021-05-11"> + expires_after="2021-08-09"> <owner>vasilvv@chromium.org</owner> <owner>src/net/quic/OWNERS</owner> <summary> @@ -4312,7 +4312,7 @@ </histogram> <histogram name="Net.QuicTransportClient.Error" enum="NetErrorCodes" - expires_after="2021-05-11"> + expires_after="2021-08-09"> <owner>vasilvv@chromium.org</owner> <owner>src/net/quic/OWNERS</owner> <summary>The code for QuicTransport errors.</summary> @@ -4452,7 +4452,7 @@ </histogram> <histogram name="Net.SpdyFrameStreamAndSessionFlowControlState" - enum="SpdyFrameFlowControlState" expires_after="2021-05-11"> + enum="SpdyFrameFlowControlState" expires_after="2021-08-09"> <owner>dschinazi@chromium.org</owner> <owner>src/net/OWNERS</owner> <summary> @@ -4527,7 +4527,7 @@ </histogram> <histogram name="Net.SpdySession.PushedAndUnclaimedBytes" units="count" - expires_after="2021-05-11"> + expires_after="2021-08-09"> <owner>zhongyi@chromium.org</owner> <owner>src/net/OWNERS</owner> <summary> @@ -4536,7 +4536,7 @@ </histogram> <histogram name="Net.SpdySession.PushedBytes" units="count" - expires_after="2021-05-11"> + expires_after="2021-08-09"> <owner>zhongyi@chromium.org</owner> <owner>dschinazi@chromium.org</owner> <owner>src/net/OWNERS</owner> @@ -4592,7 +4592,7 @@ </histogram> <histogram name="Net.SpdyStreamsAbandonedPerSession" units="units" - expires_after="2021-05-11"> + expires_after="2021-08-09"> <owner>dschinazi@chromium.org</owner> <owner>src/net/OWNERS</owner> <summary> @@ -4601,7 +4601,7 @@ </histogram> <histogram name="Net.SpdyStreamsPerSession" units="units" - expires_after="2021-05-11"> + expires_after="2021-08-09"> <owner>dschinazi@chromium.org</owner> <owner>src/net/OWNERS</owner> <summary>The number of streams issued over a single session.</summary> @@ -4707,7 +4707,7 @@ </histogram> <histogram name="Net.SSLHandshakeEarlyDataReason" - enum="SSLHandshakeEarlyDataReason" expires_after="2021-06-01"> + enum="SSLHandshakeEarlyDataReason" expires_after="2021-08-09"> <owner>davidben@chromium.org</owner> <owner>svaldez@chromium.org</owner> <owner>src/net/OWNERS</owner> @@ -4755,7 +4755,7 @@ </histogram> <histogram name="Net.SSLRSAKeyUsage.UnknownRoot" enum="RSAKeyUsage" - expires_after="2021-06-01"> + expires_after="2021-08-09"> <owner>davidben@chromium.org</owner> <summary> For each TLS connection which uses a unknown root, an RSA key, and TLS 1.2 @@ -5036,7 +5036,7 @@ <summary>Chromium error code from call to RandomBind() UDP socket.</summary> </histogram> -<histogram name="Net.UDPSocketWinClose" units="ms" expires_after="2021-05-11"> +<histogram name="Net.UDPSocketWinClose" units="ms" expires_after="2021-08-09"> <owner>dschinazi@chromium.org</owner> <owner>src/net/OWNERS</owner> <summary>The time spent in closesocket call in UDPSocketWin::Close.</summary>
diff --git a/tools/metrics/histograms/histograms_xml/network/histograms.xml b/tools/metrics/histograms/histograms_xml/network/histograms.xml index e588f87..d154e2f 100644 --- a/tools/metrics/histograms/histograms_xml/network/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/network/histograms.xml
@@ -2112,7 +2112,7 @@ </histogram> <histogram name="NetworkService.CorsForcedOffForIsolatedWorldOrigin" - enum="BooleanForceDisabled" expires_after="M92"> + enum="BooleanForceDisabled" expires_after="2021-08-09"> <owner>lukasza@chromium.org</owner> <owner>rdevlin.cronin@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/new_tab_page/histograms.xml b/tools/metrics/histograms/histograms_xml/new_tab_page/histograms.xml index bb13104..0050e9e4 100644 --- a/tools/metrics/histograms/histograms_xml/new_tab_page/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/new_tab_page/histograms.xml
@@ -34,7 +34,7 @@ </histogram> <histogram name="NewTabPage.ActioniOS" enum="NewTabPageActioniOS" - expires_after="2021-06-10"> + expires_after="2021-08-09"> <owner>justincohen@chromium.org</owner> <owner>gambard@chromium.org</owner> <summary> @@ -917,7 +917,7 @@ </histogram> <histogram name="NewTabPage.MostVisitedAge" units="seconds" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>tiborg@chromium.org</owner> <owner>yyushkina@chromium.org</owner> <owner>chrome-desktop-ntp@google.com</owner> @@ -1227,7 +1227,7 @@ </histogram> <histogram name="NewTabPage.SearchAvailableLoadTime2.ColdStart" units="ms" - expires_after="2021-06-08"> + expires_after="2021-08-09"> <owner>fgorski@chromium.org</owner> <owner>ender@google.com</owner> <owner>yyushkina@chromium.org</owner> @@ -1239,7 +1239,7 @@ </histogram> <histogram name="NewTabPage.SearchAvailableLoadTime2.WarmStart" units="ms" - expires_after="2021-06-08"> + expires_after="2021-08-09"> <owner>fgorski@chromium.org</owner> <owner>ender@google.com</owner> <owner>yyushkina@chromium.org</owner> @@ -1506,7 +1506,7 @@ </histogram> <histogram name="NewTabPage.SuggestionsImpressionAge" units="seconds" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>tiborg@chromium.org</owner> <owner>yyushkina@chromium.org</owner> <owner>chrome-desktop-ntp@google.com</owner>
diff --git a/tools/metrics/histograms/histograms_xml/omnibox/histograms.xml b/tools/metrics/histograms/histograms_xml/omnibox/histograms.xml index 917d01e..3852848 100644 --- a/tools/metrics/histograms/histograms_xml/omnibox/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/omnibox/histograms.xml
@@ -581,7 +581,7 @@ </histogram> <histogram name="Omnibox.OnDeviceHeadSuggest.ResultCount" units="count" - expires_after="2021-05-09"> + expires_after="2021-08-09"> <owner>cch@chromium.org</owner> <owner>suggest-2g@google.com</owner> <summary> @@ -729,7 +729,7 @@ </histogram> <histogram name="Omnibox.SelectedPosition" units="position" - expires_after="2021-08-01"> + expires_after="2021-08-09"> <owner>jdonnelly@chromium.org</owner> <owner>mpearson@chromium.org</owner> <owner>chrome-omnibox-team@google.com</owner>
diff --git a/tools/metrics/histograms/histograms_xml/oobe/histograms.xml b/tools/metrics/histograms/histograms_xml/oobe/histograms.xml index fc857fdb..17d0ca29 100644 --- a/tools/metrics/histograms/histograms_xml/oobe/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/oobe/histograms.xml
@@ -102,7 +102,7 @@ </histogram> <histogram name="OOBE.FingerprintSetupScreen.UserActions" - enum="FingerprintSetupScreenUserAction" expires_after="2021-06-06"> + enum="FingerprintSetupScreenUserAction" expires_after="2021-08-09"> <owner>raleksandrov@google.com</owner> <owner>cros-oac@google.com</owner> <summary> @@ -122,7 +122,7 @@ </histogram> <histogram base="true" name="OOBE.GestureNavigationScreen.PageShownTime" - units="ms" expires_after="2021-04-01"> + units="ms" expires_after="2021-08-09"> <!-- Name completed by histogram_suffixes name="GestureNavigationOOBEPage" --> @@ -167,7 +167,7 @@ </histogram> <histogram name="OOBE.MarketingOptInScreen.GeolocationResolveLength" - units="chars" expires_after="2021-05-30"> + units="chars" expires_after="2021-08-09"> <owner>rrsilva@google.com</owner> <owner>cros-oac@google.com</owner> <summary> @@ -289,7 +289,7 @@ </histogram> <histogram name="OOBE.SyncConsentScreen.Behavior" enum="SyncConsentBehavior" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>jamescook@chromium.org</owner> <owner>cros-oac@google.com</owner> <summary> @@ -301,7 +301,7 @@ </histogram> <histogram name="OOBE.SyncConsentScreen.ReviewFollowingSetup" - enum="BooleanChecked" expires_after="2021-04-11"> + enum="BooleanChecked" expires_after="2021-08-09"> <owner>raleksandrov@google.com</owner> <owner>cros-oac@google.com</owner> <summary> @@ -311,7 +311,7 @@ </histogram> <histogram name="OOBE.SyncConsentScreen.SyncEnabled" enum="BooleanEnabled" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>jamescook@chromium.org</owner> <owner>cros-oac@google.com</owner> <summary> @@ -322,7 +322,7 @@ </histogram> <histogram name="OOBE.SyncConsentScreen.UserChoice" - enum="SyncConsentUserChoice" expires_after="2021-06-06"> + enum="SyncConsentUserChoice" expires_after="2021-08-09"> <owner>jamescook@chromium.org</owner> <owner>cros-oac@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/optimization/histograms.xml b/tools/metrics/histograms/histograms_xml/optimization/histograms.xml index 0f280a6..eb0f2ba 100644 --- a/tools/metrics/histograms/histograms_xml/optimization/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/optimization/histograms.xml
@@ -22,7 +22,7 @@ <histograms> <histogram base="true" name="OptimizationGuide.ApplyDecision" - enum="OptimizationGuideOptimizationTypeDecision" expires_after="2021-06-06"> + enum="OptimizationGuideOptimizationTypeDecision" expires_after="2021-08-09"> <owner>sophiechang@chromium.org</owner> <owner>mcrouse@chromium.org</owner> <summary> @@ -32,7 +32,7 @@ </histogram> <histogram base="true" name="OptimizationGuide.ApplyDecisionAsync" - enum="OptimizationGuideOptimizationTypeDecision" expires_after="2021-06-06"> + enum="OptimizationGuideOptimizationTypeDecision" expires_after="2021-08-09"> <owner>sophiechang@chromium.org</owner> <owner>mcrouse@chromium.org</owner> <summary> @@ -106,7 +106,7 @@ </histogram> <histogram name="OptimizationGuide.HintsFetcher.GetHintsRequest.FetchLatency" - units="ms" expires_after="2021-06-06"> + units="ms" expires_after="2021-08-09"> <owner>sophiechang@chromium.org</owner> <owner>mcrouse@chromium.org</owner> <summary> @@ -127,7 +127,7 @@ </histogram> <histogram name="OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount" - units="total host count" expires_after="2021-05-16"> + units="total host count" expires_after="2021-08-09"> <owner>mcrouse@chromium.org</owner> <owner>sophiechang@chromium.org</owner> <summary> @@ -137,7 +137,7 @@ </histogram> <histogram name="OptimizationGuide.HintsFetcher.GetHintsRequest.NetErrorCode" - enum="NetErrorCodes" expires_after="2021-06-06"> + enum="NetErrorCodes" expires_after="2021-08-09"> <owner>mcrouse@chromium.org</owner> <owner>sophiechang@chromium.org</owner> <summary> @@ -147,7 +147,7 @@ </histogram> <histogram name="OptimizationGuide.HintsFetcher.GetHintsRequest.Status" - enum="HttpResponseCode" expires_after="2021-06-06"> + enum="HttpResponseCode" expires_after="2021-08-09"> <owner>mcrouse@chromium.org</owner> <owner>sophiechang@chromium.org</owner> <summary> @@ -227,7 +227,7 @@ <histogram name="OptimizationGuide.HintsManager.RaceNavigationFetchAttemptStatus" enum="OptimizationGuideRaceNavigationFetchAttemptStatus" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>mcrouse@chromium.org</owner> <owner>sophiechang@chromium.org</owner> <summary> @@ -463,7 +463,7 @@ </histogram> <histogram name="OptimizationGuide.RemoteFetchingEnabled" - units="BooleanEnabled" expires_after="2021-06-06"> + units="BooleanEnabled" expires_after="2021-08-09"> <owner>sophiechang@chromium.org</owner> <owner>mcrouse@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/others/histograms.xml b/tools/metrics/histograms/histograms_xml/others/histograms.xml index 78e4c138..d778aa0 100644 --- a/tools/metrics/histograms/histograms_xml/others/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/others/histograms.xml
@@ -144,7 +144,7 @@ </histogram> <histogram name="AccountManager.Migrations.Result" enum="BooleanSuccess" - expires_after="2021-03-28"> + expires_after="2021-08-09"> <owner>sinhak@chromium.org</owner> <summary> Tracks the final result of migrating accounts to Chrome OS Account Manager. @@ -166,7 +166,7 @@ </histogram> <histogram name="AccountManager.MirrorReauthenticationRequest" - enum="BooleanHit" expires_after="2021-03-28"> + enum="BooleanHit" expires_after="2021-08-09"> <owner>sinhak@chromium.org</owner> <owner>anastasiian@chromium.org</owner> <summary> @@ -186,7 +186,7 @@ </histogram> <histogram name="AccountManager.TokenLoadStatus" - enum="AccountManagerTokenLoadStatus" expires_after="2021-06-07"> + enum="AccountManagerTokenLoadStatus" expires_after="2021-08-09"> <owner>sinhak@chromium.org</owner> <owner>anastasiian@chromium.org</owner> <summary> @@ -352,7 +352,7 @@ </histogram> <histogram name="Ads.Media.LoadType" enum="MediaLoadType" - expires_after="2021-04-11"> + expires_after="2021-08-09"> <owner>johnidel@chromium.org</owner> <owner>jkarlin@chromium.org</owner> <summary> @@ -398,7 +398,7 @@ </histogram> <histogram name="AnchorElementMetrics.Clicked.OnDSE.SameHost" - enum="BooleanAnchorElementSameHost" expires_after="2021-05-02"> + enum="BooleanAnchorElementSameHost" expires_after="2021-08-09"> <owner>tbansal@chromium.org</owner> <summary> True if the target link of the anchor element has the same host as the root @@ -581,7 +581,7 @@ </histogram> <histogram name="AppBanners.InstallableStatusCode" - enum="AppBannersInstallableStatusCode" expires_after="2021-06-06"> + enum="AppBannersInstallableStatusCode" expires_after="2021-08-09"> <owner>dominickn@chromium.org</owner> <owner>pjmclachlan@google.com</owner> <summary> @@ -668,14 +668,14 @@ </histogram> <histogram name="appcache.UpdateJob.Canceled" enum="BooleanCanceled" - expires_after="2021-05-25"> + expires_after="2021-08-09"> <owner>cmp@chromium.org</owner> <owner>pwnall@chromium.org</owner> <summary>Tracks whether the update job was canceled.</summary> </histogram> <histogram name="appcache.UpdateJob.ExistingCorruptionFixedInUpdate" - units="resources" expires_after="2021-05-25"> + units="resources" expires_after="2021-08-09"> <owner>cmp@chromium.org</owner> <owner>pwnall@chromium.org</owner> <summary> @@ -688,7 +688,7 @@ </histogram> <histogram name="appcache.UpdateJob.ExistingResourceCheck" units="units" - expires_after="2021-05-25"> + expires_after="2021-08-09"> <owner>cmp@chromium.org</owner> <owner>pwnall@chromium.org</owner> <summary> @@ -698,7 +698,7 @@ </histogram> <histogram name="appcache.UpdateJob.ExistingResourceCorrupt" units="units" - expires_after="2021-05-25"> + expires_after="2021-08-09"> <owner>cmp@chromium.org</owner> <owner>pwnall@chromium.org</owner> <summary> @@ -729,7 +729,7 @@ </histogram> <histogram name="appcache.UpdateJob.ExistingResourceNotCorrupt" - units="resources" expires_after="2021-05-25"> + units="resources" expires_after="2021-08-09"> <owner>cmp@chromium.org</owner> <owner>pwnall@chromium.org</owner> <summary> @@ -742,7 +742,7 @@ </histogram> <histogram name="appcache.UpdateJob.ExistingResourceOnlyCorrupt" - units="resources" expires_after="2021-05-25"> + units="resources" expires_after="2021-08-09"> <owner>cmp@chromium.org</owner> <owner>enne@chromium.org</owner> <summary> @@ -757,7 +757,7 @@ </histogram> <histogram name="appcache.UpdateJob.ExistingResourceOnlyNotCorrupt" - units="resources" expires_after="2021-05-25"> + units="resources" expires_after="2021-08-09"> <owner>cmp@chromium.org</owner> <owner>enne@chromium.org</owner> <summary> @@ -772,7 +772,7 @@ </histogram> <histogram name="appcache.UpdateJob.ExistingResourceReused" units="units" - expires_after="2021-05-25"> + expires_after="2021-08-09"> <owner>cmp@chromium.org</owner> <owner>pwnall@chromium.org</owner> <summary> @@ -782,14 +782,14 @@ </histogram> <histogram name="appcache.UpdateJob.FinalInternalState" - enum="AppCacheUpdateJobInternalState" expires_after="2021-05-25"> + enum="AppCacheUpdateJobInternalState" expires_after="2021-08-09"> <owner>cmp@chromium.org</owner> <owner>pwnall@chromium.org</owner> <summary>Tracks the final internal state for the update job.</summary> </histogram> <histogram name="appcache.UpdateJob.ResourceFreshness" units="days" - expires_after="2021-05-25"> + expires_after="2021-08-09"> <owner>cmp@chromium.org</owner> <owner>pwnall@chromium.org</owner> <summary> @@ -821,7 +821,7 @@ </histogram> <histogram name="AppManagement.EntryPoints" enum="AppManagementEntryPoint" - expires_after="2021-05-16"> + expires_after="2021-08-09"> <owner>jshikaram@chromium.org</owner> <owner>dominickn@chromium.org</owner> <summary>The ways the user opens up the App Management interface.</summary> @@ -1572,7 +1572,7 @@ </histogram> <histogram name="Bookmarks.BookmarkAllTabsWithTabsCount.Incognito" units="tabs" - expires_after="2021-06-01"> + expires_after="2021-08-09"> <owner>rhalavati@chromium.org</owner> <owner>chrome-privacy-core@google.com</owner> <summary> @@ -1623,7 +1623,7 @@ </histogram> <histogram name="Bookmarks.Count.OnProfileLoad" units="bookmarks" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>supertri@chromium.org</owner> <owner>isherman@chromium.org</owner> <owner>aidanday@google.com</owner> @@ -1800,7 +1800,7 @@ </histogram> <histogram name="Bookmarks.ReadingList.NumberOfUnreadItems" units="items" - expires_after="M91"> + expires_after="2021-08-09"> <owner>shaktisahu@chromium.org</owner> <owner>xingliu@chromium.org</owner> <summary> @@ -1810,7 +1810,7 @@ </histogram> <histogram name="Bookmarks.StarEntryPoint.ClickedAction" - enum="StarEntryPointAction" expires_after="M92"> + enum="StarEntryPointAction" expires_after="2021-08-09"> <owner>corising@chromium.org</owner> <owner>chrome-desktop-ui-sea@google.com</owner> <summary> @@ -1930,7 +1930,7 @@ </histogram> <histogram name="CaptivePortal.ProbeReason" enum="CaptivePortalProbeReason" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>ericorth@chromium.org</owner> <owner>doh-core@google.com</owner> <owner>cros-networking@google.com</owner> @@ -2287,7 +2287,7 @@ </histogram> <histogram name="ChildProcess.Launched.UtilityProcessHash" - enum="UtilityProcessNameHash" expires_after="2021-06-06"> + enum="UtilityProcessNameHash" expires_after="2021-08-09"> <owner>wfh@chromium.org</owner> <summary> Count of child utility process launches, bucketed by the hash of their @@ -2571,7 +2571,7 @@ </histogram> <histogram name="Clipboard.ExtensionContentScriptReadHasUserActivation" - units="proportion" expires_after="2021-06-06"> + units="proportion" expires_after="2021-08-09"> <owner>huangdarwin@chromium.org</owner> <owner>src/third_party/blink/renderer/modules/clipboard/OWNERS</owner> <summary> @@ -2690,7 +2690,7 @@ </histogram> <histogram base="true" name="CompositorLatency.CompositorOnlyFrame" - units="microseconds" expires_after="2021-06-06"> + units="microseconds" expires_after="2021-08-09"> <owner>sadrul@chromium.org</owner> <owner>graphics-dev@chromium.org</owner> <summary> @@ -2721,7 +2721,7 @@ </histogram> <histogram base="true" name="CompositorLatency.DroppedFrame" - units="microseconds" expires_after="2021-06-06"> + units="microseconds" expires_after="2021-08-09"> <owner>sadrul@chromium.org</owner> <owner>graphics-dev@chromium.org</owner> <summary> @@ -3194,7 +3194,7 @@ </histogram> <histogram name="ContextMenu.ViewsTextServices.Emoji" enum="Boolean" - expires_after="M91"> + expires_after="2021-08-09"> <owner>ramyan@chromium.org</owner> <owner>yyushkina@chromium.org</owner> <summary> @@ -3204,7 +3204,7 @@ </histogram> <histogram name="ContextMenu.WaitingForElementDetails" enum="BooleanHit" - expires_after="2021-05-23"> + expires_after="2021-08-09"> <owner>michaeldo@chromium.org</owner> <owner>src/ios/web/OWNERS</owner> <summary> @@ -3225,7 +3225,7 @@ </histogram> <histogram name="Conversions.ExtraReportDelay" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>johnidel@chromium.org</owner> <owner>csharrison@chromium.org</owner> <summary> @@ -3250,7 +3250,7 @@ </histogram> <histogram name="Conversions.ReportStatus" enum="ConversionReportStatus" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>johnidel@chromium.org</owner> <owner>csharrison@chromium.org</owner> <summary> @@ -3797,7 +3797,8 @@ </summary> </histogram> -<histogram name="DemoMode.ActiveApp" enum="DemoModeApp" expires_after="M92"> +<histogram name="DemoMode.ActiveApp" enum="DemoModeApp" + expires_after="2021-08-09"> <owner>drcrash@chromium.org</owner> <owner>cros-demo-mode-eng@google.com</owner> <summary> @@ -3806,7 +3807,8 @@ </summary> </histogram> -<histogram name="DemoMode.AppLaunched" enum="DemoModeApp" expires_after="M92"> +<histogram name="DemoMode.AppLaunched" enum="DemoModeApp" + expires_after="2021-08-09"> <owner>drcrash@chromium.org</owner> <owner>cros-demo-mode-eng@google.com</owner> <summary> @@ -3817,7 +3819,7 @@ </histogram> <histogram name="DemoMode.AppLaunchSource" enum="DemoModeAppLaunchSource" - expires_after="M92"> + expires_after="2021-08-09"> <owner>drcrash@chromium.org</owner> <owner>cros-demo-mode-eng@google.com</owner> <summary> @@ -3826,7 +3828,7 @@ </summary> </histogram> -<histogram name="DemoMode.DwellTime" units="seconds" expires_after="M92"> +<histogram name="DemoMode.DwellTime" units="seconds" expires_after="2021-08-09"> <owner>drcrash@chromium.org</owner> <owner>cros-demo-mode-eng@google.com</owner> <summary> @@ -3838,7 +3840,7 @@ </histogram> <histogram name="DemoMode.IdleLogoutWarningEvent" - enum="DemoModeIdleLogoutWarningEvent" expires_after="M92"> + enum="DemoModeIdleLogoutWarningEvent" expires_after="2021-08-09"> <owner>drcrash@chromium.org</owner> <owner>cros-demo-mode-eng@google.com</owner> <summary> @@ -3876,7 +3878,8 @@ </summary> </histogram> -<histogram name="DemoMode.SessionLength" units="minutes" expires_after="M92"> +<histogram name="DemoMode.SessionLength" units="minutes" + expires_after="2021-08-09"> <owner>drcrash@chromium.org</owner> <owner>cros-demo-mode-eng@google.com</owner> <summary> @@ -3890,7 +3893,7 @@ </histogram> <histogram name="DemoMode.Setup.DownloadDuration" units="minutes" - expires_after="M92"> + expires_after="2021-08-09"> <owner>drcrash@chromium.org</owner> <owner>cros-demo-mode-eng@google.com</owner> <summary> @@ -3900,7 +3903,7 @@ </histogram> <histogram name="DemoMode.Setup.EnrollDuration" units="minutes" - expires_after="M92"> + expires_after="2021-08-09"> <owner>drcrash@chromium.org</owner> <owner>cros-demo-mode-eng@google.com</owner> <summary> @@ -3910,7 +3913,7 @@ </histogram> <histogram name="DemoMode.Setup.LoadingDuration" units="minutes" - expires_after="M92"> + expires_after="2021-08-09"> <owner>drcrash@chromium.org</owner> <owner>cros-demo-mode-eng@google.com</owner> <summary> @@ -3921,7 +3924,8 @@ </summary> </histogram> -<histogram name="DemoMode.Setup.NumRetries" units="units" expires_after="M92"> +<histogram name="DemoMode.Setup.NumRetries" units="units" + expires_after="2021-08-09"> <owner>drcrash@chromium.org</owner> <owner>cros-demo-mode-eng@google.com</owner> <summary> @@ -3931,7 +3935,8 @@ </summary> </histogram> -<histogram name="DemoMode.UniqueAppsLaunched" units="units" expires_after="M92"> +<histogram name="DemoMode.UniqueAppsLaunched" units="units" + expires_after="2021-08-09"> <owner>drcrash@chromium.org</owner> <owner>cros-demo-mode-eng@google.com</owner> <summary> @@ -4087,7 +4092,7 @@ </histogram> <histogram name="Discarding.OnCriticalPressure.TotalRSS_PercentOfRAM" units="%" - expires_after="2021-04-04"> + expires_after="2021-08-09"> <owner>sebmarchand@chromium.org</owner> <owner>catan-team@chromium.org</owner> <summary> @@ -4269,7 +4274,7 @@ </summary> </histogram> -<histogram name="DnsProbe.ProbeDuration2" units="ms" expires_after="2021-06-04"> +<histogram name="DnsProbe.ProbeDuration2" units="ms" expires_after="2021-08-09"> <owner>ericorth@chromium.org</owner> <owner>src/net/OWNERS</owner> <summary> @@ -4278,7 +4283,7 @@ </histogram> <histogram name="DnsProbe.ProbeResult" enum="DnsProbe.ProbeStatus" - expires_after="2021-06-04"> + expires_after="2021-08-09"> <owner>ericorth@chromium.org</owner> <owner>src/net/OWNERS</owner> <summary>Result of DNS diagnostics probes sent by the probe service.</summary> @@ -4577,7 +4582,7 @@ </histogram> <histogram name="Downgrade.TakeSnapshot.FailureCount" units="count" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>grt@chromium.org</owner> <owner>ydago@chromium.org</owner> <summary> @@ -4587,7 +4592,7 @@ </histogram> <histogram name="Downgrade.TakeSnapshot.ItemFailure" enum="SnapshotItemId" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>grt@chromium.org</owner> <owner>ydago@chromium.org</owner> <summary> @@ -4646,7 +4651,7 @@ </histogram> <histogram name="Downgrade.Type" enum="UserDataDowngradeType" - expires_after="2021-05-09"> + expires_after="2021-08-09"> <owner>grt@chromium.org</owner> <summary> The type of User Data downgrade detected, if any. The "none" @@ -4695,7 +4700,7 @@ </histogram> <histogram name="DriveCommon.Lifecycle.FirstLaunchTime" units="ms" - expires_after="2021-04-19"> + expires_after="2021-08-09"> <owner>simmonsjosh@google.com</owner> <owner>src/ui/file_manager/OWNERS</owner> <summary> @@ -4971,7 +4976,8 @@ </summary> </histogram> -<histogram name="EphemeralTab.Ctr" enum="BooleanOpened" expires_after="M92"> +<histogram name="EphemeralTab.Ctr" enum="BooleanOpened" + expires_after="2021-08-09"> <owner>donnd@chromium.org</owner> <owner>jinsukkim@chromium.org</owner> <summary> @@ -4980,7 +4986,8 @@ </summary> </histogram> -<histogram name="EphemeralTab.CtrPeek" enum="BooleanOpened" expires_after="M92"> +<histogram name="EphemeralTab.CtrPeek" enum="BooleanOpened" + expires_after="2021-08-09"> <owner>donnd@chromium.org</owner> <owner>jinsukkim@chromium.org</owner> <summary> @@ -4989,7 +4996,8 @@ </summary> </histogram> -<histogram name="EphemeralTab.DurationOpened" units="ms" expires_after="M92"> +<histogram name="EphemeralTab.DurationOpened" units="ms" + expires_after="2021-08-09"> <owner>donnd@chromium.org</owner> <owner>jinsukkim@chromium.org</owner> <summary> @@ -4998,7 +5006,8 @@ </summary> </histogram> -<histogram name="EphemeralTab.DurationPeeked" units="ms" expires_after="M92"> +<histogram name="EphemeralTab.DurationPeeked" units="ms" + expires_after="2021-08-09"> <owner>donnd@chromium.org</owner> <owner>jinsukkim@chromium.org</owner> <summary> @@ -5176,7 +5185,7 @@ </histogram> <histogram name="ExploreSites.RequestStatus" enum="ExploreSitesRequestStatus" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>dimich@chromium.org</owner> <owner>freedjm@chromium.org</owner> <summary> @@ -5186,7 +5195,7 @@ </histogram> <histogram name="ExploreSites.SiteTilesClickIndex2" units="units" - expires_after="2021-04-18"> + expires_after="2021-08-09"> <owner>dewittj@chromium.org</owner> <owner>petewil@chromium.org</owner> <summary> @@ -5844,7 +5853,7 @@ </histogram> <histogram name="Gamepad.KnownGamepadConnectedWithId" - enum="GamepadVendorProduct" expires_after="2021-06-06"> + enum="GamepadVendorProduct" expires_after="2021-08-09"> <owner>mattreynolds@chromium.org</owner> <owner>deviceapi-team@google.com</owner> <summary> @@ -6526,7 +6535,7 @@ </histogram> <histogram base="true" name="GridTabSwitcher.FramePerSecond" units="frame/sec" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>yusufo@chromium.org</owner> <owner>wychen@chromium.org</owner> <summary> @@ -6600,7 +6609,7 @@ </summary> </histogram> -<histogram name="Hardware.TotalDiskSpace" units="GB" expires_after="2021-05-02"> +<histogram name="Hardware.TotalDiskSpace" units="GB" expires_after="2021-08-09"> <owner>sadrul@chromium.org</owner> <owner>zmo@chromium.org</owner> <summary> @@ -6610,7 +6619,7 @@ </histogram> <histogram name="HeapProfiling.ProfiledProcess.Type" - enum="HeapProfilingProcessType" expires_after="2021-05-02"> + enum="HeapProfilingProcessType" expires_after="2021-08-09"> <owner>erikchen@chromium.org</owner> <owner>chrome-memory@google.com</owner> <summary> @@ -6794,7 +6803,7 @@ </summary> </histogram> -<histogram name="HttpCache.AccessToDone" units="ms" expires_after="2021-05-02"> +<histogram name="HttpCache.AccessToDone" units="ms" expires_after="2021-08-09"> <owner>morlovich@chromium.org</owner> <summary> For every http cache transaction with a pattern (see HttpCache.Pattern), the @@ -6859,7 +6868,7 @@ </histogram> <histogram name="HttpCache.MaxFileSizeOnInit" units="KB" - expires_after="2021-05-02"> + expires_after="2021-08-09"> <owner>shivanisha@chromium.org</owner> <owner>jkarlin@chromium.org</owner> <summary> @@ -7033,7 +7042,7 @@ </histogram> <histogram name="ImportantFile.FileDeleteRetrySuccessCount" - units="attept number" expires_after="2021-05-02"> + units="attept number" expires_after="2021-08-09"> <owner>grt@chromium.org</owner> <owner>xaerox@yandex-team.ru</owner> <summary> @@ -7073,7 +7082,7 @@ </histogram> <histogram name="ImportantFile.SerializationDuration" units="ms" - expires_after="M92"> + expires_after="2021-08-09"> <owner>battre@chromium.org</owner> <owner>gab@chromium.org</owner> <summary>CPU time used to serialize preferences into a JSON string.</summary> @@ -8020,7 +8029,7 @@ </histogram> <histogram name="Launch.HomeScreenSource" enum="LaunchFromHomeScreenSource" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>dominickn@chromium.org</owner> <owner>hartmanng@chromium.org</owner> <owner>peconn@chromium.org</owner> @@ -8594,7 +8603,7 @@ </histogram> <histogram base="true" name="LoadingPredictor.PreconnectLearningRecall" - units="%" expires_after="2021-04-18"> + units="%" expires_after="2021-08-09"> <owner>alexilin@chromium.org</owner> <owner>tbansal@chromium.org</owner> <summary> @@ -8921,7 +8930,7 @@ </histogram> <histogram name="Manifest.HasProperty" enum="Boolean" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>mgiuca@chromium.org</owner> <owner>mlamouri@chromium.org</owner> <summary> @@ -9310,7 +9319,7 @@ </histogram> <histogram base="true" name="Mouse.ScrollAcceleration" enum="BooleanEnabled" - expires_after="2021-05-16"> + expires_after="2021-08-09"> <!-- Name completed by histogram_suffixes name="PreferenceChangeType" --> <owner>khorimoto@chromium.org</owner> @@ -9379,7 +9388,7 @@ </histogram> <histogram name="MultiDeviceSetup.OOBE.UserChoice" - enum="MultiDeviceSetupOOBEUserChoice" expires_after="2021-06-06"> + enum="MultiDeviceSetupOOBEUserChoice" expires_after="2021-08-09"> <owner>vecore@google.com</owner> <owner>better-together-dev@google.com</owner> <owner>hsuregan@chromium.org</owner> @@ -9390,7 +9399,7 @@ </histogram> <histogram name="MultiDeviceSetup_NotificationClicked" - enum="MultiDeviceSetupNotification" expires_after="2021-06-06"> + enum="MultiDeviceSetupNotification" expires_after="2021-08-09"> <owner>vecore@google.com</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -9400,7 +9409,7 @@ </histogram> <histogram name="MultiDeviceSetup_NotificationDismissed" - enum="MultiDeviceSetupNotification" expires_after="2021-04-04"> + enum="MultiDeviceSetupNotification" expires_after="2021-08-09"> <owner>vecore@google.com</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -9581,7 +9590,7 @@ </histogram> <histogram name="NativeTheme.GetSystemColor.UsesColorProvider" enum="Boolean" - expires_after="2021-04-04"> + expires_after="2021-08-09"> <owner>pkasting@chromium.org</owner> <owner>robliao@chromium.org</owner> <summary>Records if the color provider computed the color.</summary> @@ -10473,7 +10482,7 @@ </histogram> <histogram name="NQE.CachedNetworkQualityAvailable" enum="BooleanAvailable" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>tbansal@chromium.org</owner> <owner>bengr@chromium.org</owner> <summary> @@ -10483,7 +10492,7 @@ </histogram> <histogram name="NQE.CellularSignalStrength.ECTReduction" - units="ECT level reduction" expires_after="2021-06-06"> + units="ECT level reduction" expires_after="2021-08-09"> <owner>tbansal@chromium.org</owner> <summary> Number of buckets by which effective connection type was reduced or capped @@ -10493,7 +10502,7 @@ </histogram> <histogram name="NQE.CellularSignalStrength.LevelAvailable" - enum="BooleanAvailable" expires_after="2021-06-06"> + enum="BooleanAvailable" expires_after="2021-08-09"> <owner>tbansal@chromium.org</owner> <owner>bengr@chromium.org</owner> <summary> @@ -10541,7 +10550,7 @@ </histogram> <histogram name="NQE.EndToEndRTT.OnECTComputation" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>tbansal@chromium.org</owner> <owner>src/net/nqe/OWNERS</owner> <summary> @@ -10582,7 +10591,7 @@ </summary> </histogram> -<histogram name="NQE.Prefs.ReadCount" units="count" expires_after="2021-06-06"> +<histogram name="NQE.Prefs.ReadCount" units="count" expires_after="2021-08-09"> <owner>tbansal@chromium.org</owner> <owner>bengr@chromium.org</owner> <summary> @@ -10591,7 +10600,7 @@ </summary> </histogram> -<histogram name="NQE.Prefs.ReadSize" units="count" expires_after="2021-06-06"> +<histogram name="NQE.Prefs.ReadSize" units="count" expires_after="2021-08-09"> <owner>tbansal@chromium.org</owner> <owner>bengr@chromium.org</owner> <summary> @@ -10600,7 +10609,7 @@ </summary> </histogram> -<histogram name="NQE.Prefs.WriteCount" units="count" expires_after="2021-06-06"> +<histogram name="NQE.Prefs.WriteCount" units="count" expires_after="2021-08-09"> <owner>tbansal@chromium.org</owner> <owner>bengr@chromium.org</owner> <summary> @@ -10763,7 +10772,7 @@ </histogram> <histogram name="OriginTrials.ValidationResult" enum="OriginTrialTokenStatus" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>chasej@chromium.org</owner> <owner>iclelland@chromium.org</owner> <owner>feature-control@chromium.org</owner> @@ -11157,7 +11166,7 @@ </histogram> <histogram name="PartnerBookmark.Count2" units="bookmarks" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>bttk@chromium.org</owner> <owner>wychen@chromium.org</owner> <summary> @@ -11188,7 +11197,7 @@ </histogram> <histogram name="PDF.Actions" enum="ChromePDFViewerActions" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>hnakashima@chromium.org</owner> <summary> Tracks user actions in the PDF viewer. Logged when the document is opened @@ -11260,7 +11269,7 @@ </summary> </histogram> -<histogram name="PDF.Version" enum="PDFVersion" expires_after="2021-06-06"> +<histogram name="PDF.Version" enum="PDFVersion" expires_after="2021-08-09"> <owner>dhoss@chromium.org</owner> <owner>thestig@chromium.org</owner> <summary>Tracks versions of documents opened in the PDF viewer.</summary> @@ -11708,7 +11717,7 @@ </histogram> <histogram name="PrefetchedSignedExchangeCache.BodySize" units="bytes" - expires_after="2021-05-30"> + expires_after="2021-08-09"> <owner>horo@chromium.org</owner> <owner>webpackage-dev@chromium.org</owner> <summary> @@ -11731,7 +11740,7 @@ </histogram> <histogram name="PrefetchedSignedExchangeCache.Count" units="count" - expires_after="2021-05-30"> + expires_after="2021-08-09"> <owner>horo@chromium.org</owner> <owner>webpackage-dev@chromium.org</owner> <summary> @@ -11925,7 +11934,7 @@ </histogram> <histogram name="Previews.CacheControlNoTransform.BlockedPreview" - enum="PreviewsType" expires_after="2021-06-06"> + enum="PreviewsType" expires_after="2021-08-09"> <owner>sophiechang@chromium.org</owner> <owner>mcrouse@chromium.org</owner> <owner>src/components/previews/OWNERS</owner> @@ -12028,7 +12037,7 @@ </histogram> <histogram name="Previews.LitePageNotificationInfoBar" - enum="PreviewsLitePageInfoBarAction" expires_after="2021-06-06"> + enum="PreviewsLitePageInfoBarAction" expires_after="2021-08-09"> <owner>robertogden@chromium.org</owner> <owner>src/components/data_reduction_proxy/OWNERS</owner> <summary> @@ -12037,7 +12046,7 @@ </histogram> <histogram name="Previews.OmniboxAction" enum="PreviewsUserOmniboxAction" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>robertogden@chromium.org</owner> <summary>User interactions with the Previews Android Omnibox UI.</summary> </histogram> @@ -12062,7 +12071,7 @@ </histogram> <histogram name="Previews.PageEndReason" enum="PageEndReason" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>robertogden@chromium.org</owner> <summary>Records why the page load ended on a given preview type.</summary> </histogram> @@ -12955,7 +12964,7 @@ </histogram> <histogram name="RenderTextHarfBuzz.GetFallbackFontsTime" units="ms" - expires_after="2021-05-09"> + expires_after="2021-08-09"> <owner>ccameron@chromium.org</owner> <owner>etienneb@chromium.org</owner> <summary> @@ -12966,7 +12975,7 @@ </histogram> <histogram name="RenderTextHarfBuzz.GetFallbackFontTime" units="ms" - expires_after="2021-05-09"> + expires_after="2021-08-09"> <owner>ccameron@chromium.org</owner> <owner>etienneb@chromium.org</owner> <summary> @@ -12977,7 +12986,7 @@ </histogram> <histogram name="RenderTextHarfBuzz.ShapeRunsFallback" enum="ShapeRunFallback" - expires_after="2021-05-09"> + expires_after="2021-08-09"> <owner>ccameron@chromium.org</owner> <owner>etienneb@chromium.org</owner> <summary> @@ -12987,7 +12996,7 @@ </histogram> <histogram name="RenderTextHarfBuzz.ShapeRunsWithFallbackFontsTime" units="ms" - expires_after="2021-05-09"> + expires_after="2021-08-09"> <owner>ccameron@chromium.org</owner> <owner>etienneb@chromium.org</owner> <summary> @@ -14261,7 +14270,7 @@ </histogram> <histogram name="SignedExchange.CertVerificationResult" enum="NetErrorCodes" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>ksakamoto@chromium.org</owner> <owner>kinuko@chromium.org</owner> <owner>horo@chromium.org</owner> @@ -14329,7 +14338,7 @@ </histogram> <histogram name="SignedExchange.Prefetch.LoadResult2" - enum="SignedExchangeLoadResult" expires_after="2021-06-06"> + enum="SignedExchangeLoadResult" expires_after="2021-08-09"> <owner>kinuko@chromium.org</owner> <owner>ksakamoto@chromium.org</owner> <owner>horo@chromium.org</owner> @@ -14945,7 +14954,7 @@ </histogram> <histogram name="Spellcheck.Android.Available" enum="BooleanAvailable" - expires_after="M92"> + expires_after="2021-08-09"> <owner>timvolodine@chromium.org</owner> <owner>chrome-language@google.com</owner> <summary> @@ -14989,7 +14998,7 @@ </histogram> <histogram name="SpellCheck.SpellingService.Enabled" enum="BooleanEnabled" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>groby@chromium.org</owner> <owner>chrome-language@google.com</owner> <summary> @@ -15352,7 +15361,7 @@ </histogram> <histogram name="Style.InvalidationTime" units="microseconds" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>futhark@chromium.org</owner> <summary> Microseconds spent in StyleEngine::InvalidateStyle. Only samples from high @@ -15361,7 +15370,7 @@ </histogram> <histogram name="Style.RebuildLayoutTreeTime" units="microseconds" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>futhark@chromium.org</owner> <summary> Microseconds spent in RebuildLayoutTree called from Document::UpdateStyle. @@ -15369,13 +15378,51 @@ </histogram> <histogram name="Style.RecalcTime" units="microseconds" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>futhark@chromium.org</owner> <summary> Microseconds spent in RecalcStyle called from Document::UpdateStyle. </summary> </histogram> +<histogram name="SubresourceWebBundles.ContentLength" units="bytes" + expires_after="M94"> + <owner>horo@chromium.org</owner> + <owner>webpackage-dev@chromium.org</owner> + <summary> + The value of content length header of a subresource web bundle, or zero if + the content-length header is missing. + </summary> +</histogram> + +<histogram name="SubresourceWebBundles.LoadResult" + enum="SubresourceWebBundleLoadResult" expires_after="M94"> + <owner>horo@chromium.org</owner> + <owner>webpackage-dev@chromium.org</owner> + <summary>The result of loading subresource web bundles.</summary> +</histogram> + +<histogram name="SubresourceWebBundles.MaxMemoryUsagePerProcess" units="bytes" + expires_after="M94"> + <owner>horo@chromium.org</owner> + <owner>webpackage-dev@chromium.org</owner> + <summary> + The max memory usage per renderer process for subresource web bundles which + are kept in the network process's memory. Recorded when all the subresource + web bundles for the renderer process are released. + </summary> +</histogram> + +<histogram name="SubresourceWebBundles.ReceivedSize" units="bytes" + expires_after="M94"> + <owner>horo@chromium.org</owner> + <owner>webpackage-dev@chromium.org</owner> + <summary> + The received data size of a subresource web bundle. Recorded when received + all the body of the subresource web bundle. + </summary> +</histogram> + <histogram name="Suggestions.FailedRequestErrorCode" enum="NetErrorCodes" expires_after="2020-02-23"> <owner>mathp@chromium.org</owner> @@ -15716,7 +15763,7 @@ </histogram> <histogram name="Tablet.AppDrag.EndWindowState" - enum="AppWindowDragEndWindowState" expires_after="2021-06-01"> + enum="AppWindowDragEndWindowState" expires_after="2021-08-09"> <owner>minch@chromium.org</owner> <owner>omrilio@chromium.org</owner> <summary> @@ -16668,7 +16715,7 @@ </histogram> <histogram name="Tracing.Background.FinalizationDisallowedReason" - enum="TracingFinalizationDisallowedReason" expires_after="2021-06-06"> + enum="TracingFinalizationDisallowedReason" expires_after="2021-08-09"> <owner>ssid@chromium.org</owner> <summary> Reason why background tracing finalization was not allowed. Also see @@ -16839,7 +16886,7 @@ </histogram> <histogram name="TrustedWebActivity.SplashScreenShown" enum="Boolean" - expires_after="M92"> + expires_after="2021-08-09"> <owner>peconn@chromium.org</owner> <owner>peter@chromium.org</owner> <summary> @@ -17073,7 +17120,7 @@ </histogram> <histogram name="UserManager.LoginUserType" enum="UserType" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>achuith@chromium.org</owner> <summary> The number of users of different types that log in to the system (Chrome @@ -17590,7 +17637,7 @@ </histogram> <histogram name="Webapp.AddToHomescreenDialog.Timeout" units="ms" - expires_after="2021-05-09"> + expires_after="2021-08-09"> <owner>dominickn@chromium.org</owner> <owner>peconn@chromium.org</owner> <summary> @@ -17734,7 +17781,7 @@ </histogram> <histogram name="WebApp.InstallIphPromo.Result" enum="WebAppInstallIphResult" - expires_after="M92"> + expires_after="2021-08-09"> <owner>phillis@chromium.org</owner> <owner>dmurph@chromium.org</owner> <summary> @@ -17785,7 +17832,7 @@ </histogram> <histogram name="WebApp.Launcher.LaunchResult" - enum="WebAppLauncherLaunchResult" expires_after="2021-04-10"> + enum="WebAppLauncherLaunchResult" expires_after="2021-08-09"> <owner>davidbienvenu@chromium.org</owner> <owner>jessemckenna@google.com</owner> <summary> @@ -17795,7 +17842,7 @@ </histogram> <histogram name="WebApp.Launcher.UpdateResult" - enum="WebAppLauncherUpdateResult" expires_after="2021-04-10"> + enum="WebAppLauncherUpdateResult" expires_after="2021-08-09"> <owner>davidbienvenu@chromium.org</owner> <owner>jessemckenna@google.com</owner> <summary> @@ -17823,7 +17870,7 @@ </histogram> <histogram name="WebApp.Mover.Result" enum="WebAppMoverResult" - expires_after="2021-06-01"> + expires_after="2021-08-09"> <owner>dmurph@chromium.org</owner> <owner>desktop-pwas-team@google.com</owner> <summary> @@ -17959,7 +18006,7 @@ </histogram> <histogram name="Webapp.Update.ManifestUpdateResult" - enum="WebAppManifestUpdateResult" expires_after="M92"> + enum="WebAppManifestUpdateResult" expires_after="2021-08-09"> <owner>alancutter@chromium.org</owner> <owner>desktop-pwas-team@chromium.org</owner> <owner>loyso@chromium.org</owner> @@ -18009,7 +18056,7 @@ </histogram> <histogram name="WebAuthentication.CableV1DiscoveryEvent" - enum="WebAuthenticationCableV1DiscoveryEvent" expires_after="2021-06-06"> + enum="WebAuthenticationCableV1DiscoveryEvent" expires_after="2021-08-09"> <owner>agl@chromium.org</owner> <owner>martinkr@google.com</owner> <summary> @@ -18212,7 +18259,7 @@ </histogram> <histogram name="WebController.ExternalURLRequestBlocking" - enum="IOSExternalURLRequestStatus" expires_after="2021-04-25"> + enum="IOSExternalURLRequestStatus" expires_after="2021-08-09"> <owner>mrefaat@chromium.org</owner> <summary> [iOS] Measures the proportion of external URL requests that originate from a @@ -18431,7 +18478,7 @@ </histogram> <histogram name="WebShare.ApiCount" enum="WebShareMethod" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>mgiuca@chromium.org</owner> <summary> Counts the number of calls to navigator.share. Includes both successful and @@ -18475,7 +18522,7 @@ </histogram> <histogram name="WebsiteSettings.AllSitesAction2" - enum="WebSiteSettingsAllSitesAction2" expires_after="2021-04-18"> + enum="WebSiteSettingsAllSitesAction2" expires_after="2021-08-09"> <owner>jarrydg@chromium.org</owner> <owner>mxcai@chromium.org</owner> <summary> @@ -18629,7 +18676,7 @@ </histogram> <histogram name="WebUI.Settings.PathVisited" enum="WebUISettingsPathHashes" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>dschuyler@chromium.org</owner> <owner>tbuckley@chromium.org</owner> <owner>bettes@chromium.org</owner> @@ -18653,7 +18700,7 @@ </histogram> <histogram name="WebUITabStrip.CloseTabAction" - enum="WebUITabStripCloseTabActions" expires_after="2021-06-06"> + enum="WebUITabStripCloseTabActions" expires_after="2021-08-09"> <owner>johntlee@chromium.org</owner> <owner>dpapad@chromium.org</owner> <summary> @@ -18675,7 +18722,7 @@ </histogram> <histogram name="WebUITabStrip.OpenDuration" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>collinbaker@chromium.org</owner> <owner>dfried@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/page/histograms.xml b/tools/metrics/histograms/histograms_xml/page/histograms.xml index ce522962..ce2d5dd 100644 --- a/tools/metrics/histograms/histograms_xml/page/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/page/histograms.xml
@@ -143,7 +143,7 @@ </histogram> <histogram name="PageLoad.Clients.Ads.AllPages.PercentNetworkBytesAds" - units="%" expires_after="2021-05-30"> + units="%" expires_after="2021-08-09"> <owner>alexmt@chromium.org</owner> <owner>johnidel@chromium.org</owner> <summary> @@ -169,7 +169,7 @@ </histogram> <histogram name="PageLoad.Clients.Ads.FrameCounts.IgnoredByRestrictedAdTagging" - enum="BooleanIgnored" expires_after="2021-04-04"> + enum="BooleanIgnored" expires_after="2021-08-09"> <owner>johnidel@chromium.org</owner> <owner>jkarlin@chromium.org</owner> <summary> @@ -209,7 +209,7 @@ </histogram> <histogram name="PageLoad.Clients.Ads.HeavyAds.IgnoredByReload" - enum="BooleanIgnored" expires_after="2021-03-28"> + enum="BooleanIgnored" expires_after="2021-08-09"> <owner>johnidel@chromium.org</owner> <owner>jkarlin@chromium.org</owner> <summary> @@ -223,7 +223,7 @@ </histogram> <histogram name="PageLoad.Clients.Ads.HeavyAds.NetworkBytesAtFrameUnload" - units="bytes" expires_after="2021-04-04"> + units="bytes" expires_after="2021-08-09"> <owner>johnidel@chromium.org</owner> <owner>justinmiron@google.com</owner> <summary> @@ -235,7 +235,7 @@ </histogram> <histogram name="PageLoad.Clients.Ads.HeavyAds.UserDidReload" - enum="BooleanReloaded" expires_after="2021-05-30"> + enum="BooleanReloaded" expires_after="2021-08-09"> <owner>johnidel@chromium.org</owner> <owner>jkarlin@chromium.org</owner> <summary> @@ -251,6 +251,7 @@ <owner>cammie@chromium.org</owner> <owner>jkarlin@chromium.org</owner> <owner>johnidel@chromium.org</owner> + <owner>chrome-ads-histograms@google.com</owner> <summary> The maximum reported number of kilobytes of memory used by V8 by the main frame in this pageload. @@ -264,9 +265,15 @@ <histogram name="PageLoad.Clients.Ads.Memory.MissedMeasurementCount" units="count" expires_after="2021-04-18"> + <obsolete> + Removed 02/2021. Seen to be ~0.04 (sample mean) compared to a sample mean + UpdateCount of ~58.38 measured over all OSes for Dev and Canary for ending + date 10/28/2020 with 7-day aggregation. + </obsolete> <owner>cammie@chromium.org</owner> <owner>jkarlin@chromium.org</owner> <owner>johnidel@chromium.org</owner> + <owner>chrome-ads-histograms@google.com</owner> <summary> The number of V8 per-frame memory measurements received by AdsPageLoadMetricsObserver after the corresponding RenderFrameHost has @@ -280,6 +287,7 @@ <owner>cammie@chromium.org</owner> <owner>jkarlin@chromium.org</owner> <owner>johnidel@chromium.org</owner> + <owner>chrome-ads-histograms@google.com</owner> <summary> The number of V8 memory measurement updates received by AdsPageLoadMetricsObserver per pageload. Only recorded if the page has at @@ -814,7 +822,7 @@ <histogram name="PageLoad.DocumentTiming.NavigationToDOMContentLoadedEventFired" - units="ms" expires_after="2021-06-06"> + units="ms" expires_after="2021-08-09"> <owner>bmcquade@chromium.org</owner> <owner>csharrison@chromium.org</owner> <summary> @@ -824,7 +832,7 @@ </histogram> <histogram name="PageLoad.DocumentTiming.NavigationToLoadEventFired" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>bmcquade@chromium.org</owner> <owner>csharrison@chromium.org</owner> <summary> @@ -834,7 +842,7 @@ </histogram> <histogram base="true" name="PageLoad.Experimental.AbortTiming.Background" - units="ms" expires_after="2021-06-06"> + units="ms" expires_after="2021-08-09"> <owner>bmcquade@chromium.org</owner> <owner>csharrison@chromium.org</owner> <summary> @@ -845,7 +853,7 @@ </histogram> <histogram base="true" name="PageLoad.Experimental.AbortTiming.Close" - units="ms" expires_after="2021-06-06"> + units="ms" expires_after="2021-08-09"> <owner>csharrison@chromium.org</owner> <summary> This metric is still experimental and not yet ready to be relied upon. @@ -856,7 +864,7 @@ <histogram base="true" name="PageLoad.Experimental.AbortTiming.ForwardBackNavigation" units="ms" - expires_after="2021-04-04"> + expires_after="2021-08-09"> <owner>csharrison@chromium.org</owner> <summary> This metric is still experimental and not yet ready to be relied upon. @@ -866,7 +874,7 @@ </histogram> <histogram base="true" name="PageLoad.Experimental.AbortTiming.NewNavigation" - units="ms" expires_after="2021-06-06"> + units="ms" expires_after="2021-08-09"> <owner>csharrison@chromium.org</owner> <summary> This metric is still experimental and not yet ready to be relied upon. @@ -886,7 +894,7 @@ </histogram> <histogram base="true" name="PageLoad.Experimental.AbortTiming.Reload" - units="ms" expires_after="2021-06-06"> + units="ms" expires_after="2021-08-09"> <owner>csharrison@chromium.org</owner> <summary> This metric is still experimental and not yet ready to be relied upon. @@ -896,7 +904,7 @@ </histogram> <histogram base="true" name="PageLoad.Experimental.AbortTiming.Stop" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>csharrison@chromium.org</owner> <summary> This metric is still experimental and not yet ready to be relied upon. @@ -918,7 +926,7 @@ </histogram> <histogram name="PageLoad.Experimental.Bytes.Network" units="KB" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>jkarlin@chromium.org</owner> <summary> The number of prefiltered (e.g., compressed) response body KiloBytes loaded @@ -929,7 +937,7 @@ </histogram> <histogram name="PageLoad.Experimental.Bytes.NetworkIncludingHeaders" - units="KB" expires_after="2021-06-06"> + units="KB" expires_after="2021-08-09"> <owner>jkarlin@chromium.org</owner> <summary> The number of prefiltered (e.g., compressed) KiloBytes loaded over the @@ -964,7 +972,7 @@ </histogram> <histogram name="PageLoad.Experimental.ClickInputBurst" units="count" - expires_after="2021-05-02"> + expires_after="2021-08-09"> <owner>dougarnett@chromium.org</owner> <owner>tbansal@chromium.org</owner> <owner>sullivan@chromium.org</owner> @@ -1221,7 +1229,7 @@ </histogram> <histogram name="PageLoad.Experimental.PageLoadType" enum="PageLoadType" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>npm@chromium.org</owner> <owner>speed-metrics-dev@chromium.org</owner> <summary> @@ -1246,7 +1254,7 @@ </histogram> <histogram name="PageLoad.Experimental.PaintTiming.InputToFirstContentfulPaint" - units="ms" expires_after="2021-06-06"> + units="ms" expires_after="2021-08-09"> <owner>sullivan@chromium.org</owner> <summary> The time between the OS-level input event that initiated a navigation, and @@ -1287,7 +1295,7 @@ <histogram name="PageLoad.Experimental.PaintTiming.NavigationToFirstMeaningfulPaint" - units="ms" expires_after="2021-06-06"> + units="ms" expires_after="2021-08-09"> <owner>ksakamoto@chromium.org</owner> <owner>speed-metrics-dev@chromium.org</owner> <summary> @@ -1311,7 +1319,7 @@ </histogram> <histogram name="PageLoad.Experimental.TotalForegroundDuration" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>npm@chromium.org</owner> <owner>speed-metrics-dev@chromium.org</owner> <summary> @@ -1598,7 +1606,7 @@ </histogram> <histogram name="PageLoad.Internal.ClientRedirect.NavigationWithoutPaint" - enum="Boolean" expires_after="2021-04-18"> + enum="Boolean" expires_after="2021-08-09"> <owner>bmcquade@chromium.org</owner> <summary> Counts how often a client-side redirect was initiated from a page that did @@ -1619,7 +1627,7 @@ </histogram> <histogram name="PageLoad.Internal.NavigationStartedInForeground" - enum="BooleanForeground" expires_after="2021-06-06"> + enum="BooleanForeground" expires_after="2021-08-09"> <owner>bmcquade@chromium.org</owner> <summary>Whether a navigation started in the foreground.</summary> </histogram> @@ -1691,7 +1699,7 @@ <histogram name="PageLoad.Internal.PaintTiming.LargestContentfulPaint.ContentType" - enum="LargestContentType" expires_after="2021-06-06"> + enum="LargestContentType" expires_after="2021-08-09"> <owner>maxlg@chromium.org</owner> <owner>npm@chromium.org</owner> <owner>speed-metrics-dev@chromium.org</owner> @@ -1705,7 +1713,7 @@ <histogram name="PageLoad.Internal.PaintTiming.LargestContentfulPaint.MainFrame.ContentType" - enum="LargestContentType" expires_after="2021-04-04"> + enum="LargestContentType" expires_after="2021-08-09"> <owner>maxlg@chromium.org</owner> <owner>npm@chromium.org</owner> <owner>speed-metrics-dev@chromium.org</owner> @@ -1829,9 +1837,12 @@ </histogram> <histogram name="PageLoad.LayoutInstability.CumulativeShiftScore" - units="scorex10" expires_after="2021-08-08"> + units="scorex10" expires_after="never"> +<!-- expires-never: guiding metric (internal: go/chrome-browser-guiding-metrics) --> + <owner>bmcquade@chromium.org</owner> <owner>skobes@chromium.org</owner> + <owner>chrome-analysis-team@google.com</owner> <summary> Measures the cumulative layout shift score (bit.ly/lsm-explainer) that has occurred on the page (including all subframes). Recorded at the end of the @@ -1839,6 +1850,9 @@ tab is being closed. Stable since M79; previous versions are expermental and subject to fluctuation between releases. + This histogram is of special interest to the chrome-analysis-team@. Do not + change its semantics or retire it without talking to them first. + Log of major changes: http://bit.ly/chrome-speed-metrics-changelog </summary> </histogram> @@ -1858,7 +1872,7 @@ </histogram> <histogram name="PageLoad.LayoutInstability.CumulativeShiftScore.MainFrame" - units="scorex10" expires_after="2021-06-06"> + units="scorex10" expires_after="2021-08-09"> <owner>bmcquade@chromium.org</owner> <owner>skobes@chromium.org</owner> <summary> @@ -1883,10 +1897,11 @@ </histogram> <histogram name="PageLoad.Memory.Aggregate.Max" units="KiB" - expires_after="2021-01-31"> + expires_after="2021-07-31"> <owner>cammie@chromium.org</owner> <owner>jkarlin@chromium.org</owner> <owner>johnidel@chromium.org</owner> + <owner>chrome-ads-histograms@google.com</owner> <summary> The maximum reported aggregate number of kilobytes of memory used by V8 by ad frames in this pageload. The value recorded is the maximum simultaneous @@ -1900,10 +1915,11 @@ </histogram> <histogram name="PageLoad.Memory.PerFrame.Max" units="KiB" - expires_after="2021-01-31"> + expires_after="2021-07-31"> <owner>cammie@chromium.org</owner> <owner>jkarlin@chromium.org</owner> <owner>johnidel@chromium.org</owner> + <owner>chrome-ads-histograms@google.com</owner> <summary> The maximum reported number of kilobytes of memory used by V8 by frames in the ad frame tree in this pageload. The value recorded is the maximum @@ -1926,7 +1942,7 @@ </histogram> <histogram name="PageLoad.PageTiming.ForegroundDuration" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>bmcquade@chromium.org</owner> <summary> For page loads that start in the foreground, measures the duration of time @@ -1963,7 +1979,7 @@ </histogram> <histogram name="PageLoad.PageTiming.NavigationToFirstForeground" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>bmcquade@chromium.org</owner> <owner>csharrison@chromium.org</owner> <summary> @@ -1974,7 +1990,7 @@ </histogram> <histogram name="PageLoad.PaintTiming.ForegroundToFirstContentfulPaint" - units="ms" expires_after="2021-06-06"> + units="ms" expires_after="2021-08-09"> <owner>sullivan@chromium.org</owner> <owner>speed-metrics-dev@chromium.org</owner> <summary> @@ -2048,7 +2064,7 @@ </histogram> <histogram name="PageLoad.PaintTiming.NavigationToFirstImagePaint" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>sullivan@chromium.org</owner> <owner>speed-metrics-dev@chromium.org</owner> <summary> @@ -2059,7 +2075,7 @@ </histogram> <histogram name="PageLoad.PaintTiming.NavigationToFirstPaint" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>ksakamoto@chromium.org</owner> <owner>speed-metrics-dev@chromium.org</owner> <summary> @@ -2130,7 +2146,7 @@ <histogram name="PageLoad.PaintTiming.NavigationToLargestContentfulPaint.MainFrame" - units="ms" expires_after="2021-06-06"> + units="ms" expires_after="2021-08-09"> <owner>maxlg@chromium.org</owner> <owner>speed-metrics-dev@chromium.org</owner> <summary> @@ -2171,7 +2187,7 @@ </histogram> <histogram name="PageLoad.PaintTiming.ParseStartToFirstContentfulPaint" - units="ms" expires_after="2021-06-06"> + units="ms" expires_after="2021-08-09"> <owner>bmcquade@chromium.org</owner> <owner>csharrison@chromium.org</owner> <owner>speed-metrics-dev@chromium.org</owner> @@ -2182,7 +2198,7 @@ </histogram> <histogram name="PageLoad.ParseTiming.NavigationToParseStart" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>bmcquade@chromium.org</owner> <owner>csharrison@chromium.org</owner> <summary> @@ -2214,7 +2230,7 @@ </histogram> <histogram name="PageLoad.ParseTiming.ParseBlockedOnScriptLoad" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>bmcquade@chromium.org</owner> <owner>csharrison@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/password/histograms.xml b/tools/metrics/histograms/histograms_xml/password/histograms.xml index 86a1382..e825558 100644 --- a/tools/metrics/histograms/histograms_xml/password/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/password/histograms.xml
@@ -42,7 +42,7 @@ </histogram> <histogram name="PasswordBubble.DisplayDisposition" - enum="PasswordBubbleDisplayDisposition" expires_after="2021-06-06"> + enum="PasswordBubbleDisplayDisposition" expires_after="2021-08-09"> <owner>vasilii@chromium.org</owner> <summary> When the password management bubble opened, what state was it in? @@ -50,7 +50,7 @@ </histogram> <histogram name="PasswordGeneration.Event" enum="PasswordGenerationEvent" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>jdoerrie@chromium.org</owner> <owner>kolos@chromium.org</owner> <owner>vasilii@chromium.org</owner> @@ -87,7 +87,7 @@ </histogram> <histogram name="PasswordGeneration.PopupShown" - enum="PasswordGenerationPopupShown" expires_after="M92"> + enum="PasswordGenerationPopupShown" expires_after="2021-08-09"> <owner>jdoerrie@chromium.org</owner> <owner>kazinova@google.com</owner> <summary>Records an entry if (and only if) a popup was shown.</summary> @@ -170,7 +170,7 @@ </histogram> <histogram name="PasswordManager.AccessPasswordInSettings" - enum="AccessPasswordInSettingsEvent" expires_after="M92"> + enum="AccessPasswordInSettingsEvent" expires_after="2021-08-09"> <owner>jdoerrie@chromium.org</owner> <owner>vasilii@chromium.org</owner> <summary> @@ -744,7 +744,7 @@ </histogram> <histogram base="true" name="PasswordManager.BlacklistedSitesHiRes" - units="sites" expires_after="M92"> + units="sites" expires_after="2021-08-09"> <owner>jdoerrie@chromium.org</owner> <owner>vasilii@chromium.org</owner> <summary> @@ -776,7 +776,7 @@ </histogram> <histogram name="PasswordManager.BulkCheck.CanceledTime" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>vasilii@chromium.org</owner> <owner>jdoerrie@chromium.org</owner> <summary> @@ -785,7 +785,7 @@ </histogram> <histogram name="PasswordManager.BulkCheck.CheckedCredentials" - units="credentials" expires_after="2021-06-06"> + units="credentials" expires_after="2021-08-09"> <owner>vasilii@chromium.org</owner> <owner>jdoerrie@chromium.org</owner> <summary> @@ -795,14 +795,14 @@ </histogram> <histogram name="PasswordManager.BulkCheck.Error" - enum="PasswordLeakDetectionError" expires_after="2021-06-06"> + enum="PasswordLeakDetectionError" expires_after="2021-08-09"> <owner>vasilii@chromium.org</owner> <owner>jdoerrie@chromium.org</owner> <summary>Error encountered during the password bulk check.</summary> </histogram> <histogram name="PasswordManager.BulkCheck.LeaksFound" units="credentials" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>vasilii@chromium.org</owner> <owner>jdoerrie@chromium.org</owner> <summary> @@ -831,7 +831,7 @@ </histogram> <histogram name="PasswordManager.BulkCheck.Time" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>vasilii@chromium.org</owner> <owner>jdoerrie@chromium.org</owner> <summary> @@ -840,7 +840,7 @@ </histogram> <histogram name="PasswordManager.BulkCheck.TimePerCredential" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>vasilii@chromium.org</owner> <owner>jdoerrie@chromium.org</owner> <summary> @@ -850,14 +850,14 @@ </histogram> <histogram name="PasswordManager.BulkCheck.UserAction" - enum="PasswordCheckInteraction" expires_after="2021-06-06"> + enum="PasswordCheckInteraction" expires_after="2021-08-09"> <owner>jdoerrie@chromium.org</owner> <owner>vasilii@chromium.org</owner> <summary>User actions performed on the Password Check settings page.</summary> </histogram> <histogram name="PasswordManager.BulkCheck.UserActionAndroid" - enum="PasswordCheckUIUserActionAndroid" expires_after="2021-06-06"> + enum="PasswordCheckUIUserActionAndroid" expires_after="2021-08-09"> <owner>ioanap@chromium.org</owner> <owner>fhorschigg@chromium.org</owner> <summary>User actions performed on the Password Check settings view.</summary> @@ -1098,7 +1098,7 @@ </histogram> <histogram name="PasswordManager.FillingAssistance" - enum="PasswordManagerFillingAssistance" expires_after="2021-06-06"> + enum="PasswordManagerFillingAssistance" expires_after="2021-08-09"> <owner>jdoerrie@chromium.org</owner> <owner>battre@chromium.org</owner> <summary> @@ -1144,7 +1144,7 @@ </histogram> <histogram name="PasswordManager.FirstRendererFillingResult" - enum="PasswordManagerFirstRendererFillingResult" expires_after="M92"> + enum="PasswordManagerFirstRendererFillingResult" expires_after="2021-08-09"> <owner>jdoerrie@chromium.org</owner> <owner>battre@chromium.org</owner> <summary> @@ -1157,7 +1157,7 @@ </histogram> <histogram name="PasswordManager.FirstWaitForUsernameReason" - enum="PasswordManagerFirstWaitForUsernameReason" expires_after="M92"> + enum="PasswordManagerFirstWaitForUsernameReason" expires_after="2021-08-09"> <owner>jdoerrie@chromium.org</owner> <owner>battre@chromium.org</owner> <summary> @@ -1348,7 +1348,7 @@ </histogram> <histogram name="PasswordManager.JavaScriptOnlyValueInSubmittedForm" - enum="JavaScriptOnlyValueInPasswordForm" expires_after="M92"> + enum="JavaScriptOnlyValueInPasswordForm" expires_after="2021-08-09"> <owner>jdoerrie@chromium.org</owner> <owner>battre@chromium.org</owner> <summary> @@ -1358,7 +1358,7 @@ </histogram> <histogram name="PasswordManager.LeakDetection.AccessTokenFetchStatus" - enum="GoogleServiceAuthError" expires_after="M92"> + enum="GoogleServiceAuthError" expires_after="2021-08-09"> <owner>jdoerrie@chromium.org</owner> <owner>vasilii@chromium.org</owner> <summary> @@ -1368,7 +1368,7 @@ </histogram> <histogram name="PasswordManager.LeakDetection.AccessTokenNetErrorCode" - enum="NetErrorCodes" expires_after="M92"> + enum="NetErrorCodes" expires_after="2021-08-09"> <owner>jdoerrie@chromium.org</owner> <owner>vasilii@chromium.org</owner> <summary> @@ -1378,21 +1378,22 @@ </histogram> <histogram name="PasswordManager.LeakDetection.AnalyzeSingleLeakResponseResult" - enum="PasswordAnalyzeLeakResponseResult" expires_after="M92"> + enum="PasswordAnalyzeLeakResponseResult" expires_after="2021-08-09"> <owner>jdoerrie@chromium.org</owner> <owner>vasilii@chromium.org</owner> <summary>Result of analyzing a single leak response.</summary> </histogram> <histogram name="PasswordManager.LeakDetection.AnalyzeSingleLeakResponseTime" - units="ms" expires_after="M92"> + units="ms" expires_after="2021-08-09"> <owner>jdoerrie@chromium.org</owner> <owner>vasilii@chromium.org</owner> <summary>The time it took to analyze a single leak lookup response.</summary> </histogram> <histogram name="PasswordManager.LeakDetection.DialogDismissalReason" - enum="PasswordLeakDetectionDialogDismissalReason" expires_after="M92"> + enum="PasswordLeakDetectionDialogDismissalReason" + expires_after="2021-08-09"> <owner>jdoerrie@chromium.org</owner> <owner>vasilii@chromium.org</owner> <summary> @@ -1421,7 +1422,7 @@ </histogram> <histogram name="PasswordManager.LeakDetection.HttpResponseCode" - enum="HttpResponseCode" expires_after="M92"> + enum="HttpResponseCode" expires_after="2021-08-09"> <owner>jdoerrie@chromium.org</owner> <owner>vasilii@chromium.org</owner> <summary> @@ -1431,7 +1432,7 @@ </histogram> <histogram name="PasswordManager.LeakDetection.IsPasswordReused" enum="Boolean" - expires_after="M92"> + expires_after="2021-08-09"> <owner>vasilii@chromium.org</owner> <owner>jdoerrie@chromium.org</owner> <summary> @@ -1441,7 +1442,7 @@ </histogram> <histogram name="PasswordManager.LeakDetection.IsPasswordSaved" enum="Boolean" - expires_after="M92"> + expires_after="2021-08-09"> <owner>vasilii@chromium.org</owner> <owner>jdoerrie@chromium.org</owner> <summary> @@ -1460,7 +1461,7 @@ </histogram> <histogram name="PasswordManager.LeakDetection.LookupSingleLeakResponseResult" - enum="PasswordLeakLookupResponseResult" expires_after="M92"> + enum="PasswordLeakLookupResponseResult" expires_after="2021-08-09"> <owner>jdoerrie@chromium.org</owner> <owner>vasilii@chromium.org</owner> <summary> @@ -1480,7 +1481,7 @@ </histogram> <histogram name="PasswordManager.LeakDetection.NotifyIsLeakedTime" units="ms" - expires_after="M92"> + expires_after="2021-08-09"> <owner>jdoerrie@chromium.org</owner> <owner>vasilii@chromium.org</owner> <summary> @@ -1490,7 +1491,7 @@ </histogram> <histogram name="PasswordManager.LeakDetection.ObtainAccessTokenTime" - units="ms" expires_after="M92"> + units="ms" expires_after="2021-08-09"> <owner>jdoerrie@chromium.org</owner> <owner>vasilii@chromium.org</owner> <summary> @@ -1500,7 +1501,7 @@ </histogram> <histogram name="PasswordManager.LeakDetection.PrepareSingleLeakRequestTime" - units="ms" expires_after="M92"> + units="ms" expires_after="2021-08-09"> <owner>jdoerrie@chromium.org</owner> <owner>vasilii@chromium.org</owner> <summary> @@ -1509,7 +1510,7 @@ </histogram> <histogram name="PasswordManager.LeakDetection.ReceiveSingleLeakResponseTime" - units="ms" expires_after="M92"> + units="ms" expires_after="2021-08-09"> <owner>jdoerrie@chromium.org</owner> <owner>vasilii@chromium.org</owner> <summary> @@ -1519,7 +1520,7 @@ </histogram> <histogram name="PasswordManager.LeakDetection.SingleLeakResponsePrefixes" - units="prefixes" expires_after="M92"> + units="prefixes" expires_after="2021-08-09"> <owner>jdoerrie@chromium.org</owner> <owner>vasilii@chromium.org</owner> <summary> @@ -1529,7 +1530,7 @@ </histogram> <histogram name="PasswordManager.LeakDetection.SingleLeakResponseSize" - units="bytes" expires_after="M92"> + units="bytes" expires_after="2021-08-09"> <owner>jdoerrie@chromium.org</owner> <owner>vasilii@chromium.org</owner> <summary> @@ -1546,7 +1547,7 @@ </histogram> <histogram name="PasswordManager.ManagePasswordsReferrer" - enum="ManagePasswordsReferrer" expires_after="M92"> + enum="ManagePasswordsReferrer" expires_after="2021-08-09"> <owner>jdoerrie@chromium.org</owner> <owner>vasilii@chromium.org</owner> <summary> @@ -1705,7 +1706,7 @@ </histogram> <histogram name="PasswordManager.PasswordDropdownItemSelected" - enum="PasswordDropdownSelectedOption" expires_after="2021-06-06"> + enum="PasswordDropdownSelectedOption" expires_after="2021-08-09"> <owner>jdoerrie@chromium.org</owner> <owner>vasilii@chromium.org</owner> <summary> @@ -1714,14 +1715,14 @@ </histogram> <histogram name="PasswordManager.PasswordDropdownShown" - enum="PasswordDropdownState" expires_after="2021-06-06"> + enum="PasswordDropdownState" expires_after="2021-08-09"> <owner>jdoerrie@chromium.org</owner> <owner>vasilii@chromium.org</owner> <summary>Logs the state of the password dropdown when it's shown.</summary> </histogram> <histogram name="PasswordManager.PasswordEditUpdatedValues" - enum="PasswordEditUpdatedValues" expires_after="M92"> + enum="PasswordEditUpdatedValues" expires_after="2021-08-09"> <owner>vsemeniuk@google.com</owner> <owner>vasilii@chromium.org</owner> <summary> @@ -1808,7 +1809,7 @@ </histogram> <histogram name="PasswordManager.PasswordScriptsFetcher.CacheState" - enum="PasswordScriptsFetcherCacheState" expires_after="M92"> + enum="PasswordScriptsFetcherCacheState" expires_after="2021-08-09"> <owner>kolos@chromium.org</owner> <owner>battre@chromium.org</owner> <summary> @@ -1819,7 +1820,7 @@ <histogram name="PasswordManager.PasswordScriptsFetcher.HttpResponseAndNetErrorCode" - enum="CombinedHttpResponseAndNetErrorCode" expires_after="M92"> + enum="CombinedHttpResponseAndNetErrorCode" expires_after="2021-08-09"> <owner>kolos@chromium.org</owner> <owner>battre@chromium.org</owner> <summary> @@ -1829,14 +1830,14 @@ </histogram> <histogram name="PasswordManager.PasswordScriptsFetcher.ParsingResult" - enum="PasswordScriptsFetcherParsingResult" expires_after="M92"> + enum="PasswordScriptsFetcherParsingResult" expires_after="2021-08-09"> <owner>kolos@chromium.org</owner> <owner>battre@chromium.org</owner> <summary>Result of parsing of a list of available password scripts.</summary> </histogram> <histogram name="PasswordManager.PasswordScriptsFetcher.ResponseTime" - units="ms" expires_after="M92"> + units="ms" expires_after="2021-08-09"> <owner>kolos@chromium.org</owner> <owner>battre@chromium.org</owner> <summary> @@ -1869,7 +1870,7 @@ </histogram> <histogram name="PasswordManager.PasswordSyncState" enum="PasswordSyncState" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>jdoerrie@chromium.org</owner> <owner>vasilii@chromium.org</owner> <summary> @@ -1912,7 +1913,7 @@ </histogram> <histogram name="PasswordManager.RemoveCompromisedCredentials" - enum="PasswordStoreChange" expires_after="2021-06-06"> + enum="PasswordStoreChange" expires_after="2021-08-09"> <owner>bdea@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <summary> @@ -1922,7 +1923,7 @@ </histogram> <histogram name="PasswordManager.RemoveCompromisedCredentials.RemoveReason" - enum="RemoveCompromisedCredentialsReason" expires_after="2021-06-06"> + enum="RemoveCompromisedCredentialsReason" expires_after="2021-08-09"> <owner>bdea@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <summary> @@ -1941,7 +1942,7 @@ </histogram> <histogram name="PasswordManager.RequirementsSpecFetcher.NetErrorCode" - enum="NetErrorCodes" expires_after="2021-06-06"> + enum="NetErrorCodes" expires_after="2021-08-09"> <owner>battre@chromium.org</owner> <owner>jdoerrie@chromium.org</owner> <summary> @@ -2002,7 +2003,7 @@ </histogram> <histogram name="PasswordManager.SaveUIDismissalReason" - enum="PasswordManagerUIDismissalReason" expires_after="2021-06-06"> + enum="PasswordManagerUIDismissalReason" expires_after="2021-08-09"> <!-- Name completed by histogram_suffixes name="PasswordAccountStorageUserState" --> <owner>vasilii@chromium.org</owner> @@ -2023,7 +2024,7 @@ </histogram> <histogram name="PasswordManager.SavingOnUsernameFirstFlow" - enum="SavingOnUsernameFirstFlow" expires_after="M92"> + enum="SavingOnUsernameFirstFlow" expires_after="2021-08-09"> <owner>jdoerrie@chromium.org</owner> <owner>vasilii@chromium.org</owner> <summary> @@ -2034,7 +2035,7 @@ </histogram> <histogram name="PasswordManager.StoreDecryptionResult" - enum="PasswordDecryptionResult" expires_after="2021-06-01"> + enum="PasswordDecryptionResult" expires_after="2021-08-09"> <owner>cfroussios@chromium.org</owner> <owner>jdoerrie@chromium.org</owner> <summary> @@ -2200,7 +2201,7 @@ </histogram> <histogram name="PasswordManager.TouchToFill.CredentialIndex" units="index" - expires_after="M92"> + expires_after="2021-08-09"> <owner>jdoerrie@chromium.org</owner> <owner>fhorschig@chromium.org</owner> <summary> @@ -2210,7 +2211,7 @@ </histogram> <histogram name="PasswordManager.TouchToFill.DismissalReason" - enum="BottomSheet.StateChangeReason" expires_after="2021-06-06"> + enum="BottomSheet.StateChangeReason" expires_after="2021-08-09"> <owner>jdoerrie@chromium.org</owner> <owner>fhorschig@chromium.org</owner> <summary> @@ -2245,7 +2246,7 @@ </histogram> <histogram name="PasswordManager.UpdateUIDismissalReason" - enum="PasswordManagerUIDismissalReason" expires_after="2021-06-06"> + enum="PasswordManagerUIDismissalReason" expires_after="2021-08-09"> <owner>vasilii@chromium.org</owner> <summary>Why was the update password UI (bubble or infobar) closed?</summary> </histogram> @@ -2281,7 +2282,7 @@ </histogram> <histogram name="PasswordManager.WeakCheck.CheckedPasswords" units="passwords" - expires_after="M92"> + expires_after="2021-08-09"> <owner>jdoerrie@chromium.org</owner> <owner>vasilii@chromium.org</owner> <summary> @@ -2290,7 +2291,7 @@ </histogram> <histogram name="PasswordManager.WeakCheck.PasswordScore" - enum="PasswordWeaknessScore" expires_after="M92"> + enum="PasswordWeaknessScore" expires_after="2021-08-09"> <owner>jdoerrie@chromium.org</owner> <owner>vasilii@chromium.org</owner> <summary> @@ -2299,14 +2300,15 @@ </summary> </histogram> -<histogram name="PasswordManager.WeakCheck.Time" units="ms" expires_after="M92"> +<histogram name="PasswordManager.WeakCheck.Time" units="ms" + expires_after="2021-08-09"> <owner>jdoerrie@chromium.org</owner> <owner>vasilii@chromium.org</owner> <summary>The time it took to complete the passwords weak check.</summary> </histogram> <histogram name="PasswordManager.WeakCheck.WeakPasswords" units="passwords" - expires_after="M92"> + expires_after="2021-08-09"> <owner>jdoerrie@chromium.org</owner> <owner>vasilii@chromium.org</owner> <summary> @@ -2316,7 +2318,7 @@ <histogram name="PasswordManager.WellKnownChangePassword.GetChangePasswordUsage" - enum="GetChangePasswordUrlMetric" expires_after="2021-06-06"> + enum="GetChangePasswordUrlMetric" expires_after="2021-08-09"> <owner>jdoerrie@chromium.org</owner> <owner>vasilii@chromium.org</owner> <summary> @@ -2346,7 +2348,7 @@ </histogram> <histogram name="PasswordManager.WellKnownChangePassword.GstaticFetchResult" - enum="ChangePasswordUrlFetchResult" expires_after="2021-06-06"> + enum="ChangePasswordUrlFetchResult" expires_after="2021-08-09"> <owner>jdoerrie@chromium.org</owner> <owner>vasilii@chromium.org</owner> <summary> @@ -2356,7 +2358,7 @@ </histogram> <histogram name="PasswordManager.WellKnownChangePassword.GstaticFetchTime" - units="ms" expires_after="2021-06-06"> + units="ms" expires_after="2021-08-09"> <owner>jdoerrie@chromium.org</owner> <owner>vasilii@chromium.org</owner> <summary>Logs the loading time for the gstatic file request.</summary> @@ -2494,7 +2496,7 @@ </histogram> <histogram name="PasswordProtection.RequestNetworkDuration" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>vakh@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/permissions/histograms.xml b/tools/metrics/histograms/histograms_xml/permissions/histograms.xml index 513215c5..6aa69c1 100644 --- a/tools/metrics/histograms/histograms_xml/permissions/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/permissions/histograms.xml
@@ -181,7 +181,7 @@ </histogram> <histogram name="Permissions.CrowdDeny.PreloadData.NotificationUxQuality" - enum="CrowdDenyNotificationUxQuality" expires_after="2021-06-06"> + enum="CrowdDenyNotificationUxQuality" expires_after="2021-08-09"> <owner>andypaicu@chromium.org</owner> <owner>engedy@chromium.org</owner> <owner>hkamila@chromium.org</owner> @@ -214,7 +214,7 @@ </histogram> <histogram name="Permissions.CrowdDeny.SafeBrowsing.RequestDuration" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>andypaicu@chromium.org</owner> <owner>engedy@chromium.org</owner> <owner>hkamila@chromium.org</owner> @@ -226,7 +226,7 @@ </histogram> <histogram name="Permissions.CrowdDeny.SafeBrowsing.Verdict" - enum="CrowdDenySafeBrowsingVerdict" expires_after="2021-06-06"> + enum="CrowdDenySafeBrowsingVerdict" expires_after="2021-08-09"> <owner>andypaicu@chromium.org</owner> <owner>engedy@chromium.org</owner> <owner>hkamila@chromium.org</owner> @@ -512,7 +512,7 @@ <histogram name="Permissions.QuietNotificationPrompts.DidEnableAdapativelyInPrefs" - enum="Boolean" expires_after="2021-06-06"> + enum="Boolean" expires_after="2021-08-09"> <owner>andypaicu@chromium.org</owner> <owner>engedy@chromium.org</owner> <owner>hkamila@chromium.org</owner> @@ -524,7 +524,7 @@ <histogram name="Permissions.QuietNotificationPrompts.EnabledStateInPrefsChangedTo" - enum="BooleanEnabled" expires_after="2021-06-06"> + enum="BooleanEnabled" expires_after="2021-08-09"> <owner>andypaicu@chromium.org</owner> <owner>engedy@chromium.org</owner> <owner>hkamila@chromium.org</owner> @@ -535,7 +535,7 @@ </histogram> <histogram name="Permissions.QuietNotificationPrompts.IsEnabledInPrefs" - enum="BooleanEnabled" expires_after="2021-06-06"> + enum="BooleanEnabled" expires_after="2021-08-09"> <owner>andypaicu@chromium.org</owner> <owner>engedy@chromium.org</owner> <owner>hkamila@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/platform/histograms.xml b/tools/metrics/histograms/histograms_xml/platform/histograms.xml index dfe3ec13a..30c3358 100644 --- a/tools/metrics/histograms/histograms_xml/platform/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/platform/histograms.xml
@@ -226,7 +226,7 @@ </histogram> <histogram name="Platform.CrOS.CrashSenderRemoveReason" - enum="CrosCrashSenderRemoveReason" expires_after="2021-06-06"> + enum="CrosCrashSenderRemoveReason" expires_after="2021-08-09"> <owner>iby@chromium.org</owner> <owner>mutexlox@chromium.org</owner> <owner>cros-telemetry@google.com</owner> @@ -360,7 +360,7 @@ </histogram> <histogram name="Platform.DetachableBase.RWUpdateResult" - enum="DetachableBaseRWUpdateResult" expires_after="2021-06-02"> + enum="DetachableBaseRWUpdateResult" expires_after="2021-08-09"> <owner>drinkcat@chromium.org</owner> <owner>fshao@chromium.org</owner> <owner>chromeos-kukui@google.com</owner> @@ -626,7 +626,7 @@ </summary> </histogram> -<histogram name="Platform.Memory.Gpu" units="MiB" expires_after="2021-06-06"> +<histogram name="Platform.Memory.Gpu" units="MiB" expires_after="2021-08-09"> <!-- Name completed by histogram_suffixes name="ProcessMemoryType" --> <owner>sonnyrao@chromium.org</owner> @@ -945,7 +945,7 @@ </summary> </histogram> -<histogram name="Platform.SwapInDaily" units="pages" expires_after="2021-04-28"> +<histogram name="Platform.SwapInDaily" units="pages" expires_after="2021-08-09"> <owner>asavery@chromium.org</owner> <owner>chromeos-storage@google.com</owner> <summary>Number of pages swapped IN over a day, sampled daily.</summary>
diff --git a/tools/metrics/histograms/histograms_xml/plugin/histograms.xml b/tools/metrics/histograms/histograms_xml/plugin/histograms.xml index f084f2f..907b42a8 100644 --- a/tools/metrics/histograms/histograms_xml/plugin/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/plugin/histograms.xml
@@ -28,7 +28,7 @@ </histogram> <histogram name="Plugin.FlashUsage" enum="FlashUsage" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>yzshen@chromium.org</owner> <owner>thestig@chromium.org</owner> <summary>Collects Flash usage data.</summary> @@ -132,7 +132,7 @@ </histogram> <histogram name="PluginVm.EngagementTime.Background" units="ms" - expires_after="2021-04-18"> + expires_after="2021-08-09"> <owner>timloh@google.com</owner> <owner>joelhockey@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/power/histograms.xml b/tools/metrics/histograms/histograms_xml/power/histograms.xml index ad14612..9c8789a 100644 --- a/tools/metrics/histograms/histograms_xml/power/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/power/histograms.xml
@@ -64,7 +64,7 @@ </histogram> <histogram name="Power.BatteryChargeHealth" units="%" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>tbroch@chromium.org</owner> <summary> Chrome OS battery charge health percentage. Sampled once when device starts @@ -82,7 +82,7 @@ </histogram> <histogram name="Power.BatteryDischargeRateWhileSuspended" units="mW" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>tbroch@chromium.org</owner> <summary> Chrome OS battery discharge rate in mW while the system was suspended, @@ -102,7 +102,7 @@ </summary> </histogram> -<histogram name="Power.BatteryPercentDrop" units="%" expires_after="2021-06-06"> +<histogram name="Power.BatteryPercentDrop" units="%" expires_after="2021-08-09"> <owner>ryansturm@chromium.org</owner> <owner>tbansal@chromium.org</owner> <summary> @@ -154,7 +154,7 @@ </histogram> <histogram name="Power.BatteryRemainingWhenChargeStarts" units="%" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>tbroch@chromium.org</owner> <summary> Chrome OS remaining battery charge as percent of the maximum battery charge, @@ -243,7 +243,7 @@ </histogram> <histogram name="Power.CpuTimeSecondsPerThreadType" - enum="CpuTimeMetricsThreadType" expires_after="2021-06-10"> + enum="CpuTimeMetricsThreadType" expires_after="2021-08-09"> <owner>eseckler@chromium.org</owner> <owner>skyostil@chromium.org</owner> <summary> @@ -593,7 +593,7 @@ </histogram> <histogram name="Power.IdleSuspendCountDaily" units="count" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>tbroch@chromium.org</owner> <owner>napper@chromium.org</owner> <summary> @@ -720,7 +720,7 @@ </histogram> <histogram name="Power.LidClosedSuspendCountDaily" units="count" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>tbroch@chromium.org</owner> <summary> Number of times that that the system has suspended in response to its lid @@ -871,7 +871,7 @@ </histogram> <histogram name="Power.PowerButtonPressInTabletMode" - enum="PowerButtonPressType" expires_after="2021-06-06"> + enum="PowerButtonPressType" expires_after="2021-08-09"> <owner>minch@chromium.org</owner> <owner>xdai@chromium.org</owner> <summary> @@ -930,7 +930,7 @@ </histogram> <histogram name="Power.SuspendAttempt" enum="SuspendAttempt" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>tbroch@chromium.org</owner> <summary> The number of suspend attempts on Chrome OS. Samples are reported before @@ -940,7 +940,7 @@ </histogram> <histogram name="Power.SuspendAttemptsBeforeCancel" units="units" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>tbroch@chromium.org</owner> <summary> The number of suspend attempts performed for a single suspend request (e.g. @@ -951,7 +951,7 @@ </histogram> <histogram name="Power.SuspendAttemptsBeforeSuccess" units="units" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>tbroch@chromium.org</owner> <summary> The number of suspend attempts performed for a single suspend request (e.g. @@ -961,7 +961,7 @@ </histogram> <histogram name="Power.SuspendResult" enum="SuspendResult" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>tbroch@chromium.org</owner> <summary> The results of suspend attempts on Chrome OS. Samples are reported after @@ -1060,7 +1060,7 @@ <histogram name="PowerML.SmartDimComponent.LoadComponentEvent" enum="PowerMLSmartDimComponentLoadComponentEvent" - expires_after="2021-04-25"> + expires_after="2021-08-09"> <owner>alanlxl@chromium.org</owner> <owner>amoylan@chromium.org</owner> <owner>napper@chromium.org</owner> @@ -1071,7 +1071,7 @@ </histogram> <histogram name="PowerML.SmartDimComponent.VersionType" - enum="PowerMLSmartDimComponentVersionType" expires_after="2021-04-25"> + enum="PowerMLSmartDimComponentVersionType" expires_after="2021-08-09"> <owner>alanlxl@chromium.org</owner> <owner>amoylan@chromium.org</owner> <owner>napper@chromium.org</owner> @@ -1082,7 +1082,7 @@ </histogram> <histogram name="PowerML.SmartDimComponent.WorkerType" - enum="PowerMLSmartDimComponentWorkerType" expires_after="2021-04-25"> + enum="PowerMLSmartDimComponentWorkerType" expires_after="2021-08-09"> <owner>alanlxl@chromium.org</owner> <owner>amoylan@chromium.org</owner> <owner>napper@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/print/histograms.xml b/tools/metrics/histograms/histograms_xml/print/histograms.xml index 341a93f..f8ffcee6 100644 --- a/tools/metrics/histograms/histograms_xml/print/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/print/histograms.xml
@@ -225,7 +225,7 @@ </histogram> <histogram name="PrintPreview.UserAction" enum="PrintPreviewUserActionType" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>thestig@chromium.org</owner> <owner>awscreen@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/printing/histograms.xml b/tools/metrics/histograms/histograms_xml/printing/histograms.xml index 6b51e4c3..a96dab4 100644 --- a/tools/metrics/histograms/histograms_xml/printing/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/printing/histograms.xml
@@ -199,7 +199,7 @@ </histogram> <histogram name="Printing.CUPS.MigratedMakeAndModel" enum="BooleanMigrated" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>luum@chromium.org</owner> <owner>cros-printing-dev@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/profile/histograms.xml b/tools/metrics/histograms/histograms_xml/profile/histograms.xml index 1350583..b538945 100644 --- a/tools/metrics/histograms/histograms_xml/profile/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/profile/histograms.xml
@@ -52,7 +52,7 @@ </histogram> <histogram name="Profile.AllAccounts.Names" enum="ProfileAllAccountsNames" - expires_after="2021-05-16"> + expires_after="2021-08-09"> <owner>jkrcal@chromium.org</owner> <owner>droger@chromium.org</owner> <summary> @@ -129,7 +129,7 @@ </histogram> <histogram name="Profile.CreateResult" enum="ProfileCreateResult" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>treib@chromium.org</owner> <owner>rogerta@chromium.org</owner> <owner>msarda@chromium.org</owner> @@ -229,7 +229,7 @@ </histogram> <histogram name="Profile.Guest.ForcedByPolicy" enum="BooleanForced" - expires_after="M92"> + expires_after="2021-08-09"> <owner>rhalavati@chromium.org</owner> <owner>chrome-privacy-core@google.com</owner> <summary> @@ -308,7 +308,7 @@ </histogram> <histogram name="Profile.Menu.OpenedAfterAvatarAnimation" units="ms" - expires_after="2021-04-15"> + expires_after="2021-08-09"> <owner>droger@chromium.org</owner> <owner>jkrcal@chromium.org</owner> <summary> @@ -584,7 +584,7 @@ </histogram> <histogram name="Profile.SyncCustomize" enum="ProfileSyncCustomize" - expires_after="M92"> + expires_after="2021-08-09"> <owner>msalama@chromium.org</owner> <owner>chrome-signin-team@google.com</owner> <summary> @@ -596,7 +596,7 @@ </histogram> <histogram name="Profile.TimeToOpenUserManagerUpTo1min" units="ms" - expires_after="2021-05-02"> + expires_after="2021-08-09"> <owner>msarda@chromium.org</owner> <owner>droger@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/quota/histograms.xml b/tools/metrics/histograms/histograms_xml/quota/histograms.xml index 136885f..d1f3f1d6 100644 --- a/tools/metrics/histograms/histograms_xml/quota/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/quota/histograms.xml
@@ -139,7 +139,7 @@ </histogram> <histogram name="Quota.GlobalUsageOfTemporaryStorage" units="MB" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>jarrydg@chromium.org</owner> <summary>Global usage of temporary storage.</summary> </histogram> @@ -246,7 +246,7 @@ <summary>Time spent to an eviction round.</summary> </histogram> -<histogram name="Quota.TotalDiskSpace" units="MB" expires_after="2021-06-06"> +<histogram name="Quota.TotalDiskSpace" units="MB" expires_after="2021-08-09"> <owner>jarrydg@chromium.org</owner> <summary> Total disk space for the storage directory. Logged at irregular intervals.
diff --git a/tools/metrics/histograms/histograms_xml/renderer/histograms.xml b/tools/metrics/histograms/histograms_xml/renderer/histograms.xml index 3501550e..7d626fcf 100644 --- a/tools/metrics/histograms/histograms_xml/renderer/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/renderer/histograms.xml
@@ -200,7 +200,7 @@ </histogram> <histogram base="true" name="RendererScheduler.QueueingDurationPerQueueType" - units="ms" expires_after="2021-06-06"> + units="ms" expires_after="2021-08-09"> <!-- Name completed by histogram_suffixes name="RendererScheduler.QueueType" --> <owner>kdillon@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/renderer4/histograms.xml b/tools/metrics/histograms/histograms_xml/renderer4/histograms.xml index 59a2585..a7bf634d 100644 --- a/tools/metrics/histograms/histograms_xml/renderer4/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/renderer4/histograms.xml
@@ -36,7 +36,7 @@ </histogram> <histogram name="Renderer4.Browser.RasterTaskTotalDuration" - units="microseconds" expires_after="2021-06-01"> + units="microseconds" expires_after="2021-08-09"> <owner>khushalsagar@chromium.org</owner> <owner>chrome-gpu@google.com</owner> <summary> @@ -71,7 +71,7 @@ </histogram> <histogram name="Renderer4.GpuImageDecodeState" enum="GpuImageUsageState" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>cblume@chromium.org</owner> <owner>vmpstr@chromium.org</owner> <summary> @@ -81,7 +81,7 @@ </histogram> <histogram name="Renderer4.GpuImageDecodeState.CachePeakUsagePercent" - units="units" expires_after="2021-06-06"> + units="units" expires_after="2021-08-09"> <owner>sashamcintosh@chromium.org</owner> <owner>ericrk@chromium.org</owner> <summary> @@ -158,7 +158,7 @@ </histogram> <histogram base="true" name="Renderer4.ImageUploadTaskDurationUs" - units="microseconds" expires_after="2021-05-30"> + units="microseconds" expires_after="2021-08-09"> <!-- Name completed by histogram_suffixes name="DecodedImageType" --> <owner>sashamcintosh@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/safe_browsing/histograms.xml b/tools/metrics/histograms/histograms_xml/safe_browsing/histograms.xml index e8899f8d..4931119 100644 --- a/tools/metrics/histograms/histograms_xml/safe_browsing/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/safe_browsing/histograms.xml
@@ -78,7 +78,7 @@ </histogram> <histogram name="SafeBrowsing.BlockingPage.RequestDestination" - enum="RequestDestination" expires_after="2021-05-30"> + enum="RequestDestination" expires_after="2021-08-09"> <owner>xinghuilu@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <summary> @@ -694,7 +694,7 @@ </histogram> <histogram name="SafeBrowsing.FileTypeUpdate.DynamicUpdateVersion" - units="FileTypePolicies Version" expires_after="2021-04-13"> + units="FileTypePolicies Version" expires_after="2021-08-09"> <owner>drubery@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <summary> @@ -822,7 +822,7 @@ </histogram> <histogram name="SafeBrowsing.Pref.Enhanced" enum="BooleanEnabled" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>bdea@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <summary> @@ -832,7 +832,7 @@ </histogram> <histogram name="SafeBrowsing.Pref.Extended" enum="BooleanEnabled" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>vakh@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <summary> @@ -842,7 +842,7 @@ </histogram> <histogram name="SafeBrowsing.Pref.General" enum="BooleanEnabled" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>vakh@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <summary> @@ -1187,7 +1187,7 @@ </histogram> <histogram name="SafeBrowsing.TokenFetcher.ErrorType" - enum="GoogleServiceAuthError" expires_after="2021-06-06"> + enum="GoogleServiceAuthError" expires_after="2021-08-09"> <owner>xinghuilu@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <summary> @@ -1382,7 +1382,7 @@ <histogram name="SafeBrowsing.V4LocalDatabaseManager.TimeSinceLastUpdateResponse" - units="ms" expires_after="2021-05-09"> + units="ms" expires_after="2021-08-09"> <owner>ajuma@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/sb_client/histograms.xml b/tools/metrics/histograms/histograms_xml/sb_client/histograms.xml index 7211130..cfe1786 100644 --- a/tools/metrics/histograms/histograms_xml/sb_client/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/sb_client/histograms.xml
@@ -630,7 +630,7 @@ </histogram> <histogram name="SBClientPhishing.VisualFeatureTime" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>drubery@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/search/histograms.xml b/tools/metrics/histograms/histograms_xml/search/histograms.xml index e94e728..d97c776ec 100644 --- a/tools/metrics/histograms/histograms_xml/search/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/search/histograms.xml
@@ -214,7 +214,7 @@ </histogram> <histogram name="Search.ContextualSearch.ResolveRequested" - enum="ContextualSearchGestureIsTap" expires_after="M91"> + enum="ContextualSearchGestureIsTap" expires_after="2021-08-09"> <owner>donnd@chromium.org</owner> <owner>twellington@chromium.org</owner> <summary> @@ -225,7 +225,7 @@ </histogram> <histogram name="Search.ContextualSearch.SelectionExpanded" - enum="ContextualSearchGestureIsTap" expires_after="M92"> + enum="ContextualSearchGestureIsTap" expires_after="2021-08-09"> <owner>donnd@chromium.org</owner> <owner>twellington@chromium.org</owner> <summary> @@ -1288,7 +1288,7 @@ </histogram> <histogram name="Search.QueryTiles.FetcherNetErrorCode" enum="NetErrorCodes" - expires_after="M91"> + expires_after="2021-08-09"> <owner>hesen@chromium.org</owner> <owner>chrome-upboarding-eng@google.com</owner> <summary>Records the net error code get from TileFetcher.</summary>
diff --git a/tools/metrics/histograms/histograms_xml/security/histograms.xml b/tools/metrics/histograms/histograms_xml/security/histograms.xml index 0760514..7cd53b77 100644 --- a/tools/metrics/histograms/histograms_xml/security/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/security/histograms.xml
@@ -52,7 +52,7 @@ </histogram> <histogram name="Security.LegacyTLS.DownloadStarted" enum="Boolean" - expires_after="M92"> + expires_after="2021-08-09"> <owner>cthomp@chromium.org</owner> <owner>security-enamel@chromium.org</owner> <summary> @@ -66,7 +66,7 @@ </histogram> <histogram name="Security.LegacyTLS.FormSubmission" enum="Boolean" - expires_after="M92"> + expires_after="2021-08-09"> <owner>cthomp@chromium.org</owner> <owner>security-enamel@chromium.org</owner> <summary> @@ -78,7 +78,7 @@ </histogram> <histogram name="Security.LegacyTLS.OnCommit" enum="Boolean" - expires_after="M92"> + expires_after="2021-08-09"> <owner>cthomp@chromium.org</owner> <owner>estark@chromium.org</owner> <owner>security-enamel@chromium.org</owner> @@ -110,7 +110,7 @@ </histogram> <histogram base="true" name="Security.PageEndReason" enum="PageEndReason" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>cthomp@chromium.org</owner> <owner>security-enamel@chromium.org</owner> <summary> @@ -195,7 +195,7 @@ </histogram> <histogram name="Security.PageInfo.TimeOpen.Action" units="units" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>cthomp@chromium.org</owner> <owner>security-enamel@chromium.org</owner> <summary> @@ -205,7 +205,7 @@ </histogram> <histogram name="Security.PageInfo.TimeOpen.NoAction" units="units" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>cthomp@chromium.org</owner> <owner>security-enamel@chromium.org</owner> <summary> @@ -444,7 +444,7 @@ </histogram> <histogram name="Security.SCTAuditing.OptIn.CacheHWM" units="reports" - expires_after="M92"> + expires_after="2021-08-09"> <owner>cthomp@chromium.org</owner> <owner>security-enamel@chromium.org</owner> <summary> @@ -456,7 +456,7 @@ </histogram> <histogram name="Security.SCTAuditing.OptIn.ReportDeduplicated" enum="Boolean" - expires_after="M92"> + expires_after="2021-08-09"> <owner>cthomp@chromium.org</owner> <owner>security-enamel@chromium.org</owner> <summary> @@ -467,7 +467,7 @@ </histogram> <histogram name="Security.SCTAuditing.OptIn.ReportSampled" enum="Boolean" - expires_after="M92"> + expires_after="2021-08-09"> <owner>cthomp@chromium.org</owner> <owner>security-enamel@chromium.org</owner> <summary> @@ -478,7 +478,7 @@ </histogram> <histogram name="Security.SCTAuditing.OptIn.ReportSize" units="bytes" - expires_after="M92"> + expires_after="2021-08-09"> <owner>cthomp@chromium.org</owner> <owner>security-enamel@chromium.org</owner> <summary> @@ -488,7 +488,7 @@ </histogram> <histogram name="Security.SCTAuditing.OptIn.ReportSucceeded" enum="Boolean" - expires_after="M92"> + expires_after="2021-08-09"> <owner>cthomp@chromium.org</owner> <owner>security-enamel@chromium.org</owner> <summary> @@ -587,7 +587,7 @@ </histogram> <histogram name="Security.SecurityLevel.OnCommit" enum="SecurityLevel" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>cthomp@chromium.org</owner> <owner>security-enamel@chromium.org</owner> <summary> @@ -599,7 +599,7 @@ </histogram> <histogram name="Security.SecurityLevel.OnComplete" enum="SecurityLevel" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>cthomp@chromium.org</owner> <owner>security-enamel@chromium.org</owner> <summary> @@ -622,7 +622,7 @@ </histogram> <histogram base="true" name="Security.SiteEngagementDelta" units="units" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>cthomp@chromium.org</owner> <owner>security-enamel@chromium.org</owner> <summary> @@ -637,7 +637,7 @@ </histogram> <histogram base="true" name="Security.TimeOnPage2" units="units" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>cthomp@chromium.org</owner> <owner>security-enamel@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/service/histograms.xml b/tools/metrics/histograms/histograms_xml/service/histograms.xml index 1939c79..e5d2f42b 100644 --- a/tools/metrics/histograms/histograms_xml/service/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/service/histograms.xml
@@ -312,7 +312,7 @@ </histogram> <histogram name="ServiceWorker.FetchEvent.HasResponse.Time" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>falken@chromium.org</owner> <owner>chrome-worker@google.com</owner> <summary> @@ -747,7 +747,7 @@ </histogram> <histogram name="ServiceWorker.ScriptCachedMetadataSize" units="bytes" - expires_after="2021-05-18"> + expires_after="2021-08-09"> <owner>falken@chromium.org</owner> <owner>chrome-worker@google.com</owner> <summary> @@ -1122,7 +1122,7 @@ </histogram> <histogram name="ServiceWorker.WorkerStopped" enum="ServiceWorkerStoppedStatus" - expires_after="2021-04-04"> + expires_after="2021-08-09"> <owner>falken@chromium.org</owner> <owner>chrome-worker@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/session/histograms.xml b/tools/metrics/histograms/histograms_xml/session/histograms.xml index 72be82c..6b28698 100644 --- a/tools/metrics/histograms/histograms_xml/session/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/session/histograms.xml
@@ -465,7 +465,7 @@ </histogram> <histogram name="Session.WebStates.ReadFromFileTime" units="ms" - expires_after="2021-06-10"> + expires_after="2021-08-09"> <owner>justincohen@chromium.org</owner> <owner>rohitrao@chromium.org</owner> <summary> @@ -486,7 +486,7 @@ </histogram> <histogram name="Session.WebStates.SerializedSize" units="KB" - expires_after="2021-06-10"> + expires_after="2021-08-09"> <owner>justincohen@chromium.org</owner> <owner>rohitrao@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/settings/histograms.xml b/tools/metrics/histograms/histograms_xml/settings/histograms.xml index 6ca0f9c..8518a27 100644 --- a/tools/metrics/histograms/histograms_xml/settings/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/settings/histograms.xml
@@ -60,7 +60,7 @@ </histogram> <histogram name="Settings.Homepage.LocationType" enum="HomepageLocationType" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>bttk@chromium.org</owner> <owner>twellington@chromium.org</owner> <owner>wenyufu@chromium.org</owner> @@ -174,7 +174,7 @@ </histogram> <histogram name="Settings.SafetyCheck.ChromeCleanerResult" - enum="SafetyCheckChromeCleanerStatus" expires_after="M92"> + enum="SafetyCheckChromeCleanerStatus" expires_after="2021-08-09"> <owner>rainhard@chromium.org</owner> <owner>msramek@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/sharing/histograms.xml b/tools/metrics/histograms/histograms_xml/sharing/histograms.xml index 9745395..97b099c 100644 --- a/tools/metrics/histograms/histograms_xml/sharing/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/sharing/histograms.xml
@@ -218,7 +218,7 @@ </histogram> <histogram name="Sharing.MessageReceivedType" enum="SharingMessageType" - expires_after="M92"> + expires_after="2021-08-09"> <owner>mvanouwerkerk@chromium.org</owner> <owner>peter@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/signin/histograms.xml b/tools/metrics/histograms/histograms_xml/signin/histograms.xml index ea42aaf..cbc416df 100644 --- a/tools/metrics/histograms/histograms_xml/signin/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/signin/histograms.xml
@@ -203,7 +203,7 @@ </histogram> <histogram name="Signin.AuthError" enum="GoogleServiceAuthError" - expires_after="2021-05-09"> + expires_after="2021-08-09"> <owner>msarda@chromium.org</owner> <owner>droger@chromium.org</owner> <summary> @@ -308,7 +308,7 @@ </histogram> <histogram name="Signin.Extensions.GaiaRemoteConsentFlowResult" - enum="GaiaRemoteConsentFlowResult" expires_after="2021-03-28"> + enum="GaiaRemoteConsentFlowResult" expires_after="2021-08-09"> <owner>alexilin@chromium.org</owner> <owner>droger@chromium.org</owner> <summary> @@ -318,7 +318,7 @@ </histogram> <histogram name="Signin.Extensions.GetAuthTokenResult" - enum="GetAuthTokenResult" expires_after="2021-03-28"> + enum="GetAuthTokenResult" expires_after="2021-08-09"> <!-- Name completed by histogram_suffixes name="GetAuthTokenType" --> <owner>alexilin@chromium.org</owner> @@ -922,7 +922,7 @@ </histogram> <histogram name="Signin.SecondaryAccountConsentLog" - enum="SecondaryAccountConsentLoggerResult" expires_after="2021-06-06"> + enum="SecondaryAccountConsentLoggerResult" expires_after="2021-08-09"> <owner>anastasiian@chromium.org</owner> <owner>sinhak@chromium.org</owner> <summary> @@ -1178,7 +1178,7 @@ </histogram> <histogram base="true" name="Signin.SyncErrorInfoBar" - enum="SyncErrorInfoBarAction" expires_after="2021-06-01"> + enum="SyncErrorInfoBarAction" expires_after="2021-08-09"> <!-- Name completed by histogram_suffixes name="SyncErrorInfoBarType" --> <owner>triploblastic@chromium.org</owner> @@ -1190,7 +1190,7 @@ </histogram> <histogram name="Signin.SyncFirstSetupCompleteSource" - enum="SyncFirstSetupCompleteSource" expires_after="2021-06-01"> + enum="SyncFirstSetupCompleteSource" expires_after="2021-08-09"> <owner>triploblastic@chromium.org</owner> <owner>bsazonov@chromium.org</owner> <summary>Tracks where FirstSetupComplete bit is set from.</summary>
diff --git a/tools/metrics/histograms/histograms_xml/stability/histograms.xml b/tools/metrics/histograms/histograms_xml/stability/histograms.xml index 5d1f36a4..58b3b24 100644 --- a/tools/metrics/histograms/histograms_xml/stability/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/stability/histograms.xml
@@ -86,7 +86,7 @@ </histogram> <histogram name="Stability.Android.RendererCrash" enum="Boolean" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>wnwen@chromium.org</owner> <summary> Counts renderer crashes including OOMs. Android only. Mirrors old stability @@ -96,7 +96,7 @@ <histogram name="Stability.Android.StrongBindingOomRemainingBindingState" enum="Android.ChildProcessBindingStateCombination" - expires_after="2021-04-25"> + expires_after="2021-08-09"> <owner>boliu@chromium.org</owner> <owner>ssid@chromium.org</owner> <summary> @@ -415,7 +415,7 @@ </histogram> <histogram name="Stability.iOS.UTE.AvailableStorage" units="KB" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>michaeldo@chromium.org</owner> <owner>olivierrobin@chromium.org</owner> <summary> @@ -441,7 +441,7 @@ </histogram> <histogram name="Stability.iOS.UTE.DeviceThermalState" - enum="IOSDeviceThermalState" expires_after="2021-06-06"> + enum="IOSDeviceThermalState" expires_after="2021-08-09"> <owner>michaeldo@chromium.org</owner> <owner>olivierrobin@chromium.org</owner> <summary> @@ -451,7 +451,7 @@ </histogram> <histogram name="Stability.iOS.UTE.HasPossibleExplanation" - enum="BooleanHasPossibleExplanation" expires_after="2021-06-06"> + enum="BooleanHasPossibleExplanation" expires_after="2021-08-09"> <owner>michaeldo@chromium.org</owner> <owner>olivierrobin@chromium.org</owner> <summary> @@ -508,7 +508,7 @@ </histogram> <histogram name="Stability.iOS.UTE.OSRestartedAfterPreviousSession" - enum="BooleanRebooted" expires_after="2021-06-06"> + enum="BooleanRebooted" expires_after="2021-08-09"> <owner>olivierrobin@chromium.org</owner> <owner>michaeldo@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/startup/histograms.xml b/tools/metrics/histograms/histograms_xml/startup/histograms.xml index 5b8314f..dd4f040 100644 --- a/tools/metrics/histograms/histograms_xml/startup/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/startup/histograms.xml
@@ -40,7 +40,7 @@ </histogram> <histogram name="Startup.Android.CachedFeedVisibilityConsistency" - enum="BooleanConsistent" expires_after="2021-06-10"> + enum="BooleanConsistent" expires_after="2021-08-09"> <owner>hanxi@chromium.org</owner> <owner>spdonghao@chromium.org</owner> <owner>wychen@chromium.org</owner> @@ -112,7 +112,7 @@ </histogram> <histogram name="Startup.Android.FeedsLoadingPlaceholderShown.Instant" - units="ms" expires_after="2021-06-10"> + units="ms" expires_after="2021-08-09"> <owner>hanxi@chromium.org</owner> <owner>spdonghao@chromium.org</owner> <owner>wychen@chromium.org</owner> @@ -125,7 +125,7 @@ </histogram> <histogram base="true" name="Startup.Android.FeedStreamCreatedTime" units="ms" - expires_after="2021-06-10"> + expires_after="2021-08-09"> <!-- Name completed by histogram_suffixes name="JavaStartMode" --> <owner>hanxi@chromium.org</owner> @@ -139,7 +139,7 @@ </histogram> <histogram base="true" name="Startup.Android.FirstDrawCompletedTime" units="ms" - expires_after="2021-06-10"> + expires_after="2021-08-09"> <!-- Name completed by histogram_suffixes name="JavaStartMode" --> <owner>hanxi@chromium.org</owner> @@ -161,7 +161,7 @@ </histogram> <histogram base="true" name="Startup.Android.SingleTabTitleAvailableTime" - units="ms" expires_after="2021-06-10"> + units="ms" expires_after="2021-08-09"> <!-- Name completed by histogram_suffixes name="JavaStartMode" --> <owner>hanxi@chromium.org</owner> @@ -377,6 +377,9 @@ <histogram name="Startup.BrowserWindow.FirstPaint.CompositingEnded" units="ms" expires_after="2020-04-26"> + <obsolete> + Removed 02/2021. + </obsolete> <owner>sebmarchand@chromium.org</owner> <owner>mblsha@yandex-team.ru</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/subresource/histograms.xml b/tools/metrics/histograms/histograms_xml/subresource/histograms.xml index a76e0c98..3057aec 100644 --- a/tools/metrics/histograms/histograms_xml/subresource/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/subresource/histograms.xml
@@ -243,7 +243,7 @@ </histogram> <histogram name="SubresourceFilter.DocumentLoad.SubframeFilteringDelay.Allowed" - units="microseconds" expires_after="M92"> + units="microseconds" expires_after="2021-08-09"> <owner>alexmt@chromium.org</owner> <owner>chrome-ads-histograms@google.com</owner> <summary> @@ -349,7 +349,7 @@ <histogram name="SubresourceFilter.MainFrameLoad.RulesetIsAvailableAnyActivationLevel" - enum="BooleanAvailable" expires_after="2021-05-16"> + enum="BooleanAvailable" expires_after="2021-08-09"> <owner>alexmt@chromium.org</owner> <owner>jkarlin@chromium.org</owner> <summary> @@ -464,7 +464,7 @@ </histogram> <histogram name="SubresourceFilter.PageLoad.NumSubresourceLoads.Disallowed" - units="resource loads" expires_after="M92"> + units="resource loads" expires_after="2021-08-09"> <owner>jkarlin@chromium.org</owner> <owner>chrome-ads-histograms@google.com</owner> <summary> @@ -488,7 +488,7 @@ </histogram> <histogram name="SubresourceFilter.PageLoad.NumSubresourceLoads.MatchedRules" - units="resource loads" expires_after="M92"> + units="resource loads" expires_after="2021-08-09"> <owner>jkarlin@chromium.org</owner> <owner>chrome-ads-histograms@google.com</owner> <summary> @@ -647,7 +647,7 @@ </histogram> <histogram name="SubresourceRedirect.Blink.Ineligibility" - enum="BlinkSubresourceRedirectIneligibility" expires_after="M92"> + enum="BlinkSubresourceRedirectIneligibility" expires_after="2021-08-09"> <owner>rajendrant@chromium.org</owner> <owner>mcrouse@chromium.org</owner> <summary> @@ -723,7 +723,7 @@ </histogram> <histogram name="SubresourceRedirect.ImageCompressionNotificationInfoBar" - enum="HttpsImageCompressionInfoBarAction" expires_after="M92"> + enum="HttpsImageCompressionInfoBarAction" expires_after="2021-08-09"> <owner>rajendrant@chromium.org</owner> <owner>src/components/data_reduction_proxy/OWNERS</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/sync/histograms.xml b/tools/metrics/histograms/histograms_xml/sync/histograms.xml index bfbece06..16e4342 100644 --- a/tools/metrics/histograms/histograms_xml/sync/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/sync/histograms.xml
@@ -98,7 +98,7 @@ </histogram> <histogram name="Sync.BookmarksModelMetadataCorruptionReason" - enum="SyncBookmarkModelMetadataCorruptionReason" expires_after="M92"> + enum="SyncBookmarkModelMetadataCorruptionReason" expires_after="2021-08-09"> <owner>rushans@google.com</owner> <owner>mastiz@chromium.org</owner> <summary> @@ -161,7 +161,7 @@ </histogram> <histogram name="Sync.ConfigureDataTypes" enum="SyncModelTypes" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>mastiz@chromium.org</owner> <owner>treib@chromium.org</owner> <summary> @@ -186,7 +186,7 @@ </histogram> <histogram base="true" name="Sync.ConfigureTime_Initial" units="ms" - expires_after="2021-04-01"> + expires_after="2021-08-09"> <owner>victorvianna@google.com</owner> <owner>jkrcal@chromium.org</owner> <summary> @@ -196,7 +196,7 @@ </histogram> <histogram base="true" name="Sync.ConfigureTime_Subsequent" units="ms" - expires_after="2021-04-01"> + expires_after="2021-08-09"> <owner>victorvianna@google.com</owner> <owner>jkrcal@chromium.org</owner> <summary> @@ -233,7 +233,7 @@ <histogram name="Sync.Crypto.CustomPassphraseKeyDerivationMethodOnNewPassphrase" enum="SyncCustomPassphraseKeyDerivationMethodState" - expires_after="2021-05-09"> + expires_after="2021-08-09"> <owner>vitaliii@chromium.org</owner> <owner>treib@chromium.org</owner> <summary> @@ -261,7 +261,7 @@ <histogram name="Sync.Crypto.CustomPassphraseKeyDerivationMethodStateOnStartup" enum="SyncCustomPassphraseKeyDerivationMethodState" - expires_after="2021-04-04"> + expires_after="2021-08-09"> <owner>vitaliii@chromium.org</owner> <owner>treib@chromium.org</owner> <summary> @@ -271,7 +271,7 @@ </histogram> <histogram base="true" name="Sync.Crypto.NigoriKeyDerivationDuration" - units="ms" expires_after="2021-04-04"> + units="ms" expires_after="2021-08-09"> <owner>vitaliii@chromium.org</owner> <owner>treib@chromium.org</owner> <summary> @@ -414,7 +414,7 @@ </histogram> <histogram name="Sync.InitialState" enum="SyncInitialState" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>treib@chromium.org</owner> <owner>mastiz@chromium.org</owner> <summary> @@ -589,7 +589,7 @@ </histogram> <histogram base="true" name="Sync.ModelTypeErrorSite" - enum="SyncModelTypeErrorSite" expires_after="2021-06-06"> + enum="SyncModelTypeErrorSite" expires_after="2021-08-09"> <!-- Name completed by histogram_suffixes name="SyncModelType" --> <owner>jkrcal@chromium.org</owner> @@ -623,7 +623,7 @@ </histogram> <histogram base="true" name="Sync.ModelTypeStoreCommitWriteBatchOutcome" - enum="LevelDBStatus" expires_after="2021-06-06"> + enum="LevelDBStatus" expires_after="2021-08-09"> <!-- Name completed by histogram_suffixes name="SyncModelType" --> <owner>qjw@chromium.org</owner> @@ -979,7 +979,7 @@ </histogram> <histogram name="Sync.SharingMessage.CommitResult" - enum="SyncSharingMessageCommitErrorCode" expires_after="2021-06-06"> + enum="SyncSharingMessageCommitErrorCode" expires_after="2021-08-09"> <owner>rushans@google.com</owner> <owner>treib@chromium.org</owner> <summary> @@ -1100,7 +1100,7 @@ </histogram> <histogram name="Sync.SyncEverything2" enum="Boolean" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>treib@chromium.org</owner> <owner>mastiz@chromium.org</owner> <summary> @@ -1159,7 +1159,7 @@ </histogram> <histogram base="true" name="Sync.UndecryptedEntitiesOnDataTypeDisabled" - units="sync entities" expires_after="2021-06-06"> + units="sync entities" expires_after="2021-08-09"> <owner>victorvianna@google.com</owner> <owner>treib@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/tab/histograms.xml b/tools/metrics/histograms/histograms_xml/tab/histograms.xml index faa38c3..474a15a 100644 --- a/tools/metrics/histograms/histograms_xml/tab/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/tab/histograms.xml
@@ -250,7 +250,7 @@ </histogram> <histogram name="Tab.Preview.MemoryUsage.CompressedData.PerThumbnailKiB" - units="KB" expires_after="M92"> + units="KB" expires_after="2021-08-09"> <owner>dfried@chromium.org</owner> <owner>collinbaker@chromium.org</owner> <summary> @@ -260,7 +260,7 @@ </histogram> <histogram name="Tab.Preview.MemoryUsage.CompressedData.TotalKiB" units="KB" - expires_after="M92"> + expires_after="2021-08-09"> <owner>dfried@chromium.org</owner> <owner>collinbaker@chromium.org</owner> <summary> @@ -318,7 +318,7 @@ </histogram> <histogram name="Tab.Preview.VideoCaptureDuration" units="ms" - expires_after="M92"> + expires_after="2021-08-09"> <owner>dfried@chromium.org</owner> <owner>collinbaker@chromium.org</owner> <summary> @@ -608,7 +608,7 @@ </histogram> <histogram name="TabGroups.SessionsPerGroup" units="sessions" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>yusufo@chromium.org</owner> <owner>wychen@chromium.org</owner> <summary> @@ -651,7 +651,7 @@ </histogram> <histogram name="TabGroups.UserGroupCount" units="groups" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>yusufo@chromium.org</owner> <owner>wychen@chromium.org</owner> <summary> @@ -672,7 +672,7 @@ </histogram> <histogram name="TabGroups.UserNamedGroupCount" units="groups" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>yusufo@chromium.org</owner> <owner>wychen@chromium.org</owner> <summary> @@ -1248,7 +1248,7 @@ </summary> </histogram> -<histogram name="Tabs.CountAtStartup" units="tabs" expires_after="M92"> +<histogram name="Tabs.CountAtStartup" units="tabs" expires_after="2021-08-09"> <owner>marq@chromium.org</owner> <summary>[Android and iOS] The number of tabs open at cold launch.</summary> </histogram> @@ -2605,7 +2605,7 @@ </histogram> <histogram name="TabStrip.TabCountOnPageLoad" units="tabs" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>yusufo@chromium.org</owner> <owner>wychen@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/translate/histograms.xml b/tools/metrics/histograms/histograms_xml/translate/histograms.xml index 85877894..1c7dde7 100644 --- a/tools/metrics/histograms/histograms_xml/translate/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/translate/histograms.xml
@@ -61,7 +61,7 @@ </histogram> <histogram name="Translate.CLD3.LanguageDetected" enum="CLD3LanguageCode" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>frechette@chromium.org</owner> <owner>chrome-language@google.com</owner> <summary> @@ -71,7 +71,7 @@ </histogram> <histogram name="Translate.CLD3.LanguagePercentage" units="%" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>frechette@chromium.org</owner> <owner>chrome-language@google.com</owner> <summary> @@ -99,7 +99,7 @@ </histogram> <histogram name="Translate.CompactInfobar.Language.AlwaysTranslate" - enum="CLD3LanguageCode" expires_after="2021-06-06"> + enum="CLD3LanguageCode" expires_after="2021-08-09"> <owner>anthonyvd@chromium.org</owner> <owner>chrome-language@google.com</owner> <summary> @@ -109,7 +109,7 @@ </histogram> <histogram name="Translate.CompactInfobar.Language.MoreLanguages" - enum="CLD3LanguageCode" expires_after="2021-04-04"> + enum="CLD3LanguageCode" expires_after="2021-08-09"> <owner>anthonyvd@chromium.org</owner> <owner>chrome-language@google.com</owner> <summary> @@ -118,7 +118,7 @@ </histogram> <histogram name="Translate.CompactInfobar.Language.NeverTranslate" - enum="CLD3LanguageCode" expires_after="2021-06-06"> + enum="CLD3LanguageCode" expires_after="2021-08-09"> <owner>anthonyvd@chromium.org</owner> <owner>chrome-language@google.com</owner> <summary> @@ -128,7 +128,7 @@ </histogram> <histogram name="Translate.CompactInfobar.Language.PageNotIn" - enum="CLD3LanguageCode" expires_after="2021-06-06"> + enum="CLD3LanguageCode" expires_after="2021-08-09"> <owner>anthonyvd@chromium.org</owner> <owner>chrome-language@google.com</owner> <summary> @@ -147,7 +147,7 @@ </histogram> <histogram name="Translate.CompactInfobar.TranslationsPerPage" - units="translations" expires_after="2021-06-06"> + units="translations" expires_after="2021-08-09"> <owner>anthonyvd@chromium.org</owner> <owner>chrome-language@google.com</owner> <summary> @@ -168,7 +168,7 @@ </histogram> <histogram name="Translate.ContentLanguage" enum="TranslateLanguage" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>kenjibaheux@google.com</owner> <owner>chrome-language@google.com</owner> <summary> @@ -178,7 +178,7 @@ </histogram> <histogram name="Translate.DeclineTranslate" units="units" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>kenjibaheux@google.com</owner> <owner>chrome-language@google.com</owner> <summary> @@ -188,7 +188,7 @@ </histogram> <histogram name="Translate.DeclineTranslateCloseInfobar" units="units" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>kenjibaheux@google.com</owner> <owner>chrome-language@google.com</owner> <summary> @@ -212,7 +212,7 @@ </histogram> <histogram name="Translate.ExplicitLanguageAsk.Event" - enum="TranslateExplicitAskPromptEventType" expires_after="2021-06-06"> + enum="TranslateExplicitAskPromptEventType" expires_after="2021-08-09"> <owner>yyushkina@google.com</owner> <owner>anthonyvd@google.com</owner> <owner>chrome-language@google.com</owner> @@ -223,7 +223,7 @@ </histogram> <histogram name="Translate.ExplicitLanguageAsk.LanguageAdded" - enum="CLD3LanguageCode" expires_after="2021-06-06"> + enum="CLD3LanguageCode" expires_after="2021-08-09"> <owner>yyushkina@google.com</owner> <owner>anthonyvd@google.com</owner> <owner>chrome-language@google.com</owner> @@ -234,7 +234,7 @@ </histogram> <histogram name="Translate.ExplicitLanguageAsk.LanguageRemoved" - enum="CLD3LanguageCode" expires_after="2021-06-06"> + enum="CLD3LanguageCode" expires_after="2021-08-09"> <owner>yyushkina@google.com</owner> <owner>anthonyvd@google.com</owner> <owner>chrome-language@google.com</owner> @@ -304,7 +304,7 @@ </histogram> <histogram name="Translate.LanguageDetection.ContentLength" units="characters" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>sclittle@chromium.org</owner> <owner>megjablon@chromium.org</owner> <owner>chrome-language@google.com</owner> @@ -339,7 +339,7 @@ </histogram> <histogram name="Translate.LanguageSettingsIsShown" enum="BooleanShown" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>frechette@chromium.org</owner> <owner>chrome-language@google.com</owner> <summary> @@ -382,7 +382,7 @@ </histogram> <histogram name="Translate.MenuTranslation.IsAvailable" enum="BooleanAvailable" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>cuianthony@google.com</owner> <owner>chrome-language@google.com</owner> <summary> @@ -419,7 +419,7 @@ </histogram> <histogram name="Translate.ModifyOriginalLang" units="units" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>kenjibaheux@google.com</owner> <owner>chrome-language@google.com</owner> <summary> @@ -429,7 +429,7 @@ </histogram> <histogram name="Translate.ModifyTargetLang" units="units" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>kenjibaheux@google.com</owner> <owner>chrome-language@google.com</owner> <summary> @@ -439,7 +439,7 @@ </histogram> <histogram name="Translate.NeverTranslateLang" units="units" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>kenjibaheux@google.com</owner> <owner>chrome-language@google.com</owner> <summary> @@ -449,7 +449,7 @@ </histogram> <histogram name="Translate.NeverTranslateSite" units="units" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>kenjibaheux@google.com</owner> <owner>chrome-language@google.com</owner> <summary> @@ -472,7 +472,7 @@ </histogram> <histogram name="Translate.PageLoad.FinalSourceLanguage" - enum="CLD3LanguageCode" expires_after="2021-06-06"> + enum="CLD3LanguageCode" expires_after="2021-08-09"> <owner>curranmax@google.com</owner> <owner>megjablon@google.com</owner> <owner>chrome-language@google.com</owner> @@ -486,7 +486,7 @@ </histogram> <histogram name="Translate.PageLoad.FinalState" enum="TranslateState" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>curranmax@google.com</owner> <owner>megjablon@google.com</owner> <owner>chrome-language@google.com</owner> @@ -500,7 +500,7 @@ </histogram> <histogram name="Translate.PageLoad.FinalTargetLanguage" - enum="CLD3LanguageCode" expires_after="2021-06-06"> + enum="CLD3LanguageCode" expires_after="2021-08-09"> <owner>curranmax@google.com</owner> <owner>megjablon@google.com</owner> <owner>chrome-language@google.com</owner> @@ -528,7 +528,7 @@ </histogram> <histogram name="Translate.PageLoad.InitialState" enum="TranslateState" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>curranmax@google.com</owner> <owner>megjablon@google.com</owner> <owner>chrome-language@google.com</owner> @@ -572,7 +572,7 @@ </histogram> <histogram name="Translate.PageLoad.NumReversions" units="reversions" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>curranmax@google.com</owner> <owner>megjablon@google.com</owner> <owner>chrome-language@google.com</owner> @@ -585,7 +585,7 @@ </histogram> <histogram name="Translate.PageLoad.NumTargetLanguageChanges" - units="target language changes" expires_after="2021-06-06"> + units="target language changes" expires_after="2021-08-09"> <owner>curranmax@google.com</owner> <owner>megjablon@google.com</owner> <owner>chrome-language@google.com</owner> @@ -598,7 +598,7 @@ </histogram> <histogram name="Translate.PageLoad.NumTranslations" units="translations" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>curranmax@google.com</owner> <owner>megjablon@google.com</owner> <owner>chrome-language@google.com</owner> @@ -610,7 +610,7 @@ </histogram> <histogram name="Translate.PageLoad.Ranker.Decision" - enum="TranslateRankerDecision" expires_after="2021-06-06"> + enum="TranslateRankerDecision" expires_after="2021-08-09"> <owner>curranmax@google.com</owner> <owner>megjablon@google.com</owner> <owner>chrome-language@google.com</owner> @@ -623,7 +623,7 @@ </histogram> <histogram name="Translate.PageLoad.Ranker.Version" units="version" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>curranmax@google.com</owner> <owner>megjablon@google.com</owner> <owner>chrome-language@google.com</owner> @@ -635,7 +635,7 @@ </histogram> <histogram name="Translate.PageLoad.TriggerDecision" - enum="TranslateTriggerDecision" expires_after="2021-06-06"> + enum="TranslateTriggerDecision" expires_after="2021-08-09"> <owner>curranmax@google.com</owner> <owner>megjablon@google.com</owner> <owner>chrome-language@google.com</owner> @@ -754,7 +754,7 @@ </histogram> <histogram name="Translate.RevertTranslation" units="units" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>kenjibaheux@google.com</owner> <owner>chrome-language@google.com</owner> <summary> @@ -799,7 +799,7 @@ </histogram> <histogram name="Translate.TargetLanguage" enum="CLD3LanguageCode" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>yyushkina@google.com</owner> <owner>chrome-language@google.com</owner> <summary> @@ -809,7 +809,7 @@ </histogram> <histogram name="Translate.TargetLanguage.Origin" - enum="TranslateTargetLanguageOrigin" expires_after="2021-06-06"> + enum="TranslateTargetLanguageOrigin" expires_after="2021-08-09"> <owner>megjablon@google.com</owner> <owner>chrome-language@google.com</owner> <summary> @@ -854,7 +854,7 @@ </histogram> <histogram name="Translate.Translate.AMPCacheURL" enum="BooleanTranslate" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>sclittle@google.com</owner> <owner>megjablon@google.com</owner> <owner>chrome-language@google.com</owner> @@ -1011,7 +1011,7 @@ </histogram> <histogram name="Translate.UserActionDuration" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>kenjibaheux@google.com</owner> <owner>chrome-language@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/uma/histograms.xml b/tools/metrics/histograms/histograms_xml/uma/histograms.xml index af1e97c..42472eb0 100644 --- a/tools/metrics/histograms/histograms_xml/uma/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/uma/histograms.xml
@@ -79,7 +79,7 @@ </histogram> <histogram name="UMA.EntropySourceType" enum="UmaEntropySourceType" - expires_after="2021-04-15"> + expires_after="2021-08-09"> <owner>asvitkine@chromium.org</owner> <owner>src/base/metrics/OWNERS</owner> <summary> @@ -273,7 +273,7 @@ </histogram> <histogram name="UMA.LowEntropySourceValue" units="units" - expires_after="2021-04-15"> + expires_after="2021-08-09"> <owner>asvitkine@chromium.org</owner> <owner>mpearson@chromium.org</owner> <owner>src/base/metrics/OWNERS</owner> @@ -580,7 +580,7 @@ </histogram> <histogram name="UMA.TruncatedEvents.UserAction" units="events" - expires_after="2021-08-01"> + expires_after="2021-08-09"> <owner>rkaplow@chromium.org</owner> <owner>src/base/metrics/OWNERS</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/update_engine/histograms.xml b/tools/metrics/histograms/histograms_xml/update_engine/histograms.xml index d88e83d..ffe6402 100644 --- a/tools/metrics/histograms/histograms_xml/update_engine/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/update_engine/histograms.xml
@@ -298,7 +298,7 @@ </histogram> <histogram name="UpdateEngine.Check.RollbackTargetVersion" - enum="UpdateEngineChromeOsVersionPrefix" expires_after="2021-05-16"> + enum="UpdateEngineChromeOsVersionPrefix" expires_after="2021-08-09"> <owner>mpolzer@google.com</owner> <owner>managed-platforms@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/v8/histograms.xml b/tools/metrics/histograms/histograms_xml/v8/histograms.xml index d0df313a..5510e913c 100644 --- a/tools/metrics/histograms/histograms_xml/v8/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/v8/histograms.xml
@@ -163,7 +163,7 @@ </histogram> <histogram name="V8.CompileScriptMicroSeconds.BackgroundThread" - units="microseconds" expires_after="2021-06-06"> + units="microseconds" expires_after="2021-08-09"> <owner>leszeks@chromium.org</owner> <owner>rmcilroy@chromium.org</owner> <owner>v8-runtime@google.com</owner> @@ -180,7 +180,7 @@ </histogram> <histogram name="V8.CompileScriptMicroSeconds.ConsumeCache" - units="microseconds" expires_after="2021-06-06"> + units="microseconds" expires_after="2021-08-09"> <owner>leszeks@chromium.org</owner> <owner>v8-runtime@google.com</owner> <summary> @@ -228,7 +228,7 @@ </histogram> <histogram name="V8.CompileScriptMicroSeconds.NoCache.CacheTooCold" - units="microseconds" expires_after="2021-06-06"> + units="microseconds" expires_after="2021-08-09"> <owner>leszeks@chromium.org</owner> <owner>v8-runtime@google.com</owner> <summary> @@ -396,7 +396,7 @@ </summary> </histogram> -<histogram name="V8.GCBackgroundMarking" units="ms" expires_after="2021-06-06"> +<histogram name="V8.GCBackgroundMarking" units="ms" expires_after="2021-08-09"> <owner>ulan@chromium.org</owner> <owner>v8-memory-sheriffs@google.com</owner> <summary> @@ -424,7 +424,7 @@ </summary> </histogram> -<histogram name="V8.GCCompactor" units="ms" expires_after="2021-06-06"> +<histogram name="V8.GCCompactor" units="ms" expires_after="2021-08-09"> <owner>hpayer@chromium.org</owner> <owner>v8-memory-sheriffs@google.com</owner> <summary>Time spent in mark-sweep phase of GC.</summary> @@ -440,7 +440,7 @@ </histogram> <histogram name="V8.GCCompactorForeground" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>hpayer@chromium.org</owner> <owner>v8-memory-sheriffs@google.com</owner> <summary> @@ -448,7 +448,7 @@ </summary> </histogram> -<histogram name="V8.GCFinalizeMC" units="ms" expires_after="2021-06-06"> +<histogram name="V8.GCFinalizeMC" units="ms" expires_after="2021-08-09"> <owner>ulan@chromium.org</owner> <owner>hpayer@chromium.org</owner> <owner>v8-memory-sheriffs@google.com</owner> @@ -489,7 +489,7 @@ </summary> </histogram> -<histogram name="V8.GCFinalizeMC.Finish" units="ms" expires_after="2021-06-06"> +<histogram name="V8.GCFinalizeMC.Finish" units="ms" expires_after="2021-08-09"> <owner>ulan@chromium.org</owner> <owner>hpayer@chromium.org</owner> <owner>v8-memory-sheriffs@google.com</owner> @@ -499,7 +499,7 @@ </summary> </histogram> -<histogram name="V8.GCFinalizeMC.Mark" units="ms" expires_after="2021-04-01"> +<histogram name="V8.GCFinalizeMC.Mark" units="ms" expires_after="2021-08-09"> <owner>ulan@chromium.org</owner> <owner>hpayer@chromium.org</owner> <owner>v8-memory-sheriffs@google.com</owner> @@ -552,7 +552,7 @@ </histogram> <histogram name="V8.GCFinalizeMCReduceMemory" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>ulan@chromium.org</owner> <owner>hpayer@chromium.org</owner> <owner>v8-memory-sheriffs@google.com</owner> @@ -584,7 +584,7 @@ </summary> </histogram> -<histogram name="V8.GCIncrementalMarking" units="ms" expires_after="2021-06-06"> +<histogram name="V8.GCIncrementalMarking" units="ms" expires_after="2021-08-09"> <owner>hpayer@chromium.org</owner> <owner>v8-memory-sheriffs@google.com</owner> <summary>Time spent doing incremental marking steps during GC.</summary> @@ -598,21 +598,21 @@ </histogram> <histogram name="V8.GCIncrementalMarkingReason" enum="GarbageCollectionReason" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>ulan@chromium.org</owner> <owner>v8-memory-sheriffs@google.com</owner> <summary>Reason an incremental marking was started in V8.</summary> </histogram> <histogram name="V8.GCIncrementalMarkingStart" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>hpayer@chromium.org</owner> <owner>v8-memory-sheriffs@google.com</owner> <summary>Time spent in starting incremental marking.</summary> </histogram> <histogram name="V8.GCIncrementalMarkingSum" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>ulan@chromium.org</owner> <owner>v8-memory-sheriffs@google.com</owner> <summary> @@ -644,7 +644,7 @@ </histogram> <histogram name="V8.GCMarkCompactReason" enum="GarbageCollectionReason" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>ulan@chromium.org</owner> <owner>v8-memory-sheriffs@google.com</owner> <summary>Reason a mark-compact garbage collection was started in V8.</summary> @@ -660,14 +660,14 @@ </summary> </histogram> -<histogram name="V8.GCScavenger" units="ms" expires_after="2021-06-06"> +<histogram name="V8.GCScavenger" units="ms" expires_after="2021-08-09"> <owner>hpayer@chromium.org</owner> <owner>v8-memory-sheriffs@google.com</owner> <summary>Time spent in scavenging phase of GC.</summary> </histogram> <histogram name="V8.GCScavenger.ScavengeMain" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>mlippautz@chromium.org</owner> <owner>v8-memory-sheriffs@google.com</owner> <summary> @@ -700,7 +700,7 @@ </histogram> <histogram name="V8.GCScavengerForeground" units="ms" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>hpayer@chromium.org</owner> <owner>v8-memory-sheriffs@google.com</owner> <summary> @@ -815,7 +815,7 @@ </histogram> <histogram name="V8.RegExpBacktracks" units="backtracks" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>jgruber@chromium.org</owner> <owner>mvstanton@chromium.org</owner> <summary> @@ -1167,7 +1167,7 @@ </histogram> <histogram name="V8.WasmMemoryAllocationResult" enum="WasmAllocationResult" - expires_after="2021-03-31"> + expires_after="2021-08-09"> <owner>ecmziegler@chromium.org</owner> <owner>adamk@chromium.org</owner> <owner>ahaas@chromium.org</owner> @@ -1234,7 +1234,7 @@ </histogram> <histogram name="V8.WasmModuleNumberOfCodeGCsTriggered" units="gcs" - expires_after="2021-03-31"> + expires_after="2021-08-09"> <owner>ecmziegler@chromium.org</owner> <owner>adamk@chromium.org</owner> <owner>clemensb@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/variations/histograms.xml b/tools/metrics/histograms/histograms_xml/variations/histograms.xml index 070aba8..e6cd288 100644 --- a/tools/metrics/histograms/histograms_xml/variations/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/variations/histograms.xml
@@ -88,7 +88,7 @@ </histogram> <histogram name="Variations.FirstRun.SeedFetchTime" units="ms" - expires_after="2021-04-15"> + expires_after="2021-08-09"> <owner>asvitkine@chromium.org</owner> <owner>rkaplow@chromium.org</owner> <owner>src/base/metrics/OWNERS</owner>
diff --git a/tools/metrics/histograms/histograms_xml/web_audio/histograms.xml b/tools/metrics/histograms/histograms_xml/web_audio/histograms.xml index 20b9e2d..8081271 100644 --- a/tools/metrics/histograms/histograms_xml/web_audio/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/web_audio/histograms.xml
@@ -108,7 +108,7 @@ </histogram> <histogram name="WebAudio.AudioContextOptions.sampleRate" units="Hz" - expires_after="2021-04-18"> + expires_after="2021-08-09"> <owner>rtoy@chromium.org</owner> <owner>hongchan@chromium.org</owner> <summary> @@ -119,7 +119,7 @@ </histogram> <histogram name="WebAudio.AudioContextOptions.sampleRateRatio" units="units" - expires_after="2021-04-18"> + expires_after="2021-08-09"> <owner>rtoy@chromium.org</owner> <owner>hongchan@chromium.org</owner> <summary> @@ -142,7 +142,7 @@ </histogram> <histogram name="WebAudio.AudioDestination.HardwareBufferSize" units="units" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>rtoy@chromium.org</owner> <owner>hongchan@chromium.org</owner> <summary> @@ -152,7 +152,7 @@ </histogram> <histogram name="WebAudio.Autoplay" enum="WebAudioAutoplayStatus" - expires_after="2021-06-01"> + expires_after="2021-08-09"> <owner>mlamouri@google.com</owner> <owner>media-dev@chromium.org</owner> <owner>rtoy@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/web_core/histograms.xml b/tools/metrics/histograms/histograms_xml/web_core/histograms.xml index 8512a002..ba45de4 100644 --- a/tools/metrics/histograms/histograms_xml/web_core/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/web_core/histograms.xml
@@ -800,35 +800,35 @@ </histogram> <histogram name="WebCore.Scripts.Async.NotStreamingReason" - enum="NotStreamingReason" expires_after="2021-06-06"> + enum="NotStreamingReason" expires_after="2021-08-09"> <owner>leszeks@chromium.org</owner> <owner>v8-runtime@google.com</owner> <summary>Reason for not streaming an async script.</summary> </histogram> <histogram name="WebCore.Scripts.Async.StartedStreaming" enum="BooleanStreamed" - expires_after="2021-06-06"> + expires_after="2021-08-09"> <owner>leszeks@chromium.org</owner> <owner>v8-runtime@google.com</owner> <summary>Whether an async script was streamed or not.</summary> </histogram> <histogram name="WebCore.Scripts.Deferred.NotStreamingReason" - enum="NotStreamingReason" expires_after="2021-06-06"> + enum="NotStreamingReason" expires_after="2021-08-09"> <owner>leszeks@chromium.org</owner> <owner>v8-runtime@google.com</owner> <summary>Reason for not streaming a deferred script.</summary> </histogram> <histogram name="WebCore.Scripts.Deferred.StartedStreaming" - enum="BooleanStreamed" expires_after="2021-06-06"> + enum="BooleanStreamed" expires_after="2021-08-09"> <owner>leszeks@chromium.org</owner> <owner>v8-runtime@google.com</owner> <summary>Whether a deferred script was streamed or not.</summary> </histogram> <histogram name="WebCore.Scripts.Other.NotStreamingReason" - enum="NotStreamingReason" expires_after="2021-06-06"> + enum="NotStreamingReason" expires_after="2021-08-09"> <owner>leszeks@chromium.org</owner> <owner>v8-runtime@google.com</owner> <summary> @@ -848,14 +848,14 @@ </histogram> <histogram name="WebCore.Scripts.ParsingBlocking.NotStreamingReason" - enum="NotStreamingReason" expires_after="2021-06-06"> + enum="NotStreamingReason" expires_after="2021-08-09"> <owner>leszeks@chromium.org</owner> <owner>v8-runtime@google.com</owner> <summary>Reason for not streaming a parsing blocking script.</summary> </histogram> <histogram name="WebCore.Scripts.ParsingBlocking.StartedStreaming" - enum="BooleanStreamed" expires_after="2021-06-06"> + enum="BooleanStreamed" expires_after="2021-08-09"> <owner>leszeks@chromium.org</owner> <owner>v8-runtime@google.com</owner> <summary>Whether a parsing blocking script was streamed or not.</summary>
diff --git a/tools/metrics/histograms/histograms_xml/web_rtc/histograms.xml b/tools/metrics/histograms/histograms_xml/web_rtc/histograms.xml index dc9cebbb..87067654 100644 --- a/tools/metrics/histograms/histograms_xml/web_rtc/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/web_rtc/histograms.xml
@@ -1071,7 +1071,7 @@ </histogram> <histogram name="WebRTC.Call.TimeReceivingVideoRtpPacketsInSeconds" units="s" - expires_after="2021-05-02"> + expires_after="2021-08-09"> <owner>saza@chromium.org</owner> <summary> The amount of time between the arrival of the first and last video RTP @@ -1178,7 +1178,7 @@ </histogram> <histogram name="WebRTC.PeerConnection.AddIceCandidate" - enum="AddIceCandidateResult" expires_after="2021-05-09"> + enum="AddIceCandidateResult" expires_after="2021-08-09"> <owner>hta@chromium.org</owner> <owner>webrtc-dev@chromium.org</owner> <summary> @@ -1223,7 +1223,7 @@ </histogram> <histogram name="WebRTC.PeerConnection.ConnectionState" - enum="IceConnectionStates" expires_after="2021-06-06"> + enum="IceConnectionStates" expires_after="2021-08-09"> <owner>qingsi@google.com</owner> <owner>jeroendb@google.com</owner> <summary> @@ -1438,7 +1438,7 @@ </histogram> <histogram name="WebRTC.PeerConnection.SdpFormatReceived" - enum="PeerConnectionSdpFormatReceived" expires_after="2021-06-06"> + enum="PeerConnectionSdpFormatReceived" expires_after="2021-08-09"> <owner>steveanton@chromium.org</owner> <owner>hta@chromium.org</owner> <owner>webrtc-dev@chromium.org</owner> @@ -1455,7 +1455,7 @@ </histogram> <histogram name="WebRTC.PeerConnection.SdpFormatReceivedAnswer" - enum="PeerConnectionSdpFormatReceived" expires_after="2021-06-06"> + enum="PeerConnectionSdpFormatReceived" expires_after="2021-08-09"> <owner>steveanton@chromium.org</owner> <owner>hta@chromium.org</owner> <owner>webrtc-dev@chromium.org</owner> @@ -3638,7 +3638,7 @@ </histogram> <histogram name="WebRtcTextLogging.UploadFailureReason" - enum="WebRtcLoggingUploadFailureReason" expires_after="2021-06-01"> + enum="WebRtcLoggingUploadFailureReason" expires_after="2021-08-09"> <owner>guidou@chromium.org</owner> <owner>webrtc-dev@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/windows/histograms.xml b/tools/metrics/histograms/histograms_xml/windows/histograms.xml index 6d060f2..83501ddd 100644 --- a/tools/metrics/histograms/histograms_xml/windows/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/windows/histograms.xml
@@ -360,7 +360,7 @@ </histogram> <histogram name="Windows.TmpFileDeleter.FailCount" units="files" - expires_after="2021-05-02"> + expires_after="2021-08-09"> <owner>grt@chromium.org</owner> <owner>etiennep@chromium.org</owner> <summary> @@ -374,7 +374,7 @@ </histogram> <histogram name="Windows.TmpFileDeleter.SuccessCount" units="files" - expires_after="2021-05-02"> + expires_after="2021-08-09"> <owner>grt@chromium.org</owner> <owner>etiennep@chromium.org</owner> <summary>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml index cf7c6e731..4d56c4f 100644 --- a/tools/metrics/ukm/ukm.xml +++ b/tools/metrics/ukm/ukm.xml
@@ -10565,6 +10565,12 @@ different renderer process than the current document or not. </summary> </metric> + <metric name="IsExistingPartOfTabGroup" enum="Boolean"> + <summary> + Marked true if the page was already part of a tab group when the + navigation committed. + </summary> + </metric> <metric name="IsSignedExchangeInnerResponse"> <obsolete> Migrated to the PageLoad.SignedExchange event. The presence of that event
diff --git a/tools/perf/benchmark.csv b/tools/perf/benchmark.csv index 29462bda..0f2e3d8 100644 --- a/tools/perf/benchmark.csv +++ b/tools/perf/benchmark.csv
@@ -76,4 +76,4 @@ v8.browsing_mobile-future,"mythria@chromium.org, tmrts@chromium.org",Blink>JavaScript,,"2018,2019,2020,emerging_market,health_check,images,infinite_scroll,international,javascript_heavy" v8.runtime_stats.top_25,"mythria@chromium.org, ulan@chromium.org",Blink>JavaScript,,"cold,hot,warm" views_perftests,tapted@chromium.org,Internals>Views,, -webrtc,"qiangchen@chromium.org, mbonadei@chromium.org",Blink>WebRTC,http://bit.ly/webrtc-benchmark,"datachannel,getusermedia,insertableStreams,pauseplay,smoothness,stress,videoConstraints" +webrtc,"qiangchen@chromium.org, mbonadei@chromium.org",Blink>WebRTC,http://bit.ly/webrtc-benchmark,"datachannel,getusermedia,insertableStreams,pauseplay,sdp,smoothness,stress,videoConstraints"
diff --git a/tools/perf/chrome_telemetry_build/BUILD.gn b/tools/perf/chrome_telemetry_build/BUILD.gn index 99ec0639..8a7da08 100644 --- a/tools/perf/chrome_telemetry_build/BUILD.gn +++ b/tools/perf/chrome_telemetry_build/BUILD.gn
@@ -8,8 +8,26 @@ # Pull in enable_chrome_android_internal and public_android_sdk import("//build/config/android/config.gni") } -if (is_chromeos_ash) { + +if (is_chromeos_device) { import("//build/config/chromeos/rules.gni") + + generate_runner_script("cros_update_wrapper") { + generated_script = "$root_build_dir/bin/cros_update_wrapper" + deploy_chrome = true + } + + if (cros_boards != "") { + foreach(_board, string_split(cros_boards, ":")) { + _board_underscore = string_replace(_board, "-", "_") + generate_runner_script("cros_update_wrapper_${_board_underscore}") { + generated_script = + "$root_build_dir/bin/cros_update_wrapper_${_board_underscore}" + deploy_chrome = true + override_board = _board + } + } + } } group("telemetry_chrome_test") { @@ -65,6 +83,16 @@ ] } + if (is_chromeos_device) { + data_deps += [ ":cros_update_wrapper" ] + if (cros_boards != "") { + foreach(_board, string_split(cros_boards, ":")) { + _board_underscore = string_replace(_board, "-", "_") + data_deps += [ ":cros_update_wrapper_${_board_underscore}" ] + } + } + } + if (is_chromeos_ash && is_chromeos_device) { data_deps += [ "//:chromiumos_preflight",
diff --git a/tools/perf/cli_tools/tbmv3/validators/simple_configs.pyl b/tools/perf/cli_tools/tbmv3/validators/simple_configs.pyl index 00d7e3c..abc594f 100644 --- a/tools/perf/cli_tools/tbmv3/validators/simple_configs.pyl +++ b/tools/perf/cli_tools/tbmv3/validators/simple_configs.pyl
@@ -21,4 +21,14 @@ 'console:error:network': 'console_error::network_errors', }, }, + 'reported_by_page': { + 'v2_metric': 'reportedByPageMetric', + 'v3_metric': 'reported_by_page', + 'histogram_mappings': { + # mappings are 'v2_histogram: 'v3_histogram'. + 'reported_by_page:time_to_viewable': 'reported_by_page::time_to_viewable', + 'reported_by_page:time_to_interactive': 'reported_by_page::time_to_interactive', + 'reported_by_page:benchmark_time': 'reported_by_page::benchmark_time', + }, + }, }
diff --git a/tools/perf/cli_tools/tbmv3/validators/simple_validator.py b/tools/perf/cli_tools/tbmv3/validators/simple_validator.py index 5042a08a..9ba4033 100644 --- a/tools/perf/cli_tools/tbmv3/validators/simple_validator.py +++ b/tools/perf/cli_tools/tbmv3/validators/simple_validator.py
@@ -5,6 +5,7 @@ Validates the rendering/frame_times metric. """ +import sys from cli_tools.tbmv3.validators import utils CONFIG_FORMAT = ('Config must contain "v2_metric", "v3_metric", and ' @@ -30,7 +31,7 @@ msg = ('List of histograms produced by TBM%s metric %s:\n' % (version, metric)) msg += '\n'.join([h.name for h in histogram_set]) - raise Exception('Histgoram %s not found.\n%s' % (name, msg)) + raise Exception('Histogram %s not found.\n%s' % (name, msg)) if len(hists) > 1: raise Exception('Multiple histograms named %s found for TBM%s metric %s' % (name, version, metric)) @@ -50,5 +51,11 @@ v2_hist = GetHistogram(v2_histograms, v2_hist_name, v2_metric, 'v2') v3_hist = GetHistogram(v3_histograms, v3_hist_name, v3_metric, 'v3') - utils.AssertHistogramStatsAlmostEqual(test_ctx, v2_hist, v3_hist) - utils.AssertHistogramSamplesAlmostEqual(test_ctx, v2_hist, v3_hist) + try: + utils.AssertHistogramStatsAlmostEqual(test_ctx, v2_hist, v3_hist) + utils.AssertHistogramSamplesAlmostEqual(test_ctx, v2_hist, v3_hist) + except AssertionError as err: + message = ( + 'Error comparing TBMv2 histogram %s with TBMv3 histogram %s: %s' % + (v2_hist.name, v3_hist.name, err.message)) + raise AssertionError, message, sys.exc_info()[2]
diff --git a/tools/perf/cli_tools/tbmv3/validators/utils.py b/tools/perf/cli_tools/tbmv3/validators/utils.py index 99a6da7d..f0c7b0e 100644 --- a/tools/perf/cli_tools/tbmv3/validators/utils.py +++ b/tools/perf/cli_tools/tbmv3/validators/utils.py
@@ -23,7 +23,5 @@ test_ctx.assertEqual(len(v2_samples), len(v3_samples)) v2_samples.sort() v3_samples.sort() - msg = ('Comparing TBMv2 histogram %s with TBMv3 hisogram %s.' % - (v2_hist.name, v3_hist.name)) for v2_sample, v3_sample in zip(v2_samples, v3_samples): - test_ctx.assertAlmostEqual(v2_sample, v3_sample, places=3, msg=msg) + test_ctx.assertAlmostEqual(v2_sample, v3_sample, places=3)
diff --git a/tools/perf/core/bot_platforms.py b/tools/perf/core/bot_platforms.py index 80bce935..a89ee0f 100644 --- a/tools/perf/core/bot_platforms.py +++ b/tools/perf/core/bot_platforms.py
@@ -463,14 +463,14 @@ # Linux LINUX = PerfPlatform( 'linux-perf', - 'Ubuntu-14.04, 8 core, NVIDIA Quadro P400', + 'Ubuntu-18.04, 8 core, NVIDIA Quadro P400', _LINUX_BENCHMARK_CONFIGS, 26, 'linux', executables=_LINUX_EXECUTABLE_CONFIGS) LINUX_REL = PerfPlatform( 'linux-perf-rel', - 'Ubuntu-14.04, 8 core, NVIDIA Quadro P400', + 'Ubuntu-18.04, 8 core, NVIDIA Quadro P400', _CHROME_HEALTH_BENCHMARK_CONFIGS_DESKTOP, 2, 'linux',
diff --git a/tools/perf/core/perf_data_generator.py b/tools/perf/core/perf_data_generator.py index 0f6866a..7d2fa92 100755 --- a/tools/perf/core/perf_data_generator.py +++ b/tools/perf/core/perf_data_generator.py
@@ -205,7 +205,9 @@ 'extra_args': [ 'hardware_accelerated_feature', '--show-stdout', '--browser=web-engine-shell', '--passthrough', '-v', - '--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc' + '--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc', + '--device=custom', + '--custom-device-target=internal.astro_target' ], 'type': TEST_TYPES.GENERIC, @@ -213,6 +215,7 @@ 'platform': 'fuchsia', 'dimension': { + 'cpu': None, 'device_type': 'Astro', 'os': 'Fuchsia', 'pool': 'chrome.tests', @@ -279,7 +282,7 @@ 'tests': [ { 'isolate': - 'performance_test_suite', + 'performance_test_suite_eve', 'extra_args': [ # The magic hostname that resolves to a CrOS device in the test lab '--remote=variable_chromeos_device_hostname', @@ -446,7 +449,7 @@ 'additional_compile_targets': ['chromedriver', 'chromium_builder_perf'], }, 'linux-builder-perf-rel': { - 'additional_compile_targets': ['chromedriver', 'chromium_builder_perf'], + 'additional_compile_targets': ['chromium_builder_perf'], }, 'mac-builder-perf': { 'additional_compile_targets': ['chromedriver', 'chromium_builder_perf'],
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json index e8ee1ea..2fdf9ee 100644 --- a/tools/perf/core/perfetto_binary_roller/binary_deps.json +++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -1,16 +1,16 @@ { "trace_processor_shell": { "win": { - "hash": "05f898ec237791c9d9d6d1901e9cef62888eb944", - "remote_path": "perfetto_binaries/trace_processor_shell/win/64c64075bae21d3d7d37e56fdc71f57d2de9c712/trace_processor_shell.exe" + "hash": "172c53a6397bd548931b8f6dbc9abab3bf4db702", + "remote_path": "perfetto_binaries/trace_processor_shell/win/c0182a50034c0c17a444c40aec96ee54239bc269/trace_processor_shell.exe" }, "mac": { - "hash": "e8bf46a9b6e7b5d5bb248ebc388e543d238a79dc", - "remote_path": "perfetto_binaries/trace_processor_shell/mac/f69ae0481064617cba71c34be1570fa56b49d076/trace_processor_shell" + "hash": "b983f5d7f044777facbf785367a560e7d8b07c6c", + "remote_path": "perfetto_binaries/trace_processor_shell/mac/c0182a50034c0c17a444c40aec96ee54239bc269/trace_processor_shell" }, "linux": { - "hash": "88cccc124fe04445c17f1b2649ac1b7d44c53296", - "remote_path": "perfetto_binaries/trace_processor_shell/linux/0ac08fa635ec4fb59dcde90542f7e850ec5fa010/trace_processor_shell" + "hash": "ecf01a77a074b6ac612cb19909eba5ea93d8cf75", + "remote_path": "perfetto_binaries/trace_processor_shell/linux/c0182a50034c0c17a444c40aec96ee54239bc269/trace_processor_shell" } }, "power_profile.sql": {
diff --git a/tools/perf/core/shard_maps/timing_data/win-10_laptop_low_end-perf_timing.json b/tools/perf/core/shard_maps/timing_data/win-10_laptop_low_end-perf_timing.json index 41a01f6..269476c 100644 --- a/tools/perf/core/shard_maps/timing_data/win-10_laptop_low_end-perf_timing.json +++ b/tools/perf/core/shard_maps/timing_data/win-10_laptop_low_end-perf_timing.json
@@ -12,7 +12,7 @@ "name": "blink_perf.accessibility/line-breaks.html" }, { - "duration": "36.0", + "duration": "37.0", "name": "blink_perf.accessibility/many-text-changes-deep-block-subtree.html" }, { @@ -24,7 +24,7 @@ "name": "blink_perf.accessibility/many-text-changes-deep-inline-subtree.html" }, { - "duration": "37.0", + "duration": "38.0", "name": "blink_perf.accessibility/many-text-changes-small-wait-between.html" }, { @@ -52,15 +52,15 @@ "name": "blink_perf.bindings/first-child.html" }, { - "duration": "12.0", + "duration": "11.0", "name": "blink_perf.bindings/gc-forest.html" }, { - "duration": "15.0", + "duration": "14.0", "name": "blink_perf.bindings/gc-mini-tree.html" }, { - "duration": "21.0", + "duration": "19.0", "name": "blink_perf.bindings/gc-tree.html" }, { @@ -100,7 +100,7 @@ "name": "blink_perf.bindings/named-property-enumerator.html" }, { - "duration": "19.0", + "duration": "20.0", "name": "blink_perf.bindings/node-list-access.html" }, { @@ -148,7 +148,7 @@ "name": "blink_perf.bindings/structured-clone-json-deserialize.html" }, { - "duration": "18.0", + "duration": "17.0", "name": "blink_perf.bindings/structured-clone-json-serialize.html" }, { @@ -196,11 +196,11 @@ "name": "blink_perf.bindings/worker-structured-clone-json-from-worker.html" }, { - "duration": "29.0", + "duration": "28.0", "name": "blink_perf.bindings/worker-structured-clone-json-roundtrip.html" }, { - "duration": "29.0", + "duration": "28.0", "name": "blink_perf.bindings/worker-structured-clone-json-to-worker.html" }, { @@ -236,7 +236,7 @@ "name": "blink_perf.bindings/worker-transferable-to-worker.html" }, { - "duration": "23.0", + "duration": "25.0", "name": "blink_perf.css/AttributeDescendantSelector.html" }, { @@ -244,7 +244,7 @@ "name": "blink_perf.css/CSSLogicalDirection.html" }, { - "duration": "14.0", + "duration": "15.0", "name": "blink_perf.css/CSSPropertySetterGetter.html" }, { @@ -256,11 +256,11 @@ "name": "blink_perf.css/CSSPropertyUpdateValue.html" }, { - "duration": "13.0", + "duration": "12.0", "name": "blink_perf.css/ChangeStyleCSSVariableRecalc.html" }, { - "duration": "12.0", + "duration": "13.0", "name": "blink_perf.css/ChangeStyleChildClassSelector.html" }, { @@ -272,15 +272,15 @@ "name": "blink_perf.css/ChangeStyleCustomPropertyDeclaration.html" }, { - "duration": "13.0", + "duration": "12.0", "name": "blink_perf.css/ChangeStyleElementSelector.html" }, { - "duration": "12.0", + "duration": "13.0", "name": "blink_perf.css/ChangeStyleGrandChildElementSelector.html" }, { - "duration": "12.0", + "duration": "13.0", "name": "blink_perf.css/ChangeStyleMultipleClassSelector.html" }, { @@ -296,15 +296,15 @@ "name": "blink_perf.css/ChangeStylePairOfNthChildSelector.html" }, { - "duration": "13.0", + "duration": "12.0", "name": "blink_perf.css/ChangeStylePartialAttributeMatchingSelector.html" }, { - "duration": "13.0", + "duration": "12.0", "name": "blink_perf.css/ChangeStyleQualifiedDataAttributeSelector.html" }, { - "duration": "12.0", + "duration": "13.0", "name": "blink_perf.css/ChangeStyleQualifiedDataAttributeWithValueSelector.html" }, { @@ -328,11 +328,11 @@ "name": "blink_perf.css/ChangeStyleUniversalSelector.html" }, { - "duration": "13.0", + "duration": "12.0", "name": "blink_perf.css/ChangeStyleUnqualifiedDataAttributeSelector.html" }, { - "duration": "12.0", + "duration": "13.0", "name": "blink_perf.css/ChangeStyleUnqualifiedDataAttributeWithValueSelector.html" }, { @@ -340,7 +340,7 @@ "name": "blink_perf.css/ClassDescendantSelector.html" }, { - "duration": "15.0", + "duration": "16.0", "name": "blink_perf.css/ClassInvalidation.html" }, { @@ -356,7 +356,7 @@ "name": "blink_perf.css/CustomPropertiesNonRootInheritance.html" }, { - "duration": "10.0", + "duration": "8.0", "name": "blink_perf.css/CustomPropertiesPendingSubstitution.html" }, { @@ -396,11 +396,11 @@ "name": "blink_perf.css/SelectorCountScaling.html" }, { - "duration": "16.0", + "duration": "17.0", "name": "blink_perf.dom/custom-element-default-style-with-shadow.html" }, { - "duration": "9.0", + "duration": "10.0", "name": "blink_perf.dom/custom-element-default-style.html" }, { @@ -408,7 +408,7 @@ "name": "blink_perf.dom/long-sibling-list.html" }, { - "duration": "7.0", + "duration": "8.0", "name": "blink_perf.dom/modify-element-classname.html" }, { @@ -416,307 +416,307 @@ "name": "blink_perf.dom/modify-element-id.html" }, { - "duration": "5.0", + "duration": "6.0", "name": "blink_perf.dom/modify-element-title.html" }, { - "duration": "10.0", + "duration": "11.0", "name": "blink_perf.dom/select-multiple-add.html" }, { - "duration": "10.0", + "duration": "11.0", "name": "blink_perf.dom/select-single-add.html" }, { - "duration": "9.0", + "duration": "11.0", "name": "blink_perf.dom/select-single-remove.html" }, { - "duration": "17.0", + "duration": "20.0", "name": "blink_perf.events/EventsDispatching.html" }, { - "duration": "12.0", + "duration": "16.0", "name": "blink_perf.events/EventsDispatchingInDeeplyNestedV1ShadowTrees.html" }, { - "duration": "26.0", + "duration": "31.0", "name": "blink_perf.events/EventsDispatchingInV1ShadowTrees.html" }, { - "duration": "25.0", + "duration": "30.0", "name": "blink_perf.events/hit-test-lots-of-layers.html" }, { - "duration": "11.0", + "duration": "14.0", "name": "blink_perf.events/is-input-pending-default-events.html" }, { - "duration": "10.0", + "duration": "14.0", "name": "blink_perf.events/is-input-pending-include-continuous-events.html" }, { - "duration": "28.0", + "duration": "33.0", "name": "blink_perf.image_decoder/decode-gif.html" }, { - "duration": "20.0", + "duration": "26.0", "name": "blink_perf.image_decoder/decode-jpeg-h1v1.html" }, { - "duration": "20.0", + "duration": "26.0", "name": "blink_perf.image_decoder/decode-jpeg-h1v2.html" }, { - "duration": "21.0", + "duration": "27.0", "name": "blink_perf.image_decoder/decode-jpeg-h2v1.html" }, { - "duration": "21.0", + "duration": "27.0", "name": "blink_perf.image_decoder/decode-jpeg-h2v2.html" }, { - "duration": "31.0", + "duration": "41.0", "name": "blink_perf.image_decoder/decode-lossless-webp.html" }, { - "duration": "18.0", + "duration": "23.0", "name": "blink_perf.image_decoder/decode-lossy-webp.html" }, { - "duration": "25.0", + "duration": "31.0", "name": "blink_perf.image_decoder/decode-png-palette-opaque.html" }, { - "duration": "20.0", + "duration": "28.0", "name": "blink_perf.image_decoder/decode-png-palette.html" }, { - "duration": "32.0", + "duration": "42.0", "name": "blink_perf.image_decoder/decode-png.html" }, { - "duration": "23.0", + "duration": "25.0", "name": "blink_perf.layout/ArabicLineLayout.html" }, { - "duration": "4.0", + "duration": "7.0", "name": "blink_perf.layout/Shapes/MultipleShapes.html" }, { - "duration": "10.0", + "duration": "15.0", "name": "blink_perf.layout/SimpleTextPathLineLayout.html" }, { - "duration": "23.0", + "duration": "30.0", "name": "blink_perf.layout/abspos.html" }, { - "duration": "9.0", + "duration": "13.0", "name": "blink_perf.layout/add-remove-inline-floats.html" }, { - "duration": "5.0", + "duration": "8.0", "name": "blink_perf.layout/animate-abspos-deep.html" }, { - "duration": "10.0", + "duration": "15.0", "name": "blink_perf.layout/attach-inlines-2.html" }, { - "duration": "9.0", + "duration": "13.0", "name": "blink_perf.layout/attach-inlines.html" }, { - "duration": "10.0", + "duration": "16.0", "name": "blink_perf.layout/auto-grid-lots-of-data.html" }, { - "duration": "10.0", + "duration": "15.0", "name": "blink_perf.layout/auto-grid-lots-of-spanning-data.html" }, { - "duration": "13.0", + "duration": "19.0", "name": "blink_perf.layout/change-text-css-contain.html" }, { - "duration": "10.0", + "duration": "14.0", "name": "blink_perf.layout/chapter-reflow-once-random.html" }, { - "duration": "11.0", + "duration": "15.0", "name": "blink_perf.layout/chapter-reflow-once.html" }, { - "duration": "10.0", + "duration": "14.0", "name": "blink_perf.layout/chapter-reflow-thrice.html" }, { - "duration": "10.0", + "duration": "16.0", "name": "blink_perf.layout/chapter-reflow-twice.html" }, { - "duration": "10.0", + "duration": "16.0", "name": "blink_perf.layout/chapter-reflow.html" }, { - "duration": "6.0", + "duration": "11.0", "name": "blink_perf.layout/character_fallback.html" }, { - "duration": "9.0", + "duration": "12.0", "name": "blink_perf.layout/contain-content-style-change.html" }, { - "duration": "5.0", + "duration": "9.0", "name": "blink_perf.layout/culled-inline-bounding-rects.html" }, { - "duration": "4.0", + "duration": "7.0", "name": "blink_perf.layout/culled-inline-hittest.html" }, { - "duration": "10.0", + "duration": "16.0", "name": "blink_perf.layout/deeply-nested-grid.html" }, { - "duration": "9.0", + "duration": "14.0", "name": "blink_perf.layout/editing_append.html" }, { - "duration": "9.0", + "duration": "14.0", "name": "blink_perf.layout/editing_append_single_line.html" }, { - "duration": "9.0", + "duration": "13.0", "name": "blink_perf.layout/editing_delete.html" }, { - "duration": "9.0", + "duration": "14.0", "name": "blink_perf.layout/editing_insert.html" }, { - "duration": "9.0", + "duration": "13.0", "name": "blink_perf.layout/editing_prepend.html" }, { - "duration": "19.0", + "duration": "24.0", "name": "blink_perf.layout/fit-content-change-available-size-blocks.html" }, { - "duration": "10.0", + "duration": "14.0", "name": "blink_perf.layout/fit-content-change-available-size-text.html" }, { - "duration": "11.0", + "duration": "16.0", "name": "blink_perf.layout/fixed-grid-lots-of-data.html" }, { - "duration": "11.0", + "duration": "16.0", "name": "blink_perf.layout/fixed-grid-lots-of-stretched-data.html" }, { - "duration": "9.0", + "duration": "14.0", "name": "blink_perf.layout/flexbox-column-nowrap.html" }, { - "duration": "10.0", + "duration": "15.0", "name": "blink_perf.layout/flexbox-column-wrap.html" }, { - "duration": "10.0", + "duration": "15.0", "name": "blink_perf.layout/flexbox-deeply-nested-column-flow.html" }, { - "duration": "10.0", + "duration": "15.0", "name": "blink_perf.layout/flexbox-hittest.html" }, { - "duration": "11.0", + "duration": "16.0", "name": "blink_perf.layout/flexbox-input.html" }, { - "duration": "10.0", + "duration": "15.0", "name": "blink_perf.layout/flexbox-lots-of-data.html" }, { - "duration": "9.0", + "duration": "14.0", "name": "blink_perf.layout/flexbox-row-nowrap.html" }, { - "duration": "14.0", + "duration": "20.0", "name": "blink_perf.layout/flexbox-row-stretch-height-definite.html" }, { - "duration": "10.0", + "duration": "14.0", "name": "blink_perf.layout/flexbox-row-stretch-height-indefinite.html" }, { - "duration": "10.0", + "duration": "15.0", "name": "blink_perf.layout/flexbox-row-wrap.html" }, { - "duration": "9.0", + "duration": "14.0", "name": "blink_perf.layout/flexbox-with-stretch-layout.html" }, { - "duration": "15.0", + "duration": "20.0", "name": "blink_perf.layout/flexbox_with_list_item.html" }, { - "duration": "14.0", + "duration": "18.0", "name": "blink_perf.layout/floats_100_100.html" }, { - "duration": "14.0", + "duration": "19.0", "name": "blink_perf.layout/floats_100_100_nested.html" }, { - "duration": "15.0", + "duration": "19.0", "name": "blink_perf.layout/floats_10_1000.html" }, { - "duration": "7.0", + "duration": "11.0", "name": "blink_perf.layout/floats_20_100.html" }, { - "duration": "14.0", + "duration": "11.0", "name": "blink_perf.layout/floats_20_100_nested.html" }, { - "duration": "6.0", + "duration": "9.0", "name": "blink_perf.layout/floats_2_100.html" }, { - "duration": "5.0", + "duration": "7.0", "name": "blink_perf.layout/floats_2_100_nested.html" }, { - "duration": "7.0", + "duration": "11.0", "name": "blink_perf.layout/floats_50_100.html" }, { - "duration": "7.0", + "duration": "13.0", "name": "blink_perf.layout/floats_50_100_nested.html" }, { - "duration": "10.0", + "duration": "14.0", "name": "blink_perf.layout/floats_show_hide.html" }, { - "duration": "32.0", + "duration": "25.0", "name": "blink_perf.layout/hindi-line-layout.html" }, { - "duration": "7.0", + "duration": "9.0", "name": "blink_perf.layout/hittest-block-children.html" }, { - "duration": "10.0", + "duration": "12.0", "name": "blink_perf.layout/japanese-kokoro-insert.html" }, { - "duration": "18.0", + "duration": "19.0", "name": "blink_perf.layout/large-grid.html" }, { @@ -724,11 +724,11 @@ "name": "blink_perf.layout/large-spanning-grid-item.html" }, { - "duration": "29.0", + "duration": "27.0", "name": "blink_perf.layout/large-table-with-collapsed-borders-and-colspans-wider-than-table.html" }, { - "duration": "28.0", + "duration": "25.0", "name": "blink_perf.layout/large-table-with-collapsed-borders-and-colspans.html" }, { @@ -736,7 +736,7 @@ "name": "blink_perf.layout/large-table-with-collapsed-borders-and-no-colspans.html" }, { - "duration": "19.0", + "duration": "18.0", "name": "blink_perf.layout/latin-ebook-resize.html" }, { @@ -744,11 +744,11 @@ "name": "blink_perf.layout/latin-ebook.html" }, { - "duration": "10.0", + "duration": "9.0", "name": "blink_perf.layout/layers_overlap_2d.html" }, { - "duration": "10.0", + "duration": "9.0", "name": "blink_perf.layout/layers_overlap_3d.html" }, { @@ -756,11 +756,11 @@ "name": "blink_perf.layout/line-layout-fit-content-break-word.html" }, { - "duration": "17.0", + "duration": "18.0", "name": "blink_perf.layout/line-layout-fit-content.html" }, { - "duration": "22.0", + "duration": "21.0", "name": "blink_perf.layout/line-layout-line-height.html" }, { @@ -772,7 +772,7 @@ "name": "blink_perf.layout/line-layout-repeat-append.html" }, { - "duration": "14.0", + "duration": "15.0", "name": "blink_perf.layout/line-layout.html" }, { @@ -784,7 +784,7 @@ "name": "blink_perf.layout/long-line-nowrap-spans-collapse.html" }, { - "duration": "16.0", + "duration": "15.0", "name": "blink_perf.layout/long-line-nowrap.html" }, { @@ -792,11 +792,11 @@ "name": "blink_perf.layout/many-block-children-auto-inline-size.html" }, { - "duration": "16.0", + "duration": "15.0", "name": "blink_perf.layout/many-block-children-fixed-inline-size.html" }, { - "duration": "15.0", + "duration": "14.0", "name": "blink_perf.layout/multicol/balance-forced-breaks.html" }, { @@ -808,271 +808,271 @@ "name": "blink_perf.layout/multicol/fixed-height-with-spanner-and-nested-tables.html" }, { - "duration": "15.0", + "duration": "10.0", "name": "blink_perf.layout/multicol/lots-of-small-nested-unbreakable-blocks-autofill.html" }, { - "duration": "14.0", + "duration": "10.0", "name": "blink_perf.layout/multicol/lots-of-small-unbreakable-blocks-autofill.html" }, { - "duration": "14.0", + "duration": "10.0", "name": "blink_perf.layout/multicol/lots-of-text-autofill.html" }, { - "duration": "14.0", + "duration": "9.0", "name": "blink_perf.layout/multicol/lots-of-text-balanced-orphans-widows.html" }, { - "duration": "13.0", + "duration": "9.0", "name": "blink_perf.layout/multicol/lots-of-text-balanced.html" }, { - "duration": "46.0", + "duration": "38.0", "name": "blink_perf.layout/multicol/nested-forced-breaks.html" }, { - "duration": "11.0", + "duration": "9.0", "name": "blink_perf.layout/multicol/tall-content-short-columns-realistic.html" }, { - "duration": "14.0", + "duration": "9.0", "name": "blink_perf.layout/multicol/tall-content-short-columns.html" }, { - "duration": "15.0", + "duration": "10.0", "name": "blink_perf.layout/nested-blocks-with-percent-height-and-max-height.html" }, { - "duration": "15.0", + "duration": "10.0", "name": "blink_perf.layout/nested-grid-lots-of-tracks.html" }, { - "duration": "14.0", + "duration": "10.0", "name": "blink_perf.layout/nested-grid.html" }, { - "duration": "13.0", + "duration": "9.0", "name": "blink_perf.layout/nested-percent-height-tables.html" }, { - "duration": "21.0", + "duration": "16.0", "name": "blink_perf.layout/ruby.html" }, { - "duration": "91.0", + "duration": "76.0", "name": "blink_perf.layout/subtree-detaching.html" }, { - "duration": "13.0", + "duration": "8.0", "name": "blink_perf.layout/vertical-japanese-kokoro-insert.html" }, { - "duration": "7.0", + "duration": "4.0", "name": "blink_perf.layout/word-break-break-all.html" }, { - "duration": "7.0", + "duration": "4.0", "name": "blink_perf.layout/word-break-break-word.html" }, { - "duration": "6.0", + "duration": "4.0", "name": "blink_perf.layout/word-wrap-break-word.html" }, { - "duration": "26.0", + "duration": "25.0", "name": "blink_perf.owp_storage/blob-perf-files.html" }, { - "duration": "26.0", + "duration": "21.0", "name": "blink_perf.owp_storage/blob-perf-ipc.html" }, { - "duration": "25.0", + "duration": "20.0", "name": "blink_perf.owp_storage/blob-perf-shm.html" }, { - "duration": "29.0", + "duration": "22.0", "name": "blink_perf.owp_storage/blob-perf-tiny.html" }, { - "duration": "28.0", + "duration": "22.0", "name": "blink_perf.owp_storage/idb-load-docs.html" }, { - "duration": "28.0", + "duration": "20.0", "name": "blink_perf.paint/appending-text.html" }, { - "duration": "40.0", + "duration": "26.0", "name": "blink_perf.paint/color-changes.html" }, { - "duration": "36.0", + "duration": "22.0", "name": "blink_perf.paint/complex-content-slow-scroll.html" }, { - "duration": "34.0", + "duration": "21.0", "name": "blink_perf.paint/complex-iframe-filtered.html" }, { - "duration": "72.0", + "duration": "50.0", "name": "blink_perf.paint/contain-update-layer-tree.html" }, { - "duration": "35.0", + "duration": "23.0", "name": "blink_perf.paint/containment-resize.html" }, { - "duration": "33.0", + "duration": "20.0", "name": "blink_perf.paint/fixed-and-many-layers-scroll.html" }, { - "duration": "37.0", + "duration": "23.0", "name": "blink_perf.paint/large-table-background-change.html" }, { - "duration": "32.0", + "duration": "20.0", "name": "blink_perf.paint/large-table-collapsed-border-change.html" }, { - "duration": "28.0", + "duration": "18.0", "name": "blink_perf.paint/modify-selection.html" }, { - "duration": "29.0", + "duration": "18.0", "name": "blink_perf.paint/move-text-with-mask.html" }, { - "duration": "33.0", + "duration": "20.0", "name": "blink_perf.paint/paint-offset-changes.html" }, { - "duration": "45.0", + "duration": "27.0", "name": "blink_perf.paint/transform-changes.html" }, { - "duration": "17.0", + "duration": "15.0", "name": "blink_perf.parser/css-parser-yui.html" }, { - "duration": "13.0", + "duration": "12.0", "name": "blink_perf.parser/declarative-shadow-dom-cloning.html" }, { - "duration": "15.0", + "duration": "10.0", "name": "blink_perf.parser/declarative-shadow-dom.html" }, { - "duration": "15.0", + "duration": "9.0", "name": "blink_perf.parser/html-parser-threaded.html" }, { - "duration": "16.0", + "duration": "9.0", "name": "blink_perf.parser/html-parser.html" }, { - "duration": "55.0", + "duration": "43.0", "name": "blink_perf.parser/html5-full-render.html" }, { - "duration": "26.0", + "duration": "24.0", "name": "blink_perf.parser/iframe-append-remove.html" }, { - "duration": "16.0", + "duration": "10.0", "name": "blink_perf.parser/innerHTML-setter-siblings.html" }, { - "duration": "15.0", + "duration": "10.0", "name": "blink_perf.parser/innerHTML-setter.html" }, { - "duration": "14.0", + "duration": "9.0", "name": "blink_perf.parser/query-selector-all-attribute-complex.html" }, { - "duration": "14.0", + "duration": "9.0", "name": "blink_perf.parser/query-selector-all-attribute.html" }, { - "duration": "14.0", + "duration": "10.0", "name": "blink_perf.parser/query-selector-all-class-deep.html" }, { - "duration": "15.0", + "duration": "10.0", "name": "blink_perf.parser/query-selector-all-class-first.html" }, { - "duration": "16.0", + "duration": "10.0", "name": "blink_perf.parser/query-selector-all-class-last.html" }, { - "duration": "15.0", + "duration": "9.0", "name": "blink_perf.parser/query-selector-all-class.html" }, { - "duration": "15.0", + "duration": "10.0", "name": "blink_perf.parser/query-selector-all-deep.html" }, { - "duration": "14.0", + "duration": "10.0", "name": "blink_perf.parser/query-selector-all-first.html" }, { - "duration": "16.0", + "duration": "11.0", "name": "blink_perf.parser/query-selector-all-id-deep.html" }, { - "duration": "14.0", + "duration": "10.0", "name": "blink_perf.parser/query-selector-all-id-first.html" }, { - "duration": "17.0", + "duration": "11.0", "name": "blink_perf.parser/query-selector-all-id-last.html" }, { - "duration": "14.0", + "duration": "10.0", "name": "blink_perf.parser/query-selector-all-last.html" }, { - "duration": "15.0", + "duration": "10.0", "name": "blink_perf.parser/query-selector-deep.html" }, { - "duration": "14.0", + "duration": "15.0", "name": "blink_perf.parser/query-selector-first.html" }, { - "duration": "15.0", + "duration": "11.0", "name": "blink_perf.parser/query-selector-id-deep.html" }, { - "duration": "15.0", + "duration": "11.0", "name": "blink_perf.parser/query-selector-id-last.html" }, { - "duration": "15.0", + "duration": "10.0", "name": "blink_perf.parser/query-selector-last.html" }, { - "duration": "15.0", + "duration": "10.0", "name": "blink_perf.parser/simple-url.html" }, { - "duration": "16.0", + "duration": "12.0", "name": "blink_perf.parser/textarea-parsing.html" }, { - "duration": "15.0", + "duration": "11.0", "name": "blink_perf.parser/tiny-innerHTML.html" }, { - "duration": "15.0", + "duration": "11.0", "name": "blink_perf.parser/url-parser.html" }, { - "duration": "14.0", + "duration": "10.0", "name": "blink_perf.parser/xml-parser.html" }, { @@ -1084,7 +1084,7 @@ "name": "blink_perf.shadow_dom/imperative-api-appendchild.html" }, { - "duration": "4.0", + "duration": "3.0", "name": "blink_perf.shadow_dom/imperative-api-assign.html" }, { @@ -1096,19 +1096,19 @@ "name": "blink_perf.shadow_dom/imperative-api-assigned-slot.html" }, { - "duration": "4.0", + "duration": "3.0", "name": "blink_perf.shadow_dom/imperative-api-custom-detail-summary-large.html" }, { - "duration": "4.0", + "duration": "3.0", "name": "blink_perf.shadow_dom/imperative-api-custom-detail-summary.html" }, { - "duration": "4.0", + "duration": "3.0", "name": "blink_perf.shadow_dom/imperative-api-detail-summary-large.html" }, { - "duration": "5.0", + "duration": "4.0", "name": "blink_perf.shadow_dom/imperative-api-detail-summary.html" }, { @@ -1116,79 +1116,79 @@ "name": "blink_perf.shadow_dom/imperative-api-insertbefore.html" }, { - "duration": "5.0", + "duration": "3.0", "name": "blink_perf.shadow_dom/imperative-api.html" }, { - "duration": "30.0", + "duration": "21.0", "name": "blink_perf.shadow_dom/shadow-dom-overhead.html" }, { - "duration": "9.0", + "duration": "5.0", "name": "blink_perf.shadow_dom/shadow-style-share-attr-selectors.html" }, { - "duration": "7.0", + "duration": "4.0", "name": "blink_perf.shadow_dom/shadow-style-share-media-query.html" }, { - "duration": "7.0", + "duration": "4.0", "name": "blink_perf.shadow_dom/shadow-style-share-with-distribution.html" }, { - "duration": "6.0", + "duration": "4.0", "name": "blink_perf.shadow_dom/shadow-style-share.html" }, { - "duration": "6.0", + "duration": "4.0", "name": "blink_perf.shadow_dom/style-sheet-insert.html" }, { - "duration": "17.0", + "duration": "12.0", "name": "blink_perf.shadow_dom/v1-distribution-disconnected-and-reconnected.html" }, { - "duration": "8.0", + "duration": "4.0", "name": "blink_perf.shadow_dom/v1-distribution.html" }, { - "duration": "7.0", + "duration": "4.0", "name": "blink_perf.shadow_dom/v1-host-child-append.html" }, { - "duration": "19.0", + "duration": "11.0", "name": "blink_perf.shadow_dom/v1-large-deep-distribution.html" }, { - "duration": "23.0", + "duration": "16.0", "name": "blink_perf.shadow_dom/v1-large-deep-layout.html" }, { - "duration": "7.0", + "duration": "3.0", "name": "blink_perf.shadow_dom/v1-large-shallow-append-layout.html" }, { - "duration": "5.0", + "duration": "3.0", "name": "blink_perf.shadow_dom/v1-large-shallow-distribution.html" }, { - "duration": "5.0", + "duration": "3.0", "name": "blink_perf.shadow_dom/v1-large-shallow-layout.html" }, { - "duration": "5.0", + "duration": "3.0", "name": "blink_perf.shadow_dom/v1-large-shallow-prepend-layout.html" }, { - "duration": "7.0", + "duration": "4.0", "name": "blink_perf.shadow_dom/v1-mutate-deep-tree-then-re-layout.html" }, { - "duration": "6.0", + "duration": "3.0", "name": "blink_perf.shadow_dom/v1-mutate-deep-tree-then-slot-assigned-nodes.html" }, { - "duration": "5.0", + "duration": "3.0", "name": "blink_perf.shadow_dom/v1-mutate-deep-tree-then-slot-flatten.html" }, { @@ -1196,47 +1196,47 @@ "name": "blink_perf.shadow_dom/v1-mutate-shallow-tree-then-re-layout.html" }, { - "duration": "5.0", + "duration": "3.0", "name": "blink_perf.shadow_dom/v1-mutate-shallow-tree-then-slot-assigned-nodes.html" }, { - "duration": "5.0", + "duration": "3.0", "name": "blink_perf.shadow_dom/v1-mutate-shallow-tree-then-slot-flatten.html" }, { - "duration": "7.0", + "duration": "3.0", "name": "blink_perf.shadow_dom/v1-slot-append.html" }, { - "duration": "11.0", + "duration": "5.0", "name": "blink_perf.shadow_dom/v1-small-deep-distribution.html" }, { - "duration": "8.0", + "duration": "5.0", "name": "blink_perf.shadow_dom/v1-small-deep-layout.html" }, { - "duration": "5.0", + "duration": "3.0", "name": "blink_perf.shadow_dom/v1-small-shallow-distribution.html" }, { - "duration": "6.0", + "duration": "4.0", "name": "blink_perf.shadow_dom/v1-small-shallow-layout.html" }, { - "duration": "14.0", + "duration": "10.0", "name": "blink_perf.svg/AzLizardBenjiPark.html" }, { - "duration": "10.0", + "duration": "7.0", "name": "blink_perf.svg/Bamboo.html" }, { - "duration": "6.0", + "duration": "4.0", "name": "blink_perf.svg/Cactus.html" }, { - "duration": "8.0", + "duration": "4.0", "name": "blink_perf.svg/Cowboy.html" }, { @@ -1244,51 +1244,51 @@ "name": "blink_perf.svg/Cowboy_transform.html" }, { - "duration": "6.0", + "duration": "4.0", "name": "blink_perf.svg/CrawFishGanson.html" }, { - "duration": "6.0", + "duration": "4.0", "name": "blink_perf.svg/Debian.html" }, { - "duration": "5.0", + "duration": "4.0", "name": "blink_perf.svg/DropsOnABlade.html" }, { - "duration": "6.0", + "duration": "4.0", "name": "blink_perf.svg/FlowerFromMyGarden.html" }, { - "duration": "7.0", + "duration": "4.0", "name": "blink_perf.svg/FoodLeifLodahl.html" }, { - "duration": "7.0", + "duration": "4.0", "name": "blink_perf.svg/France.html" }, { - "duration": "6.0", + "duration": "4.0", "name": "blink_perf.svg/FrancoBolloGnomeEzechi.html" }, { - "duration": "6.0", + "duration": "4.0", "name": "blink_perf.svg/GearFlowers.html" }, { - "duration": "7.0", + "duration": "4.0", "name": "blink_perf.svg/HarveyRayner.html" }, { - "duration": "7.0", + "duration": "4.0", "name": "blink_perf.svg/HereGear.html" }, { - "duration": "15.0", + "duration": "8.0", "name": "blink_perf.svg/MtSaintHelens.html" }, { - "duration": "8.0", + "duration": "4.0", "name": "blink_perf.svg/Samurai.html" }, { @@ -1296,123 +1296,123 @@ "name": "blink_perf.svg/SierpinskiCarpet.html" }, { - "duration": "9.0", + "duration": "5.0", "name": "blink_perf.svg/SvgCubics.html" }, { - "duration": "6.0", + "duration": "4.0", "name": "blink_perf.svg/SvgHitTesting.html" }, { - "duration": "16.0", + "duration": "11.0", "name": "blink_perf.svg/SvgNestedUse.html" }, { - "duration": "6.0", + "duration": "4.0", "name": "blink_perf.svg/UnderTheSee.html" }, { - "duration": "7.0", + "duration": "5.0", "name": "blink_perf.svg/WorldIso.html" }, { - "duration": "12.0", + "duration": "7.0", "name": "blink_perf.svg/Worldcup.html" }, { - "duration": "38.0", + "duration": "33.0", "name": "blink_perf.webaudio/audio-buffer-source-node.html" }, { - "duration": "149.0", + "duration": "182.0", "name": "blink_perf.webaudio/audio-worklet-node.html" }, { - "duration": "143.0", + "duration": "180.0", "name": "blink_perf.webaudio/biquad-filter-node.html" }, { - "duration": "144.0", + "duration": "180.0", "name": "blink_perf.webaudio/gain-node.html" }, { - "duration": "59.0", + "duration": "72.0", "name": "blink_perf.webaudio/panner-node.html" }, { - "duration": "13.0", + "duration": "10.0", "name": "blink_perf.webgl/binding-draw-arrays.html" }, { - "duration": "15.0", + "duration": "11.0", "name": "blink_perf.webgl_fast_call/binding-draw-arrays.html" }, { - "duration": "15.0", + "duration": "11.0", "name": "blink_perf.webgpu/binding-draw.html" }, { - "duration": "16.0", + "duration": "11.0", "name": "blink_perf.webgpu_fast_call/binding-draw.html" }, { - "duration": "39.0", + "duration": "47.0", "name": "desktop_ui/tab_search:clean_slate" }, { - "duration": "76.0", + "duration": "92.0", "name": "desktop_ui/tab_search:close_and_open:2020" }, { - "duration": "61.0", + "duration": "74.0", "name": "desktop_ui/tab_search:close_and_open:loading:2020" }, { - "duration": "42.0", + "duration": "51.0", "name": "desktop_ui/tab_search:measure_memory:2tab_search" }, { - "duration": "42.0", + "duration": "41.0", "name": "desktop_ui/tab_search:measure_memory:3tab_search" }, { - "duration": "43.0", + "duration": "51.0", "name": "desktop_ui/tab_search:measure_memory:after" }, { - "duration": "44.0", + "duration": "52.0", "name": "desktop_ui/tab_search:measure_memory:before" }, { - "duration": "47.0", + "duration": "55.0", "name": "desktop_ui/tab_search:measure_memory:multiwindow" }, { - "duration": "153.0", + "duration": "162.0", "name": "desktop_ui/tab_search:scroll_up_and_down:2020" }, { - "duration": "352.0", + "duration": "423.0", "name": "desktop_ui/tab_search:top100:2020" }, { - "duration": "155.0", + "duration": "168.0", "name": "desktop_ui/tab_search:top100:loading:2020" }, { - "duration": "82.0", + "duration": "93.0", "name": "desktop_ui/tab_search:top10:2020" }, { - "duration": "55.0", + "duration": "64.0", "name": "desktop_ui/tab_search:top10:loading:2020" }, { - "duration": "206.0", + "duration": "258.0", "name": "desktop_ui/tab_search:top50:2020" }, { - "duration": "95.0", + "duration": "104.0", "name": "desktop_ui/tab_search:top50:loading:2020" }, { @@ -1420,7 +1420,7 @@ "name": "dromaeo/http://dromaeo.com?dom-attr" }, { - "duration": "34.0", + "duration": "35.0", "name": "dromaeo/http://dromaeo.com?dom-modify" }, { @@ -1436,75 +1436,75 @@ "name": "dummy_benchmark.noisy_benchmark_1/dummy_page.html" }, { - "duration": "4.0", + "duration": "5.0", "name": "dummy_benchmark.stable_benchmark_1/dummy_page.html" }, { - "duration": "230.0", + "duration": "256.0", "name": "jetstream/JetStream" }, { - "duration": "319.0", + "duration": "386.0", "name": "jetstream2/JetStream2" }, { - "duration": "39.0", + "duration": "44.0", "name": "kraken/http://krakenbenchmark.mozilla.org/kraken-1.1/driver.html" }, { - "duration": "60.0", + "duration": "105.0", "name": "loading.desktop/24h_cold" }, { - "duration": "63.0", + "duration": "91.0", "name": "loading.desktop/24h_warm" }, { - "duration": "55.0", + "duration": "66.0", "name": "loading.desktop/AirBnB_cold" }, { - "duration": "66.0", + "duration": "76.0", "name": "loading.desktop/AirBnB_warm" }, { - "duration": "38.0", + "duration": "44.0", "name": "loading.desktop/Aljayyash_cold" }, { - "duration": "38.0", + "duration": "44.0", "name": "loading.desktop/Aljayyash_warm" }, { - "duration": "36.0", + "duration": "32.0", "name": "loading.desktop/AllRecipes_cold" }, { - "duration": "66.0", + "duration": "61.0", "name": "loading.desktop/AllRecipes_warm" }, { - "duration": "53.0", + "duration": "49.0", "name": "loading.desktop/ArsTechnica_cold" }, { - "duration": "62.0", + "duration": "59.0", "name": "loading.desktop/ArsTechnica_warm" }, { - "duration": "77.0", + "duration": "48.0", "name": "loading.desktop/Baidu_cold" }, { - "duration": "59.0", + "duration": "46.0", "name": "loading.desktop/Baidu_warm" }, { - "duration": "51.0", + "duration": "45.0", "name": "loading.desktop/Bhaskar_cold" }, { - "duration": "58.0", + "duration": "79.0", "name": "loading.desktop/Bhaskar_warm" }, { @@ -1512,11 +1512,11 @@ "name": "loading.desktop/Chosun_cold" }, { - "duration": "54.0", + "duration": "53.0", "name": "loading.desktop/Chosun_warm" }, { - "duration": "49.0", + "duration": "48.0", "name": "loading.desktop/Colorado.edu_cold" }, { @@ -1528,47 +1528,47 @@ "name": "loading.desktop/Danawa_cold" }, { - "duration": "53.0", + "duration": "52.0", "name": "loading.desktop/Danawa_warm" }, { - "duration": "49.0", + "duration": "66.0", "name": "loading.desktop/Daum_cold" }, { - "duration": "51.0", + "duration": "50.0", "name": "loading.desktop/Daum_warm" }, { - "duration": "51.0", + "duration": "50.0", "name": "loading.desktop/Donga_cold" }, { - "duration": "55.0", + "duration": "54.0", "name": "loading.desktop/Donga_warm" }, { - "duration": "54.0", + "duration": "50.0", "name": "loading.desktop/Economist_cold" }, { - "duration": "64.0", + "duration": "60.0", "name": "loading.desktop/Economist_warm" }, { - "duration": "44.0", + "duration": "50.0", "name": "loading.desktop/Elmundo_cold" }, { - "duration": "25.0", + "duration": "26.0", "name": "loading.desktop/Elmundo_warm" }, { - "duration": "47.0", + "duration": "50.0", "name": "loading.desktop/FC2Blog_cold" }, { - "duration": "50.0", + "duration": "53.0", "name": "loading.desktop/FC2Blog_warm" }, { @@ -1576,19 +1576,19 @@ "name": "loading.desktop/FIFA_cold" }, { - "duration": "55.0", + "duration": "68.0", "name": "loading.desktop/FIFA_warm" }, { - "duration": "57.0", + "duration": "62.0", "name": "loading.desktop/FarsNews_cold" }, { - "duration": "41.0", + "duration": "46.0", "name": "loading.desktop/FarsNews_warm" }, { - "duration": "49.0", + "duration": "66.0", "name": "loading.desktop/Flickr_cold" }, { @@ -1596,135 +1596,135 @@ "name": "loading.desktop/Flickr_warm" }, { - "duration": "46.0", + "duration": "49.0", "name": "loading.desktop/FlipKart_cold" }, { - "duration": "48.0", + "duration": "51.0", "name": "loading.desktop/FlipKart_warm" }, { - "duration": "38.0", + "duration": "57.0", "name": "loading.desktop/Free.fr_cold" }, { - "duration": "38.0", + "duration": "40.0", "name": "loading.desktop/Free.fr_warm" }, { - "duration": "66.0", + "duration": "46.0", "name": "loading.desktop/HTML5Rocks_cold" }, { - "duration": "48.0", + "duration": "44.0", "name": "loading.desktop/HTML5Rocks_warm" }, { - "duration": "38.0", + "duration": "43.0", "name": "loading.desktop/Haraj_cold" }, { - "duration": "38.0", + "duration": "43.0", "name": "loading.desktop/Haraj_warm" }, { - "duration": "47.0", + "duration": "50.0", "name": "loading.desktop/HatenaBookmark_cold" }, { - "duration": "51.0", + "duration": "54.0", "name": "loading.desktop/HatenaBookmark_warm" }, { - "duration": "50.0", + "duration": "60.0", "name": "loading.desktop/IGN_cold" }, { - "duration": "53.0", + "duration": "64.0", "name": "loading.desktop/IGN_warm" }, { - "duration": "51.0", + "duration": "47.0", "name": "loading.desktop/IMDB_cold" }, { - "duration": "54.0", + "duration": "50.0", "name": "loading.desktop/IMDB_warm" }, { - "duration": "47.0", + "duration": "41.0", "name": "loading.desktop/IndiaTimes_cold" }, { - "duration": "51.0", + "duration": "45.0", "name": "loading.desktop/IndiaTimes_warm" }, { - "duration": "48.0", + "duration": "51.0", "name": "loading.desktop/Kakaku_cold" }, { - "duration": "53.0", + "duration": "56.0", "name": "loading.desktop/Kakaku_warm" }, { - "duration": "68.0", + "duration": "99.0", "name": "loading.desktop/Kenh14_cold" }, { - "duration": "80.0", + "duration": "112.0", "name": "loading.desktop/Kenh14_warm" }, { - "duration": "39.0", + "duration": "41.0", "name": "loading.desktop/Mercadolivre_cold" }, { - "duration": "68.0", + "duration": "45.0", "name": "loading.desktop/Mercadolivre_warm" }, { - "duration": "59.0", + "duration": "88.0", "name": "loading.desktop/Naver_cold" }, { - "duration": "70.0", + "duration": "89.0", "name": "loading.desktop/Naver_warm" }, { - "duration": "25.0", + "duration": "26.0", "name": "loading.desktop/Orange_cold" }, { - "duration": "25.0", + "duration": "26.0", "name": "loading.desktop/Orange_warm" }, { - "duration": "50.0", + "duration": "49.0", "name": "loading.desktop/Pantip_cold" }, { - "duration": "53.0", + "duration": "52.0", "name": "loading.desktop/Pantip_warm" }, { - "duration": "51.0", + "duration": "50.0", "name": "loading.desktop/PremierLeague_cold" }, { - "duration": "55.0", + "duration": "56.0", "name": "loading.desktop/PremierLeague_warm" }, { - "duration": "62.0", + "duration": "50.0", "name": "loading.desktop/QQ_cold" }, { - "duration": "69.0", + "duration": "56.0", "name": "loading.desktop/QQ_warm" }, { - "duration": "50.0", + "duration": "49.0", "name": "loading.desktop/REI_cold" }, { @@ -1732,35 +1732,35 @@ "name": "loading.desktop/REI_warm" }, { - "duration": "59.0", + "duration": "47.0", "name": "loading.desktop/Ruten_cold" }, { - "duration": "60.0", + "duration": "48.0", "name": "loading.desktop/Ruten_warm" }, { - "duration": "61.0", + "duration": "48.0", "name": "loading.desktop/Sina_cold" }, { - "duration": "66.0", + "duration": "53.0", "name": "loading.desktop/Sina_warm" }, { - "duration": "65.0", + "duration": "53.0", "name": "loading.desktop/Taobao_cold" }, { - "duration": "75.0", + "duration": "63.0", "name": "loading.desktop/Taobao_warm" }, { - "duration": "52.0", + "duration": "48.0", "name": "loading.desktop/TheOnion_cold" }, { - "duration": "36.0", + "duration": "32.0", "name": "loading.desktop/TheOnion_warm" }, { @@ -1768,11 +1768,11 @@ "name": "loading.desktop/TheVerge_cold" }, { - "duration": "59.0", + "duration": "86.0", "name": "loading.desktop/TheVerge_warm" }, { - "duration": "53.0", + "duration": "52.0", "name": "loading.desktop/TicketMaster_cold" }, { @@ -1780,55 +1780,55 @@ "name": "loading.desktop/TicketMaster_warm" }, { - "duration": "65.0", + "duration": "95.0", "name": "loading.desktop/Vietnamnet_cold" }, { - "duration": "74.0", + "duration": "106.0", "name": "loading.desktop/Vietnamnet_warm" }, { - "duration": "62.0", + "duration": "91.0", "name": "loading.desktop/Vnexpress_cold" }, { - "duration": "70.0", + "duration": "99.0", "name": "loading.desktop/Vnexpress_warm" }, { - "duration": "35.0", + "duration": "34.0", "name": "loading.desktop/Walgreens_cold" }, { - "duration": "35.0", + "duration": "34.0", "name": "loading.desktop/Walgreens_warm" }, { - "duration": "46.0", + "duration": "41.0", "name": "loading.desktop/Yandex_cold" }, { - "duration": "49.0", + "duration": "43.0", "name": "loading.desktop/Yandex_warm" }, { - "duration": "48.0", + "duration": "51.0", "name": "loading.desktop/amazon.co.jp_cold" }, { - "duration": "55.0", + "duration": "58.0", "name": "loading.desktop/amazon.co.jp_warm" }, { - "duration": "49.0", + "duration": "51.0", "name": "loading.desktop/ja.wikipedia_cold" }, { - "duration": "53.0", + "duration": "71.0", "name": "loading.desktop/ja.wikipedia_warm" }, { - "duration": "54.0", + "duration": "53.0", "name": "loading.desktop/money.cnn_cold" }, { @@ -1836,55 +1836,55 @@ "name": "loading.desktop/money.cnn_warm" }, { - "duration": "47.0", + "duration": "42.0", "name": "loading.desktop/ru.wikipedia_cold" }, { - "duration": "51.0", + "duration": "45.0", "name": "loading.desktop/ru.wikipedia_warm" }, { - "duration": "42.0", + "duration": "44.0", "name": "loading.desktop/uol.com.br_cold" }, { - "duration": "51.0", + "duration": "53.0", "name": "loading.desktop/uol.com.br_warm" }, { - "duration": "47.0", + "duration": "49.0", "name": "loading.desktop/yahoo.co.jp_cold" }, { - "duration": "49.0", + "duration": "52.0", "name": "loading.desktop/yahoo.co.jp_warm" }, { - "duration": "29.0", + "duration": "26.0", "name": "media.desktop/mse.html?media=aac_audio.mp4" }, { - "duration": "29.0", + "duration": "26.0", "name": "media.desktop/mse.html?media=aac_audio.mp4,h264_video.mp4" }, { - "duration": "28.0", + "duration": "25.0", "name": "media.desktop/mse.html?media=h264_video.mp4" }, { - "duration": "28.0", + "duration": "24.0", "name": "media.desktop/mse.html?media=tulip0.av1.mp4" }, { - "duration": "29.0", + "duration": "25.0", "name": "media.desktop/mse.html?media=tulip2.vp9.webm" }, { - "duration": "148.0", + "duration": "155.0", "name": "media.desktop/video.html?src=boat_1080p60fps_vp9.webm" }, { - "duration": "44.0", + "duration": "43.0", "name": "media.desktop/video.html?src=crowd1080.mp4" }, { @@ -1892,71 +1892,71 @@ "name": "media.desktop/video.html?src=crowd1080.webm" }, { - "duration": "34.0", + "duration": "42.0", "name": "media.desktop/video.html?src=crowd1080_vp9.webm" }, { - "duration": "147.0", + "duration": "154.0", "name": "media.desktop/video.html?src=foodmarket_720p30fps.mp4" }, { - "duration": "20.0", + "duration": "17.0", "name": "media.desktop/video.html?src=garden2_10s.mp4&seek" }, { - "duration": "30.0", + "duration": "37.0", "name": "media.desktop/video.html?src=garden2_10s.webm&seek" }, { - "duration": "20.0", + "duration": "17.0", "name": "media.desktop/video.html?src=smpte_3840x2160_60fps_vp9.webm&seek" }, { - "duration": "34.0", + "duration": "31.0", "name": "media.desktop/video.html?src=tulip0.av1.mp4" }, { - "duration": "28.0", + "duration": "24.0", "name": "media.desktop/video.html?src=tulip0.av1.mp4&seek" }, { - "duration": "40.0", + "duration": "48.0", "name": "media.desktop/video.html?src=tulip2.m4a&type=audio" }, { - "duration": "40.0", + "duration": "48.0", "name": "media.desktop/video.html?src=tulip2.mp3&type=audio" }, { - "duration": "27.0", + "duration": "34.0", "name": "media.desktop/video.html?src=tulip2.mp3&type=audio&seek" }, { - "duration": "40.0", + "duration": "48.0", "name": "media.desktop/video.html?src=tulip2.mp4" }, { - "duration": "41.0", + "duration": "49.0", "name": "media.desktop/video.html?src=tulip2.mp4&busyjs" }, { - "duration": "40.0", + "duration": "48.0", "name": "media.desktop/video.html?src=tulip2.ogg&type=audio" }, { - "duration": "27.0", + "duration": "34.0", "name": "media.desktop/video.html?src=tulip2.ogg&type=audio&seek" }, { - "duration": "40.0", + "duration": "48.0", "name": "media.desktop/video.html?src=tulip2.vp9.webm" }, { - "duration": "35.0", + "duration": "32.0", "name": "media.desktop/video.html?src=tulip2.vp9.webm&background" }, { - "duration": "40.0", + "duration": "48.0", "name": "media.desktop/video.html?src=tulip2.vp9.webm_WiFi" }, { @@ -1992,95 +1992,95 @@ "name": "memory.desktop/TrivialWebGLPageSharedPageState" }, { - "duration": "70.0", + "duration": "65.0", "name": "memory.desktop/WebWorker" }, { - "duration": "52.0", + "duration": "48.0", "name": "octane/Octane" }, { - "duration": "58.0", + "duration": "55.0", "name": "power.desktop/TrivialAnimationPageSharedPageState" }, { - "duration": "57.0", + "duration": "55.0", "name": "power.desktop/TrivialBlinkingCursorPageSharedPageState" }, { - "duration": "58.0", + "duration": "55.0", "name": "power.desktop/TrivialBlurAnimationPageSharedPageState" }, { - "duration": "58.0", + "duration": "55.0", "name": "power.desktop/TrivialCanvasPageSharedPageState" }, { - "duration": "59.0", + "duration": "56.0", "name": "power.desktop/TrivialFullscreenVideoPageSharedPageState" }, { - "duration": "57.0", + "duration": "55.0", "name": "power.desktop/TrivialGifPageSharedPageState" }, { - "duration": "58.0", + "duration": "56.0", "name": "power.desktop/TrivialScrollingPageSharedPageState" }, { - "duration": "58.0", + "duration": "55.0", "name": "power.desktop/TrivialWebGLPageSharedPageState" }, { - "duration": "24.0", + "duration": "21.0", "name": "power.desktop/abcnews" }, { - "duration": "60.0", + "duration": "57.0", "name": "power.desktop/indiatimes" }, { - "duration": "58.0", + "duration": "55.0", "name": "power.desktop/instagram" }, { - "duration": "59.0", + "duration": "56.0", "name": "power.desktop/microsoft" }, { - "duration": "62.0", + "duration": "58.0", "name": "power.desktop/sina" }, { - "duration": "68.0", + "duration": "64.0", "name": "power.desktop/slideshare" }, { - "duration": "61.0", + "duration": "58.0", "name": "power.desktop/uol" }, { - "duration": "32.0", + "duration": "29.0", "name": "rasterize_and_record_micro.top_25/file://static_top_25/amazon.html" }, { - "duration": "12.0", + "duration": "11.0", "name": "rasterize_and_record_micro.top_25/file://static_top_25/blogger.html" }, { - "duration": "15.0", + "duration": "14.0", "name": "rasterize_and_record_micro.top_25/file://static_top_25/booking.html" }, { - "duration": "17.0", + "duration": "16.0", "name": "rasterize_and_record_micro.top_25/file://static_top_25/cnn.html" }, { - "duration": "15.0", + "duration": "14.0", "name": "rasterize_and_record_micro.top_25/file://static_top_25/ebay.html" }, { - "duration": "25.0", + "duration": "35.0", "name": "rasterize_and_record_micro.top_25/file://static_top_25/espn.html" }, { @@ -2144,7 +2144,7 @@ "name": "rasterize_and_record_micro.top_25/file://static_top_25/yahooanswers.html" }, { - "duration": "16.0", + "duration": "17.0", "name": "rasterize_and_record_micro.top_25/file://static_top_25/yahoogames.html" }, { @@ -2160,359 +2160,359 @@ "name": "rasterize_and_record_micro.top_25/file://static_top_25/youtube.html" }, { - "duration": "57.0", + "duration": "65.0", "name": "rendering.desktop/accu_weather_2018" }, { - "duration": "59.0", + "duration": "65.0", "name": "rendering.desktop/accu_weather_pinch_2018" }, { - "duration": "48.0", + "duration": "53.0", "name": "rendering.desktop/amazon_2018" }, { - "duration": "46.0", + "duration": "51.0", "name": "rendering.desktop/amazon_pinch_2018" }, { - "duration": "48.0", + "duration": "53.0", "name": "rendering.desktop/analog_clock_svg" }, { - "duration": "53.0", + "duration": "57.0", "name": "rendering.desktop/animometer_webgl" }, { - "duration": "49.0", + "duration": "54.0", "name": "rendering.desktop/animometer_webgl_attrib_arrays" }, { - "duration": "51.0", + "duration": "56.0", "name": "rendering.desktop/animometer_webgl_fast_call" }, { - "duration": "51.0", + "duration": "56.0", "name": "rendering.desktop/animometer_webgl_indexed" }, { - "duration": "50.0", + "duration": "56.0", "name": "rendering.desktop/animometer_webgl_indexed_fast_call" }, { - "duration": "49.0", + "duration": "55.0", "name": "rendering.desktop/animometer_webgl_indexed_multi_draw" }, { - "duration": "49.0", + "duration": "54.0", "name": "rendering.desktop/animometer_webgl_indexed_multi_draw_base_vertex_base_instance" }, { - "duration": "49.0", + "duration": "54.0", "name": "rendering.desktop/animometer_webgl_multi_draw" }, { - "duration": "54.0", + "duration": "59.0", "name": "rendering.desktop/aquarium" }, { - "duration": "57.0", + "duration": "61.0", "name": "rendering.desktop/aquarium_20k" }, { - "duration": "57.0", + "duration": "61.0", "name": "rendering.desktop/aquarium_20k_fast_call" }, { - "duration": "49.0", + "duration": "54.0", "name": "rendering.desktop/background_color_animation" }, { - "duration": "47.0", + "duration": "53.0", "name": "rendering.desktop/background_color_animation_with_gradient" }, { - "duration": "48.0", + "duration": "53.0", "name": "rendering.desktop/balls_css_key_frame_animations" }, { - "duration": "50.0", + "duration": "55.0", "name": "rendering.desktop/balls_css_key_frame_animations_composited_transform" }, { - "duration": "47.0", + "duration": "44.0", "name": "rendering.desktop/balls_css_transition_2_properties" }, { - "duration": "47.0", + "duration": "43.0", "name": "rendering.desktop/balls_css_transition_40_properties" }, { - "duration": "47.0", + "duration": "43.0", "name": "rendering.desktop/balls_css_transition_all_properties" }, { - "duration": "46.0", + "duration": "43.0", "name": "rendering.desktop/balls_javascript_canvas" }, { - "duration": "46.0", + "duration": "43.0", "name": "rendering.desktop/balls_javascript_css" }, { - "duration": "47.0", + "duration": "44.0", "name": "rendering.desktop/balls_svg_animations" }, { - "duration": "56.0", + "duration": "47.0", "name": "rendering.desktop/blob" }, { - "duration": "62.0", + "duration": "56.0", "name": "rendering.desktop/blogspot_2018" }, { - "duration": "57.0", + "duration": "49.0", "name": "rendering.desktop/blogspot_pinch_2018" }, { - "duration": "42.0", + "duration": "39.0", "name": "rendering.desktop/blur_rotating_background" }, { - "duration": "47.0", + "duration": "40.0", "name": "rendering.desktop/booking.com_2018" }, { - "duration": "49.0", + "duration": "41.0", "name": "rendering.desktop/booking_pinch_2018" }, { - "duration": "45.0", + "duration": "42.0", "name": "rendering.desktop/bouncing_balls_15" }, { - "duration": "49.0", + "duration": "45.0", "name": "rendering.desktop/bouncing_balls_shadow" }, { - "duration": "50.0", + "duration": "44.0", "name": "rendering.desktop/bouncing_clipped_rectangles" }, { - "duration": "50.0", + "duration": "43.0", "name": "rendering.desktop/bouncing_gradient_circles" }, { - "duration": "48.0", + "duration": "42.0", "name": "rendering.desktop/bouncing_png_images" }, { - "duration": "53.0", + "duration": "45.0", "name": "rendering.desktop/bouncing_svg_images" }, { - "duration": "31.0", + "duration": "28.0", "name": "rendering.desktop/camera_to_webgl" }, { - "duration": "49.0", + "duration": "42.0", "name": "rendering.desktop/canvas2d_to_texture.html" }, { - "duration": "56.0", + "duration": "53.0", "name": "rendering.desktop/canvas_05000_pixels_per_second" }, { - "duration": "54.0", + "duration": "50.0", "name": "rendering.desktop/canvas_10000_pixels_per_second" }, { - "duration": "51.0", + "duration": "50.0", "name": "rendering.desktop/canvas_20000_pixels_per_second" }, { - "duration": "52.0", + "duration": "48.0", "name": "rendering.desktop/canvas_40000_pixels_per_second" }, { - "duration": "52.0", + "duration": "48.0", "name": "rendering.desktop/canvas_60000_pixels_per_second" }, { - "duration": "52.0", + "duration": "48.0", "name": "rendering.desktop/canvas_75000_pixels_per_second" }, { - "duration": "52.0", + "duration": "48.0", "name": "rendering.desktop/canvas_90000_pixels_per_second" }, { - "duration": "53.0", + "duration": "43.0", "name": "rendering.desktop/canvas_animation_no_clear" }, { - "duration": "54.0", + "duration": "43.0", "name": "rendering.desktop/canvas_arcs" }, { - "duration": "52.0", + "duration": "43.0", "name": "rendering.desktop/canvas_font_cycler" }, { - "duration": "49.0", + "duration": "43.0", "name": "rendering.desktop/canvas_lines" }, { - "duration": "49.0", + "duration": "43.0", "name": "rendering.desktop/canvas_to_blob" }, { - "duration": "48.0", + "duration": "41.0", "name": "rendering.desktop/canvas_to_canvas_draw" }, { - "duration": "40.0", + "duration": "42.0", "name": "rendering.desktop/cats_unscaled" }, { - "duration": "38.0", + "duration": "33.0", "name": "rendering.desktop/cats_viewport_width" }, { - "duration": "51.0", + "duration": "45.0", "name": "rendering.desktop/cc_poster_circle" }, { - "duration": "44.0", + "duration": "39.0", "name": "rendering.desktop/cc_scroll_text_only" }, { - "duration": "57.0", + "duration": "45.0", "name": "rendering.desktop/chip_tune" }, { - "duration": "53.0", + "duration": "44.0", "name": "rendering.desktop/cnn_2018" }, { - "duration": "63.0", + "duration": "54.0", "name": "rendering.desktop/cnn_pinch_2018" }, { - "duration": "56.0", + "duration": "41.0", "name": "rendering.desktop/compositor_heavy_animation" }, { - "duration": "50.0", + "duration": "40.0", "name": "rendering.desktop/crafty_mind" }, { - "duration": "59.0", + "duration": "42.0", "name": "rendering.desktop/css_animations_many_keyframes" }, { - "duration": "56.0", + "duration": "40.0", "name": "rendering.desktop/css_animations_simultaneous_inline_style" }, { - "duration": "51.0", + "duration": "40.0", "name": "rendering.desktop/css_animations_simultaneous_new_element" }, { - "duration": "46.0", + "duration": "40.0", "name": "rendering.desktop/css_animations_simultaneous_style_element" }, { - "duration": "45.0", + "duration": "39.0", "name": "rendering.desktop/css_animations_simultaneous_updating_class" }, { - "duration": "46.0", + "duration": "39.0", "name": "rendering.desktop/css_animations_staggered_infinite_iterations" }, { - "duration": "50.0", + "duration": "41.0", "name": "rendering.desktop/css_animations_staggered_inline_style" }, { - "duration": "51.0", + "duration": "41.0", "name": "rendering.desktop/css_animations_staggered_new_element" }, { - "duration": "51.0", + "duration": "41.0", "name": "rendering.desktop/css_animations_staggered_style_element" }, { - "duration": "51.0", + "duration": "41.0", "name": "rendering.desktop/css_animations_staggered_updating_class" }, { - "duration": "51.0", + "duration": "41.0", "name": "rendering.desktop/css_animations_triggered_inline_style" }, { - "duration": "51.0", + "duration": "41.0", "name": "rendering.desktop/css_animations_triggered_new_element" }, { - "duration": "51.0", + "duration": "40.0", "name": "rendering.desktop/css_animations_triggered_style_element" }, { - "duration": "50.0", + "duration": "41.0", "name": "rendering.desktop/css_animations_triggered_updating_class" }, { - "duration": "51.0", + "duration": "45.0", "name": "rendering.desktop/css_opacity_plus_n_layers_99" }, { - "duration": "47.0", + "duration": "39.0", "name": "rendering.desktop/css_transitions_inline_style" }, { - "duration": "47.0", + "duration": "40.0", "name": "rendering.desktop/css_transitions_new_element" }, { - "duration": "47.0", + "duration": "40.0", "name": "rendering.desktop/css_transitions_staggered_inline_style" }, { - "duration": "50.0", + "duration": "40.0", "name": "rendering.desktop/css_transitions_staggered_new_element" }, { - "duration": "48.0", + "duration": "40.0", "name": "rendering.desktop/css_transitions_staggered_style_element" }, { - "duration": "47.0", + "duration": "45.0", "name": "rendering.desktop/css_transitions_staggered_updating_class" }, { - "duration": "47.0", + "duration": "43.0", "name": "rendering.desktop/css_transitions_style_element" }, { - "duration": "49.0", + "duration": "44.0", "name": "rendering.desktop/css_transitions_triggered_inline_style" }, { - "duration": "51.0", + "duration": "44.0", "name": "rendering.desktop/css_transitions_triggered_new_element" }, { - "duration": "50.0", + "duration": "44.0", "name": "rendering.desktop/css_transitions_triggered_style_element" }, { - "duration": "49.0", + "duration": "44.0", "name": "rendering.desktop/css_transitions_triggered_updating_class" }, { - "duration": "44.0", + "duration": "42.0", "name": "rendering.desktop/css_transitions_updating_class" }, { @@ -2524,23 +2524,23 @@ "name": "rendering.desktop/css_value_type_filter" }, { - "duration": "42.0", + "duration": "43.0", "name": "rendering.desktop/css_value_type_length" }, { - "duration": "42.0", + "duration": "43.0", "name": "rendering.desktop/css_value_type_length_complex" }, { - "duration": "42.0", + "duration": "43.0", "name": "rendering.desktop/css_value_type_length_simple" }, { - "duration": "42.0", + "duration": "43.0", "name": "rendering.desktop/css_value_type_path" }, { - "duration": "42.0", + "duration": "43.0", "name": "rendering.desktop/css_value_type_shadow" }, { @@ -2552,15 +2552,15 @@ "name": "rendering.desktop/css_value_type_transform_simple" }, { - "duration": "42.0", + "duration": "43.0", "name": "rendering.desktop/docs_paper.html" }, { - "duration": "42.0", + "duration": "43.0", "name": "rendering.desktop/docs_resume.html" }, { - "duration": "42.0", + "duration": "43.0", "name": "rendering.desktop/docs_table.html" }, { @@ -2572,7 +2572,7 @@ "name": "rendering.desktop/draw_image_not_pixel_aligned" }, { - "duration": "42.0", + "duration": "43.0", "name": "rendering.desktop/dynamic_canvas_to_hw_accelerated_canvas.html" }, { @@ -2580,11 +2580,11 @@ "name": "rendering.desktop/dynamic_cube_map" }, { - "duration": "42.0", + "duration": "43.0", "name": "rendering.desktop/dynamic_webgl_to_hw_accelerated_canvas.html" }, { - "duration": "44.0", + "duration": "45.0", "name": "rendering.desktop/earth" }, { @@ -2592,7 +2592,7 @@ "name": "rendering.desktop/ebay_2018" }, { - "duration": "51.0", + "duration": "50.0", "name": "rendering.desktop/ebay_pinch_2018" }, { @@ -2600,163 +2600,163 @@ "name": "rendering.desktop/effect_games" }, { - "duration": "60.0", + "duration": "58.0", "name": "rendering.desktop/espn_2018" }, { - "duration": "47.0", + "duration": "48.0", "name": "rendering.desktop/espn_pinch_2018" }, { - "duration": "43.0", + "duration": "42.0", "name": "rendering.desktop/extra_large_texture_uploads" }, { - "duration": "41.0", + "duration": "48.0", "name": "rendering.desktop/facebook_2018" }, { - "duration": "44.0", + "duration": "45.0", "name": "rendering.desktop/facebook_pinch_2018" }, { - "duration": "42.0", + "duration": "39.0", "name": "rendering.desktop/falling_particle_simulation_cpu.html" }, { - "duration": "42.0", + "duration": "39.0", "name": "rendering.desktop/falling_particle_simulation_gpu.html" }, { - "duration": "42.0", + "duration": "39.0", "name": "rendering.desktop/fill_clear_rect.html" }, { - "duration": "42.0", + "duration": "39.0", "name": "rendering.desktop/fill_shapes" }, { - "duration": "46.0", + "duration": "42.0", "name": "rendering.desktop/filter_terrain_svg" }, { - "duration": "41.0", + "duration": "42.0", "name": "rendering.desktop/geo_apis" }, { - "duration": "42.0", + "duration": "39.0", "name": "rendering.desktop/get_image_data_cpu.html" }, { - "duration": "42.0", + "duration": "39.0", "name": "rendering.desktop/get_image_data_gpu.html" }, { - "duration": "45.0", + "duration": "39.0", "name": "rendering.desktop/gmail_2018" }, { - "duration": "60.0", + "duration": "54.0", "name": "rendering.desktop/gmail_move_2018" }, { - "duration": "44.0", + "duration": "39.0", "name": "rendering.desktop/gmail_pinch_2018" }, { - "duration": "37.0", + "duration": "34.0", "name": "rendering.desktop/google_calendar_2018" }, { - "duration": "41.0", + "duration": "37.0", "name": "rendering.desktop/google_calendar_pinch_2018" }, { - "duration": "44.0", + "duration": "40.0", "name": "rendering.desktop/google_docs_2018" }, { - "duration": "39.0", + "duration": "36.0", "name": "rendering.desktop/google_image_pinch_2018" }, { - "duration": "39.0", + "duration": "36.0", "name": "rendering.desktop/google_image_search_2018" }, { - "duration": "40.0", + "duration": "37.0", "name": "rendering.desktop/google_plus_2018" }, { - "duration": "39.0", + "duration": "36.0", "name": "rendering.desktop/google_search_pinch_2018" }, { - "duration": "38.0", + "duration": "34.0", "name": "rendering.desktop/google_web_search_2018" }, { - "duration": "42.0", + "duration": "38.0", "name": "rendering.desktop/gpu_bound_shader.html" }, { - "duration": "43.0", + "duration": "39.0", "name": "rendering.desktop/guimark_vector_chart" }, { - "duration": "43.0", + "duration": "39.0", "name": "rendering.desktop/hakim" }, { - "duration": "42.0", + "duration": "39.0", "name": "rendering.desktop/hw_accelerated_canvas_to_sw_canvas.html" }, { - "duration": "63.0", + "duration": "55.0", "name": "rendering.desktop/ie_chalkboard" }, { - "duration": "50.0", + "duration": "73.0", "name": "rendering.desktop/ie_pirate_mark" }, { - "duration": "44.0", + "duration": "40.0", "name": "rendering.desktop/infinite_scroll_element_n_layers_99" }, { - "duration": "44.0", + "duration": "40.0", "name": "rendering.desktop/infinite_scroll_root_fixed_n_layers_99" }, { - "duration": "44.0", + "duration": "40.0", "name": "rendering.desktop/infinite_scroll_root_n_layers_99" }, { - "duration": "45.0", + "duration": "50.0", "name": "rendering.desktop/jarro_doverson" }, { - "duration": "35.0", + "duration": "36.0", "name": "rendering.desktop/jpeg_decoding_rgb_and_gpu_rasterization" }, { - "duration": "35.0", + "duration": "36.0", "name": "rendering.desktop/jpeg_decoding_yuv_and_gpu_rasterization" }, { - "duration": "46.0", + "duration": "42.0", "name": "rendering.desktop/js_full_screen_invalidation" }, { - "duration": "44.0", + "duration": "41.0", "name": "rendering.desktop/js_opacity_plus_n_layers_99" }, { - "duration": "42.0", + "duration": "45.0", "name": "rendering.desktop/js_paint_plus_n_layers_99" }, { - "duration": "41.0", + "duration": "42.0", "name": "rendering.desktop/js_poster_circle" }, { @@ -2764,11 +2764,11 @@ "name": "rendering.desktop/js_scroll_text_only" }, { - "duration": "39.0", + "duration": "40.0", "name": "rendering.desktop/kevs_3d" }, { - "duration": "39.0", + "duration": "40.0", "name": "rendering.desktop/keyframed_animations" }, { @@ -2776,79 +2776,79 @@ "name": "rendering.desktop/large_texture_uploads" }, { - "duration": "37.0", + "duration": "38.0", "name": "rendering.desktop/linkedin_2018" }, { - "duration": "45.0", + "duration": "46.0", "name": "rendering.desktop/linkedin_pinch_2018" }, { - "duration": "84.0", + "duration": "85.0", "name": "rendering.desktop/lost_crypt" }, { - "duration": "75.0", + "duration": "76.0", "name": "rendering.desktop/lost_crypt_fast_call" }, { - "duration": "39.0", + "duration": "40.0", "name": "rendering.desktop/main_0fps_impl_60fps" }, { - "duration": "39.0", + "duration": "40.0", "name": "rendering.desktop/main_0fps_impl_60fps_no_update" }, { - "duration": "39.0", + "duration": "40.0", "name": "rendering.desktop/main_0fps_impl_60fps_no_update_jank" }, { - "duration": "38.0", + "duration": "40.0", "name": "rendering.desktop/main_0fps_with_jank_impl_0fps" }, { - "duration": "39.0", + "duration": "40.0", "name": "rendering.desktop/main_15fps_impl_0fps" }, { - "duration": "39.0", + "duration": "40.0", "name": "rendering.desktop/main_15fps_with_jank_impl_0fps" }, { - "duration": "39.0", + "duration": "40.0", "name": "rendering.desktop/main_30fps_impl_0fps" }, { - "duration": "39.0", + "duration": "40.0", "name": "rendering.desktop/main_30fps_impl_60fps" }, { - "duration": "39.0", + "duration": "40.0", "name": "rendering.desktop/main_60fps_impl_0fps" }, { - "duration": "39.0", + "duration": "40.0", "name": "rendering.desktop/main_60fps_impl_60fps" }, { - "duration": "39.0", + "duration": "40.0", "name": "rendering.desktop/main_60fps_impl_60fps_no_update" }, { - "duration": "39.0", + "duration": "40.0", "name": "rendering.desktop/main_60fps_impl_60fps_no_update_jank" }, { - "duration": "53.0", + "duration": "54.0", "name": "rendering.desktop/main_60fps_with_extreme_jank_impl_0fps" }, { - "duration": "39.0", + "duration": "40.0", "name": "rendering.desktop/main_60fps_with_jank_and_delay_impl_60fps" }, { - "duration": "39.0", + "duration": "40.0", "name": "rendering.desktop/main_60fps_with_jank_impl_0fps" }, { @@ -2856,587 +2856,587 @@ "name": "rendering.desktop/main_animations_half_presented" }, { - "duration": "39.0", + "duration": "40.0", "name": "rendering.desktop/man_in_blue" }, { - "duration": "42.0", + "duration": "43.0", "name": "rendering.desktop/many_images" }, { - "duration": "42.0", + "duration": "43.0", "name": "rendering.desktop/many_planets_deep" }, { - "duration": "43.0", + "duration": "39.0", "name": "rendering.desktop/maps_move_2018" }, { - "duration": "41.0", + "duration": "75.0", "name": "rendering.desktop/maps_perf_test" }, { - "duration": "39.0", + "duration": "69.0", "name": "rendering.desktop/medium_texture_uploads" }, { - "duration": "39.0", + "duration": "73.0", "name": "rendering.desktop/megi_dish" }, { - "duration": "73.0", + "duration": "131.0", "name": "rendering.desktop/microgame_fps" }, { - "duration": "75.0", + "duration": "117.0", "name": "rendering.desktop/microgame_fps_fast_call" }, { - "duration": "39.0", + "duration": "69.0", "name": "rendering.desktop/microsoft_asteroid_belt" }, { - "duration": "40.0", + "duration": "69.0", "name": "rendering.desktop/microsoft_fireflies" }, { - "duration": "39.0", + "duration": "69.0", "name": "rendering.desktop/microsoft_fish_ie_tank" }, { - "duration": "39.0", + "duration": "68.0", "name": "rendering.desktop/microsoft_performance" }, { - "duration": "39.0", + "duration": "71.0", "name": "rendering.desktop/microsoft_snow" }, { - "duration": "39.0", + "duration": "70.0", "name": "rendering.desktop/microsoft_speed_reading" }, { - "duration": "40.0", + "duration": "68.0", "name": "rendering.desktop/microsoft_tweet_map" }, { - "duration": "41.0", + "duration": "74.0", "name": "rendering.desktop/microsoft_video_city" }, { - "duration": "39.0", + "duration": "67.0", "name": "rendering.desktop/microsoft_worker_fountains" }, { - "duration": "39.0", + "duration": "67.0", "name": "rendering.desktop/mix_10k" }, { - "duration": "39.0", + "duration": "73.0", "name": "rendering.desktop/mix_blend_mode_animation_difference" }, { - "duration": "39.0", + "duration": "72.0", "name": "rendering.desktop/mix_blend_mode_animation_hue" }, { - "duration": "39.0", + "duration": "71.0", "name": "rendering.desktop/mix_blend_mode_animation_propagating_isolation" }, { - "duration": "39.0", + "duration": "65.0", "name": "rendering.desktop/mix_blend_mode_animation_screen" }, { - "duration": "44.0", + "duration": "68.0", "name": "rendering.desktop/motion_mark_canvas_fill_shapes" }, { - "duration": "39.0", + "duration": "67.0", "name": "rendering.desktop/motion_mark_canvas_stroke_shapes" }, { - "duration": "49.0", + "duration": "71.0", "name": "rendering.desktop/new_tilings" }, { - "duration": "51.0", + "duration": "74.0", "name": "rendering.desktop/nvidia_vertex_buffer_object" }, { - "duration": "48.0", + "duration": "68.0", "name": "rendering.desktop/off_screen_main_60fps" }, { - "duration": "46.0", + "duration": "68.0", "name": "rendering.desktop/off_screen_main_60fps_jank" }, { - "duration": "46.0", + "duration": "69.0", "name": "rendering.desktop/overlay_background_color_css_transitions_page" }, { - "duration": "49.0", + "duration": "70.0", "name": "rendering.desktop/particles" }, { - "duration": "56.0", + "duration": "85.0", "name": "rendering.desktop/pinterest_2018" }, { - "duration": "48.0", + "duration": "68.0", "name": "rendering.desktop/put_and_create_imagebitmap_from_imagedata" }, { - "duration": "46.0", + "duration": "45.0", "name": "rendering.desktop/put_get_image_data" }, { - "duration": "47.0", + "duration": "43.0", "name": "rendering.desktop/put_image_data.html" }, { - "duration": "44.0", + "duration": "40.0", "name": "rendering.desktop/raf" }, { - "duration": "44.0", + "duration": "40.0", "name": "rendering.desktop/raf_animation" }, { - "duration": "43.0", + "duration": "40.0", "name": "rendering.desktop/raf_canvas" }, { - "duration": "44.0", + "duration": "39.0", "name": "rendering.desktop/raf_touch_animation" }, { - "duration": "46.0", + "duration": "42.0", "name": "rendering.desktop/repaint_amazon_2018" }, { - "duration": "43.0", + "duration": "39.0", "name": "rendering.desktop/repaint_cnn_2018" }, { - "duration": "43.0", + "duration": "39.0", "name": "rendering.desktop/repaint_facebook_2018" }, { - "duration": "43.0", + "duration": "39.0", "name": "rendering.desktop/repaint_google_search_2018" }, { - "duration": "43.0", + "duration": "39.0", "name": "rendering.desktop/repaint_instagram_2018" }, { - "duration": "43.0", + "duration": "39.0", "name": "rendering.desktop/repaint_reddit_2018" }, { - "duration": "43.0", + "duration": "39.0", "name": "rendering.desktop/repaint_theverge_2018" }, { - "duration": "43.0", + "duration": "39.0", "name": "rendering.desktop/repaint_twitter_2018" }, { - "duration": "42.0", + "duration": "39.0", "name": "rendering.desktop/repaint_wikipedia_2018" }, { - "duration": "43.0", + "duration": "39.0", "name": "rendering.desktop/repaint_yahoo_homepage_2018" }, { - "duration": "47.0", + "duration": "46.0", "name": "rendering.desktop/runway_2019" }, { - "duration": "49.0", + "duration": "46.0", "name": "rendering.desktop/san_angeles" }, { - "duration": "37.0", + "duration": "44.0", "name": "rendering.desktop/second_batch_js_heavy" }, { - "duration": "37.0", + "duration": "44.0", "name": "rendering.desktop/second_batch_js_light" }, { - "duration": "37.0", + "duration": "44.0", "name": "rendering.desktop/second_batch_js_medium" }, { - "duration": "44.0", + "duration": "50.0", "name": "rendering.desktop/sheets_render.html" }, { - "duration": "40.0", + "duration": "47.0", "name": "rendering.desktop/simple_text_page" }, { - "duration": "38.0", + "duration": "40.0", "name": "rendering.desktop/simple_touch_drag" }, { - "duration": "87.0", + "duration": "94.0", "name": "rendering.desktop/skelebuddies_wasm_2020" }, { - "duration": "76.0", + "duration": "83.0", "name": "rendering.desktop/skelebuddies_wasm_2020_fast_call" }, { - "duration": "43.0", + "duration": "50.0", "name": "rendering.desktop/small_texture_uploads" }, { - "duration": "49.0", + "duration": "60.0", "name": "rendering.desktop/smash_cat" }, { - "duration": "43.0", + "duration": "50.0", "name": "rendering.desktop/spielzeugz" }, { - "duration": "43.0", + "duration": "48.0", "name": "rendering.desktop/static_canvas_to_hw_accelerated_canvas.html" }, { - "duration": "43.0", + "duration": "46.0", "name": "rendering.desktop/static_webgl_to_hw_accelerated_canvas.html" }, { - "duration": "44.0", + "duration": "46.0", "name": "rendering.desktop/stroke_shapes" }, { - "duration": "40.0", + "duration": "42.0", "name": "rendering.desktop/sync_scroll_offset" }, { - "duration": "57.0", + "duration": "60.0", "name": "rendering.desktop/techcrunch_2018" }, { - "duration": "55.0", + "duration": "52.0", "name": "rendering.desktop/text_05000_pixels_per_second" }, { - "duration": "54.0", + "duration": "50.0", "name": "rendering.desktop/text_10000_pixels_per_second" }, { - "duration": "52.0", + "duration": "50.0", "name": "rendering.desktop/text_20000_pixels_per_second" }, { - "duration": "51.0", + "duration": "48.0", "name": "rendering.desktop/text_40000_pixels_per_second" }, { - "duration": "52.0", + "duration": "58.0", "name": "rendering.desktop/text_60000_pixels_per_second" }, { - "duration": "52.0", + "duration": "56.0", "name": "rendering.desktop/text_75000_pixels_per_second" }, { - "duration": "52.0", + "duration": "56.0", "name": "rendering.desktop/text_90000_pixels_per_second" }, { - "duration": "57.0", + "duration": "61.0", "name": "rendering.desktop/text_constant_full_page_raster_05000_pixels_per_second" }, { - "duration": "55.0", + "duration": "59.0", "name": "rendering.desktop/text_constant_full_page_raster_10000_pixels_per_second" }, { - "duration": "53.0", + "duration": "57.0", "name": "rendering.desktop/text_constant_full_page_raster_20000_pixels_per_second" }, { - "duration": "53.0", + "duration": "57.0", "name": "rendering.desktop/text_constant_full_page_raster_40000_pixels_per_second" }, { - "duration": "50.0", + "duration": "56.0", "name": "rendering.desktop/text_constant_full_page_raster_60000_pixels_per_second" }, { - "duration": "49.0", + "duration": "56.0", "name": "rendering.desktop/text_constant_full_page_raster_75000_pixels_per_second" }, { - "duration": "49.0", + "duration": "56.0", "name": "rendering.desktop/text_constant_full_page_raster_90000_pixels_per_second" }, { - "duration": "56.0", + "duration": "60.0", "name": "rendering.desktop/text_hover_05000_pixels_per_second" }, { - "duration": "54.0", + "duration": "58.0", "name": "rendering.desktop/text_hover_10000_pixels_per_second" }, { - "duration": "52.0", + "duration": "56.0", "name": "rendering.desktop/text_hover_20000_pixels_per_second" }, { - "duration": "52.0", + "duration": "56.0", "name": "rendering.desktop/text_hover_40000_pixels_per_second" }, { - "duration": "52.0", + "duration": "56.0", "name": "rendering.desktop/text_hover_60000_pixels_per_second" }, { - "duration": "52.0", + "duration": "56.0", "name": "rendering.desktop/text_hover_75000_pixels_per_second" }, { - "duration": "51.0", + "duration": "56.0", "name": "rendering.desktop/text_hover_90000_pixels_per_second" }, { - "duration": "47.0", + "duration": "49.0", "name": "rendering.desktop/throughput_scrolling_active_handler" }, { - "duration": "46.0", + "duration": "49.0", "name": "rendering.desktop/throughput_scrolling_composited" }, { - "duration": "47.0", + "duration": "49.0", "name": "rendering.desktop/throughput_scrolling_passive_handler" }, { - "duration": "46.0", + "duration": "49.0", "name": "rendering.desktop/throughput_scrolling_uncomposited" }, { - "duration": "77.0", + "duration": "89.0", "name": "rendering.desktop/tiny_racing_v3_wasm_2020" }, { - "duration": "77.0", + "duration": "79.0", "name": "rendering.desktop/tiny_racing_v3_wasm_2020_fast_call" }, { - "duration": "44.0", + "duration": "46.0", "name": "rendering.desktop/toBlob_duration.html" }, { - "duration": "44.0", + "duration": "46.0", "name": "rendering.desktop/toBlob_duration_jpeg.html" }, { - "duration": "45.0", + "duration": "47.0", "name": "rendering.desktop/toBlob_small_canvas_in_worker.html" }, { - "duration": "41.0", + "duration": "42.0", "name": "rendering.desktop/touch_handler_scrolling" }, { - "duration": "43.0", + "duration": "45.0", "name": "rendering.desktop/transfer_from_imageBitmap.html" }, { - "duration": "43.0", + "duration": "45.0", "name": "rendering.desktop/transform_transitions" }, { - "duration": "43.0", + "duration": "45.0", "name": "rendering.desktop/transform_transitions_js_block" }, { - "duration": "43.0", + "duration": "45.0", "name": "rendering.desktop/twitch_2018" }, { - "duration": "53.0", + "duration": "55.0", "name": "rendering.desktop/twitch_pinch_2018" }, { - "duration": "44.0", + "duration": "46.0", "name": "rendering.desktop/twitter_2018" }, { - "duration": "43.0", + "duration": "45.0", "name": "rendering.desktop/twitter_pinch_2018" }, { - "duration": "44.0", + "duration": "46.0", "name": "rendering.desktop/video_to_hw_accelerated_canvas" }, { - "duration": "44.0", + "duration": "46.0", "name": "rendering.desktop/video_to_sub_texture" }, { - "duration": "44.0", + "duration": "46.0", "name": "rendering.desktop/video_to_sub_texture_flip_and_premultiply" }, { - "duration": "44.0", + "duration": "46.0", "name": "rendering.desktop/video_to_sub_texture_flip_y" }, { - "duration": "44.0", + "duration": "38.0", "name": "rendering.desktop/video_to_sub_texture_premultiply" }, { - "duration": "45.0", + "duration": "37.0", "name": "rendering.desktop/video_to_texture" }, { - "duration": "43.0", + "duration": "36.0", "name": "rendering.desktop/web_animation_value_type_color" }, { - "duration": "43.0", + "duration": "37.0", "name": "rendering.desktop/web_animation_value_type_length_3d" }, { - "duration": "44.0", + "duration": "37.0", "name": "rendering.desktop/web_animation_value_type_length_complex" }, { - "duration": "43.0", + "duration": "37.0", "name": "rendering.desktop/web_animation_value_type_length_simple" }, { - "duration": "41.0", + "duration": "36.0", "name": "rendering.desktop/web_animation_value_type_path" }, { - "duration": "40.0", + "duration": "36.0", "name": "rendering.desktop/web_animation_value_type_shadow" }, { - "duration": "39.0", + "duration": "36.0", "name": "rendering.desktop/web_animation_value_type_transform_complex" }, { - "duration": "39.0", + "duration": "36.0", "name": "rendering.desktop/web_animation_value_type_transform_simple" }, { - "duration": "43.0", + "duration": "39.0", "name": "rendering.desktop/web_animations_many_keyframes" }, { - "duration": "39.0", + "duration": "36.0", "name": "rendering.desktop/web_animations_set_current_time" }, { - "duration": "39.0", + "duration": "36.0", "name": "rendering.desktop/web_animations_simultaneous" }, { - "duration": "40.0", + "duration": "37.0", "name": "rendering.desktop/web_animations_staggered_chaining" }, { - "duration": "43.0", + "duration": "36.0", "name": "rendering.desktop/web_animations_staggered_infinite_iterations" }, { - "duration": "40.0", + "duration": "37.0", "name": "rendering.desktop/web_animations_staggered_triggering_page" }, { - "duration": "40.0", + "duration": "37.0", "name": "rendering.desktop/webgl_to_texture" }, { - "duration": "35.0", + "duration": "32.0", "name": "rendering.desktop/webp_decoding_rgb_and_gpu_rasterization" }, { - "duration": "35.0", + "duration": "32.0", "name": "rendering.desktop/webp_decoding_yuv_and_gpu_rasterization" }, { - "duration": "54.0", + "duration": "44.0", "name": "rendering.desktop/wikipedia_2018" }, { - "duration": "40.0", + "duration": "36.0", "name": "rendering.desktop/wordpress_2018" }, { - "duration": "35.0", + "duration": "32.0", "name": "rendering.desktop/yahoo_answers_2018" }, { - "duration": "38.0", + "duration": "35.0", "name": "rendering.desktop/yahoo_news_2018" }, { - "duration": "46.0", + "duration": "41.0", "name": "rendering.desktop/yahoo_news_pinch_2018" }, { - "duration": "40.0", + "duration": "36.0", "name": "rendering.desktop/yahoo_sports_2018" }, { - "duration": "41.0", + "duration": "37.0", "name": "rendering.desktop/yahoo_sports_pinch_2018" }, { - "duration": "26.0", + "duration": "24.0", "name": "rendering.desktop/youtube_2018" }, { - "duration": "26.0", + "duration": "24.0", "name": "rendering.desktop/youtube_pinch_2018" }, { - "duration": "82.0", + "duration": "73.0", "name": "speedometer-future/http://browserbench.org/Speedometer/" }, { - "duration": "80.0", + "duration": "67.0", "name": "speedometer/http://browserbench.org/Speedometer/" }, { - "duration": "149.0", + "duration": "124.0", "name": "speedometer2-future/Speedometer2" }, { - "duration": "180.0", + "duration": "152.0", "name": "speedometer2-pcscan/Speedometer2" }, { - "duration": "142.0", + "duration": "120.0", "name": "speedometer2/Speedometer2" }, { - "duration": "61.0", + "duration": "60.0", "name": "system_health.common_desktop/browse:media:googleplaystore:2018" }, { - "duration": "100.0", + "duration": "99.0", "name": "system_health.common_desktop/browse:media:imgur" }, { - "duration": "124.0", + "duration": "113.0", "name": "system_health.common_desktop/browse:media:pinterest:2018" }, { - "duration": "99.0", + "duration": "97.0", "name": "system_health.common_desktop/browse:media:tumblr:2018" }, { @@ -3444,99 +3444,99 @@ "name": "system_health.common_desktop/browse:media:youtube:2019" }, { - "duration": "96.0", + "duration": "95.0", "name": "system_health.common_desktop/browse:media:youtubetv:2019" }, { - "duration": "105.0", + "duration": "104.0", "name": "system_health.common_desktop/browse:media:youtubetv_watch:2020" }, { - "duration": "101.0", + "duration": "94.0", "name": "system_health.common_desktop/browse:news:cnn:2020" }, { - "duration": "78.0", + "duration": "73.0", "name": "system_health.common_desktop/browse:news:flipboard:2020" }, { - "duration": "23.0", + "duration": "22.0", "name": "system_health.common_desktop/browse:news:hackernews:2020" }, { - "duration": "120.0", + "duration": "106.0", "name": "system_health.common_desktop/browse:news:nytimes:2020" }, { - "duration": "98.0", + "duration": "93.0", "name": "system_health.common_desktop/browse:news:reddit:2020" }, { - "duration": "69.0", + "duration": "68.0", "name": "system_health.common_desktop/browse:search:google:2020" }, { - "duration": "53.0", + "duration": "52.0", "name": "system_health.common_desktop/browse:search:google_india:2018" }, { - "duration": "104.0", + "duration": "99.0", "name": "system_health.common_desktop/browse:social:facebook_infinite_scroll:2018" }, { - "duration": "97.0", + "duration": "94.0", "name": "system_health.common_desktop/browse:social:tumblr_infinite_scroll:2018" }, { - "duration": "80.0", + "duration": "78.0", "name": "system_health.common_desktop/browse:social:twitter:2018" }, { - "duration": "93.0", + "duration": "92.0", "name": "system_health.common_desktop/browse:social:twitter_infinite_scroll:2018" }, { - "duration": "88.0", + "duration": "84.0", "name": "system_health.common_desktop/browse:tech:discourse_infinite_scroll:2018" }, { - "duration": "118.0", + "duration": "30.0", "name": "system_health.common_desktop/browse:tools:autocad:2021" }, { - "duration": "55.0", + "duration": "54.0", "name": "system_health.common_desktop/browse:tools:docs_scrolling" }, { - "duration": "137.0", + "duration": "128.0", "name": "system_health.common_desktop/browse:tools:earth:2020" }, { - "duration": "33.0", + "duration": "30.0", "name": "system_health.common_desktop/browse:tools:gmail-compose:2020" }, { - "duration": "33.0", + "duration": "22.0", "name": "system_health.common_desktop/browse:tools:gmail-labelclick:2020" }, { - "duration": "33.0", + "duration": "22.0", "name": "system_health.common_desktop/browse:tools:gmail-openconversation:2020" }, { - "duration": "23.0", + "duration": "22.0", "name": "system_health.common_desktop/browse:tools:gmail-search:2020" }, { - "duration": "94.0", + "duration": "93.0", "name": "system_health.common_desktop/browse:tools:maps:2019" }, { - "duration": "23.0", + "duration": "22.0", "name": "system_health.common_desktop/browse:tools:sheets:2019" }, { - "duration": "33.0", + "duration": "30.0", "name": "system_health.common_desktop/browse_accessibility:media:youtube" }, { @@ -3544,279 +3544,279 @@ "name": "system_health.common_desktop/browse_accessibility:tech:codesearch:2018" }, { - "duration": "46.0", + "duration": "44.0", "name": "system_health.common_desktop/load:chrome:blank" }, { - "duration": "38.0", + "duration": "37.0", "name": "system_health.common_desktop/load:games:alphabetty:2018" }, { - "duration": "36.0", + "duration": "35.0", "name": "system_health.common_desktop/load:games:bubbles:2020" }, { - "duration": "36.0", + "duration": "42.0", "name": "system_health.common_desktop/load:games:lazors" }, { - "duration": "41.0", + "duration": "42.0", "name": "system_health.common_desktop/load:games:miniclip:2018" }, { - "duration": "41.0", + "duration": "42.0", "name": "system_health.common_desktop/load:games:spychase:2018" }, { - "duration": "45.0", + "duration": "44.0", "name": "system_health.common_desktop/load:media:9gag" }, { - "duration": "38.0", + "duration": "37.0", "name": "system_health.common_desktop/load:media:dailymotion:2019" }, { - "duration": "40.0", + "duration": "39.0", "name": "system_health.common_desktop/load:media:facebook_feed:desktop:2020" }, { - "duration": "40.0", + "duration": "38.0", "name": "system_health.common_desktop/load:media:facebook_photos:2018" }, { - "duration": "40.0", + "duration": "39.0", "name": "system_health.common_desktop/load:media:facebook_photos:desktop:2020" }, { - "duration": "39.0", + "duration": "38.0", "name": "system_health.common_desktop/load:media:flickr:2018" }, { - "duration": "37.0", + "duration": "38.0", "name": "system_health.common_desktop/load:media:google_images:2018" }, { - "duration": "39.0", + "duration": "40.0", "name": "system_health.common_desktop/load:media:imgur:2018" }, { - "duration": "41.0", + "duration": "42.0", "name": "system_health.common_desktop/load:media:soundcloud:2018" }, { - "duration": "38.0", + "duration": "39.0", "name": "system_health.common_desktop/load:media:youtube:2018" }, { - "duration": "37.0", + "duration": "39.0", "name": "system_health.common_desktop/load:media:youtubelivingroom:2020" }, { - "duration": "38.0", + "duration": "37.0", "name": "system_health.common_desktop/load:news:bbc:2018" }, { - "duration": "39.0", + "duration": "38.0", "name": "system_health.common_desktop/load:news:cnn:2020" }, { - "duration": "38.0", + "duration": "37.0", "name": "system_health.common_desktop/load:news:flipboard" }, { - "duration": "36.0", + "duration": "37.0", "name": "system_health.common_desktop/load:news:hackernews:2018" }, { - "duration": "43.0", + "duration": "44.0", "name": "system_health.common_desktop/load:news:nytimes:2018" }, { - "duration": "39.0", + "duration": "40.0", "name": "system_health.common_desktop/load:news:qq:2018" }, { - "duration": "40.0", + "duration": "41.0", "name": "system_health.common_desktop/load:news:reddit:2018" }, { - "duration": "38.0", + "duration": "40.0", "name": "system_health.common_desktop/load:news:wikipedia:2018" }, { - "duration": "37.0", + "duration": "36.0", "name": "system_health.common_desktop/load:search:amazon:2018" }, { - "duration": "37.0", + "duration": "36.0", "name": "system_health.common_desktop/load:search:baidu:2018" }, { - "duration": "38.0", + "duration": "37.0", "name": "system_health.common_desktop/load:search:ebay:2018" }, { - "duration": "38.0", + "duration": "37.0", "name": "system_health.common_desktop/load:search:flipkart:2018" }, { - "duration": "38.0", + "duration": "39.0", "name": "system_health.common_desktop/load:search:google:2018" }, { - "duration": "37.0", + "duration": "38.0", "name": "system_health.common_desktop/load:search:taobao:2018" }, { - "duration": "36.0", + "duration": "38.0", "name": "system_health.common_desktop/load:search:yahoo:2018" }, { - "duration": "38.0", + "duration": "39.0", "name": "system_health.common_desktop/load:search:yandex:2018" }, { - "duration": "38.0", + "duration": "39.0", "name": "system_health.common_desktop/load:social:instagram:2018" }, { - "duration": "40.0", + "duration": "41.0", "name": "system_health.common_desktop/load:social:pinterest:2019" }, { - "duration": "38.0", + "duration": "39.0", "name": "system_health.common_desktop/load:social:vk:2018" }, { - "duration": "50.0", + "duration": "48.0", "name": "system_health.common_desktop/load:tools:chat:2020" }, { - "duration": "45.0", + "duration": "43.0", "name": "system_health.common_desktop/load:tools:docs:2019" }, { - "duration": "39.0", + "duration": "37.0", "name": "system_health.common_desktop/load:tools:drive:2019" }, { - "duration": "23.0", + "duration": "22.0", "name": "system_health.common_desktop/load:tools:gmail:2019" }, { - "duration": "38.0", + "duration": "39.0", "name": "system_health.common_desktop/load:tools:stackoverflow:2018" }, { - "duration": "38.0", + "duration": "39.0", "name": "system_health.common_desktop/load:tools:weather:2019" }, { - "duration": "48.0", + "duration": "45.0", "name": "system_health.common_desktop/load_accessibility:media:wikipedia:2018" }, { - "duration": "48.0", + "duration": "45.0", "name": "system_health.common_desktop/load_accessibility:shopping:amazon:2018" }, { - "duration": "146.0", + "duration": "147.0", "name": "system_health.common_desktop/long_running:tools:gmail-background" }, { - "duration": "34.0", + "duration": "25.0", "name": "system_health.common_desktop/long_running:tools:gmail-foreground" }, { - "duration": "34.0", + "duration": "25.0", "name": "system_health.common_desktop/multitab:misc:typical24" }, { - "duration": "34.0", + "duration": "25.0", "name": "system_health.common_desktop/multitab:misc:typical24:2018" }, { - "duration": "66.0", + "duration": "65.0", "name": "system_health.common_desktop/play:media:google_play_music" }, { - "duration": "76.0", + "duration": "75.0", "name": "system_health.common_desktop/play:media:soundcloud:2018" }, { - "duration": "48.0", + "duration": "46.0", "name": "system_health.memory_desktop/browse:media:googleplaystore:2018" }, { - "duration": "85.0", + "duration": "81.0", "name": "system_health.memory_desktop/browse:media:imgur" }, { - "duration": "97.0", + "duration": "93.0", "name": "system_health.memory_desktop/browse:media:pinterest:2018" }, { - "duration": "72.0", + "duration": "69.0", "name": "system_health.memory_desktop/browse:media:tumblr:2018" }, { - "duration": "11.0", + "duration": "7.0", "name": "system_health.memory_desktop/browse:media:youtube:2019" }, { - "duration": "69.0", + "duration": "65.0", "name": "system_health.memory_desktop/browse:media:youtubetv:2019" }, { - "duration": "78.0", + "duration": "74.0", "name": "system_health.memory_desktop/browse:media:youtubetv_watch:2020" }, { - "duration": "70.0", + "duration": "65.0", "name": "system_health.memory_desktop/browse:news:cnn:2020" }, { - "duration": "50.0", + "duration": "47.0", "name": "system_health.memory_desktop/browse:news:flipboard:2020" }, { - "duration": "59.0", + "duration": "57.0", "name": "system_health.memory_desktop/browse:news:hackernews:2020" }, { - "duration": "88.0", + "duration": "80.0", "name": "system_health.memory_desktop/browse:news:nytimes:2020" }, { - "duration": "71.0", + "duration": "65.0", "name": "system_health.memory_desktop/browse:news:reddit:2020" }, { - "duration": "56.0", + "duration": "51.0", "name": "system_health.memory_desktop/browse:search:google:2020" }, { - "duration": "40.0", + "duration": "35.0", "name": "system_health.memory_desktop/browse:search:google_india:2018" }, { - "duration": "75.0", + "duration": "73.0", "name": "system_health.memory_desktop/browse:social:facebook_infinite_scroll:2018" }, { - "duration": "11.0", + "duration": "9.0", "name": "system_health.memory_desktop/browse:social:tumblr_infinite_scroll:2018" }, { - "duration": "53.0", + "duration": "50.0", "name": "system_health.memory_desktop/browse:social:twitter:2018" }, { - "duration": "11.0", + "duration": "7.0", "name": "system_health.memory_desktop/browse:social:twitter_infinite_scroll:2018" }, { - "duration": "61.0", + "duration": "58.0", "name": "system_health.memory_desktop/browse:tech:discourse_infinite_scroll:2018" }, { @@ -3824,35 +3824,35 @@ "name": "system_health.memory_desktop/browse:tools:autocad:2021" }, { - "duration": "43.0", + "duration": "37.0", "name": "system_health.memory_desktop/browse:tools:docs_scrolling" }, { - "duration": "9.0", + "duration": "8.0", "name": "system_health.memory_desktop/browse:tools:earth:2020" }, { - "duration": "9.0", + "duration": "8.0", "name": "system_health.memory_desktop/browse:tools:gmail-compose:2020" }, { - "duration": "9.0", + "duration": "8.0", "name": "system_health.memory_desktop/browse:tools:gmail-labelclick:2020" }, { - "duration": "12.0", + "duration": "8.0", "name": "system_health.memory_desktop/browse:tools:gmail-openconversation:2020" }, { - "duration": "12.0", + "duration": "8.0", "name": "system_health.memory_desktop/browse:tools:gmail-search:2020" }, { - "duration": "82.0", + "duration": "75.0", "name": "system_health.memory_desktop/browse:tools:maps:2019" }, { - "duration": "12.0", + "duration": "11.0", "name": "system_health.memory_desktop/browse:tools:sheets:2019" }, { @@ -3860,7 +3860,7 @@ "name": "system_health.memory_desktop/browse_accessibility:media:youtube" }, { - "duration": "32.0", + "duration": "31.0", "name": "system_health.memory_desktop/browse_accessibility:tech:codesearch:2018" }, { @@ -3868,135 +3868,135 @@ "name": "system_health.memory_desktop/load:chrome:blank" }, { - "duration": "27.0", + "duration": "24.0", "name": "system_health.memory_desktop/load:games:alphabetty:2018" }, { - "duration": "24.0", + "duration": "22.0", "name": "system_health.memory_desktop/load:games:bubbles:2020" }, { - "duration": "25.0", + "duration": "28.0", "name": "system_health.memory_desktop/load:games:lazors" }, { - "duration": "28.0", + "duration": "31.0", "name": "system_health.memory_desktop/load:games:miniclip:2018" }, { - "duration": "28.0", + "duration": "29.0", "name": "system_health.memory_desktop/load:games:spychase:2018" }, { - "duration": "30.0", + "duration": "27.0", "name": "system_health.memory_desktop/load:media:9gag" }, { - "duration": "27.0", + "duration": "25.0", "name": "system_health.memory_desktop/load:media:dailymotion:2019" }, { - "duration": "28.0", + "duration": "31.0", "name": "system_health.memory_desktop/load:media:facebook_feed:desktop:2020" }, { - "duration": "27.0", + "duration": "30.0", "name": "system_health.memory_desktop/load:media:facebook_photos:2018" }, { - "duration": "28.0", + "duration": "31.0", "name": "system_health.memory_desktop/load:media:facebook_photos:desktop:2020" }, { - "duration": "26.0", + "duration": "29.0", "name": "system_health.memory_desktop/load:media:flickr:2018" }, { - "duration": "25.0", + "duration": "28.0", "name": "system_health.memory_desktop/load:media:google_images:2018" }, { - "duration": "26.0", + "duration": "29.0", "name": "system_health.memory_desktop/load:media:imgur:2018" }, { - "duration": "28.0", + "duration": "29.0", "name": "system_health.memory_desktop/load:media:soundcloud:2018" }, { - "duration": "25.0", + "duration": "26.0", "name": "system_health.memory_desktop/load:media:youtube:2018" }, { - "duration": "25.0", + "duration": "26.0", "name": "system_health.memory_desktop/load:media:youtubelivingroom:2020" }, { - "duration": "26.0", + "duration": "24.0", "name": "system_health.memory_desktop/load:news:bbc:2018" }, { - "duration": "28.0", + "duration": "25.0", "name": "system_health.memory_desktop/load:news:cnn:2020" }, { - "duration": "25.0", + "duration": "29.0", "name": "system_health.memory_desktop/load:news:flipboard" }, { - "duration": "23.0", + "duration": "26.0", "name": "system_health.memory_desktop/load:news:hackernews:2018" }, { - "duration": "30.0", + "duration": "33.0", "name": "system_health.memory_desktop/load:news:nytimes:2018" }, { - "duration": "26.0", + "duration": "27.0", "name": "system_health.memory_desktop/load:news:qq:2018" }, { - "duration": "28.0", + "duration": "29.0", "name": "system_health.memory_desktop/load:news:reddit:2018" }, { - "duration": "26.0", + "duration": "27.0", "name": "system_health.memory_desktop/load:news:wikipedia:2018" }, { - "duration": "25.0", + "duration": "23.0", "name": "system_health.memory_desktop/load:search:amazon:2018" }, { - "duration": "24.0", + "duration": "23.0", "name": "system_health.memory_desktop/load:search:baidu:2018" }, { - "duration": "26.0", + "duration": "29.0", "name": "system_health.memory_desktop/load:search:ebay:2018" }, { - "duration": "25.0", + "duration": "28.0", "name": "system_health.memory_desktop/load:search:flipkart:2018" }, { - "duration": "25.0", + "duration": "28.0", "name": "system_health.memory_desktop/load:search:google:2018" }, { - "duration": "25.0", + "duration": "26.0", "name": "system_health.memory_desktop/load:search:taobao:2018" }, { - "duration": "24.0", + "duration": "25.0", "name": "system_health.memory_desktop/load:search:yahoo:2018" }, { - "duration": "25.0", + "duration": "26.0", "name": "system_health.memory_desktop/load:search:yandex:2018" }, { - "duration": "25.0", + "duration": "28.0", "name": "system_health.memory_desktop/load:social:instagram:2018" }, { @@ -4004,63 +4004,63 @@ "name": "system_health.memory_desktop/load:social:pinterest:2019" }, { - "duration": "25.0", + "duration": "26.0", "name": "system_health.memory_desktop/load:social:vk:2018" }, { - "duration": "36.0", + "duration": "33.0", "name": "system_health.memory_desktop/load:tools:chat:2020" }, { - "duration": "32.0", + "duration": "34.0", "name": "system_health.memory_desktop/load:tools:docs:2019" }, { - "duration": "27.0", + "duration": "29.0", "name": "system_health.memory_desktop/load:tools:drive:2019" }, { - "duration": "12.0", + "duration": "15.0", "name": "system_health.memory_desktop/load:tools:gmail:2019" }, { - "duration": "25.0", + "duration": "26.0", "name": "system_health.memory_desktop/load:tools:stackoverflow:2018" }, { - "duration": "25.0", + "duration": "26.0", "name": "system_health.memory_desktop/load:tools:weather:2019" }, { - "duration": "23.0", + "duration": "22.0", "name": "system_health.memory_desktop/load_accessibility:media:wikipedia:2018" }, { - "duration": "24.0", + "duration": "23.0", "name": "system_health.memory_desktop/load_accessibility:shopping:amazon:2018" }, { - "duration": "11.0", + "duration": "13.0", "name": "system_health.memory_desktop/long_running:tools:gmail-background" }, { - "duration": "145.0", + "duration": "144.0", "name": "system_health.memory_desktop/long_running:tools:gmail-foreground" }, { - "duration": "11.0", + "duration": "9.0", "name": "system_health.memory_desktop/multitab:misc:typical24" }, { - "duration": "11.0", + "duration": "9.0", "name": "system_health.memory_desktop/multitab:misc:typical24:2018" }, { - "duration": "12.0", + "duration": "11.0", "name": "system_health.memory_desktop/play:media:google_play_music" }, { - "duration": "50.0", + "duration": "47.0", "name": "system_health.memory_desktop/play:media:soundcloud:2018" }, { @@ -4072,15 +4072,15 @@ "name": "tracing.tracing_with_background_memory_infra/Facebook" }, { - "duration": "21.0", + "duration": "20.0", "name": "tracing.tracing_with_background_memory_infra/Wikipedia" }, { - "duration": "21.0", + "duration": "20.0", "name": "tracing.tracing_with_background_memory_infra/http://www.amazon.com" }, { - "duration": "21.0", + "duration": "20.0", "name": "tracing.tracing_with_background_memory_infra/http://www.ask.com/" }, { @@ -4088,7 +4088,7 @@ "name": "tracing.tracing_with_background_memory_infra/http://www.bing.com/" }, { - "duration": "21.0", + "duration": "20.0", "name": "tracing.tracing_with_background_memory_infra/http://www.yahoo.com/" }, { @@ -4096,343 +4096,343 @@ "name": "tracing.tracing_with_background_memory_infra/http://www.youtube.com" }, { - "duration": "22.0", + "duration": "21.0", "name": "tracing.tracing_with_background_memory_infra/https://www.google.com/#hl=en&q=barack+obama" }, { - "duration": "22.0", + "duration": "21.0", "name": "tracing.tracing_with_background_memory_infra/https://www.google.com/calendar/" }, { - "duration": "116.0", + "duration": "64.0", "name": "v8.browsing_desktop-future/browse:media:googleplaystore:2018" }, { - "duration": "68.0", + "duration": "25.0", "name": "v8.browsing_desktop-future/browse:media:imgur" }, { - "duration": "173.0", + "duration": "115.0", "name": "v8.browsing_desktop-future/browse:media:pinterest:2018" }, { - "duration": "159.0", + "duration": "153.0", "name": "v8.browsing_desktop-future/browse:media:tumblr:2018" }, { - "duration": "68.0", + "duration": "85.0", "name": "v8.browsing_desktop-future/browse:media:youtube:2019" }, { - "duration": "145.0", + "duration": "148.0", "name": "v8.browsing_desktop-future/browse:media:youtubetv:2019" }, { - "duration": "149.0", + "duration": "157.0", "name": "v8.browsing_desktop-future/browse:media:youtubetv_watch:2020" }, { - "duration": "60.0", + "duration": "62.0", "name": "v8.browsing_desktop-future/browse:news:cnn:2020" }, { - "duration": "136.0", + "duration": "110.0", "name": "v8.browsing_desktop-future/browse:news:flipboard:2020" }, { - "duration": "68.0", + "duration": "25.0", "name": "v8.browsing_desktop-future/browse:news:hackernews:2020" }, { - "duration": "68.0", + "duration": "25.0", "name": "v8.browsing_desktop-future/browse:news:nytimes:2020" }, { - "duration": "182.0", + "duration": "91.0", "name": "v8.browsing_desktop-future/browse:news:reddit:2020" }, { - "duration": "128.0", + "duration": "77.0", "name": "v8.browsing_desktop-future/browse:search:google:2020" }, { - "duration": "68.0", + "duration": "25.0", "name": "v8.browsing_desktop-future/browse:search:google_india:2018" }, { - "duration": "177.0", + "duration": "141.0", "name": "v8.browsing_desktop-future/browse:social:facebook_infinite_scroll:2018" }, { - "duration": "146.0", + "duration": "150.0", "name": "v8.browsing_desktop-future/browse:social:tumblr_infinite_scroll:2018" }, { - "duration": "126.0", + "duration": "131.0", "name": "v8.browsing_desktop-future/browse:social:twitter:2018" }, { - "duration": "144.0", + "duration": "145.0", "name": "v8.browsing_desktop-future/browse:social:twitter_infinite_scroll:2018" }, { - "duration": "116.0", + "duration": "118.0", "name": "v8.browsing_desktop-future/browse:tech:discourse_infinite_scroll:2018" }, { - "duration": "118.0", + "duration": "62.0", "name": "v8.browsing_desktop-future/browse:tools:autocad:2021" }, { - "duration": "110.0", + "duration": "57.0", "name": "v8.browsing_desktop-future/browse:tools:docs_scrolling" }, { - "duration": "73.0", + "duration": "64.0", "name": "v8.browsing_desktop-future/browse:tools:earth:2020" }, { - "duration": "68.0", + "duration": "25.0", "name": "v8.browsing_desktop-future/browse:tools:gmail-compose:2020" }, { - "duration": "68.0", + "duration": "25.0", "name": "v8.browsing_desktop-future/browse:tools:gmail-labelclick:2020" }, { - "duration": "68.0", + "duration": "25.0", "name": "v8.browsing_desktop-future/browse:tools:gmail-openconversation:2020" }, { - "duration": "68.0", + "duration": "25.0", "name": "v8.browsing_desktop-future/browse:tools:gmail-search:2020" }, { - "duration": "68.0", + "duration": "25.0", "name": "v8.browsing_desktop-future/browse:tools:maps:2019" }, { - "duration": "68.0", + "duration": "25.0", "name": "v8.browsing_desktop-future/browse:tools:sheets:2019" }, { - "duration": "86.0", + "duration": "81.0", "name": "v8.browsing_desktop/browse:media:googleplaystore:2018" }, { - "duration": "48.0", + "duration": "43.0", "name": "v8.browsing_desktop/browse:media:imgur" }, { - "duration": "137.0", + "duration": "131.0", "name": "v8.browsing_desktop/browse:media:pinterest:2018" }, { - "duration": "113.0", + "duration": "150.0", "name": "v8.browsing_desktop/browse:media:tumblr:2018" }, { - "duration": "48.0", + "duration": "84.0", "name": "v8.browsing_desktop/browse:media:youtube:2019" }, { - "duration": "110.0", + "duration": "146.0", "name": "v8.browsing_desktop/browse:media:youtubetv:2019" }, { - "duration": "119.0", + "duration": "156.0", "name": "v8.browsing_desktop/browse:media:youtubetv_watch:2020" }, { - "duration": "94.0", + "duration": "69.0", "name": "v8.browsing_desktop/browse:news:cnn:2020" }, { - "duration": "91.0", + "duration": "85.0", "name": "v8.browsing_desktop/browse:news:flipboard:2020" }, { - "duration": "48.0", + "duration": "43.0", "name": "v8.browsing_desktop/browse:news:hackernews:2020" }, { - "duration": "48.0", + "duration": "43.0", "name": "v8.browsing_desktop/browse:news:nytimes:2020" }, { - "duration": "112.0", + "duration": "104.0", "name": "v8.browsing_desktop/browse:news:reddit:2020" }, { - "duration": "95.0", + "duration": "89.0", "name": "v8.browsing_desktop/browse:search:google:2020" }, { - "duration": "78.0", + "duration": "72.0", "name": "v8.browsing_desktop/browse:search:google_india:2018" }, { - "duration": "128.0", + "duration": "119.0", "name": "v8.browsing_desktop/browse:social:facebook_infinite_scroll:2018" }, { - "duration": "106.0", + "duration": "147.0", "name": "v8.browsing_desktop/browse:social:tumblr_infinite_scroll:2018" }, { - "duration": "93.0", + "duration": "129.0", "name": "v8.browsing_desktop/browse:social:twitter:2018" }, { - "duration": "106.0", + "duration": "143.0", "name": "v8.browsing_desktop/browse:social:twitter_infinite_scroll:2018" }, { - "duration": "155.0", + "duration": "129.0", "name": "v8.browsing_desktop/browse:tech:discourse_infinite_scroll:2018" }, { - "duration": "161.0", + "duration": "69.0", "name": "v8.browsing_desktop/browse:tools:autocad:2021" }, { - "duration": "80.0", + "duration": "74.0", "name": "v8.browsing_desktop/browse:tools:docs_scrolling" }, { - "duration": "195.0", + "duration": "168.0", "name": "v8.browsing_desktop/browse:tools:earth:2020" }, { - "duration": "48.0", + "duration": "43.0", "name": "v8.browsing_desktop/browse:tools:gmail-compose:2020" }, { - "duration": "48.0", + "duration": "43.0", "name": "v8.browsing_desktop/browse:tools:gmail-labelclick:2020" }, { - "duration": "48.0", + "duration": "43.0", "name": "v8.browsing_desktop/browse:tools:gmail-openconversation:2020" }, { - "duration": "48.0", + "duration": "43.0", "name": "v8.browsing_desktop/browse:tools:gmail-search:2020" }, { - "duration": "121.0", + "duration": "115.0", "name": "v8.browsing_desktop/browse:tools:maps:2019" }, { - "duration": "48.0", + "duration": "43.0", "name": "v8.browsing_desktop/browse:tools:sheets:2019" }, { - "duration": "44.0", + "duration": "48.0", "name": "v8.runtime_stats.top_25/AdsAMPAds_cold" }, { - "duration": "50.0", + "duration": "54.0", "name": "v8.runtime_stats.top_25/AdsAMPAds_hot" }, { - "duration": "46.0", + "duration": "51.0", "name": "v8.runtime_stats.top_25/AdsAMPAds_warm" }, { - "duration": "44.0", + "duration": "48.0", "name": "v8.runtime_stats.top_25/AdsAdSenseAsyncAds_cold" }, { - "duration": "50.0", + "duration": "54.0", "name": "v8.runtime_stats.top_25/AdsAdSenseAsyncAds_hot" }, { - "duration": "47.0", + "duration": "51.0", "name": "v8.runtime_stats.top_25/AdsAdSenseAsyncAds_warm" }, { - "duration": "44.0", + "duration": "42.0", "name": "v8.runtime_stats.top_25/AdsAsyncAdSenseImage_cold" }, { - "duration": "48.0", + "duration": "47.0", "name": "v8.runtime_stats.top_25/AdsAsyncAdSenseImage_hot" }, { - "duration": "46.0", + "duration": "45.0", "name": "v8.runtime_stats.top_25/AdsAsyncAdSenseImage_warm" }, { - "duration": "44.0", + "duration": "43.0", "name": "v8.runtime_stats.top_25/AdsDoubleClickAsyncAds_cold" }, { - "duration": "49.0", + "duration": "56.0", "name": "v8.runtime_stats.top_25/AdsDoubleClickAsyncAds_hot" }, { - "duration": "47.0", + "duration": "45.0", "name": "v8.runtime_stats.top_25/AdsDoubleClickAsyncAds_warm" }, { - "duration": "44.0", + "duration": "47.0", "name": "v8.runtime_stats.top_25/AdsMultipleAdSlots_cold" }, { - "duration": "49.0", + "duration": "53.0", "name": "v8.runtime_stats.top_25/AdsMultipleAdSlots_hot" }, { - "duration": "46.0", + "duration": "51.0", "name": "v8.runtime_stats.top_25/AdsMultipleAdSlots_warm" }, { - "duration": "43.0", + "duration": "48.0", "name": "v8.runtime_stats.top_25/AdsOnScreenDetection_cold" }, { - "duration": "48.0", + "duration": "53.0", "name": "v8.runtime_stats.top_25/AdsOnScreenDetection_hot" }, { - "duration": "46.0", + "duration": "50.0", "name": "v8.runtime_stats.top_25/AdsOnScreenDetection_warm" }, { - "duration": "44.0", + "duration": "43.0", "name": "v8.runtime_stats.top_25/AdsSyncAdSenseImage_cold" }, { - "duration": "50.0", + "duration": "48.0", "name": "v8.runtime_stats.top_25/AdsSyncAdSenseImage_hot" }, { - "duration": "47.0", + "duration": "46.0", "name": "v8.runtime_stats.top_25/AdsSyncAdSenseImage_warm" }, { - "duration": "44.0", + "duration": "42.0", "name": "v8.runtime_stats.top_25/AdsSyncLoadAsyncRenderAdSenseImage_cold" }, { - "duration": "49.0", + "duration": "47.0", "name": "v8.runtime_stats.top_25/AdsSyncLoadAsyncRenderAdSenseImage_hot" }, { - "duration": "47.0", + "duration": "45.0", "name": "v8.runtime_stats.top_25/AdsSyncLoadAsyncRenderAdSenseImage_warm" }, { - "duration": "51.0", + "duration": "55.0", "name": "v8.runtime_stats.top_25/AdsViewOptimizedRendering_cold" }, { - "duration": "71.0", + "duration": "76.0", "name": "v8.runtime_stats.top_25/AdsViewOptimizedRendering_hot" }, { - "duration": "62.0", + "duration": "66.0", "name": "v8.runtime_stats.top_25/AdsViewOptimizedRendering_warm" }, { @@ -4440,7 +4440,7 @@ "name": "v8.runtime_stats.top_25/http://edition.cnn.com_cold" }, { - "duration": "58.0", + "duration": "59.0", "name": "v8.runtime_stats.top_25/http://edition.cnn.com_hot" }, { @@ -4448,7 +4448,7 @@ "name": "v8.runtime_stats.top_25/http://edition.cnn.com_warm" }, { - "duration": "47.0", + "duration": "46.0", "name": "v8.runtime_stats.top_25/http://hi.wikipedia.org/wiki/%E0%A4%AE%E0%A5%81%E0%A4%96%E0%A4%AA%E0%A5%83%E0%A4%B7%E0%A5%8D%E0%A4%A0_cold" }, { @@ -4472,7 +4472,7 @@ "name": "v8.runtime_stats.top_25/http://inbox.google.com_warm" }, { - "duration": "48.0", + "duration": "49.0", "name": "v8.runtime_stats.top_25/http://maps.google.co.jp/maps/search/restaurant+tokyo_cold" }, { @@ -4488,71 +4488,71 @@ "name": "v8.runtime_stats.top_25/http://meta.discourse.org_cold" }, { - "duration": "57.0", + "duration": "56.0", "name": "v8.runtime_stats.top_25/http://meta.discourse.org_hot" }, { - "duration": "54.0", + "duration": "53.0", "name": "v8.runtime_stats.top_25/http://meta.discourse.org_warm" }, { - "duration": "48.0", + "duration": "47.0", "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?angular_cold" }, { - "duration": "53.0", + "duration": "47.0", "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?angular_hot" }, { - "duration": "50.0", + "duration": "56.0", "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?angular_warm" }, { - "duration": "47.0", + "duration": "42.0", "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?backbone_cold" }, { - "duration": "58.0", + "duration": "48.0", "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?backbone_hot" }, { - "duration": "50.0", + "duration": "44.0", "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?backbone_warm" }, { - "duration": "43.0", + "duration": "42.0", "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?ember_cold" }, { - "duration": "49.0", + "duration": "47.0", "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?ember_hot" }, { - "duration": "47.0", + "duration": "44.0", "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?ember_warm" }, { - "duration": "48.0", + "duration": "42.0", "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?jquery_cold" }, { - "duration": "53.0", + "duration": "47.0", "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?jquery_hot" }, { - "duration": "50.0", + "duration": "45.0", "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?jquery_warm" }, { - "duration": "44.0", + "duration": "42.0", "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?vanilla_cold" }, { - "duration": "49.0", + "duration": "47.0", "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?vanilla_hot" }, { - "duration": "46.0", + "duration": "44.0", "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?vanilla_warm" }, { @@ -4568,15 +4568,15 @@ "name": "v8.runtime_stats.top_25/http://reddit.musicplayer.io_warm" }, { - "duration": "48.0", + "duration": "58.0", "name": "v8.runtime_stats.top_25/http://weibo.com_cold" }, { - "duration": "55.0", + "duration": "56.0", "name": "v8.runtime_stats.top_25/http://weibo.com_hot" }, { - "duration": "52.0", + "duration": "53.0", "name": "v8.runtime_stats.top_25/http://weibo.com_warm" }, { @@ -4588,43 +4588,43 @@ "name": "v8.runtime_stats.top_25/http://world.taobao.com_hot" }, { - "duration": "51.0", + "duration": "50.0", "name": "v8.runtime_stats.top_25/http://world.taobao.com_warm" }, { - "duration": "46.0", + "duration": "45.0", "name": "v8.runtime_stats.top_25/http://www.amazon.com/s/?field-keywords=v8_cold" }, { - "duration": "52.0", + "duration": "51.0", "name": "v8.runtime_stats.top_25/http://www.amazon.com/s/?field-keywords=v8_hot" }, { - "duration": "50.0", + "duration": "49.0", "name": "v8.runtime_stats.top_25/http://www.amazon.com/s/?field-keywords=v8_warm" }, { - "duration": "47.0", + "duration": "45.0", "name": "v8.runtime_stats.top_25/http://www.baidu.com/s?wd=v8_cold" }, { - "duration": "52.0", + "duration": "51.0", "name": "v8.runtime_stats.top_25/http://www.baidu.com/s?wd=v8_hot" }, { - "duration": "50.0", + "duration": "49.0", "name": "v8.runtime_stats.top_25/http://www.baidu.com/s?wd=v8_warm" }, { - "duration": "48.0", + "duration": "46.0", "name": "v8.runtime_stats.top_25/http://www.bing.com/search?q=v8+engine_cold" }, { - "duration": "53.0", + "duration": "52.0", "name": "v8.runtime_stats.top_25/http://www.bing.com/search?q=v8+engine_hot" }, { - "duration": "50.0", + "duration": "49.0", "name": "v8.runtime_stats.top_25/http://www.bing.com/search?q=v8+engine_warm" }, { @@ -4632,7 +4632,7 @@ "name": "v8.runtime_stats.top_25/http://www.ebay.fr/sch/i.html?_nkw=v8_cold" }, { - "duration": "56.0", + "duration": "55.0", "name": "v8.runtime_stats.top_25/http://www.ebay.fr/sch/i.html?_nkw=v8_hot" }, { @@ -4640,75 +4640,75 @@ "name": "v8.runtime_stats.top_25/http://www.ebay.fr/sch/i.html?_nkw=v8_warm" }, { - "duration": "47.0", + "duration": "46.0", "name": "v8.runtime_stats.top_25/http://www.instagram.com/archdigest_cold" }, { - "duration": "67.0", + "duration": "54.0", "name": "v8.runtime_stats.top_25/http://www.instagram.com/archdigest_hot" }, { - "duration": "49.0", + "duration": "50.0", "name": "v8.runtime_stats.top_25/http://www.instagram.com/archdigest_warm" }, { - "duration": "49.0", + "duration": "47.0", "name": "v8.runtime_stats.top_25/http://www.msn.com/ar-ae_cold" }, { - "duration": "57.0", + "duration": "55.0", "name": "v8.runtime_stats.top_25/http://www.msn.com/ar-ae_hot" }, { - "duration": "53.0", + "duration": "52.0", "name": "v8.runtime_stats.top_25/http://www.msn.com/ar-ae_warm" }, { - "duration": "49.0", + "duration": "48.0", "name": "v8.runtime_stats.top_25/http://www.pinterest.com/categories/popular_cold" }, { - "duration": "58.0", + "duration": "56.0", "name": "v8.runtime_stats.top_25/http://www.pinterest.com/categories/popular_hot" }, { - "duration": "55.0", + "duration": "52.0", "name": "v8.runtime_stats.top_25/http://www.pinterest.com/categories/popular_warm" }, { - "duration": "51.0", + "duration": "49.0", "name": "v8.runtime_stats.top_25/http://www.qq.com_cold" }, { - "duration": "59.0", + "duration": "58.0", "name": "v8.runtime_stats.top_25/http://www.qq.com_hot" }, { - "duration": "56.0", + "duration": "55.0", "name": "v8.runtime_stats.top_25/http://www.qq.com_warm" }, { - "duration": "47.0", + "duration": "46.0", "name": "v8.runtime_stats.top_25/http://www.reddit.com_cold" }, { - "duration": "53.0", + "duration": "63.0", "name": "v8.runtime_stats.top_25/http://www.reddit.com_hot" }, { - "duration": "50.0", + "duration": "49.0", "name": "v8.runtime_stats.top_25/http://www.reddit.com_warm" }, { - "duration": "48.0", + "duration": "47.0", "name": "v8.runtime_stats.top_25/http://www.twitter.com/taylorswift13_cold" }, { - "duration": "55.0", + "duration": "54.0", "name": "v8.runtime_stats.top_25/http://www.twitter.com/taylorswift13_hot" }, { - "duration": "52.0", + "duration": "51.0", "name": "v8.runtime_stats.top_25/http://www.twitter.com/taylorswift13_warm" }, { @@ -4720,27 +4720,27 @@ "name": "v8.runtime_stats.top_25/http://www.wikiwand.com/en/hill_hot" }, { - "duration": "54.0", + "duration": "53.0", "name": "v8.runtime_stats.top_25/http://www.wikiwand.com/en/hill_warm" }, { - "duration": "48.0", + "duration": "46.0", "name": "v8.runtime_stats.top_25/http://www.yahoo.co.jp_cold" }, { - "duration": "52.0", + "duration": "51.0", "name": "v8.runtime_stats.top_25/http://www.yahoo.co.jp_hot" }, { - "duration": "50.0", + "duration": "49.0", "name": "v8.runtime_stats.top_25/http://www.yahoo.co.jp_warm" }, { - "duration": "49.0", + "duration": "48.0", "name": "v8.runtime_stats.top_25/http://yandex.ru/search/?text=v8_cold" }, { - "duration": "55.0", + "duration": "54.0", "name": "v8.runtime_stats.top_25/http://yandex.ru/search/?text=v8_hot" }, { @@ -4748,39 +4748,39 @@ "name": "v8.runtime_stats.top_25/http://yandex.ru/search/?text=v8_warm" }, { - "duration": "54.0", + "duration": "53.0", "name": "v8.runtime_stats.top_25/https://adwords.google.com_cold" }, { - "duration": "66.0", + "duration": "62.0", "name": "v8.runtime_stats.top_25/https://adwords.google.com_hot" }, { - "duration": "64.0", + "duration": "60.0", "name": "v8.runtime_stats.top_25/https://adwords.google.com_warm" }, { - "duration": "44.0", + "duration": "42.0", "name": "v8.runtime_stats.top_25/https://cdn.ampproject.org/c/www.bbc.co.uk/news/amp/37344292#log=3_cold" }, { - "duration": "48.0", + "duration": "47.0", "name": "v8.runtime_stats.top_25/https://cdn.ampproject.org/c/www.bbc.co.uk/news/amp/37344292#log=3_hot" }, { - "duration": "47.0", + "duration": "44.0", "name": "v8.runtime_stats.top_25/https://cdn.ampproject.org/c/www.bbc.co.uk/news/amp/37344292#log=3_warm" }, { - "duration": "19.0", + "duration": "18.0", "name": "v8.runtime_stats.top_25/https://en.wikipedia.org/w/index.php?title=Barack_Obama&veaction=edit_cold" }, { - "duration": "19.0", + "duration": "18.0", "name": "v8.runtime_stats.top_25/https://en.wikipedia.org/w/index.php?title=Barack_Obama&veaction=edit_hot" }, { - "duration": "19.0", + "duration": "18.0", "name": "v8.runtime_stats.top_25/https://en.wikipedia.org/w/index.php?title=Barack_Obama&veaction=edit_warm" }, { @@ -4792,35 +4792,35 @@ "name": "v8.runtime_stats.top_25/https://www.facebook.com/shakira_hot" }, { - "duration": "51.0", + "duration": "50.0", "name": "v8.runtime_stats.top_25/https://www.facebook.com/shakira_warm" }, { - "duration": "68.0", + "duration": "58.0", "name": "v8.runtime_stats.top_25/https://www.google.de/search?q=v8_cold" }, { - "duration": "52.0", + "duration": "55.0", "name": "v8.runtime_stats.top_25/https://www.google.de/search?q=v8_hot" }, { - "duration": "61.0", + "duration": "54.0", "name": "v8.runtime_stats.top_25/https://www.google.de/search?q=v8_warm" }, { - "duration": "48.0", + "duration": "47.0", "name": "v8.runtime_stats.top_25/https://www.linkedin.com/m/_cold" }, { - "duration": "55.0", + "duration": "54.0", "name": "v8.runtime_stats.top_25/https://www.linkedin.com/m/_hot" }, { - "duration": "53.0", + "duration": "51.0", "name": "v8.runtime_stats.top_25/https://www.linkedin.com/m/_warm" }, { - "duration": "46.0", + "duration": "50.0", "name": "v8.runtime_stats.top_25/https://www.youtube.com/watch?v=_kZsOISarzg_cold" }, { @@ -4828,19 +4828,19 @@ "name": "v8.runtime_stats.top_25/https://www.youtube.com/watch?v=_kZsOISarzg_hot" }, { - "duration": "49.0", + "duration": "59.0", "name": "v8.runtime_stats.top_25/https://www.youtube.com/watch?v=_kZsOISarzg_warm" }, { - "duration": "47.0", + "duration": "50.0", "name": "v8.runtime_stats.top_25/https://www.youtube.com_cold" }, { - "duration": "56.0", + "duration": "58.0", "name": "v8.runtime_stats.top_25/https://www.youtube.com_hot" }, { - "duration": "52.0", + "duration": "56.0", "name": "v8.runtime_stats.top_25/https://www.youtube.com_warm" }, { @@ -4868,11 +4868,15 @@ "name": "webrtc/hd_local_stream_10s" }, { - "duration": "39.0", + "duration": "38.0", "name": "webrtc/insertable_streams_video_processing_camera_canvas2d_video" }, { - "duration": "39.0", + "duration": "37.0", + "name": "webrtc/insertable_streams_video_processing_camera_noop_video" + }, + { + "duration": "38.0", "name": "webrtc/insertable_streams_video_processing_camera_webgl_pc" }, { @@ -4880,7 +4884,7 @@ "name": "webrtc/insertable_streams_video_processing_camera_webgl_video" }, { - "duration": "39.0", + "duration": "38.0", "name": "webrtc/insertable_streams_video_processing_pc_webgl_video" }, {
diff --git a/tools/perf/core/shard_maps/win-10_laptop_low_end-perf_map.json b/tools/perf/core/shard_maps/win-10_laptop_low_end-perf_map.json index 58a7af8d..02098d36 100644 --- a/tools/perf/core/shard_maps/win-10_laptop_low_end-perf_map.json +++ b/tools/perf/core/shard_maps/win-10_laptop_low_end-perf_map.json
@@ -24,7 +24,7 @@ "abridged": false }, "blink_perf.layout": { - "end": 77, + "end": 56, "abridged": false } } @@ -32,7 +32,7 @@ "2": { "benchmarks": { "blink_perf.layout": { - "begin": 77, + "begin": 56, "abridged": false }, "blink_perf.owp_storage": { @@ -42,7 +42,7 @@ "abridged": false }, "blink_perf.parser": { - "end": 22, + "end": 29, "abridged": false } } @@ -50,7 +50,7 @@ "3": { "benchmarks": { "blink_perf.parser": { - "begin": 22, + "begin": 29, "abridged": false }, "blink_perf.shadow_dom": { @@ -75,7 +75,7 @@ "abridged": false }, "desktop_ui": { - "end": 1, + "end": 2, "abridged": false } } @@ -83,7 +83,7 @@ "4": { "benchmarks": { "desktop_ui": { - "begin": 1, + "begin": 2, "end": 14, "abridged": false } @@ -114,7 +114,7 @@ "abridged": false }, "loading.desktop": { - "end": 7, + "end": 5, "abridged": false } } @@ -122,8 +122,8 @@ "6": { "benchmarks": { "loading.desktop": { - "begin": 7, - "end": 23, + "begin": 5, + "end": 21, "abridged": false } } @@ -131,8 +131,8 @@ "7": { "benchmarks": { "loading.desktop": { - "begin": 23, - "end": 37, + "begin": 21, + "end": 34, "abridged": false } } @@ -140,8 +140,8 @@ "8": { "benchmarks": { "loading.desktop": { - "begin": 37, - "end": 48, + "begin": 34, + "end": 47, "abridged": false } } @@ -149,8 +149,8 @@ "9": { "benchmarks": { "loading.desktop": { - "begin": 48, - "end": 58, + "begin": 47, + "end": 54, "abridged": false } } @@ -158,8 +158,8 @@ "10": { "benchmarks": { "loading.desktop": { - "begin": 58, - "end": 71, + "begin": 54, + "end": 63, "abridged": false } } @@ -167,8 +167,8 @@ "11": { "benchmarks": { "loading.desktop": { - "begin": 71, - "end": 84, + "begin": 63, + "end": 76, "abridged": false } } @@ -176,8 +176,8 @@ "12": { "benchmarks": { "loading.desktop": { - "begin": 84, - "end": 97, + "begin": 76, + "end": 89, "abridged": false } } @@ -185,23 +185,23 @@ "13": { "benchmarks": { "loading.desktop": { - "begin": 97, - "abridged": false - }, - "media.desktop": { - "end": 15, + "begin": 89, + "end": 101, "abridged": false } } }, "14": { "benchmarks": { + "loading.desktop": { + "begin": 101, + "abridged": false + }, "media.desktop": { - "begin": 15, "abridged": false }, "memory.desktop": { - "end": 8, + "end": 1, "abridged": false } } @@ -209,29 +209,24 @@ "15": { "benchmarks": { "memory.desktop": { - "begin": 8, + "begin": 1, "abridged": false }, "octane": { "abridged": false - }, - "power.desktop": { - "abridged": false - }, - "rasterize_and_record_micro.top_25": { - "end": 5, - "abridged": false } } }, "16": { "benchmarks": { + "power.desktop": { + "abridged": false + }, "rasterize_and_record_micro.top_25": { - "begin": 5, "abridged": false }, "rendering.desktop": { - "end": 20, + "end": 2, "abridged": false } } @@ -239,8 +234,8 @@ "17": { "benchmarks": { "rendering.desktop": { - "begin": 20, - "end": 48, + "begin": 2, + "end": 28, "abridged": false } } @@ -248,8 +243,8 @@ "18": { "benchmarks": { "rendering.desktop": { - "begin": 48, - "end": 74, + "begin": 28, + "end": 60, "abridged": false } } @@ -257,8 +252,8 @@ "19": { "benchmarks": { "rendering.desktop": { - "begin": 74, - "end": 104, + "begin": 60, + "end": 92, "abridged": false } } @@ -266,8 +261,8 @@ "20": { "benchmarks": { "rendering.desktop": { - "begin": 104, - "end": 136, + "begin": 92, + "end": 124, "abridged": false } } @@ -275,8 +270,8 @@ "21": { "benchmarks": { "rendering.desktop": { - "begin": 136, - "end": 168, + "begin": 124, + "end": 156, "abridged": false } } @@ -284,8 +279,8 @@ "22": { "benchmarks": { "rendering.desktop": { - "begin": 168, - "end": 198, + "begin": 156, + "end": 179, "abridged": false } } @@ -293,8 +288,8 @@ "23": { "benchmarks": { "rendering.desktop": { - "begin": 198, - "end": 227, + "begin": 179, + "end": 198, "abridged": false } } @@ -302,8 +297,8 @@ "24": { "benchmarks": { "rendering.desktop": { - "begin": 227, - "end": 253, + "begin": 198, + "end": 228, "abridged": false } } @@ -311,8 +306,8 @@ "25": { "benchmarks": { "rendering.desktop": { - "begin": 253, - "end": 282, + "begin": 228, + "end": 252, "abridged": false } } @@ -320,7 +315,16 @@ "26": { "benchmarks": { "rendering.desktop": { - "begin": 282, + "begin": 252, + "end": 279, + "abridged": false + } + } + }, + "27": { + "benchmarks": { + "rendering.desktop": { + "begin": 279, "abridged": false }, "speedometer": { @@ -331,7 +335,7 @@ } } }, - "27": { + "28": { "benchmarks": { "speedometer2": { "abridged": false @@ -343,16 +347,7 @@ "abridged": false }, "system_health.common_desktop": { - "end": 12, - "abridged": false - } - } - }, - "28": { - "benchmarks": { - "system_health.common_desktop": { - "begin": 12, - "end": 43, + "end": 17, "abridged": false } } @@ -360,8 +355,8 @@ "29": { "benchmarks": { "system_health.common_desktop": { - "begin": 43, - "end": 71, + "begin": 17, + "end": 49, "abridged": false } } @@ -369,20 +364,20 @@ "30": { "benchmarks": { "system_health.common_desktop": { - "begin": 71, - "abridged": false - }, - "system_health.memory_desktop": { - "end": 7, + "begin": 49, + "end": 74, "abridged": false } } }, "31": { "benchmarks": { + "system_health.common_desktop": { + "begin": 74, + "abridged": false + }, "system_health.memory_desktop": { - "begin": 7, - "end": 19, + "end": 10, "abridged": false } } @@ -390,8 +385,8 @@ "32": { "benchmarks": { "system_health.memory_desktop": { - "begin": 19, - "end": 33, + "begin": 10, + "end": 24, "abridged": false } } @@ -399,8 +394,8 @@ "33": { "benchmarks": { "system_health.memory_desktop": { - "begin": 33, - "end": 51, + "begin": 24, + "end": 40, "abridged": false } } @@ -408,8 +403,8 @@ "34": { "benchmarks": { "system_health.memory_desktop": { - "begin": 51, - "end": 67, + "begin": 40, + "end": 56, "abridged": false } } @@ -417,8 +412,8 @@ "35": { "benchmarks": { "system_health.memory_desktop": { - "begin": 67, - "end": 76, + "begin": 56, + "end": 70, "abridged": false } } @@ -426,7 +421,16 @@ "36": { "benchmarks": { "system_health.memory_desktop": { - "begin": 76, + "begin": 70, + "end": 79, + "abridged": false + } + } + }, + "37": { + "benchmarks": { + "system_health.memory_desktop": { + "begin": 79, "abridged": false }, "tab_switching.typical_25": { @@ -436,16 +440,7 @@ "abridged": false }, "v8.browsing_desktop": { - "end": 4, - "abridged": false - } - } - }, - "37": { - "benchmarks": { - "v8.browsing_desktop": { - "begin": 4, - "end": 21, + "end": 12, "abridged": false } } @@ -453,20 +448,20 @@ "38": { "benchmarks": { "v8.browsing_desktop": { - "begin": 21, - "abridged": false - }, - "v8.browsing_desktop-future": { - "end": 6, + "begin": 12, + "end": 26, "abridged": false } } }, "39": { "benchmarks": { + "v8.browsing_desktop": { + "begin": 26, + "abridged": false + }, "v8.browsing_desktop-future": { - "begin": 6, - "end": 21, + "end": 19, "abridged": false } } @@ -474,11 +469,11 @@ "40": { "benchmarks": { "v8.browsing_desktop-future": { - "begin": 21, + "begin": 19, "abridged": false }, "v8.runtime_stats.top_25": { - "end": 7, + "end": 3, "abridged": false } } @@ -486,8 +481,8 @@ "41": { "benchmarks": { "v8.runtime_stats.top_25": { - "begin": 7, - "end": 35, + "begin": 3, + "end": 32, "abridged": false } } @@ -495,8 +490,8 @@ "42": { "benchmarks": { "v8.runtime_stats.top_25": { - "begin": 35, - "end": 60, + "begin": 32, + "end": 59, "abridged": false } } @@ -504,8 +499,8 @@ "43": { "benchmarks": { "v8.runtime_stats.top_25": { - "begin": 60, - "end": 85, + "begin": 59, + "end": 84, "abridged": false } } @@ -513,8 +508,8 @@ "44": { "benchmarks": { "v8.runtime_stats.top_25": { - "begin": 85, - "end": 113, + "begin": 84, + "end": 114, "abridged": false } } @@ -522,7 +517,7 @@ "45": { "benchmarks": { "v8.runtime_stats.top_25": { - "begin": 113, + "begin": 114, "abridged": false }, "webrtc": { @@ -532,55 +527,55 @@ }, "extra_infos": { "num_stories": 1225, - "predicted_min_shard_time": 1259.0, - "predicted_min_shard_index": 3, - "predicted_max_shard_time": 1557.0, - "predicted_max_shard_index": 34, - "shard #0": 1351.0, - "shard #1": 1356.0, - "shard #2": 1354.0, - "shard #3": 1259.0, - "shard #4": 1368.0, - "shard #5": 1378.0, - "shard #6": 1386.0, - "shard #7": 1392.0, - "shard #8": 1412.0, - "shard #9": 1342.0, - "shard #10": 1336.0, - "shard #11": 1394.0, - "shard #12": 1314.0, - "shard #13": 1351.0, - "shard #14": 1420.0, - "shard #15": 1348.0, - "shard #16": 1358.0, - "shard #17": 1375.0, - "shard #18": 1334.0, - "shard #19": 1346.0, - "shard #20": 1368.0, - "shard #21": 1359.0, - "shard #22": 1343.0, - "shard #23": 1377.0, - "shard #24": 1341.0, - "shard #25": 1350.0, - "shard #26": 1321.0, - "shard #27": 1363.0, - "shard #28": 1371.0, - "shard #29": 1339.0, - "shard #30": 1339.0, - "shard #31": 1374.0, - "shard #32": 1389.0, - "shard #33": 1389.0, - "shard #34": 1557.0, - "shard #35": 1392.0, - "shard #36": 1302.0, - "shard #37": 1312.0, - "shard #38": 1375.0, - "shard #39": 1389.0, - "shard #40": 1319.0, - "shard #41": 1324.0, - "shard #42": 1312.0, - "shard #43": 1329.0, - "shard #44": 1336.0, - "shard #45": 1339.0 + "predicted_min_shard_time": 1236.0, + "predicted_min_shard_index": 36, + "predicted_max_shard_time": 1467.0, + "predicted_max_shard_index": 35, + "shard #0": 1349.0, + "shard #1": 1355.0, + "shard #2": 1357.0, + "shard #3": 1350.0, + "shard #4": 1343.0, + "shard #5": 1367.0, + "shard #6": 1326.0, + "shard #7": 1372.0, + "shard #8": 1386.0, + "shard #9": 1270.0, + "shard #10": 1316.0, + "shard #11": 1330.0, + "shard #12": 1346.0, + "shard #13": 1344.0, + "shard #14": 1408.0, + "shard #15": 1363.0, + "shard #16": 1373.0, + "shard #17": 1351.0, + "shard #18": 1372.0, + "shard #19": 1340.0, + "shard #20": 1356.0, + "shard #21": 1360.0, + "shard #22": 1381.0, + "shard #23": 1338.0, + "shard #24": 1335.0, + "shard #25": 1368.0, + "shard #26": 1351.0, + "shard #27": 1308.0, + "shard #28": 1344.0, + "shard #29": 1363.0, + "shard #30": 1348.0, + "shard #31": 1451.0, + "shard #32": 1449.0, + "shard #33": 1317.0, + "shard #34": 1335.0, + "shard #35": 1467.0, + "shard #36": 1236.0, + "shard #37": 1380.0, + "shard #38": 1328.0, + "shard #39": 1307.0, + "shard #40": 1342.0, + "shard #41": 1374.0, + "shard #42": 1382.0, + "shard #43": 1336.0, + "shard #44": 1366.0, + "shard #45": 1350.0 } } \ No newline at end of file
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config index 636f21c88..9c04e369 100644 --- a/tools/perf/expectations.config +++ b/tools/perf/expectations.config
@@ -200,6 +200,7 @@ crbug.com/1017244 [ desktop ] rendering.desktop/youtube_2018 [ Skip ] crbug.com/1017244 [ desktop ] rendering.desktop/youtube_pinch_2018 [ Skip ] crbug.com/1044962 [ win ] rendering.desktop/camera_to_webgl [ Skip ] +crbug.com/1176809 [ win ] rendering.desktop/gmail_move_2018 [ Skip ] # Benchmark: rendering.mobile crbug.com/785485 [ android-webview ] rendering.mobile/kevs_3d [ Skip ]
diff --git a/tools/perf/page_sets/update_webrtc_cases b/tools/perf/page_sets/update_webrtc_cases index 26b3434e..9321632f 100755 --- a/tools/perf/page_sets/update_webrtc_cases +++ b/tools/perf/page_sets/update_webrtc_cases
@@ -32,8 +32,9 @@ 'src/content/datachannel/datatransfer', 'src/content/getusermedia/resolution', 'src/content/insertable-streams/video-processing', - ], - 'revision': '583fc1a6efacd19d9485be381a8698d12748b671', + 'src/content/peerconnection/negotiate-timing', + ], + 'revision': '4b198b679350f836809b40516c25d4b17eb22e9d', }, }
diff --git a/tools/perf/page_sets/webrtc_cases.py b/tools/perf/page_sets/webrtc_cases.py index efa7527..f7513b5 100644 --- a/tools/perf/page_sets/webrtc_cases.py +++ b/tools/perf/page_sets/webrtc_cases.py
@@ -188,6 +188,71 @@ description='Number of frames received at the sink video.') +class NegotiateTiming(WebrtcPage): + """Why: Measure how long renegotiation takes with large SDP blobs.""" + + def __init__(self, page_set, tags): + super(NegotiateTiming, + self).__init__(url='file://webrtc_cases/negotiate-timing.html', + name='negotiate-timing', + page_set=page_set, + tags=tags) + + def ExecuteTest(self, action_runner): + action_runner.ExecuteJavaScript('start()') + action_runner.WaitForJavaScriptCondition('!callButton.disabled') + action_runner.ExecuteJavaScript('call()') + action_runner.WaitForJavaScriptCondition('!renegotiateButton.disabled') + # Due to suspicion of renegotiate activating too early: + action_runner.Wait(1) + # Negotiate 50 transceivers, then negotiate back to 1, simulating Meet "pin" + action_runner.ExecuteJavaScript('videoSectionsField.value = 50') + action_runner.ExecuteJavaScript('renegotiate()') + action_runner.WaitForJavaScriptCondition('!renegotiateButton.disabled') + action_runner.ExecuteJavaScript('videoSectionsField.value = 1') + action_runner.ExecuteJavaScript('renegotiate()') + action_runner.WaitForJavaScriptCondition('!renegotiateButton.disabled') + # Negotiate back up to 50, simulating Meet "unpin". This is what gets measured. + action_runner.ExecuteJavaScript('videoSectionsField.value = 50') + action_runner.ExecuteJavaScript('renegotiate()') + action_runner.WaitForJavaScriptCondition('!renegotiateButton.disabled') + result = action_runner.EvaluateJavaScript('result') + + self.AddMeasurement('callerSetLocalDescription', + 'ms', + result['callerSetLocalDescription'], + description='Time for caller SetLocalDescription') + self.AddMeasurement('calleeSetLocalDescription', + 'ms', + result['calleeSetLocalDescription'], + description='Time for callee SetLocalDescription') + self.AddMeasurement('callerSetRemoteDescription', + 'ms', + result['callerSetRemoteDescription'], + description='Time for caller SetRemoteDescription') + self.AddMeasurement('calleeSetRemoteDescription', + 'ms', + result['calleeSetRemoteDescription'], + description='Time for callee SetRemoteDescription') + self.AddMeasurement('callerCreateOffer', + 'ms', + result['callerCreateOffer'], + description='Time for overall offer/answer handshake') + self.AddMeasurement('calleeCreateAnswer', + 'ms', + result['calleeCreateAnswer'], + description='Time for overall offer/answer handshake') + self.AddMeasurement('elapsedTime', + 'ms', + result['elapsedTime'], + description='Time for overall offer/answer handshake') + self.AddMeasurement( + 'audioImpairment', + 'count', + result['audioImpairment'], + description='Number of late audio samples concealed during negotiation') + + class WebrtcPageSet(story.StorySet): def __init__(self): super(WebrtcPageSet, self).__init__( @@ -237,3 +302,4 @@ 'webgl', 'pc', tags=['insertableStreams'])) + self.AddStory(NegotiateTiming(self, tags=['sdp']))
diff --git a/tools/perf/page_sets/webrtc_cases/datatransfer.js b/tools/perf/page_sets/webrtc_cases/datatransfer.js index a1bb3fe..5bcbd9c4 100644 --- a/tools/perf/page_sets/webrtc_cases/datatransfer.js +++ b/tools/perf/page_sets/webrtc_cases/datatransfer.js
@@ -195,7 +195,7 @@ function onReceiveMessageCallback(event) { receiveProgress.value += event.data.length; currentThroughput = receiveProgress.value / (performance.now() - sendStartTime); - console.log('Current Throughput is:', currentThroughput, 'bytes/sec') + console.log('Current Throughput is:', currentThroughput, 'bytes/sec'); // Workaround for a bug in Chrome which prevents the closing event from being raised by the // remote side. Also a workaround for Firefox which does not send all pending data when closing
diff --git a/tools/perf/page_sets/webrtc_cases/negotiate-timing.html b/tools/perf/page_sets/webrtc_cases/negotiate-timing.html new file mode 100644 index 0000000..60c6ef0 --- /dev/null +++ b/tools/perf/page_sets/webrtc_cases/negotiate-timing.html
@@ -0,0 +1,55 @@ +<!DOCTYPE html> +<!-- + * Copyright (c) 2021 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. +--> +<html> +<head> + + + <base target="_blank"> + + <title>Peer connection - Renegotiate</title> + + +</head> + +<body> + +<div id="container"> + <h1><a href="//webrtc.github.io/samples/" title="WebRTC samples homepage">WebRTC samples</a> + <span>Peer connection negotiation timing</span></h1> + + <video id="localVideo" playsinline autoplay muted></video> + <video id="remoteVideo" playsinline autoplay></video> + + <div> + <button id="startButton">Start</button> + <button id="callButton">Call</button> + <button id="renegotiateButton">Renegotiate</button> + <button id="hangupButton">Hang Up</button> + </div> + <div> + <p> + Video sections after renegotiating: <input type="number" id="videoSections" value="5"> + </p> + </div> + <p>View the console to see logging. The <code>MediaStream</code> object <code>localStream</code>, and the <code>RTCPeerConnection</code> + objects <code>pc1</code> and <code>pc2</code> are in global scope, so you can inspect them in the console as + well.</p> + <p> + <div id="log"> + Log goes here + </div> + </p> + <a href="https://github.com/webrtc/samples/tree/gh-pages/src/content/peerconnection/negotiate-timing" + title="View source for this page on GitHub" id="viewSource">View source on GitHub</a> + +</div> + + +<script src="negotiate-timing.js"></script> +</body></html> \ No newline at end of file
diff --git a/tools/perf/page_sets/webrtc_cases/negotiate-timing.js b/tools/perf/page_sets/webrtc_cases/negotiate-timing.js new file mode 100644 index 0000000..b86c9754 --- /dev/null +++ b/tools/perf/page_sets/webrtc_cases/negotiate-timing.js
@@ -0,0 +1,242 @@ +/* + * Copyright (c) 2021 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ + +'use strict'; + +const startButton = document.getElementById('startButton'); +const callButton = document.getElementById('callButton'); +const renegotiateButton = document.getElementById('renegotiateButton'); +const hangupButton = document.getElementById('hangupButton'); +const log = document.getElementById('log'); +const videoSectionsField = document.getElementById('videoSections'); + +callButton.disabled = true; +hangupButton.disabled = true; +renegotiateButton.disabled = true; +startButton.onclick = start; +callButton.onclick = call; +renegotiateButton.onclick = renegotiate; +hangupButton.onclick = hangup; + +let startTime; +const localVideo = document.getElementById('localVideo'); +const remoteVideo = document.getElementById('remoteVideo'); + +let audioTransceiver; +let audioImpairmentAtStart = 0; + +let result; + +localVideo.addEventListener('loadedmetadata', function() { + console.log(`Local video videoWidth: ${this.videoWidth}px, videoHeight: ${this.videoHeight}px`); +}); + +remoteVideo.addEventListener('loadedmetadata', function() { + console.log(`Remote video videoWidth: ${this.videoWidth}px, videoHeight: ${this.videoHeight}px`); +}); + +remoteVideo.onresize = () => { + console.log(`Remote video size changed to ${remoteVideo.videoWidth}x${remoteVideo.videoHeight}`); + console.warn('RESIZE', remoteVideo.videoWidth, remoteVideo.videoHeight); + // We'll use the first onsize callback as an indication that video has started + // playing out. + if (startTime) { + const elapsedTime = window.performance.now() - startTime; + console.log(`Setup time: ${elapsedTime.toFixed(3)}ms`); + startTime = null; + } +}; + +let localStream; +let pc1; +let pc2; + +function logToScreen(text) { + log.append(document.createElement('br')); + log.append(text); +} + +function getName(pc) { + return (pc === pc1) ? 'pc1' : 'pc2'; +} + +function getOtherPc(pc) { + return (pc === pc1) ? pc2 : pc1; +} + +async function start() { + console.log('Requesting local stream'); + startButton.disabled = true; + const stream = await navigator.mediaDevices + .getUserMedia({ + audio: true, + video: true + }); + console.log('Received local stream'); + localVideo.srcObject = stream; + localStream = stream; + callButton.disabled = false; +} + +async function runOfferAnswer() { + const startTime = performance.now(); + const result = {}; + const offer = await pc1.createOffer(); + const markTime1 = performance.now(); + result.callerCreateOffer = markTime1 - startTime; + await pc1.setLocalDescription(offer); + const markTime2 = performance.now(); + result.callerSetLocalDescription = markTime2 - markTime1; + await pc2.setRemoteDescription(offer); + const markTime3 = performance.now(); + result.calleeSetRemoteDescription = markTime3 - markTime2; + const answer = await pc2.createAnswer(); + const markTime4 = performance.now(); + result.calleeCreateAnswer = markTime4 - markTime3; + await pc1.setRemoteDescription(answer); + const markTime5 = performance.now(); + result.callerSetRemoteDescription = markTime5 - markTime4; + await pc2.setLocalDescription(answer); + const markTime6 = performance.now(); + result.calleeSetLocalDescription = markTime6 - markTime5; + result.elapsedTime = markTime6 - startTime; + return result; +} + +async function call() { + callButton.disabled = true; + renegotiateButton.disabled = false; + hangupButton.disabled = false; + console.log('Starting call'); + startTime = window.performance.now(); + const audioTracks = localStream.getAudioTracks(); + if (audioTracks.length > 0) { + console.log(`Using audio device: ${audioTracks[0].label}`); + } + const servers = null; + pc1 = new RTCPeerConnection(servers); + console.log('Created local peer connection object pc1'); + pc1.onicecandidate = e => onIceCandidate(pc1, e); + pc2 = new RTCPeerConnection(servers); + console.log('Created remote peer connection object pc2'); + pc2.onicecandidate = e => onIceCandidate(pc2, e); + pc1.oniceconnectionstatechange = e => onIceStateChange(pc1, e); + pc2.oniceconnectionstatechange = e => onIceStateChange(pc2, e); + pc2.addEventListener('track', gotRemoteStream, {once: true}); + + localStream.getTracks().forEach(track => pc1.addTrack(track, localStream)); + console.log('Added local stream to pc1'); + + await runOfferAnswer(); + console.log('Initial negotiation complete'); +} + +function gotRemoteStream(e) { + console.log('gotRemoteStream', e.track, e.streams[0]); + if (e.streams[0]) { + // reset srcObject to work around minor bugs in Chrome and Edge. + remoteVideo.srcObject = null; + remoteVideo.srcObject = e.streams[0]; + } +} + +async function onIceCandidate(pc, event) { + if (event.candidate) { + console.log(`${getName(pc)} emitted ICE candidate for index ${event.candidate.sdpMLineIndex}:\n${event.candidate.candidate}`); + } else { + console.log(`$getName(pc)} ICE NULL candidate`); + } + await getOtherPc(pc).addIceCandidate(event.candidate); + console.log(`${getName(pc)} addIceCandidate success`); +} + +function onIceStateChange(pc, event) { + if (pc) { + console.log(`${getName(pc)} ICE state: ${pc.iceConnectionState}`); + console.log('ICE state change event, state: ', pc.iceConnectionState); + } +} + +function adjustTransceiverCounts(pc, videoCount) { + const currentVideoTransceivers = pc.getTransceivers().filter(tr => tr.receiver.track.kind == 'video'); + const currentVideoCount = currentVideoTransceivers.length; + if (currentVideoCount < videoCount) { + console.log('Adding ' + (videoCount - currentVideoCount) + ' transceivers'); + for (let i = currentVideoCount; i < videoCount; ++i) { + pc.addTransceiver('video'); + } + } else if (currentVideoCount > videoCount) { + console.log('Stopping ' + (currentVideoCount - videoCount) + ' transceivers'); + for (let i = videoCount; i < currentVideoCount; ++i) { + currentVideoTransceivers[i].stop(); + } + } else { + console.log(`No adjustment, video count is ${currentVideoCount}, target was ${videoCount}`); + } +} + +async function getAudioImpairment(audioTransceiver) { + const stats = await audioTransceiver.receiver.getStats(); + let currentImpairment; + stats.forEach(stat => { + if (stat.type == 'track') { + currentImpairment = stat.concealedSamples; + } + }); + console.log('Found impairment value ', currentImpairment); + return currentImpairment; +} + +async function baselineAudioImpairment(pc) { + audioTransceiver = pc.getTransceivers().find(tr => tr.receiver.track.kind == 'audio'); + console.log('Found audio transceiver'); + audioImpairmentAtStart = await getAudioImpairment(audioTransceiver); +} + +async function measureAudioImpairment(pc) { + const startTime = performance.now(); + const audioImpairmentNow = await getAudioImpairment(audioTransceiver); + console.log('Measurement took ' + (performance.now() - startTime) + ' msec'); + return audioImpairmentNow - audioImpairmentAtStart; +} + + +async function renegotiate() { + renegotiateButton.disabled = true; + adjustTransceiverCounts(pc1, parseInt(videoSectionsField.value)); + await baselineAudioImpairment(pc2); + const previousVideoTransceiverCount = pc2.getTransceivers().filter(tr => tr.receiver.track.kind == 'video').length; + result = await runOfferAnswer(); + console.log(`Renegotiate finished after ${result.elapsedTime} milliseconds`); + const currentVideoTransceiverCount = pc2.getTransceivers().filter(tr => tr.receiver.track.kind == 'video').length; + result.audioImpairment = await measureAudioImpairment(pc2); + logToScreen(`Negotiation from ${previousVideoTransceiverCount} to ${currentVideoTransceiverCount} video transceivers took ${result.elapsedTime.toFixed(2)} milliseconds, audio impairment ${result.audioImpairment}`); + console.log('Results: ', JSON.stringify(result, ' ', 2)); + renegotiateButton.disabled = false; +} + +function hangup() { + console.log('Ending call'); + pc1.close(); + pc2.close(); + pc1 = null; + pc2 = null; + + console.log('Releasing camera'); + const videoTracks = localStream.getVideoTracks(); + videoTracks.forEach(videoTrack => { + videoTrack.stop(); + localStream.removeTrack(videoTrack); + }); + localVideo.srcObject = null; + + hangupButton.disabled = true; + callButton.disabled = true; + renegotiateButton.disabled = true; + startButton.disabled = false; +}
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml index 69d8c2b..518f8073 100644 --- a/tools/traffic_annotation/summary/annotations.xml +++ b/tools/traffic_annotation/summary/annotations.xml
@@ -166,7 +166,7 @@ <item id="interest_feedv2_send" added_in_milestone="83" hash_code="85742023" type="0" content_hash_code="49706671" os_list="linux,windows" file_path="components/feed/core/v2/feed_network_impl.cc"/> <item id="intranet_redirect_detector" added_in_milestone="62" hash_code="21785164" type="0" content_hash_code="62025595" os_list="linux,windows" file_path="chrome/browser/intranet_redirect_detector.cc"/> <item id="invalidation_service" added_in_milestone="62" hash_code="72354423" type="0" deprecated="2020-01-23" content_hash_code="78425687" file_path=""/> - <item id="javascript_report_error" added_in_milestone="87" hash_code="109607776" type="0" content_hash_code="7229012" os_list="linux" file_path="chrome/browser/error_reporting/chrome_js_error_report_processor.cc"/> + <item id="javascript_report_error" added_in_milestone="87" hash_code="109607776" type="0" content_hash_code="7229012" os_list="linux" file_path="chrome/browser/error_reporting/chrome_js_error_report_processor_nonchromeos.cc"/> <item id="kids_chrome_management_client_classify_url" added_in_milestone="77" hash_code="109987793" type="0" deprecated="2019-07-30" content_hash_code="112740597" file_path=""/> <item id="lib_address_input" added_in_milestone="62" hash_code="50816767" type="0" content_hash_code="57977576" os_list="linux,windows" file_path="third_party/libaddressinput/chromium/chrome_metadata_source.cc"/> <item id="litepages_robots_rules" added_in_milestone="89" hash_code="50910588" type="0" content_hash_code="72567080" os_list="linux,windows" file_path="chrome/browser/subresource_redirect/origin_robots_rules.cc"/> @@ -357,6 +357,7 @@ <item id="user_info_fetcher" added_in_milestone="62" hash_code="22265491" type="0" content_hash_code="72016232" os_list="linux,windows" file_path="components/policy/core/common/cloud/user_info_fetcher.cc"/> <item id="video_tutorial_fetcher" added_in_milestone="87" hash_code="69879956" type="0" content_hash_code="121911479" os_list="linux,windows" file_path="chrome/browser/video_tutorials/internal/tutorial_fetcher.cc"/> <item id="viz_devtools_server" added_in_milestone="72" hash_code="16292315" type="0" content_hash_code="70061664" os_list="linux,windows" file_path="components/ui_devtools/devtools_server.cc"/> + <item id="web_app_origin_association_download" added_in_milestone="90" hash_code="128608592" type="0" content_hash_code="55648317" os_list="linux,windows" file_path="components/webapps/services/web_app_origin_association/web_app_origin_association_fetcher.cc"/> <item id="web_bundle_loader" added_in_milestone="84" hash_code="114615359" type="0" content_hash_code="57390734" os_list="linux,windows" file_path="content/browser/web_package/web_bundle_utils.cc"/> <item id="web_history_counter" added_in_milestone="62" hash_code="137457845" type="1" second_id="110307337" content_hash_code="49663381" os_list="linux,windows" semantics_fields="2,3,4" policy_fields="4" file_path="components/browsing_data/core/counters/history_counter.cc"/> <item id="web_history_delete_url" added_in_milestone="74" hash_code="41749213" type="1" second_id="110307337" content_hash_code="25943026" os_list="linux,windows" semantics_fields="2,3,4" policy_fields="4" file_path="components/history/core/browser/history_service.cc"/>
diff --git a/tools/traffic_annotation/summary/grouping.xml b/tools/traffic_annotation/summary/grouping.xml index 2788aa9..daab9de 100644 --- a/tools/traffic_annotation/summary/grouping.xml +++ b/tools/traffic_annotation/summary/grouping.xml
@@ -161,6 +161,7 @@ <traffic_annotation unique_id="webid"/> <traffic_annotation unique_id="managed_configuration_loader"/> <traffic_annotation unique_id="box_access_token_fetcher"/> + <traffic_annotation unique_id="web_app_origin_association_download"/> </sender> </group> <group name="Admin Features">
diff --git a/ui/android/BUILD.gn b/ui/android/BUILD.gn index 8a860687..62033b4f 100644 --- a/ui/android/BUILD.gn +++ b/ui/android/BUILD.gn
@@ -319,7 +319,6 @@ "java/src/org/chromium/ui/resources/HandleViewResources.java", "java/src/org/chromium/ui/resources/LayoutResource.java", "java/src/org/chromium/ui/resources/Resource.java", - "java/src/org/chromium/ui/resources/ResourceExtractor.java", "java/src/org/chromium/ui/resources/ResourceFactory.java", "java/src/org/chromium/ui/resources/ResourceLoader.java", "java/src/org/chromium/ui/resources/ResourceManager.java",
diff --git a/ui/android/java/src/org/chromium/ui/base/ResourceBundle.java b/ui/android/java/src/org/chromium/ui/base/ResourceBundle.java index 14be47ed..1f166ef 100644 --- a/ui/android/java/src/org/chromium/ui/base/ResourceBundle.java +++ b/ui/android/java/src/org/chromium/ui/base/ResourceBundle.java
@@ -7,7 +7,6 @@ import android.content.res.AssetFileDescriptor; import android.content.res.AssetManager; -import org.chromium.base.BundleUtils; import org.chromium.base.ContextUtils; import org.chromium.base.LocaleUtils; import org.chromium.base.Log; @@ -21,8 +20,7 @@ * This class provides the resource bundle related methods for the native * library. * - * IMPORTANT: Clients that use {@link ResourceBundle} and/or - * {@link org.chromium.ui.resources.ResourceExtractor} MUST call either + * IMPORTANT: Clients that use {@link ResourceBundle} MUST call either * {@link ResourceBundle#setAvailablePakLocales(String[], String[])} or * {@link ResourceBundle#setNoAvailableLocalePaks()} before calling the getters in this class. */ @@ -65,17 +63,13 @@ } /** - * Return the list of available locales. For bundle builds this is the uncompressed locales list - * and for apk builds this is the compressed locales list. + * Return the list of available locales. * @return The correct locale list for this build. */ public static String[] getAvailableLocales() { assert sCompressedLocales != null; assert sUncompressedLocales != null; - if (BundleUtils.isBundle()) { - return sUncompressedLocales; - } - return sCompressedLocales; + return sUncompressedLocales; } /** @@ -120,6 +114,13 @@ try (AssetFileDescriptor afd = manager.openNonAssetFd(assetPath)) { return assetPath; } catch (IOException e) { + // Fallback for apk targets. + // TODO(crbug.com/1176290): Remove the need for this fallback logic. + String fallbackPath = "assets/locales/" + locale + ".pak"; + try (AssetFileDescriptor afd = manager.openNonAssetFd(fallbackPath)) { + return fallbackPath; + } catch (IOException e2) { + } if (logError) { Log.e(TAG, "path=%s", assetPath, e); }
diff --git a/ui/android/java/src/org/chromium/ui/resources/ResourceExtractor.java b/ui/android/java/src/org/chromium/ui/resources/ResourceExtractor.java deleted file mode 100644 index ad6b0d7f..0000000 --- a/ui/android/java/src/org/chromium/ui/resources/ResourceExtractor.java +++ /dev/null
@@ -1,330 +0,0 @@ -// Copyright 2012 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.ui.resources; - -import android.content.res.AssetManager; - -import org.chromium.base.BuildInfo; -import org.chromium.base.ContextUtils; -import org.chromium.base.FileUtils; -import org.chromium.base.LocaleUtils; -import org.chromium.base.Log; -import org.chromium.base.PathUtils; -import org.chromium.base.ThreadUtils; -import org.chromium.base.TraceEvent; -import org.chromium.base.task.PostTask; -import org.chromium.base.task.TaskTraits; -import org.chromium.ui.base.LocalizationUtils; -import org.chromium.ui.base.ResourceBundle; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Locale; -import java.util.concurrent.CountDownLatch; - -/** - * Handles extracting the necessary resources bundled in an APK and moving them to a location on - * the file system accessible from the native code. - */ -public class ResourceExtractor { - private static final String TAG = "ui"; - private static final String ICU_DATA_FILENAME = "icudtl.dat"; - private static final String V8_SNAPSHOT_DATA_FILENAME = "snapshot_blob.bin"; - private static final String FALLBACK_LOCALE = "en-US"; - private static final String COMPRESSED_LOCALES_DIR = "locales"; - - private class ExtractTask implements Runnable { - private final List<Runnable> mCompletionCallbacks = new ArrayList<Runnable>(); - private final String mUiLanguage; - private final CountDownLatch mLatch = new CountDownLatch(1); - private boolean mDone; - - public ExtractTask(String uiLanguage) { - mUiLanguage = uiLanguage; - } - - @Override - public void run() { - try (TraceEvent e = TraceEvent.scoped("ResourceExtractor.ExtractTask.doInBackground")) { - doInBackgroundImpl(); - } - synchronized (this) { - mDone = true; - } - mLatch.countDown(); - - PostTask.postTask(mResultTaskTraits, () -> { - try (TraceEvent e = - TraceEvent.scoped("ResourceExtractor.ExtractTask.onPostExecute")) { - onPostExecuteImpl(); - } - }); - } - - private void doInBackgroundImpl() { - final File outputDir = getOutputDir(); - String[] assetPaths = detectFilesToExtract(mUiLanguage); - - // Use a suffix for extracted files in order to guarantee that the version of the file - // on disk matches up with the version of the APK. - String extractSuffix = BuildInfo.getInstance().extractedFileSuffix; - String[] outputNames = new String[assetPaths.length]; - for (int n = 0; n < assetPaths.length; ++n) { - String assetPath = assetPaths[n]; - outputNames[n] = - assetPath.substring(assetPath.lastIndexOf('/') + 1) + extractSuffix; - } - - String[] existingFileNames = outputDir.list(); - boolean allFilesExist = existingFileNames != null; - if (allFilesExist) { - List<String> existingFiles = Arrays.asList(existingFileNames); - for (String outputName : outputNames) { - allFilesExist &= existingFiles.contains(outputName); - } - } - // This is the normal case. - if (allFilesExist) { - return; - } - // A missing file means Chrome has updated. Delete stale files first. - deleteFiles(existingFileNames); - - outputDir.mkdirs(); - if (!outputDir.exists()) { - // Return value of mkdirs() sometimes incorrect? https://crbug.com/849550 - throw new RuntimeException(); - } - - for (int n = 0; n < assetPaths.length; ++n) { - String assetPath = assetPaths[n]; - File output = new File(outputDir, outputNames[n]); - if (!FileUtils.extractAsset( - ContextUtils.getApplicationContext(), assetPath, output)) { - // The app would just crash later if files are missing. - throw new RuntimeException(); - } - } - } - - private void onPostExecuteImpl() { - ThreadUtils.assertOnUiThread(); - for (int i = 0; i < mCompletionCallbacks.size(); i++) { - mCompletionCallbacks.get(i).run(); - } - mCompletionCallbacks.clear(); - } - - public void await() throws Exception { - mLatch.await(); - } - - public synchronized boolean isDone() { - return mDone; - } - } - - private ExtractTask mExtractTask; - private TaskTraits mResultTaskTraits; - - private static ResourceExtractor sInstance; - - public static ResourceExtractor get() { - if (sInstance == null) { - sInstance = new ResourceExtractor(); - } - return sInstance; - } - - private static String[] detectFilesToExtract(String uiLanguage) { - Locale defaultLocale = Locale.getDefault(); - String androidLanguage = defaultLocale.getLanguage(); - String chromiumLanguage = LocaleUtils.getUpdatedLanguageForChromium(androidLanguage); - - // NOTE: The UI language will differ from the application's language - // when the system locale is not directly supported by Chrome's - // resources. - Log.i(TAG, "Using UI locale %s, system locale: %s (Android name: %s)", uiLanguage, - chromiumLanguage, androidLanguage); - - // Currenty (Apr 2018), this array can be as big as 6 entries, so using a capacity - // that allows a bit of growth, but is still in the right ballpark.. - ArrayList<String> activeLocales = new ArrayList<String>(6); - String[] compressedLocales = ResourceBundle.getAvailableCompressedPakLocales(); - for (String locale : compressedLocales) { - if (LocalizationUtils.chromiumLocaleMatchesLanguage(locale, uiLanguage)) { - activeLocales.add(locale); - } - } - if (activeLocales.isEmpty()) { - assert compressedLocales.length > 0; - assert Arrays.asList(compressedLocales).contains(FALLBACK_LOCALE); - activeLocales.add(FALLBACK_LOCALE); - } - - // * For bundles, locale pak files are always stored uncompressed - // either under base.apk!/assets/fallback-locales/<locale>.pak or - // base-<lang>.apk!/assets/locales#lang_<lang>/<locale>.pak. They - // never need to be extracted. - // - // * For regular APKs, the locale pak files are stored under: - // base.apk!/assets/locales/<locale>.pak - // - // where <locale> is a Chromium-specific locale name. - // - AssetManager assetManager = ContextUtils.getApplicationAssets(); - if (!assetPathHasFile( - assetManager, COMPRESSED_LOCALES_DIR, activeLocales.get(0) + ".pak")) { - Log.i(TAG, "No locale pak files to extract, assuming app bundle."); - return new String[] {}; - } - - // This is a regular APK, and all pak files are available. - // Return the list of locale pak file paths corresponding to the current language. - String[] localePakFiles = new String[activeLocales.size()]; - for (int n = 0; n < activeLocales.size(); ++n) { - localePakFiles[n] = COMPRESSED_LOCALES_DIR + '/' + activeLocales.get(n) + ".pak"; - } - Log.i(TAG, "UI Language: %s requires .pak files: %s", uiLanguage, - Arrays.toString(activeLocales.toArray())); - - return localePakFiles; - } - - /** - * Check that an AssetManager instance has a specific asset file. - * - * @param assetManager The application's AssetManager instance. - * @param assetPath Asset directory path (e.g. "assets/locales"). - * @param assetFile Asset file name inside assetPath. - * @return true iff the asset file is available. - */ - private static boolean assetPathHasFile( - AssetManager assetManager, String assetPath, String assetFile) { - String assetFilePath = assetPath + '/' + assetFile; - try { - InputStream input = assetManager.open(assetFilePath); - input.close(); - Log.i(TAG, "Found asset file: " + assetFilePath); - return true; - } catch (IOException e) { - Log.i(TAG, "Missing asset file: " + assetFilePath); - return false; - } - } - - /** - * Synchronously wait for the resource extraction to be completed. - * <p> - * This method is bad and you should feel bad for using it. - * - * @see #addCompletionCallback(Runnable) - */ - public void waitForCompletion() { - if (mExtractTask == null || shouldSkipPakExtraction()) { - return; - } - - try { - mExtractTask.await(); - } catch (Exception e) { - assert false; - } - } - - /** - * Sets the traits to use for the reply task. - */ - public void setResultTraits(TaskTraits traits) { - mResultTaskTraits = traits; - } - - /** - * Adds a callback to be notified upon the completion of resource extraction. - * <p> - * If the resource task has already completed, the callback will be posted to the UI message - * queue. Otherwise, it will be executed after all the resources have been extracted. - * <p> - * This must be called on the UI thread. The callback will also always be executed on - * the UI thread. - * - * @param callback The callback to be enqueued. - */ - public void addCompletionCallback(Runnable callback) { - ThreadUtils.assertOnUiThread(); - - if (shouldSkipPakExtraction()) { - PostTask.postTask(mResultTaskTraits, callback); - return; - } - - assert mExtractTask != null; - if (mExtractTask.isDone()) { - PostTask.postTask(mResultTaskTraits, callback); - } else { - mExtractTask.mCompletionCallbacks.add(callback); - } - } - - /** - * This will extract the application pak resources in an - * AsyncTask. Call waitForCompletion() at the point resources - * are needed to block until the task completes. - * - * @param uiLanguage The language to extract. - */ - public void startExtractingResources(String uiLanguage) { - if (mExtractTask != null) { - return; - } - - // If a previous release extracted resources, and the current release does not, delete the - // old files since they are no longer needed. - if (shouldSkipPakExtraction()) { - PostTask.postTask( - TaskTraits.BEST_EFFORT, () -> { deleteFiles(getOutputDir().list()); }); - return; - } - - mExtractTask = new ExtractTask(uiLanguage); - PostTask.postTask(TaskTraits.USER_BLOCKING, mExtractTask); - } - - private File getAppDataDir() { - return new File(PathUtils.getDataDirectory()); - } - - private File getOutputDir() { - return new File(getAppDataDir(), "paks"); - } - - private void deleteFiles(String[] existingFileNames) { - // These used to be extracted, but no longer are, so just clean them up. - FileUtils.recursivelyDeleteFile( - new File(getAppDataDir(), ICU_DATA_FILENAME), FileUtils.DELETE_ALL); - FileUtils.recursivelyDeleteFile( - new File(getAppDataDir(), V8_SNAPSHOT_DATA_FILENAME), FileUtils.DELETE_ALL); - - if (existingFileNames != null) { - for (String fileName : existingFileNames) { - FileUtils.recursivelyDeleteFile( - new File(getOutputDir(), fileName), FileUtils.DELETE_ALL); - } - } - } - - /** - * Pak extraction not necessarily required by the embedder. - */ - private static boolean shouldSkipPakExtraction() { - // Certain apks like ContentShell.apk don't have any compressed locale - // assets however, so skip extraction entirely for them. - return ResourceBundle.getAvailableCompressedPakLocales().length == 0; - } -}
diff --git a/ui/base/clipboard/clipboard_ozone.cc b/ui/base/clipboard/clipboard_ozone.cc index ceffda9c..40a929d 100644 --- a/ui/base/clipboard/clipboard_ozone.cc +++ b/ui/base/clipboard/clipboard_ozone.cc
@@ -44,7 +44,10 @@ // Depending on the backend, the platform clipboard may or may not be // available. Should it be absent, we provide a dummy one. It always calls -// back immediately with empty data, and denies ownership of any buffer. +// back immediately with empty data. It starts without ownership of any buffers +// but will take and keep ownership after a call to OfferClipboardData(). By +// taking ownership, we allow ClipboardOzone to return existing data in +// ReadClipboardDataAndWait(). class StubPlatformClipboard : public PlatformClipboard { public: StubPlatformClipboard() = default; @@ -55,6 +58,7 @@ ClipboardBuffer buffer, const PlatformClipboard::DataMap& data_map, PlatformClipboard::OfferDataClosure callback) override { + is_owner_[buffer] = true; std::move(callback).Run(); } void RequestClipboardData( @@ -69,10 +73,15 @@ PlatformClipboard::GetMimeTypesClosure callback) override { std::move(callback).Run({}); } - bool IsSelectionOwner(ClipboardBuffer buffer) override { return false; } + bool IsSelectionOwner(ClipboardBuffer buffer) override { + return is_owner_[buffer]; + } void SetSequenceNumberUpdateCb( PlatformClipboard::SequenceNumberUpdateCb cb) override {} bool IsSelectionBufferAvailable() const override { return false; } + + private: + base::flat_map<ClipboardBuffer, bool> is_owner_; }; } // namespace
diff --git a/ui/base/resource/resource_bundle.cc b/ui/base/resource/resource_bundle.cc index c5211b08..910662d2 100644 --- a/ui/base/resource/resource_bundle.cc +++ b/ui/base/resource/resource_bundle.cc
@@ -372,22 +372,8 @@ base::FilePath locale_file_path; if (base::PathService::Get(ui::DIR_LOCALES, &locale_file_path)) { -#if defined(OS_ANDROID) - if (locale_file_path.value().find("chromium_tests") == std::string::npos) { - std::string extracted_file_suffix = - base::android::BuildInfo::GetInstance()->extracted_file_suffix(); - locale_file_path = locale_file_path.AppendASCII( - app_locale + kPakFileExtension + extracted_file_suffix); - } else { - // TODO(agrieve): Update tests to not side-load pak files and remove - // this special-case. https://crbug.com/691719 - locale_file_path = - locale_file_path.AppendASCII(app_locale + kPakFileExtension); - } -#else locale_file_path = locale_file_path.AppendASCII(app_locale + kPakFileExtension); -#endif } // Note: The delegate GetPathForLocalePack() override is currently only used
diff --git a/ui/base/resource/resource_bundle_android.cc b/ui/base/resource/resource_bundle_android.cc index ddb0e045..bc5d528 100644 --- a/ui/base/resource/resource_bundle_android.cc +++ b/ui/base/resource/resource_bundle_android.cc
@@ -106,6 +106,8 @@ } if (!GetPathForAndroidLocalePakWithinApk(locale, in_split, log_error).empty()) return true; + + // Fall back to checking on disk, which is necessary only for tests. const auto path = GetLocaleFilePath(locale); return !path.empty() && base::PathExists(path); } @@ -122,9 +124,7 @@ // a) WebView strings, which are always stored uncompressed under // assets/stored-locales/ inside the APK or App Bundle. // - // b) For APKs, the Chrome UI strings are stored under assets/locales/ - // in compressed form. The relevant pak files is extracted on startup - // and stored on the /data partition, with a version-specific suffix. + // b) For APKs, the Chrome UI strings are stored under assets/locales/. // // c) For App Bundles, Chrome UI strings are stored uncompressed under // assets/locales#lang_<lang>/ (where <lang> is an Android language code) @@ -139,8 +139,7 @@ // // If false, try to load it from the app bundle specific location // (e.g. locales#lang_<language>/<locale>.pak). If the latter does not - // exist, try to lookup the extracted APK-specific locale .pak file - // from /data/app/.../<locale>.pak@<version> instead. + // exist, try to lookup the APK-specific locale .pak file. // // g_locale_paks_in_apk is set by SetLocalePaksStoredInApk() which // is called from the WebView startup code. @@ -172,7 +171,7 @@ LoadLocalePakFromApk(app_locale, true, &g_locale_pack_region); } if (g_locale_pack_fd < 0) { - // Otherwise, try to locate the extracted locale .pak file. + // Otherwise, try to locate the side-loaded locale .pak file (for tests). if (locale_file_path.empty()) { auto path = GetLocaleFilePath(app_locale); if (base::PathExists(path))
diff --git a/ui/file_manager/integration_tests/file_manager/files_tooltip.js b/ui/file_manager/integration_tests/file_manager/files_tooltip.js index 6c54ea25..20ecb9b6 100644 --- a/ui/file_manager/integration_tests/file_manager/files_tooltip.js +++ b/ui/file_manager/integration_tests/file_manager/files_tooltip.js
@@ -91,16 +91,6 @@ await remoteCall.waitForElement(appId, [tooltipQueryVisible, '#label']); chrome.test.assertEq(expectedLabelText, label.text); - // Focus another button that has a tooltip: the view button. - chrome.test.assertTrue( - await remoteCall.callRemoteTestUtil('focus', appId, [viewButton])); - await getActiveElementById(appId, 'view-button'); - - // Check: the view button tooltip should be visible. - label = - await remoteCall.waitForElement(appId, [tooltipQueryVisible, '#label']); - chrome.test.assertEq('Switch to thumbnail view', label.text); - // Focus an element that has no tooltip: the file-list. chrome.test.assertTrue( await remoteCall.callRemoteTestUtil('focus', appId, [fileList])); @@ -127,74 +117,40 @@ }; /** - * Tests that tooltip is displayed when hovering an element with tooltip. + * Tests that tooltips display when hovering an element that has a tooltip. */ testcase.filesTooltipMouseOver = async () => { const appId = await setupAndWaitUntilReady( RootPath.DOWNLOADS, [ENTRIES.beautiful], []); - // Hover a button with tooltip. - let tooltip = await remoteCall.waitForElement(appId, tooltipQueryHidden); + // Check: initially the tooltip should be hidden. + await remoteCall.waitForElement(appId, tooltipQueryHidden); + + // Mouse hover over a button that has a tooltip: the search button. chrome.test.assertTrue(await remoteCall.callRemoteTestUtil( 'fakeMouseOver', appId, [searchButton])); - // The tooltip should be visible. - let expectedLabelText = await getExpectedLabelText('SEARCH_TEXT_LABEL'); - tooltip = await remoteCall.waitForElement(appId, tooltipQueryVisible); - let label = + // Check: the search button tooltip should be visible. + const expectedLabelText = await getExpectedLabelText('SEARCH_TEXT_LABEL'); + const firstElement = await remoteCall.waitForElement(appId, [tooltipQueryVisible, '#label']); - chrome.test.assertEq(expectedLabelText, label.text); + chrome.test.assertEq(expectedLabelText, firstElement.text); - // Hover another button with tooltip. + // Move the mouse away from the search button. chrome.test.assertTrue(await remoteCall.callRemoteTestUtil( - 'fakeMouseOver', appId, [viewButton])); + 'fakeMouseOut', appId, [searchButton])); - // The tooltip should be visible. - tooltip = await remoteCall.waitForElement(appId, tooltipQueryVisible); - label = - await remoteCall.waitForElement(appId, [tooltipQueryVisible, '#label']); - chrome.test.assertEq('Switch to thumbnail view', label.text); + // Check: the tooltip should hide. + await remoteCall.waitForElement(appId, tooltipQueryHidden); - // Go to readonly volume to have readonly indicator. - await remoteCall.simulateUiClick( - appId, ['[volume-type-for-testing=android_files]']); - - // Hover another element with card tooltip. - chrome.test.assertTrue(await remoteCall.callRemoteTestUtil( - 'fakeMouseOver', appId, [readonlyIndicator])); - - // The tooltip should be visible. - expectedLabelText = - await getExpectedLabelText('READONLY_INDICATOR_TOOLTIP'); - tooltip = await remoteCall.waitForElement(appId, tooltipQueryVisible); - label = - await remoteCall.waitForElement(appId, [tooltipQueryVisible, '#label']); - chrome.test.assertEq(expectedLabelText, label.text); - chrome.test.assertEq('card-tooltip', tooltip.attributes['class']); - chrome.test.assertEq('card-label', label.attributes['class']); - - // Send a mouseout event. - chrome.test.assertTrue(await remoteCall.callRemoteTestUtil( - 'fakeMouseOut', appId, [readonlyIndicator])); - - // The tooltip should be hidden. - tooltip = await remoteCall.waitForElement(appId, tooltipQueryHidden); - - // Hover a button with ordinary tooltip again. - tooltip = await remoteCall.waitForElement(appId, tooltipQueryHidden); + // Move the mouse over the search button again. chrome.test.assertTrue(await remoteCall.callRemoteTestUtil( 'fakeMouseOver', appId, [searchButton])); - // The tooltip should be visible. - expectedLabelText = await getExpectedLabelText('SEARCH_TEXT_LABEL'); - tooltip = await remoteCall.waitForElement(appId, tooltipQueryVisible); - label = + // Check: the search button tooltip should be visible. + const lastElement = await remoteCall.waitForElement(appId, [tooltipQueryVisible, '#label']); - chrome.test.assertEq(expectedLabelText, label.text); - - // Tooltip class should be cleared as ordinary tooltip shown. - chrome.test.assertEq('', label.attributes['class']); - chrome.test.assertEq('', tooltip.attributes['class']); + chrome.test.assertEq(expectedLabelText, lastElement.text); }; /** @@ -232,25 +188,36 @@ const appId = await setupAndWaitUntilReady( RootPath.DOWNLOADS, [ENTRIES.beautiful], []); - // Hover a button with tooltip. - await remoteCall.waitForElement(appId, tooltipQueryHidden); - - // Go to a readonly volume to have the readonly indicator. + // Click the 'Android files' volume tab in the directory tree. await remoteCall.simulateUiClick( appId, ['[volume-type-for-testing=android_files]']); - // Hover an element with card tooltip. + // Wait for the read-only bubble to appear in the files app tool bar. + const readonlyBubbleShown = '#read-only-indicator:not([hidden])'; + await remoteCall.waitForElement(appId, readonlyBubbleShown); + + // Check: initially, no tooltip should be visible. + await remoteCall.waitForElement(appId, tooltipQueryHidden); + + // Hover the mouse over the read-only bubble. chrome.test.assertTrue(await remoteCall.callRemoteTestUtil( 'fakeMouseOver', appId, [readonlyIndicator])); - // The tooltip should be visible. - await remoteCall.waitForElement(appId, tooltipQueryVisible); + // Check: the read-only bubble card tooltip should be visible. + const expectedLabelText = + await getExpectedLabelText('READONLY_INDICATOR_TOOLTIP'); + const tooltip = await remoteCall.waitForElement(appId, tooltipQueryVisible); + const label = + await remoteCall.waitForElement(appId, [tooltipQueryVisible, '#label']); + chrome.test.assertEq(expectedLabelText, label.text); + chrome.test.assertEq('card-tooltip', tooltip.attributes['class']); + chrome.test.assertEq('card-label', label.attributes['class']); - // Click on body to hide tooltip. + // Click the body element. chrome.test.assertTrue( await remoteCall.callRemoteTestUtil('fakeMouseClick', appId, ['body'])); - // The tooltip should be hidden. + // Check: the tooltip should hide. await remoteCall.waitForElement(appId, tooltipQueryHidden); }; @@ -261,20 +228,24 @@ const appId = await setupAndWaitUntilReady( RootPath.DOWNLOADS, [ENTRIES.beautiful], []); - // The tooltip should be hidden. + // Check: initially the tooltip should be hidden. await remoteCall.waitForElement(appId, tooltipQueryHidden); - // Focus a button with tooltip. + // Focus a button with tooltip: the search button. chrome.test.assertTrue( await remoteCall.callRemoteTestUtil('focus', appId, [searchButton])); + await getActiveElementById(appId, 'search-button'); - // The tooltip should be visible. - await remoteCall.waitForElement(appId, tooltipQueryVisible); + // Check: the search button tooltip should be visible. + const expectedLabelText = await getExpectedLabelText('SEARCH_TEXT_LABEL'); + const label = + await remoteCall.waitForElement(appId, [tooltipQueryVisible, '#label']); + chrome.test.assertEq(expectedLabelText, label.text); // Resize the window. await remoteCall.callRemoteTestUtil('resizeWindow', appId, [1200, 1200]); - // The tooltip should be hidden. + // Check: the tooltip should hide. await remoteCall.waitForElement(appId, tooltipQueryHidden); };
diff --git a/ui/views/controls/menu/menu_config.h b/ui/views/controls/menu/menu_config.h index c84d1377..ade60b9 100644 --- a/ui/views/controls/menu/menu_config.h +++ b/ui/views/controls/menu/menu_config.h
@@ -184,8 +184,11 @@ // Height of child MenuItemViews for touchable menus. int touchable_menu_height = 36; - // Width of touchable menus. - int touchable_menu_width = 256; + // Minimum width of touchable menus. + int touchable_menu_min_width = 256; + + // Maximum width of touchable menus. + int touchable_menu_max_width = 352; // Shadow elevation of touchable menus. int touchable_menu_shadow_elevation = 12;
diff --git a/ui/views/controls/menu/menu_controller.cc b/ui/views/controls/menu/menu_controller.cc index 867971462..b963175 100644 --- a/ui/views/controls/menu/menu_controller.cc +++ b/ui/views/controls/menu/menu_controller.cc
@@ -2569,7 +2569,7 @@ const bool create_on_right = prefer_leading != layout_is_rtl; const int width_with_right_inset = - menu_config.touchable_menu_width + border_and_shadow_insets.right(); + menu_config.touchable_menu_min_width + border_and_shadow_insets.right(); const int x_max = monitor_bounds.right() - width_with_right_inset; const int x_left = item_bounds.x() - width_with_right_inset; const int x_right = item_bounds.right() - border_and_shadow_insets.left();
diff --git a/ui/views/controls/menu/menu_controller_unittest.cc b/ui/views/controls/menu/menu_controller_unittest.cc index caa8e35..383452ec 100644 --- a/ui/views/controls/menu/menu_controller_unittest.cc +++ b/ui/views/controls/menu/menu_controller_unittest.cc
@@ -2164,7 +2164,7 @@ MenuItemView* sub_item = menu_item()->GetSubmenu()->GetMenuItemAt(0); sub_item->AppendMenuItem(11, base::ASCIIToUTF16("Subitem.One")); - const int menu_width = MenuConfig::instance().touchable_menu_width; + const int menu_width = MenuConfig::instance().touchable_menu_min_width; const gfx::Size parent_size(menu_width, menu_width); const gfx::Size parent_size_wide(menu_width * 2, menu_width);
diff --git a/ui/views/controls/menu/menu_item_view.cc b/ui/views/controls/menu/menu_item_view.cc index ab23f82..89f6c65 100644 --- a/ui/views/controls/menu/menu_item_view.cc +++ b/ui/views/controls/menu/menu_item_view.cc
@@ -1249,6 +1249,9 @@ dimensions.children_width = child_size.width(); const MenuConfig& menu_config = MenuConfig::instance(); + MenuDelegate::LabelStyle style; + GetLabelStyle(&style); + if (GetMenuController() && GetMenuController()->use_touchable_layout()) { dimensions.height = menu_config.touchable_menu_height; @@ -1259,7 +1262,15 @@ if (IsContainer()) return dimensions; - dimensions.standard_width = menu_config.touchable_menu_width; + // Calculate total item width to make sure the current |title_| + // has enough room within the context menu. + int label_start = GetLabelStartForThisItem(); + int string_width = gfx::GetStringWidth(title_, style.font_list); + int item_width = string_width + label_start + item_right_margin_; + + item_width = std::max(item_width, menu_config.touchable_menu_min_width); + item_width = std::min(item_width, menu_config.touchable_menu_max_width); + dimensions.standard_width = item_width; if (icon_view_) { dimensions.height = icon_view_->GetPreferredSize().height() + @@ -1268,8 +1279,6 @@ return dimensions; } - MenuDelegate::LabelStyle style; - GetLabelStyle(&style); base::string16 minor_text = GetMinorText(); dimensions.height = child_size.height(); @@ -1358,7 +1367,8 @@ // Touchable items with icons do not respect |label_start_|. if (GetMenuController() && GetMenuController()->use_touchable_layout() && icon_view_) { - return 2 * config.touchable_item_horizontal_padding + icon_view_->width(); + return 2 * config.touchable_item_horizontal_padding + + icon_view_->GetPreferredSize().width(); } int label_start = label_start_ + left_icon_margin_ + right_icon_margin_;
diff --git a/ui/views/controls/menu/menu_item_view_unittest.cc b/ui/views/controls/menu/menu_item_view_unittest.cc index b942a3d..cff5dcf 100644 --- a/ui/views/controls/menu/menu_item_view_unittest.cc +++ b/ui/views/controls/menu/menu_item_view_unittest.cc
@@ -16,6 +16,7 @@ #include "ui/gfx/geometry/insets.h" #include "ui/native_theme/themed_vector_icon.h" #include "ui/strings/grit/ui_strings.h" +#include "ui/views/controls/menu/menu_runner.h" #include "ui/views/controls/menu/submenu_view.h" #include "ui/views/controls/menu/test_menu_item_view.h" #include "ui/views/test/menu_test_utils.h" @@ -205,6 +206,67 @@ EXPECT_FALSE(is_selected); } +class TouchableMenuItemViewTest : public ViewsTestBase { + public: + TouchableMenuItemViewTest() = default; + ~TouchableMenuItemViewTest() override = default; + + void SetUp() override { + ViewsTestBase::SetUp(); + widget_ = CreateTestWidget(); + widget_->Show(); + + menu_delegate_ = std::make_unique<test::TestMenuDelegate>(); + menu_item_view_ = new TestMenuItemView(menu_delegate_.get()); + menu_runner_ = std::make_unique<MenuRunner>( + menu_item_view_, MenuRunner::USE_TOUCHABLE_LAYOUT); + menu_runner_->RunMenuAt(widget_.get(), nullptr, gfx::Rect(), + MenuAnchorPosition::kTopLeft, + ui::MENU_SOURCE_KEYBOARD); + } + + void TearDown() override { + widget_->CloseNow(); + ViewsTestBase::TearDown(); + } + + gfx::Size AppendItemAndGetSize(int i, const base::string16& title) { + return menu_item_view_->AppendMenuItem(i, title)->GetPreferredSize(); + } + + private: + std::unique_ptr<test::TestMenuDelegate> menu_delegate_; + std::unique_ptr<MenuRunner> menu_runner_; + std::unique_ptr<Widget> widget_; + + // Owned by MenuRunner. + TestMenuItemView* menu_item_view_ = nullptr; +}; + +// Test that touchable menu items are sized to fit the menu item titles within +// the allowed minimum and maximum width. +TEST_F(TouchableMenuItemViewTest, MinAndMaxWidth) { + const int min_menu_width = MenuConfig::instance().touchable_menu_min_width; + const int max_menu_width = MenuConfig::instance().touchable_menu_max_width; + + // Test a title shorter than the minimum width. + gfx::Size item1_size = + AppendItemAndGetSize(1, base::ASCIIToUTF16("Item1 Short title")); + EXPECT_EQ(item1_size.width(), min_menu_width); + + // Test a title which is between the min and max allowed widths. + gfx::Size item2_size = AppendItemAndGetSize( + 2, base::ASCIIToUTF16("Item2 bigger than min less than max")); + EXPECT_GT(item2_size.width(), min_menu_width); + EXPECT_LT(item2_size.width(), max_menu_width); + + // Test a title which is longer than the max touchable menu width. + gfx::Size item3_size = AppendItemAndGetSize( + 3, base::ASCIIToUTF16("Item3 Title that is longer than the maximum " + "allowed context menu width")); + EXPECT_EQ(item3_size.width(), max_menu_width); +} + class MenuItemViewLayoutTest : public ViewsTestBase { public: MenuItemViewLayoutTest() : test_item_(root_menu_.AppendMenuItem(1)) {}
diff --git a/ui/views/controls/webview/webview_unittest.cc b/ui/views/controls/webview/webview_unittest.cc index 5b9b0304..39005fa 100644 --- a/ui/views/controls/webview/webview_unittest.cc +++ b/ui/views/controls/webview/webview_unittest.cc
@@ -191,6 +191,11 @@ content::WebContents::CreateParams(browser_context_.get())); } + std::unique_ptr<content::WebContents> CreateTestWebContents() const { + return content::WebContentsTester::CreateTestWebContents( + browser_context_.get(), /*site_instnace=*/nullptr); + } + private: std::unique_ptr<content::RenderViewHostTestEnabler> rvh_enabler_; std::unique_ptr<content::TestBrowserContext> browser_context_; @@ -321,7 +326,11 @@ // Test that the specified crashed overlay view is shown when a WebContents // is in a crashed state. TEST_F(WebViewUnitTest, CrashedOverlayView) { - const std::unique_ptr<content::WebContents> web_contents(CreateWebContents()); + const std::unique_ptr<content::WebContents> web_contents = + CreateTestWebContents(); + content::WebContentsTester* tester = + content::WebContentsTester::For(web_contents.get()); + std::unique_ptr<WebView> web_view( new WebView(web_contents->GetBrowserContext())); View* contents_view = top_level_widget()->GetContentsView(); @@ -337,7 +346,7 @@ // WebContents, simulate that by calling SetIsCrashed and then // explicitly calling RenderFrameDeleted on the WebView to trigger it // to swap in the crashed overlay view. - web_contents->SetIsCrashed(base::TERMINATION_STATUS_PROCESS_CRASHED, -1); + tester->SetIsCrashed(base::TERMINATION_STATUS_PROCESS_CRASHED, -1); EXPECT_TRUE(web_contents->IsCrashed()); static_cast<content::WebContentsObserver*>(web_view.get()) ->RenderFrameDeleted(web_contents->GetMainFrame()); @@ -346,7 +355,10 @@ // Test that a crashed overlay view isn't deleted if it's owned by client. TEST_F(WebViewUnitTest, CrashedOverlayViewOwnedbyClient) { - const std::unique_ptr<content::WebContents> web_contents(CreateWebContents()); + const std::unique_ptr<content::WebContents> web_contents = + CreateTestWebContents(); + content::WebContentsTester* tester = + content::WebContentsTester::For(web_contents.get()); std::unique_ptr<WebView> web_view( new WebView(web_contents->GetBrowserContext())); View* contents_view = top_level_widget()->GetContentsView(); @@ -359,7 +371,7 @@ EXPECT_FALSE(crashed_overlay_view->IsDrawn()); // Simulate a renderer crash (see above). - web_contents->SetIsCrashed(base::TERMINATION_STATUS_PROCESS_CRASHED, -1); + tester->SetIsCrashed(base::TERMINATION_STATUS_PROCESS_CRASHED, -1); EXPECT_TRUE(web_contents->IsCrashed()); static_cast<content::WebContentsObserver*>(web_view.get()) ->RenderFrameDeleted(web_contents->GetMainFrame());
diff --git a/ui/webui/resources/cr_components/chromeos/cellular_setup/BUILD.gn b/ui/webui/resources/cr_components/chromeos/cellular_setup/BUILD.gn index 493a1a0..1fb38add 100644 --- a/ui/webui/resources/cr_components/chromeos/cellular_setup/BUILD.gn +++ b/ui/webui/resources/cr_components/chromeos/cellular_setup/BUILD.gn
@@ -165,6 +165,7 @@ ":esim_flow_ui", ":psim_flow_ui", ":setup_selection_flow", + "//ui/webui/resources/cr_components/chromeos/network:mojo_interface_provider", "//ui/webui/resources/js:i18n_behavior", ] } @@ -418,6 +419,7 @@ ":esim_flow_ui.m", ":psim_flow_ui.m", ":setup_selection_flow.m", + "//ui/webui/resources/cr_components/chromeos/network:mojo_interface_provider.m", "//ui/webui/resources/js:i18n_behavior.m", ] extra_deps = [ ":cellular_setup_module" ]
diff --git a/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.html b/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.html index ffa81e4..a287341a 100644 --- a/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.html +++ b/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.html
@@ -7,6 +7,7 @@ <link rel="import" href="cellular_setup_delegate.html"> <link rel="import" href="setup_selection_flow.html"> <link rel="import" href="../../../html/i18n_behavior.html"> +<link rel="import" href="chrome://resources/cr_components/chromeos/network/mojo_interface_provider.html"> <dom-module id="cellular-setup"> <template>
diff --git a/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.js b/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.js index 8e6a536..dbcdb67 100644 --- a/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.js +++ b/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.js
@@ -24,10 +24,7 @@ * Name of the currently displayed sub-page. * @private {!cellularSetup.CellularSetupPageName|null} */ - currentPageName: { - type: String, - value: cellularSetup.CellularSetupPageName.SETUP_FLOW_SELECTION, - }, + currentPageName: String, /** * Current user selected setup flow page name. @@ -74,6 +71,57 @@ 'cancel-requested': 'onCancelRequested_', }, + + /** @override */ + attached() { + if (!this.currentPageName) { + const networkConfig = + network_config.MojoInterfaceProviderImpl.getInstance() + .getMojoServiceRemote(); + networkConfig.getDeviceStateList().then(response => { + this.setCurrentPage_(response.result); + }); + } + }, + + /** + * @param {!Array<!chromeos.networkConfig.mojom.DeviceStateProperties>} + * deviceStateList + * @private + */ + setCurrentPage_(deviceStateList) { + let pSimSlots = 0; + let eSimSlots = 0; + + const device = deviceStateList.find( + (device) => + device.type === chromeos.networkConfig.mojom.NetworkType.kCellular); + + if (!device || !device.simInfos) { + this.currentPageName = + cellularSetup.CellularSetupPageName.SETUP_FLOW_SELECTION; + return; + } + + for (const simInfo of device.simInfos) { + if (simInfo.eid) { + eSimSlots++; + continue; + } + pSimSlots++; + } + + if (pSimSlots > 0 && eSimSlots === 0) { + this.currentPageName = cellularSetup.CellularSetupPageName.PSIM_FLOW_UI; + return; + } else if (pSimSlots === 0 && eSimSlots > 0) { + this.currentPageName = cellularSetup.CellularSetupPageName.ESIM_FLOW_UI; + return; + } + this.currentPageName = + cellularSetup.CellularSetupPageName.SETUP_FLOW_SELECTION; + }, + /** @private */ onPageChange_() { if (this.currentPage_) {
diff --git a/weblayer/app/content_main_delegate_impl.cc b/weblayer/app/content_main_delegate_impl.cc index e92cd66..c2a45cd 100644 --- a/weblayer/app/content_main_delegate_impl.cc +++ b/weblayer/app/content_main_delegate_impl.cc
@@ -23,6 +23,7 @@ #include "content/public/common/url_constants.h" #include "media/base/media_switches.h" #include "services/network/public/cpp/features.h" +#include "third_party/blink/public/common/features.h" #include "third_party/blink/public/platform/web_runtime_features.h" #include "ui/base/resource/resource_bundle.h" #include "ui/base/ui_base_paths.h" @@ -166,6 +167,8 @@ ::features::kPeriodicBackgroundSync, // TODO(crbug.com/1131017): Support SurfaceViews on WebLayer. media::kOverlayFullscreenVideo, + // TODO(crbug.com/1174856): Support Portals. + blink::features::kPortals, #if defined(OS_ANDROID) // TODO(crbug.com/1131016): Support Picture in Picture API on WebLayer. media::kPictureInPictureAPI,
diff --git a/weblayer/browser/page_load_metrics_initialize.cc b/weblayer/browser/page_load_metrics_initialize.cc index 037f984..ab7b884 100644 --- a/weblayer/browser/page_load_metrics_initialize.cc +++ b/weblayer/browser/page_load_metrics_initialize.cc
@@ -12,6 +12,14 @@ #include "weblayer/browser/no_state_prefetch/prerender_utils.h" #include "weblayer/browser/page_load_metrics_observer_impl.h" +namespace content { +class BrowserContext; +} // namespace content + +namespace page_load_metrics { +class PageLoadMetricsMemoryTracker; +} // namespace page_load_metrics + namespace weblayer { namespace { @@ -34,6 +42,11 @@ return NoStatePrefetchContentsFromWebContents(web_contents); } bool IsExtensionUrl(const GURL& url) override { return false; } + page_load_metrics::PageLoadMetricsMemoryTracker* + GetMemoryTrackerForBrowserContext( + content::BrowserContext* browser_context) override { + return nullptr; + } protected: // page_load_metrics::PageLoadMetricsEmbedderBase:
diff --git a/weblayer/browser/translate_client_impl.cc b/weblayer/browser/translate_client_impl.cc index 9bfc06e..d9b23f0 100644 --- a/weblayer/browser/translate_client_impl.cc +++ b/weblayer/browser/translate_client_impl.cc
@@ -53,7 +53,8 @@ TranslateClientImpl::TranslateClientImpl(content::WebContents* web_contents) : content::WebContentsObserver(web_contents), translate_driver_(&web_contents->GetController(), - /*url_language_histogram=*/nullptr), + /*url_language_histogram=*/nullptr, + /*translate_model_service=*/nullptr), translate_manager_(new translate::TranslateManager( this, TranslateRankerFactory::GetForBrowserContext(