diff --git a/BUILD.gn b/BUILD.gn index 50fdcb21..595c105 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -144,6 +144,7 @@ "//third_party/dawn:dawn_end2end_tests_temp_group", "//third_party/dawn:dawn_unittests_temp_group", "//third_party/pdfium/samples:pdfium_test", + "//third_party/webrtc/rtc_tools:frame_analyzer", "//tools/perf/clear_system_cache", "//tools/polymer:polymer_tools_python_unittests", "//ui/accessibility:accessibility_perftests", @@ -608,7 +609,7 @@ if (is_win) { deps += [ "//base:pe_image_test", - "//chrome/chrome_cleaner:chrome_cleaner_unittests", + "//chrome/chrome_cleaner", "//chrome/chrome_elf:chrome_elf_unittests", "//chrome/chrome_elf:dll_hash_main", "//chrome/elevation_service:elevation_service_unittests",
diff --git a/DEPS b/DEPS index 5385587..49bc735 100644 --- a/DEPS +++ b/DEPS
@@ -172,11 +172,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': '81a8d282d356667aab7bc8c0513da81bb1c5f3c4', + 'skia_revision': '99b558b594a12ec1d09172f85a6586b17de75ccc', # 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': '29e8c96fb28537121f964b7b261c7dc286dfbf2c', + 'v8_revision': '2af5f573918e2f46a0df5e9ceea380a52de7e45a', # 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. @@ -184,7 +184,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': '652dbfc63e70f7af1b4d3d9beff5ae69b1699c14', + 'angle_revision': '7f9c9a7fc00143cb5ad26a0bb5cb6950db4a1e58', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -235,7 +235,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': 'f9004ee81c432e30474b6e87216b0fb038216ccf', + 'catapult_revision': '5758cc96a5f3f0f9f3b6f64b83c4918fd2e523dd', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -303,11 +303,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. - 'shaderc_revision': '76ee91e12642e2be731aac3f0f21401b0e7d9d16', + 'shaderc_revision': 'f7e05c734266528849e861da7bee3ac734df80e6', # 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': 'c3284fa40ec6b12731ed66c2f2a9256ae3fa692e', + 'dawn_revision': 'ae1f25fee85ebf2773b24a0a4f39c160839b1dbb', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -871,7 +871,7 @@ # Build tools for Chrome OS. Note: This depends on third_party/pyelftools. 'src/third_party/chromite': { - 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'a942a9f9a2358e11484e67c9169de0e698be2723', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '8c6f1f9af3f49004e3ba87220d69e17eabaf1b58', 'condition': 'checkout_linux', }, @@ -896,7 +896,7 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '72a245e4c678f478bf7e1961cae8b2ba5bfa93bf', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '1917f7a099407369280b2cc74a33e44f4ed8c84c', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), @@ -978,7 +978,7 @@ }, 'src/third_party/glslang/src': - Var('chromium_git') + '/external/github.com/KhronosGroup/glslang.git' + '@' + 'e471df3c9154afbf125838201d2cd36cd6bdc708', + Var('chromium_git') + '/external/github.com/KhronosGroup/glslang.git' + '@' + 'f34cdc70ca1b4e741a9ea5a906f86d3593623356', 'src/third_party/google_toolbox_for_mac/src': { 'url': Var('chromium_git') + '/external/github.com/google/google-toolbox-for-mac.git' + '@' + Var('google_toolbox_for_mac_revision'), @@ -1579,7 +1579,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@275467d3f177738333504b9d2ba68e6245494ae4', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@c2eeedf4626693915c496f99d25c3fe18529cba9', 'condition': 'checkout_src_internal', },
diff --git a/android_webview/browser/network_service/aw_proxying_url_loader_factory.cc b/android_webview/browser/network_service/aw_proxying_url_loader_factory.cc index c17fe640..ee38ecd9 100644 --- a/android_webview/browser/network_service/aw_proxying_url_loader_factory.cc +++ b/android_webview/browser/network_service/aw_proxying_url_loader_factory.cc
@@ -149,7 +149,8 @@ mojo::Receiver<network::mojom::URLLoader> proxied_loader_receiver_; network::mojom::URLLoaderClientPtr target_client_; - mojo::Binding<network::mojom::URLLoaderClient> proxied_client_binding_; + mojo::Receiver<network::mojom::URLLoaderClient> proxied_client_receiver_{ + this}; network::mojom::URLLoaderPtr target_loader_; mojo::Remote<network::mojom::URLLoaderFactory> target_factory_; @@ -279,7 +280,6 @@ traffic_annotation_(traffic_annotation), proxied_loader_receiver_(this, std::move(loader_receiver)), target_client_(std::move(client)), - proxied_client_binding_(this), target_factory_(std::move(target_factory)) { // If there is a client error, clean up the request. target_client_.set_connection_error_handler(base::BindOnce( @@ -397,7 +397,7 @@ } input_stream_previously_failed_ = true; - proxied_client_binding_.Unbind(); + proxied_client_receiver_.reset(); Restart(); return true; // request restarted } @@ -417,7 +417,7 @@ (request_.url.SchemeIs(url::kContentScheme) || android_webview::IsAndroidSpecialFileUrl(request_.url))) { network::mojom::URLLoaderClientPtr proxied_client; - proxied_client_binding_.Bind(mojo::MakeRequest(&proxied_client)); + proxied_client_receiver_.Bind(mojo::MakeRequest(&proxied_client)); AndroidStreamReaderURLLoader* loader = new AndroidStreamReaderURLLoader( request_, std::move(proxied_client), traffic_annotation_, std::make_unique<ProtocolResponseDelegate>(request_.url, @@ -428,7 +428,7 @@ if (!target_loader_ && target_factory_) { network::mojom::URLLoaderClientPtr proxied_client; - proxied_client_binding_.Bind(mojo::MakeRequest(&proxied_client)); + proxied_client_receiver_.Bind(mojo::MakeRequest(&proxied_client)); target_factory_->CreateLoaderAndStart( mojo::MakeRequest(&target_loader_), routing_id_, request_id_, options_, request_, std::move(proxied_client), traffic_annotation_); @@ -438,7 +438,7 @@ void InterceptedRequest::ContinueAfterInterceptWithOverride( std::unique_ptr<AwWebResourceResponse> response) { network::mojom::URLLoaderClientPtr proxied_client; - proxied_client_binding_.Bind(mojo::MakeRequest(&proxied_client)); + proxied_client_receiver_.Bind(mojo::MakeRequest(&proxied_client)); AndroidStreamReaderURLLoader* loader = new AndroidStreamReaderURLLoader( request_, std::move(proxied_client), traffic_annotation_, std::make_unique<InterceptResponseDelegate>(std::move(response), @@ -506,7 +506,7 @@ void InterceptedRequest::OnReceiveResponse( network::mojom::URLResponseHeadPtr head) { // intercept response headers here - // pause/resume proxied_client_binding_ if necessary + // pause/resume |proxied_client_receiver_| if necessary if (head->headers && head->headers->response_code() >= 400) { // In Android WebView the WebViewClient.onReceivedHttpError callback @@ -675,7 +675,7 @@ if (proxied_loader_receiver_.is_bound() && wait_for_loader_error) { // Since the original client is gone no need to continue loading the // request. - proxied_client_binding_.Close(); + proxied_client_receiver_.reset(); target_loader_.reset(); // Don't delete |this| yet, in case the |proxied_loader_receiver_|'s
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index 3b48226..809308e 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -1645,16 +1645,21 @@ ] } -copy("dbus_service_files") { +action("dbus_service_files") { sources = [ "dbus/org.chromium.DisplayService.conf", "dbus/org.chromium.GesturePropertiesService.conf", "dbus/org.chromium.LivenessService.conf", "dbus/org.chromium.UrlHandlerService.conf", ] + output_conf_file = "$root_out_dir/dbus/ash_dbus_services.conf" outputs = [ - "$root_out_dir/dbus/{{source_file_part}}", + output_conf_file, ] + + script = "//chromeos/tools/concat_dbus_conf_files.py" + args = [ rebase_path(output_conf_file, root_build_dir) ] + args += rebase_path(sources, root_build_dir) } test("ash_unittests") {
diff --git a/ash/assistant/ui/assistant_web_view.cc b/ash/assistant/ui/assistant_web_view.cc index 1691cdf..13c4519 100644 --- a/ash/assistant/ui/assistant_web_view.cc +++ b/ash/assistant/ui/assistant_web_view.cc
@@ -176,9 +176,11 @@ SetFocusBehavior(FocusBehavior::ALWAYS); // We need to clip the corners of our web contents to match our container. - contents_->GetView()->native_view()->layer()->SetRoundedCornerRadius( - {/*top_left=*/0, /*top_right=*/0, /*bottom_right=*/kCornerRadiusDip, - /*bottom_left=*/kCornerRadiusDip}); + if (!chromeos::assistant::features::IsAssistantWebContainerEnabled()) { + contents_->GetView()->native_view()->layer()->SetRoundedCornerRadius( + {/*top_left=*/0, /*top_right=*/0, /*bottom_right=*/kCornerRadiusDip, + /*bottom_left=*/kCornerRadiusDip}); + } } void AssistantWebView::DidSuppressNavigation(const GURL& url,
diff --git a/ash/display/window_tree_host_manager.cc b/ash/display/window_tree_host_manager.cc index 392a5bd..8d98252 100644 --- a/ash/display/window_tree_host_manager.cc +++ b/ash/display/window_tree_host_manager.cc
@@ -500,7 +500,7 @@ new_root_window_controller->GetStatusAreaWidget() ->unified_system_tray(); if (old_tray->GetWidget()->IsVisible()) { - new_tray->SetVisible(true); + new_tray->SetVisiblePreferred(true); new_tray->GetWidget()->Show(); }
diff --git a/ash/home_screen/drag_window_from_shelf_controller.cc b/ash/home_screen/drag_window_from_shelf_controller.cc index f749301..eb31b8a4 100644 --- a/ash/home_screen/drag_window_from_shelf_controller.cc +++ b/ash/home_screen/drag_window_from_shelf_controller.cc
@@ -46,6 +46,12 @@ constexpr base::TimeDelta kShowOverviewTimeWhenDragSuspend = base::TimeDelta::FromMilliseconds(40); +// The distance for the dragged window to pass over the bottom of the display +// so that it can be dragged into home launcher or overview. If not pass this +// value, the window will snap back to its original position. +constexpr float kReturnToMaximizedDenseThreshold = 152.f; +constexpr float kReturnToMaximizedStandardThreshold = 164.f; + } // namespace // Hide all visible windows expect the dragged windows or the window showing in @@ -105,10 +111,20 @@ DISALLOW_COPY_AND_ASSIGN(WindowsHider); }; +// static +float DragWindowFromShelfController::GetReturnToMaximizedThreshold() { + return ShelfConfig::Get()->is_dense() ? kReturnToMaximizedDenseThreshold + : kReturnToMaximizedStandardThreshold; +} + DragWindowFromShelfController::DragWindowFromShelfController( - aura::Window* window) - : window_(window) { + aura::Window* window, + const gfx::Point& location_in_screen, + HotseatState hotseat_state) + : window_(window), hotseat_state_(hotseat_state) { + DCHECK_NE(hotseat_state, HotseatState::kShown); window_->AddObserver(this); + OnDragStarted(location_in_screen); } DragWindowFromShelfController::~DragWindowFromShelfController() { @@ -124,17 +140,9 @@ if (!window_) return; - if (!drag_started_) { - // Do not start drag until the drag goes above the hotseat. - const gfx::Rect work_area = - screen_util::GetDisplayWorkAreaBoundsInScreenForActiveDeskContainer( - window_); - if (location_in_screen.y() > - work_area.bottom() - ShelfConfig::Get()->hotseat_size()) { - return; - } - OnDragStarted(location_in_screen); - } + // TODO(xdai): clean up |drag_started_| variable. + if (!drag_started_) + return; UpdateDraggedWindow(location_in_screen); @@ -206,7 +214,7 @@ const bool in_overview = overview_controller->InOverviewSession(); const bool in_splitview = split_view_controller->InSplitViewMode(); - if (ShouldGoToHomeScreen(velocity_y)) { + if (ShouldGoToHomeScreen(location_in_screen, velocity_y)) { DCHECK(!in_splitview); if (in_overview) { overview_controller->EndOverview( @@ -397,7 +405,7 @@ DragWindowFromShelfController::GetSnapPosition( const gfx::Point& location_in_screen) const { // if |location_in_screen| is close to the bottom of the screen and is - // inside of kReturnToMaximizedThreshold threshold, we should not try to + // inside of GetReturnToMaximizedThreshold() threshold, we should not try to // snap the window. if (ShouldRestoreToOriginalBounds(location_in_screen)) return SplitViewController::NONE; @@ -423,15 +431,25 @@ bool DragWindowFromShelfController::ShouldRestoreToOriginalBounds( const gfx::Point& location_in_screen) const { - const gfx::Rect work_area = display::Screen::GetScreen() - ->GetDisplayNearestPoint(location_in_screen) - .work_area(); + const gfx::Rect display_bounds = + display::Screen::GetScreen() + ->GetDisplayNearestPoint(location_in_screen) + .bounds(); return location_in_screen.y() > - work_area.bottom() - kReturnToMaximizedThreshold; + display_bounds.bottom() - GetReturnToMaximizedThreshold(); } bool DragWindowFromShelfController::ShouldGoToHomeScreen( + const gfx::Point& location_in_screen, base::Optional<float> velocity_y) const { + // For a hidden hotseat, if the event end position does not exceed + // GetReturnToMaximizedThreshold(), it should restore back to the maximized + // bounds even though the velocity might be large. + if (hotseat_state_ == HotseatState::kHidden && + ShouldRestoreToOriginalBounds(location_in_screen)) { + return false; + } + return velocity_y.has_value() && *velocity_y < 0 && std::abs(*velocity_y) >= kVelocityToHomeScreenThreshold && !SplitViewController::Get(Shell::GetPrimaryRootWindow()) @@ -443,7 +461,7 @@ const gfx::Point& location_in_screen, base::Optional<float> velocity_y) const { if (ShouldRestoreToOriginalBounds(location_in_screen) || - ShouldGoToHomeScreen(velocity_y)) { + ShouldGoToHomeScreen(location_in_screen, velocity_y)) { return SplitViewController::NONE; } @@ -456,7 +474,7 @@ if (!Shell::Get()->overview_controller()->InOverviewSession()) return false; - if (ShouldGoToHomeScreen(velocity_y)) + if (ShouldGoToHomeScreen(location_in_screen, velocity_y)) return false; const bool in_splitview =
diff --git a/ash/home_screen/drag_window_from_shelf_controller.h b/ash/home_screen/drag_window_from_shelf_controller.h index 9d5b3ae3..280cebb 100644 --- a/ash/home_screen/drag_window_from_shelf_controller.h +++ b/ash/home_screen/drag_window_from_shelf_controller.h
@@ -8,6 +8,7 @@ #include <vector> #include "ash/ash_export.h" +#include "ash/public/cpp/shelf_types.h" #include "ash/public/cpp/window_properties.h" #include "ash/wm/splitview/split_view_controller.h" #include "base/macros.h" @@ -26,11 +27,6 @@ // swiping up from the shelf to homescreen, overview or splitview. class ASH_EXPORT DragWindowFromShelfController : public aura::WindowObserver { public: - // The distance for the dragged window to pass over shelf so that it can be - // dragged into home launcher or overview. If not pass this value, the window - // will snap back to its original position. - static constexpr float kReturnToMaximizedThreshold = 116; - // The deceleration threshold to open overview behind the dragged window // when swiping up from the shelf to drag the active window. static constexpr float kOpenOverviewThreshold = 10.f; @@ -47,7 +43,15 @@ // view is active during dragging. static constexpr float kVelocityToOverviewThreshold = 1000.f; - explicit DragWindowFromShelfController(aura::Window* window); + // The distance for the dragged window to pass over the bottom of the display + // so that it can be dragged into home launcher or overview. If not pass this + // value, the window will snap back to its original position. The value is + // different for standard or dense shelf. + static float GetReturnToMaximizedThreshold(); + + DragWindowFromShelfController(aura::Window* window, + const gfx::Point& location_in_screen, + HotseatState hotseat_state); ~DragWindowFromShelfController() override; // Called during swiping up on the shelf. @@ -81,7 +85,7 @@ // Returns true if the dragged window should restore to its original bounds // after drag ends. Happens when |location_in_screen| is within - // kReturnToMaximizedThreshold threshold. + // GetReturnToMaximizedThreshold() threshold. bool ShouldRestoreToOriginalBounds( const gfx::Point& location_in_screen) const; @@ -89,7 +93,8 @@ // the upward vertical velocity is larger than kVelocityToHomeScreenThreshold // and splitview is not active. Note when splitview is active, we do not allow // to go to home screen by fling. - bool ShouldGoToHomeScreen(base::Optional<float> velocity_y) const; + bool ShouldGoToHomeScreen(const gfx::Point& location_in_screen, + base::Optional<float> velocity_y) const; // Returns the desired snap position on |location_in_screen| when drag ends. SplitViewController::SnapPosition GetSnapPositionOnDragEnd( @@ -125,6 +130,9 @@ // Timer to show and update overview. base::OneShotTimer show_overview_timer_; + // The hotseat state when drag starts. + const HotseatState hotseat_state_; + DISALLOW_COPY_AND_ASSIGN(DragWindowFromShelfController); };
diff --git a/ash/home_screen/drag_window_from_shelf_controller_unittest.cc b/ash/home_screen/drag_window_from_shelf_controller_unittest.cc index 57cf031..838a612 100644 --- a/ash/home_screen/drag_window_from_shelf_controller_unittest.cc +++ b/ash/home_screen/drag_window_from_shelf_controller_unittest.cc
@@ -35,9 +35,11 @@ base::RunLoop().RunUntilIdle(); } - void StartDrag(aura::Window* window) { - window_drag_controller_ = - std::make_unique<DragWindowFromShelfController>(window); + void StartDrag(aura::Window* window, + const gfx::Point& location_in_screen, + HotseatState hotseat_state) { + window_drag_controller_ = std::make_unique<DragWindowFromShelfController>( + window, location_in_screen, hotseat_state); } void Drag(const gfx::Point& location_in_screen, float scroll_x, @@ -77,7 +79,7 @@ EXPECT_TRUE(window2->IsVisible()); EXPECT_TRUE(window3->IsVisible()); - StartDrag(window1.get()); + StartDrag(window1.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended); Drag(gfx::Point(200, 200), 1.f, 1.f); EXPECT_TRUE(window1->IsVisible()); EXPECT_FALSE(window2->IsVisible()); @@ -91,7 +93,7 @@ split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT); split_view_controller()->SnapWindow(window2.get(), SplitViewController::RIGHT); - StartDrag(window1.get()); + StartDrag(window1.get(), shelf_bounds.left_center(), HotseatState::kExtended); Drag(gfx::Point(0, 200), 1.f, 1.f); EXPECT_TRUE(window1->IsVisible()); EXPECT_TRUE(window2->IsVisible()); @@ -101,7 +103,8 @@ EXPECT_TRUE(window2->IsVisible()); EXPECT_TRUE(window3->IsVisible()); - StartDrag(window2.get()); + StartDrag(window2.get(), shelf_bounds.right_center(), + HotseatState::kExtended); Drag(gfx::Point(400, 200), 1.f, 1.f); EXPECT_TRUE(window1->IsVisible()); EXPECT_TRUE(window2->IsVisible()); @@ -118,7 +121,7 @@ const gfx::Rect shelf_bounds = Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); auto window = CreateTestWindow(); - StartDrag(window.get()); + StartDrag(window.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended); Drag(gfx::Point(0, 200), 0.f, 1.f); aura::Window* home_screen_window = Shell::Get()->home_screen_controller()->delegate()->GetHomeScreenWindow(); @@ -141,14 +144,14 @@ // If the dragged window restores to its original position, reshow the hidden // windows. - StartDrag(window1.get()); + StartDrag(window1.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended); Drag(gfx::Point(200, 200), 0.f, 1.f); EXPECT_FALSE(window2->IsVisible()); EndDrag(shelf_bounds.CenterPoint(), base::nullopt); EXPECT_TRUE(window2->IsVisible()); // If fling to homescreen, do not reshow the hidden windows. - StartDrag(window1.get()); + StartDrag(window1.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended); Drag(gfx::Point(200, 200), 0.f, 1.f); EXPECT_FALSE(window2->IsVisible()); EndDrag(gfx::Point(200, 200), @@ -160,7 +163,7 @@ // windows. window2->Show(); window1->Show(); - StartDrag(window1.get()); + StartDrag(window1.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended); Drag(gfx::Point(200, 200), 0.f, 1.f); EXPECT_FALSE(window2->IsVisible()); OverviewController* overview_controller = Shell::Get()->overview_controller(); @@ -176,7 +179,7 @@ // showing in overview, do not reshow the hidden windows. window2->Show(); window1->Show(); - StartDrag(window1.get()); + StartDrag(window1.get(), shelf_bounds.left_center(), HotseatState::kExtended); Drag(gfx::Point(0, 200), 0.f, 1.f); EXPECT_FALSE(window2->IsVisible()); EXPECT_TRUE(overview_controller->InOverviewSession()); @@ -191,14 +194,13 @@ // show correctly in overview. TEST_F(DragWindowFromShelfControllerTest, MinimizedWindowsShowInOverview) { UpdateDisplay("400x400"); + const gfx::Rect shelf_bounds = + Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); auto window3 = CreateTestWindow(); auto window2 = CreateTestWindow(); auto window1 = CreateTestWindow(); - StartDrag(window1.get()); - EXPECT_TRUE(window1->IsVisible()); - EXPECT_TRUE(window2->IsVisible()); - EXPECT_TRUE(window3->IsVisible()); + StartDrag(window1.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended); // Drag it far enough so overview should be open behind the dragged window. Drag(gfx::Point(200, 200), 0.f, 1.f); OverviewController* overview_controller = Shell::Get()->overview_controller(); @@ -224,9 +226,11 @@ // delta (velocity) decrease to kOpenOverviewThreshold or less. TEST_F(DragWindowFromShelfControllerTest, OpenOverviewWhenHold) { UpdateDisplay("400x400"); + const gfx::Rect shelf_bounds = + Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); auto window = CreateTestWindow(); - StartDrag(window.get()); + StartDrag(window.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended); Drag(gfx::Point(200, 200), 0.f, DragWindowFromShelfController::kOpenOverviewThreshold + 1); OverviewController* overview_controller = Shell::Get()->overview_controller(); @@ -241,13 +245,15 @@ // kReturnToMaximizedThreshold, it will restore back to its original position. TEST_F(DragWindowFromShelfControllerTest, RestoreWindowToOriginalBounds) { UpdateDisplay("400x400"); + const gfx::Rect shelf_bounds = + Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); auto window = CreateTestWindow(); - const gfx::Rect work_area = display::Screen::GetScreen() - ->GetDisplayNearestWindow(window.get()) - .work_area(); + const gfx::Rect display_bounds = display::Screen::GetScreen() + ->GetDisplayNearestWindow(window.get()) + .bounds(); // Drag it for a small distance and then release. - StartDrag(window.get()); + StartDrag(window.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended); Drag(gfx::Point(200, 200), 0.f, DragWindowFromShelfController::kShowOverviewThreshold + 1); EXPECT_FALSE(window->layer()->GetTargetTransform().IsIdentity()); @@ -258,15 +264,16 @@ EXPECT_TRUE(WindowState::Get(window.get())->IsMaximized()); // Drag it for a large distance and then drag back to release. - StartDrag(window.get()); + StartDrag(window.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended); Drag(gfx::Point(200, 200), 0.f, 1.f); EXPECT_FALSE(window->layer()->GetTargetTransform().IsIdentity()); EXPECT_TRUE(overview_controller->InOverviewSession()); EndDrag( gfx::Point( - 200, work_area.bottom() - - DragWindowFromShelfController::kReturnToMaximizedThreshold + - 1), + 200, + display_bounds.bottom() - + DragWindowFromShelfController::GetReturnToMaximizedThreshold() + + 1), base::nullopt); EXPECT_TRUE(window->layer()->GetTargetTransform().IsIdentity()); EXPECT_FALSE(overview_controller->InOverviewSession()); @@ -277,7 +284,7 @@ split_view_controller()->SnapWindow(window.get(), SplitViewController::LEFT); split_view_controller()->SnapWindow(window2.get(), SplitViewController::RIGHT); - StartDrag(window.get()); + StartDrag(window.get(), shelf_bounds.left_center(), HotseatState::kExtended); Drag(gfx::Point(0, 200), 0.f, 1.f); EXPECT_FALSE(window->layer()->GetTargetTransform().IsIdentity()); EXPECT_TRUE(overview_controller->InOverviewSession()); @@ -292,11 +299,13 @@ // TODO(https://crbug.com/1019080) This test is flaky. TEST_F(DragWindowFromShelfControllerTest, DISABLED_FlingInOverview) { UpdateDisplay("400x400"); + const gfx::Rect shelf_bounds = + Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); auto window = CreateTestWindow(); // If fling velocity is smaller than kVelocityToHomeScreenThreshold, decide // where the window should go based on the release position. - StartDrag(window.get()); + StartDrag(window.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended); Drag(gfx::Point(200, 200), 0.f, 1.f); OverviewController* overview_controller = Shell::Get()->overview_controller(); EXPECT_TRUE(overview_controller->InOverviewSession()); @@ -309,7 +318,7 @@ EXPECT_TRUE(WindowState::Get(window.get())->IsMaximized()); // If fling velocity is equal or larger than kVelocityToHomeScreenThreshold - StartDrag(window.get()); + StartDrag(window.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended); Drag(gfx::Point(200, 200), 0.f, 1.f); EXPECT_TRUE(overview_controller->InOverviewSession()); EndDrag(gfx::Point(0, 350), @@ -323,6 +332,8 @@ // overview. TEST_F(DragWindowFromShelfControllerTest, DragOrFlingInSplitView) { UpdateDisplay("400x400"); + const gfx::Rect shelf_bounds = + Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); auto window1 = CreateTestWindow(); auto window2 = CreateTestWindow(); @@ -333,7 +344,7 @@ EXPECT_TRUE(split_view_controller()->InSplitViewMode()); // If the window is only dragged for a small distance: - StartDrag(window1.get()); + StartDrag(window1.get(), shelf_bounds.left_center(), HotseatState::kExtended); Drag(gfx::Point(100, 200), 0.f, 1.f); EXPECT_TRUE(split_view_controller()->InSplitViewMode()); EXPECT_TRUE(overview_controller->InOverviewSession()); @@ -344,7 +355,7 @@ EXPECT_TRUE(split_view_controller()->IsWindowInSplitView(window2.get())); // If the window is dragged for a long distance: - StartDrag(window1.get()); + StartDrag(window1.get(), shelf_bounds.left_center(), HotseatState::kExtended); Drag(gfx::Point(100, 200), 0.f, 1.f); EXPECT_TRUE(split_view_controller()->InSplitViewMode()); EXPECT_TRUE(overview_controller->InOverviewSession()); @@ -358,7 +369,7 @@ overview_controller->EndOverview(); // If the window is flung with a small velocity: - StartDrag(window1.get()); + StartDrag(window1.get(), shelf_bounds.left_center(), HotseatState::kExtended); Drag(gfx::Point(100, 200), 0.f, 1.f); EXPECT_TRUE(split_view_controller()->InSplitViewMode()); EXPECT_TRUE(overview_controller->InOverviewSession()); @@ -372,7 +383,7 @@ EXPECT_TRUE(split_view_controller()->IsWindowInSplitView(window2.get())); // If the window is flung with a large velocity: - StartDrag(window1.get()); + StartDrag(window1.get(), shelf_bounds.left_center(), HotseatState::kExtended); Drag(gfx::Point(100, 200), 0.f, 1.f); EXPECT_TRUE(split_view_controller()->InSplitViewMode()); EXPECT_TRUE(overview_controller->InOverviewSession()); @@ -396,7 +407,7 @@ Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); auto window = CreateTestWindow(); - StartDrag(window.get()); + StartDrag(window.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended); Drag(gfx::Point(0, 200), 0.f, DragWindowFromShelfController::kShowOverviewThreshold + 1); OverviewController* overview_controller = Shell::Get()->overview_controller(); @@ -416,10 +427,12 @@ // stops. TEST_F(DragWindowFromShelfControllerTest, HideOverviewDuringDragging) { UpdateDisplay("400x400"); + const gfx::Rect shelf_bounds = + Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); auto window2 = CreateTestWindow(); auto window1 = CreateTestWindow(); - StartDrag(window1.get()); + StartDrag(window1.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended); Drag(gfx::Point(200, 200), 0.5f, 0.5f); OverviewController* overview_controller = Shell::Get()->overview_controller(); EXPECT_TRUE(overview_controller->InOverviewSession()); @@ -456,7 +469,7 @@ Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); auto window = CreateTestWindow(); - StartDrag(window.get()); + StartDrag(window.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended); Drag(gfx::Point(200, 200), 0.5f, 0.5f); OverviewController* overview_controller = Shell::Get()->overview_controller(); EXPECT_TRUE(overview_controller->InOverviewSession()); @@ -506,7 +519,7 @@ EXPECT_NE(window->GetProperty(kBackdropWindowMode), BackdropWindowMode::kDisabled); - StartDrag(window.get()); + StartDrag(window.get(), shelf_bounds.left_center(), HotseatState::kExtended); Drag(gfx::Point(0, 200), 0.f, 10.f); EndDrag(shelf_bounds.CenterPoint(), base::make_optional( @@ -520,6 +533,8 @@ // hidden windows should restore to its previous visibility state. // TODO(crbug.com/1022319): flaky. TEST_F(DragWindowFromShelfControllerTest, DISABLED_CancelDragDismissOverview) { + const gfx::Rect shelf_bounds = + Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); auto window3 = CreateTestWindow(); auto window2 = CreateTestWindow(); auto window1 = CreateTestWindow(); @@ -527,7 +542,7 @@ EXPECT_TRUE(window2->IsVisible()); EXPECT_TRUE(window3->IsVisible()); - StartDrag(window1.get()); + StartDrag(window1.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended); Drag(gfx::Point(200, 200), 0.5f, 0.5f); OverviewController* overview_controller = Shell::Get()->overview_controller(); EXPECT_TRUE(overview_controller->InOverviewSession()); @@ -545,8 +560,10 @@ // TODO(https://crbug.com/1018498) This test is flaky. TEST_F(DragWindowFromShelfControllerTest, DISABLED_CancelDragIfWindowDestroyed) { + const gfx::Rect shelf_bounds = + Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); auto window = CreateTestWindow(); - StartDrag(window.get()); + StartDrag(window.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended); Drag(gfx::Point(200, 200), 0.5f, 0.5f); EXPECT_EQ(window_drag_controller()->dragged_window(), window.get()); EXPECT_TRUE(window_drag_controller()->drag_started()); @@ -558,4 +575,28 @@ CancelDrag(); } +TEST_F(DragWindowFromShelfControllerTest, FlingWithHiddenHotseat) { + const gfx::Rect shelf_bounds = + Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); + auto window = CreateTestWindow(); + gfx::Point start = shelf_bounds.CenterPoint(); + StartDrag(window.get(), start, HotseatState::kHidden); + // Only drag for a small distance and then fling. + Drag(gfx::Point(start.x(), start.y() - 10), 0.5f, 0.5f); + EndDrag(gfx::Point(start.x(), start.y() - 10), + base::make_optional( + -DragWindowFromShelfController::kVelocityToHomeScreenThreshold)); + // The window should restore back to its original position. + EXPECT_TRUE(WindowState::Get(window.get())->IsMaximized()); + + // Now a bigger distance to fling. + StartDrag(window.get(), start, HotseatState::kHidden); + Drag(gfx::Point(start.x(), start.y() - 200), 0.5f, 0.5f); + EndDrag(gfx::Point(start.x(), start.y() - 200), + base::make_optional( + -DragWindowFromShelfController::kVelocityToHomeScreenThreshold)); + // The window should be minimized. + EXPECT_TRUE(WindowState::Get(window.get())->IsMinimized()); +} + } // namespace ash
diff --git a/ash/public/cpp/shelf_config.h b/ash/public/cpp/shelf_config.h index 02cdd8bf..6a19046 100644 --- a/ash/public/cpp/shelf_config.h +++ b/ash/public/cpp/shelf_config.h
@@ -141,6 +141,8 @@ return mousewheel_scroll_offset_threshold_; } + bool is_dense() const { return is_dense_; } + // Gets the current color for the shelf control buttons. SkColor GetShelfControlButtonColor() const;
diff --git a/ash/rotator/screen_rotation_animator_unittest.cc b/ash/rotator/screen_rotation_animator_unittest.cc index 6283148..88246f7 100644 --- a/ash/rotator/screen_rotation_animator_unittest.cc +++ b/ash/rotator/screen_rotation_animator_unittest.cc
@@ -384,7 +384,7 @@ // Long duration for hide animation, to allow it to be interrupted. ui::ScopedAnimationDurationScaleMode hide_duration( ui::ScopedAnimationDurationScaleMode::SLOW_DURATION); - GetTray()->SetVisible(false); + GetTray()->SetVisiblePreferred(false); // ScreenRotationAnimator copies the current layers, and deletes them upon // completion. Allow its animation to complete first. @@ -615,7 +615,7 @@ // Long duration for hide animation, to allow it to be interrupted. ui::ScopedAnimationDurationScaleMode hide_duration( ui::ScopedAnimationDurationScaleMode::SLOW_DURATION); - GetTray()->SetVisible(false); + GetTray()->SetVisiblePreferred(false); // Allow ScreenRotationAnimator animation to complete first. ui::ScopedAnimationDurationScaleMode rotate_duration(
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc index 25ae94a..bf1a094 100644 --- a/ash/shelf/shelf_layout_manager.cc +++ b/ash/shelf/shelf_layout_manager.cc
@@ -2456,8 +2456,8 @@ if (!window) return false; - window_drag_controller_ = - std::make_unique<DragWindowFromShelfController>(window); + window_drag_controller_ = std::make_unique<DragWindowFromShelfController>( + window, event_in_screen.location(), hotseat_state()); return true; }
diff --git a/ash/system/accessibility/dictation_button_tray.cc b/ash/system/accessibility/dictation_button_tray.cc index f4f25ec7..bd131dbd 100644 --- a/ash/system/accessibility/dictation_button_tray.cc +++ b/ash/system/accessibility/dictation_button_tray.cc
@@ -95,7 +95,7 @@ void DictationButtonTray::UpdateVisibility() { bool is_visible = Shell::Get()->accessibility_controller()->dictation_enabled(); - SetVisible(is_visible); + SetVisiblePreferred(is_visible); } void DictationButtonTray::CheckDictationStatusAndUpdateIcon() {
diff --git a/ash/system/accessibility/select_to_speak_tray.cc b/ash/system/accessibility/select_to_speak_tray.cc index 5453e7b..ce87c5e 100644 --- a/ash/system/accessibility/select_to_speak_tray.cc +++ b/ash/system/accessibility/select_to_speak_tray.cc
@@ -89,7 +89,7 @@ void SelectToSpeakTray::CheckStatusAndUpdateIcon() { if (!Shell::Get()->accessibility_controller()->select_to_speak_enabled()) { - SetVisible(false); + SetVisiblePreferred(false); return; } @@ -111,7 +111,7 @@ break; } - SetVisible(true); + SetVisiblePreferred(true); } } // namespace ash
diff --git a/ash/system/ime_menu/ime_menu_tray.cc b/ash/system/ime_menu/ime_menu_tray.cc index cf7b2a3..fc6f2fa 100644 --- a/ash/system/ime_menu/ime_menu_tray.cc +++ b/ash/system/ime_menu/ime_menu_tray.cc
@@ -489,7 +489,7 @@ } void ImeMenuTray::OnIMEMenuActivationChanged(bool is_activated) { - SetVisible(is_activated); + SetVisiblePreferred(is_activated); if (is_activated) UpdateTrayLabel(); else
diff --git a/ash/system/night_light/night_light_controller_impl.cc b/ash/system/night_light/night_light_controller_impl.cc index b3a3cb37..20e1723 100644 --- a/ash/system/night_light/night_light_controller_impl.cc +++ b/ash/system/night_light/night_light_controller_impl.cc
@@ -464,6 +464,21 @@ void NightLightControllerImpl::OnActiveUserPrefServiceChanged( PrefService* pref_service) { + // TODO(afakhry|yjliu): Remove this VLOG when https://crbug.com/1015474 is + // fixed. + auto vlog_helper = [](const PrefService* pref_service) -> std::string { + if (!pref_service) + return "None"; + return base::StringPrintf( + "{State %s, Schedule Type: %d}", + pref_service->GetBoolean(prefs::kNightLightEnabled) ? "enabled" + : "disabled", + pref_service->GetInteger(prefs::kNightLightScheduleType)); + }; + VLOG(1) << "Switching user pref service from " + << vlog_helper(active_user_pref_service_) << " to " + << vlog_helper(pref_service) << "."; + // Initial login and user switching in multi profiles. active_user_pref_service_ = pref_service; InitFromUserPrefs(); @@ -608,6 +623,7 @@ } void NightLightControllerImpl::OnEnabledPrefChanged() { + VLOG(1) << "Enable state changed. New state: " << GetEnabled() << "."; DCHECK(active_user_pref_service_); Refresh(false /* did_schedule_change */); NotifyStatusChanged(); @@ -623,6 +639,7 @@ } void NightLightControllerImpl::OnScheduleTypePrefChanged() { + VLOG(1) << "Schedule type changed. New type: " << GetScheduleType() << "."; DCHECK(active_user_pref_service_); NotifyClientWithScheduleChange(); Refresh(true /* did_schedule_change */);
diff --git a/ash/system/overview/overview_button_tray.cc b/ash/system/overview/overview_button_tray.cc index 72ce0cf..0a33119 100644 --- a/ash/system/overview/overview_button_tray.cc +++ b/ash/system/overview/overview_button_tray.cc
@@ -195,7 +195,7 @@ bool should_show = Shell::Get()->tablet_mode_controller()->ShouldShowOverviewButton(); - SetVisible(should_show && active_session && !app_mode); + SetVisiblePreferred(should_show && active_session && !app_mode); } } // namespace ash
diff --git a/ash/system/overview/overview_button_tray_unittest.cc b/ash/system/overview/overview_button_tray_unittest.cc index 4c6593a..4555a85a2 100644 --- a/ash/system/overview/overview_button_tray_unittest.cc +++ b/ash/system/overview/overview_button_tray_unittest.cc
@@ -317,7 +317,7 @@ TEST_F(OverviewButtonTrayTest, HideAnimationAlwaysCompletes) { TabletModeControllerTestApi().EnterTabletMode(); EXPECT_TRUE(GetTray()->GetVisible()); - GetTray()->SetVisible(false); + GetTray()->SetVisiblePreferred(false); EXPECT_FALSE(GetTray()->GetVisible()); } @@ -330,7 +330,7 @@ std::unique_ptr<ui::ScopedAnimationDurationScaleMode> hide_duration( new ui::ScopedAnimationDurationScaleMode( ui::ScopedAnimationDurationScaleMode::SLOW_DURATION)); - GetTray()->SetVisible(false); + GetTray()->SetVisiblePreferred(false); aura::Window* root_window = Shell::GetRootWindowForDisplayId( display::Screen::GetScreen()->GetPrimaryDisplay().id());
diff --git a/ash/system/palette/palette_tray.cc b/ash/system/palette/palette_tray.cc index 048b5e8d..6f86fac 100644 --- a/ash/system/palette/palette_tray.cc +++ b/ash/system/palette/palette_tray.cc
@@ -558,7 +558,7 @@ prefs::kEnableStylusTools); if (!is_palette_enabled_) { - SetVisible(false); + SetVisiblePreferred(false); palette_tool_manager_->DisableActiveTool(PaletteGroup::MODE); } else { UpdateIconVisibility(); @@ -591,9 +591,10 @@ } void PaletteTray::UpdateIconVisibility() { - SetVisible(HasSeenStylus() && is_palette_enabled_ && - stylus_utils::HasStylusInput() && ShouldShowOnDisplay(this) && - palette_utils::IsInUserSession()); + SetVisiblePreferred(HasSeenStylus() && is_palette_enabled_ && + stylus_utils::HasStylusInput() && + ShouldShowOnDisplay(this) && + palette_utils::IsInUserSession()); } } // namespace ash
diff --git a/ash/system/status_area_widget.cc b/ash/system/status_area_widget.cc index 0f7e51e..c895dae 100644 --- a/ash/system/status_area_widget.cc +++ b/ash/system/status_area_widget.cc
@@ -83,8 +83,7 @@ virtual_keyboard_tray_->Initialize(); ime_menu_tray_->Initialize(); select_to_speak_tray_->Initialize(); - if (dictation_button_tray_) - dictation_button_tray_->Initialize(); + dictation_button_tray_->Initialize(); overview_button_tray_->Initialize(); UpdateAfterShelfAlignmentChange(); UpdateAfterLoginStatusChange( @@ -116,8 +115,7 @@ virtual_keyboard_tray_->UpdateAfterShelfAlignmentChange(); ime_menu_tray_->UpdateAfterShelfAlignmentChange(); select_to_speak_tray_->UpdateAfterShelfAlignmentChange(); - if (dictation_button_tray_) - dictation_button_tray_->UpdateAfterShelfAlignmentChange(); + dictation_button_tray_->UpdateAfterShelfAlignmentChange(); palette_tray_->UpdateAfterShelfAlignmentChange(); overview_button_tray_->UpdateAfterShelfAlignmentChange(); status_area_widget_delegate_->UpdateLayout(); @@ -135,7 +133,7 @@ void StatusAreaWidget::SetSystemTrayVisibility(bool visible) { TrayBackgroundView* tray = unified_system_tray_.get(); - tray->SetVisible(visible); + tray->SetVisiblePreferred(visible); // Opacity is set to prevent flakiness in kiosk browser tests. See // https://crbug.com/624584. SetOpacity(visible ? 1.f : 0.f); @@ -182,8 +180,7 @@ logout_button_tray_->SchedulePaint(); ime_menu_tray_->SchedulePaint(); select_to_speak_tray_->SchedulePaint(); - if (dictation_button_tray_) - dictation_button_tray_->SchedulePaint(); + dictation_button_tray_->SchedulePaint(); palette_tray_->SchedulePaint(); overview_button_tray_->SchedulePaint(); }
diff --git a/ash/system/status_area_widget.h b/ash/system/status_area_widget.h index a9664f3..5e0236d 100644 --- a/ash/system/status_area_widget.h +++ b/ash/system/status_area_widget.h
@@ -35,6 +35,10 @@ // on secondary monitors at the login screen). class ASH_EXPORT StatusAreaWidget : public views::Widget { public: + // Whether the status area is collapsed or expanded. Currently, this is only + // applicable in in-app tablet mode. Otherwise the state is NOT_COLLAPSIBLE. + enum class CollapseState { NOT_COLLAPSIBLE, COLLAPSED, EXPANDED }; + StatusAreaWidget(aura::Window* status_container, Shelf* shelf); ~StatusAreaWidget() override; @@ -109,6 +113,8 @@ return virtual_keyboard_tray_.get(); } + CollapseState collapse_state() const { return collapse_state_; } + private: friend class StatusAreaWidgetTestApi; @@ -130,6 +136,8 @@ LoginStatus login_status_ = LoginStatus::NOT_LOGGED_IN; + CollapseState collapse_state_ = CollapseState::NOT_COLLAPSIBLE; + Shelf* shelf_; DISALLOW_COPY_AND_ASSIGN(StatusAreaWidget);
diff --git a/ash/system/status_area_widget_test_api.cc b/ash/system/status_area_widget_test_api.cc index 5a0e8a7..55846ca0 100644 --- a/ash/system/status_area_widget_test_api.cc +++ b/ash/system/status_area_widget_test_api.cc
@@ -43,4 +43,9 @@ std::move(callback).Run(); } +void StatusAreaWidgetTestApi::SetCollapseState( + StatusAreaWidget::CollapseState collapse_state) { + widget_->collapse_state_ = collapse_state; +} + } // namespace ash
diff --git a/ash/system/status_area_widget_test_api.h b/ash/system/status_area_widget_test_api.h index f75896b..7fde252 100644 --- a/ash/system/status_area_widget_test_api.h +++ b/ash/system/status_area_widget_test_api.h
@@ -24,6 +24,8 @@ // mojom::StatusAreaWidgetTestApi: void TapSelectToSpeakTray(TapSelectToSpeakTrayCallback callback) override; + void SetCollapseState(StatusAreaWidget::CollapseState collapse_state); + private: StatusAreaWidget* const widget_;
diff --git a/ash/system/status_area_widget_unittest.cc b/ash/system/status_area_widget_unittest.cc index 035cdc2..3f5762f 100644 --- a/ash/system/status_area_widget_unittest.cc +++ b/ash/system/status_area_widget_unittest.cc
@@ -14,10 +14,15 @@ #include "ash/session/session_controller_impl.h" #include "ash/session/test_session_controller_client.h" #include "ash/shell.h" +#include "ash/system/accessibility/dictation_button_tray.h" +#include "ash/system/accessibility/select_to_speak_tray.h" #include "ash/system/ime_menu/ime_menu_tray.h" +#include "ash/system/model/system_tray_model.h" +#include "ash/system/model/virtual_keyboard_model.h" #include "ash/system/overview/overview_button_tray.h" #include "ash/system/palette/palette_tray.h" #include "ash/system/session/logout_button_tray.h" +#include "ash/system/status_area_widget_test_api.h" #include "ash/system/status_area_widget_test_helper.h" #include "ash/system/tray/system_tray_notifier.h" #include "ash/system/unified/unified_system_tray.h" @@ -273,8 +278,8 @@ ClickingVirtualKeyboardTrayHidesShownKeyboard) { // Set up the virtual keyboard tray icon along with some other tray icons. StatusAreaWidget* status = StatusAreaWidgetTestHelper::GetStatusAreaWidget(); - status->virtual_keyboard_tray_for_testing()->SetVisible(true); - status->ime_menu_tray()->SetVisible(true); + status->virtual_keyboard_tray_for_testing()->SetVisiblePreferred(true); + status->ime_menu_tray()->SetVisiblePreferred(true); keyboard_ui_controller()->ShowKeyboard(false /* locked */); ASSERT_TRUE(keyboard::WaitUntilShown()); @@ -294,8 +299,8 @@ TappingVirtualKeyboardTrayHidesShownKeyboard) { // Set up the virtual keyboard tray icon along with some other tray icons. StatusAreaWidget* status = StatusAreaWidgetTestHelper::GetStatusAreaWidget(); - status->virtual_keyboard_tray_for_testing()->SetVisible(true); - status->ime_menu_tray()->SetVisible(true); + status->virtual_keyboard_tray_for_testing()->SetVisiblePreferred(true); + status->ime_menu_tray()->SetVisiblePreferred(true); keyboard_ui_controller()->ShowKeyboard(false /* locked */); ASSERT_TRUE(keyboard::WaitUntilShown()); @@ -355,4 +360,88 @@ EXPECT_FALSE(keyboard::IsKeyboardHiding()); } +class StatusAreaWidgetCollapseStateTest : public AshTestBase { + protected: + void SetUp() override { + AshTestBase::SetUp(); + + StatusAreaWidget* status_area = + StatusAreaWidgetTestHelper::GetStatusAreaWidget(); + virtual_keyboard_ = status_area->virtual_keyboard_tray_for_testing(); + ime_menu_ = status_area->ime_menu_tray(); + palette_ = status_area->palette_tray(); + dictation_button_ = status_area->dictation_button_tray(); + select_to_speak_ = status_area->select_to_speak_tray(); + + virtual_keyboard_->SetVisiblePreferred(true); + ime_menu_->SetVisiblePreferred(true); + palette_->SetVisiblePreferred(true); + dictation_button_->SetVisiblePreferred(true); + select_to_speak_->SetVisiblePreferred(true); + } + + void SetCollapseState(StatusAreaWidget::CollapseState collapse_state) { + StatusAreaWidgetTestApi test_api( + StatusAreaWidgetTestHelper::GetStatusAreaWidget()); + test_api.SetCollapseState(collapse_state); + + virtual_keyboard_->UpdateAfterStatusAreaCollapseChange(); + ime_menu_->UpdateAfterStatusAreaCollapseChange(); + palette_->UpdateAfterStatusAreaCollapseChange(); + dictation_button_->UpdateAfterStatusAreaCollapseChange(); + select_to_speak_->UpdateAfterStatusAreaCollapseChange(); + } + + TrayBackgroundView* virtual_keyboard_; + TrayBackgroundView* ime_menu_; + TrayBackgroundView* palette_; + TrayBackgroundView* dictation_button_; + TrayBackgroundView* select_to_speak_; +}; + +TEST_F(StatusAreaWidgetCollapseStateTest, TrayVisibility) { + // Initial visibility. + ime_menu_->SetVisiblePreferred(false); + virtual_keyboard_->set_show_when_collapsed(false); + palette_->set_show_when_collapsed(true); + EXPECT_FALSE(ime_menu_->GetVisible()); + EXPECT_TRUE(virtual_keyboard_->GetVisible()); + EXPECT_TRUE(palette_->GetVisible()); + + // Post-collapse visibility. + SetCollapseState(StatusAreaWidget::CollapseState::COLLAPSED); + EXPECT_FALSE(ime_menu_->GetVisible()); + EXPECT_FALSE(virtual_keyboard_->GetVisible()); + EXPECT_TRUE(palette_->GetVisible()); + + // Expanded visibility. + SetCollapseState(StatusAreaWidget::CollapseState::EXPANDED); + EXPECT_FALSE(ime_menu_->GetVisible()); + EXPECT_TRUE(virtual_keyboard_->GetVisible()); + EXPECT_TRUE(palette_->GetVisible()); +} + +TEST_F(StatusAreaWidgetCollapseStateTest, ImeMenuShownWithVirtualKeyboard) { + // Set up tray items. + ime_menu_->set_show_when_collapsed(false); + palette_->set_show_when_collapsed(true); + + // Collapsing the status area should hide the IME menu tray item. + SetCollapseState(StatusAreaWidget::CollapseState::COLLAPSED); + EXPECT_FALSE(ime_menu_->GetVisible()); + EXPECT_TRUE(palette_->GetVisible()); + + // But only the IME menu tray item should be shown after showing keyboard, + // simulated here by OnArcInputMethodSurfaceBoundsChanged(). + Shell::Get() + ->system_tray_model() + ->virtual_keyboard() + ->OnArcInputMethodSurfaceBoundsChanged(gfx::Rect(0, 0, 100, 100)); + EXPECT_TRUE(ime_menu_->GetVisible()); + EXPECT_FALSE(palette_->GetVisible()); + EXPECT_FALSE(virtual_keyboard_->GetVisible()); + EXPECT_FALSE(dictation_button_->GetVisible()); + EXPECT_FALSE(select_to_speak_->GetVisible()); +} + } // namespace ash
diff --git a/ash/system/tray/status_area_overflow_button_tray.cc b/ash/system/tray/status_area_overflow_button_tray.cc index df3784be2..128e8c5 100644 --- a/ash/system/tray/status_area_overflow_button_tray.cc +++ b/ash/system/tray/status_area_overflow_button_tray.cc
@@ -104,7 +104,7 @@ // TODO(tengs): Make this tray button visible when the device is in tablet // mode and the status area width exceeds the maximum desirable width. - SetVisible(false); + SetVisiblePreferred(false); } bool StatusAreaOverflowButtonTray::PerformAction(const ui::Event& event) {
diff --git a/ash/system/tray/tray_background_view.cc b/ash/system/tray/tray_background_view.cc index 8da2ecf..db272e2 100644 --- a/ash/system/tray/tray_background_view.cc +++ b/ash/system/tray/tray_background_view.cc
@@ -149,6 +149,7 @@ separator_visible_(true), visible_preferred_(false), show_with_virtual_keyboard_(false), + show_when_collapsed_(true), widget_observer_(new TrayWidgetObserver(this)) { DCHECK(shelf_); set_notify_enter_exit_on_child(true); @@ -202,17 +203,12 @@ window, base::TimeDelta::FromMilliseconds(kAnimationDurationForPopupMs)); } +void TrayBackgroundView::SetVisiblePreferred(bool visible_preferred) { + visible_preferred_ = visible_preferred; + SetVisible(GetEffectiveVisibility()); +} + void TrayBackgroundView::SetVisible(bool visible) { - visible_preferred_ = visible; - - // If virtual keyboard is visible and TrayBackgroundView is hidden because of - // that, ignore SetVisible() call. |visible_preferred_| will be restored - // in OnVirtualKeyboardVisibilityChanged() when virtual keyboard is hidden. - if (!show_with_virtual_keyboard_ && - Shell::Get()->system_tray_model()->virtual_keyboard()->visible()) { - return; - } - if (visible == layer()->GetTargetVisibility()) return; @@ -328,21 +324,8 @@ } void TrayBackgroundView::OnVirtualKeyboardVisibilityChanged() { - if (show_with_virtual_keyboard_) { - // The view always shows up when virtual keyboard is visible if - // |show_with_virtual_keyboard| is true. - views::View::SetVisible( - Shell::Get()->system_tray_model()->virtual_keyboard()->visible() || - visible_preferred_); - return; - } - - // If virtual keyboard is hidden and current preferred visibility is true, - // set the visibility to true. We call base class' SetVisible because we don't - // want |visible_preferred_| to be updated here. - views::View::SetVisible( - !Shell::Get()->system_tray_model()->virtual_keyboard()->visible() && - visible_preferred_); + // We call the base class' SetVisible to skip animations. + views::View::SetVisible(GetEffectiveVisibility()); } TrayBubbleView* TrayBackgroundView::GetBubbleView() { @@ -363,6 +346,11 @@ // Do nothing by default. Child class may do something. } +void TrayBackgroundView::UpdateAfterStatusAreaCollapseChange() { + // We call the base class' SetVisible to skip animations. + views::View::SetVisible(GetEffectiveVisibility()); +} + void TrayBackgroundView::BubbleResized(const TrayBubbleView* bubble_view) {} void TrayBackgroundView::OnImplicitAnimationsCompleted() { @@ -490,4 +478,25 @@ layer()->SetClipRect(GetBackgroundBounds()); } +bool TrayBackgroundView::GetEffectiveVisibility() { + // When the virtual keyboard is visible, the effective visibility of the view + // is solely determined by |show_with_virtual_keyboard_|. + if (Shell::Get()->system_tray_model()->virtual_keyboard()->visible()) + return show_with_virtual_keyboard_; + + if (!visible_preferred_) + return false; + + // When the status area is collapsed, the effective visibility of the view is + // determined by |show_when_collapsed_|. + StatusAreaWidget::CollapseState collapse_state = + Shelf::ForWindow(GetWidget()->GetNativeWindow()) + ->GetStatusAreaWidget() + ->collapse_state(); + if (collapse_state == StatusAreaWidget::CollapseState::COLLAPSED) + return show_when_collapsed_; + + return true; +} + } // namespace ash
diff --git a/ash/system/tray/tray_background_view.h b/ash/system/tray/tray_background_view.h index a46d5492..62d3287 100644 --- a/ash/system/tray/tray_background_view.h +++ b/ash/system/tray/tray_background_view.h
@@ -42,13 +42,6 @@ // Initializes animations for the bubble. static void InitializeBubbleAnimations(views::Widget* bubble_widget); - // views::View: - void SetVisible(bool visible) override; - const char* GetClassName() const override; - void AboutToRequestFocusFromTabTraversal(bool reverse) override; - void GetAccessibleNodeData(ui::AXNodeData* node_data) override; - void ChildPreferredSizeChanged(views::View* child) override; - // ActionableView: std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override; std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight() @@ -76,6 +69,9 @@ virtual void UpdateAfterRootWindowBoundsChange(const gfx::Rect& old_bounds, const gfx::Rect& new_bounds); + // Called whenever the status area's collapse state changes. + virtual void UpdateAfterStatusAreaCollapseChange(); + // Called when the anchor (tray or bubble) may have moved or changed. virtual void AnchorUpdated() {} @@ -106,6 +102,11 @@ // Updates the visibility of this tray's separator. void set_separator_visibility(bool visible) { separator_visible_ = visible; } + // Sets whether to show the view when the status area is collapsed. + void set_show_when_collapsed(bool show_when_collapsed) { + show_when_collapsed_ = show_when_collapsed; + } + // Gets the anchor for bubbles, which is tray_container(). views::View* GetBubbleAnchor() const; @@ -120,6 +121,12 @@ // based on background insets returned from GetBackgroundInsets(). gfx::Rect GetBackgroundBounds() const; + // Sets whether the tray item should be shown by default (e.g. it is + // activated). The effective visibility of the tray item is determined by the + // current state of the status tray (i.e. whether the virtual keyboard is + // showing or if it is collapsed). + void SetVisiblePreferred(bool visible_preferred); + protected: // ActionableView: void OnBoundsChanged(const gfx::Rect& previous_bounds) override; @@ -137,6 +144,13 @@ class HighlightPathGenerator; class TrayWidgetObserver; + // views::View: + void SetVisible(bool visible) override; + const char* GetClassName() const override; + void AboutToRequestFocusFromTabTraversal(bool reverse) override; + void GetAccessibleNodeData(ui::AXNodeData* node_data) override; + void ChildPreferredSizeChanged(views::View* child) override; + // ui::ImplicitAnimationObserver: void OnImplicitAnimationsCompleted() override; bool RequiresNotificationWhenAnimatorDestroyed() const override; @@ -151,6 +165,10 @@ // Updates the background layer. void UpdateBackground(); + // Returns the effective visibility of the tray item based on the current + // state. + bool GetEffectiveVisibility(); + // The shelf containing the system tray for this view. Shelf* shelf_; @@ -173,6 +191,9 @@ // If true, the view always shows up when virtual keyboard is visible. bool show_with_virtual_keyboard_; + // If true, the view is visible when the status area is collapsed. + bool show_when_collapsed_; + std::unique_ptr<TrayWidgetObserver> widget_observer_; std::unique_ptr<TrayEventFilter> tray_event_filter_;
diff --git a/ash/system/unified/unified_system_tray.cc b/ash/system/unified/unified_system_tray.cc index 13e90d3..b44acd54 100644 --- a/ash/system/unified/unified_system_tray.cc +++ b/ash/system/unified/unified_system_tray.cc
@@ -270,7 +270,7 @@ } void UnifiedSystemTray::UpdateAfterLoginStatusChange() { - SetVisible(true); + SetVisiblePreferred(true); PreferredSizeChanged(); }
diff --git a/ash/system/virtual_keyboard/virtual_keyboard_tray.cc b/ash/system/virtual_keyboard/virtual_keyboard_tray.cc index ddcb0f2..69f42ff3 100644 --- a/ash/system/virtual_keyboard/virtual_keyboard_tray.cc +++ b/ash/system/virtual_keyboard/virtual_keyboard_tray.cc
@@ -90,7 +90,7 @@ void VirtualKeyboardTray::OnAccessibilityStatusChanged() { bool new_enabled = Shell::Get()->accessibility_controller()->virtual_keyboard_enabled(); - SetVisible(new_enabled); + SetVisiblePreferred(new_enabled); } void VirtualKeyboardTray::OnKeyboardVisibilityChanged(const bool is_visible) {
diff --git a/ash/system/virtual_keyboard/virtual_keyboard_tray_unittest.cc b/ash/system/virtual_keyboard/virtual_keyboard_tray_unittest.cc index 279bb18..b39f979c 100644 --- a/ash/system/virtual_keyboard/virtual_keyboard_tray_unittest.cc +++ b/ash/system/virtual_keyboard/virtual_keyboard_tray_unittest.cc
@@ -40,7 +40,7 @@ TEST_F(VirtualKeyboardTrayTest, PerformActionTogglesVirtualKeyboard) { StatusAreaWidget* status = StatusAreaWidgetTestHelper::GetStatusAreaWidget(); VirtualKeyboardTray* tray = status->virtual_keyboard_tray_for_testing(); - tray->SetVisible(true); + tray->SetVisiblePreferred(true); ASSERT_TRUE(tray->GetVisible()); // First tap should show the virtual keyboard.
diff --git a/base/android/java/src/org/chromium/base/StrictModeContext.java b/base/android/java/src/org/chromium/base/StrictModeContext.java index 49b2ad8..2c9aa80 100644 --- a/base/android/java/src/org/chromium/base/StrictModeContext.java +++ b/base/android/java/src/org/chromium/base/StrictModeContext.java
@@ -50,6 +50,17 @@ } /** + * Convenience method for disabling all thread-level StrictMode checks with try-with-resources. + * Includes everything listed here: + * https://developer.android.com/reference/android/os/StrictMode.ThreadPolicy.Builder.html + */ + public static StrictModeContext allowAllThreadPolicies() { + StrictMode.ThreadPolicy oldPolicy = StrictMode.getThreadPolicy(); + StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.LAX); + return new StrictModeContext(oldPolicy); + } + + /** * Convenience method for disabling StrictMode for disk-writes with try-with-resources. */ public static StrictModeContext allowDiskWrites() { @@ -84,4 +95,4 @@ StrictMode.setVmPolicy(mVmPolicy); } } -} \ No newline at end of file +}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/ScreenshotOnFailureStatement.java b/base/test/android/javatests/src/org/chromium/base/test/ScreenshotOnFailureStatement.java index f982e14..3ad851a 100644 --- a/base/test/android/javatests/src/org/chromium/base/test/ScreenshotOnFailureStatement.java +++ b/base/test/android/javatests/src/org/chromium/base/test/ScreenshotOnFailureStatement.java
@@ -14,6 +14,7 @@ import org.junit.runners.model.Statement; import org.chromium.base.Log; +import org.chromium.base.StrictModeContext; import java.io.File; @@ -65,32 +66,34 @@ screenshotFile)); return; } - if (!screenshotDir.exists()) { - if (!screenshotDir.mkdirs()) { - Log.d(TAG, - String.format( - "Failed to create %s. Can't save screenshot.", screenshotDir)); + try (StrictModeContext ignored = StrictModeContext.allowAllThreadPolicies()) { + if (!screenshotDir.exists()) { + if (!screenshotDir.mkdirs()) { + Log.d(TAG, + String.format( + "Failed to create %s. Can't save screenshot.", screenshotDir)); + return; + } + } + + // The Vega standalone VR headset can't take screenshots normally (they just show a + // black screen with the VR overlay), so instead, use VrCore's RecorderService. + if (Build.DEVICE.equals("vega")) { + takeScreenshotVega(screenshotFile); return; } - } - // The Vega standalone VR headset can't take screenshots normally (they just show a black - // screen with the VR overlay), so instead, use VrCore's RecorderService. - if (Build.DEVICE.equals("vega")) { - takeScreenshotVega(screenshotFile); - return; - } + UiDevice uiDevice = null; + try { + uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); + } catch (RuntimeException ex) { + Log.d(TAG, "Failed to initialize UiDevice", ex); + return; + } - UiDevice uiDevice = null; - try { - uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); - } catch (RuntimeException ex) { - Log.d(TAG, "Failed to initialize UiDevice", ex); - return; + Log.d(TAG, String.format("Saving screenshot of test failure, %s", screenshotFile)); + uiDevice.takeScreenshot(screenshotFile); } - - Log.d(TAG, String.format("Saving screenshot of test failure, %s", screenshotFile)); - uiDevice.takeScreenshot(screenshotFile); } private void takeScreenshotVega(final File screenshotFile) {
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1 index 16110e5..1096166 100644 --- a/build/fuchsia/linux.sdk.sha1 +++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@ -8897419927696300224 \ No newline at end of file +8897393320560678400 \ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1 index ee69debb..d9f85a3 100644 --- a/build/fuchsia/mac.sdk.sha1 +++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@ -8897425289159983392 \ No newline at end of file +8897398712024874704 \ No newline at end of file
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index 9e8db5bb..4cfa0b7 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -2074,6 +2074,10 @@ // external viewport to be set otherwise. DCHECK(active_tree_->internal_device_viewport().origin().IsOrigin()); +#if DCHECK_IS_ON() + base::AutoReset<bool> reset_sync_draw(&doing_sync_draw_, true); +#endif + if (skip_draw) { client_->OnDrawForLayerTreeFrameSink(resourceless_software_draw_, true); return; @@ -2297,6 +2301,21 @@ std::move(compositor_frame), /*hit_test_data_changed=*/false, debug_state_.show_hit_test_borders); +#if DCHECK_IS_ON() + if (!doing_sync_draw_) { + // The throughput computation (in |FrameSequenceTracker|) depends on the + // compositor-frame submission to happen while a BeginFrameArgs is 'active' + // (i.e. between calls to WillBeginImplFrame() and DidFinishImplFrame()). + // Verify that this is the case. + // No begin-frame is available when doing sync draws, so avoid doing this + // check in that case. + const auto& bfargs = current_begin_frame_tracker_.Current(); + const auto& ack = compositor_frame.metadata.begin_frame_ack; + DCHECK_EQ(bfargs.source_id, ack.source_id); + DCHECK_EQ(bfargs.sequence_number, ack.sequence_number); + } +#endif + frame_trackers_.NotifySubmitFrame( compositor_frame.metadata.frame_token, frame->has_missing_content, frame->begin_frame_ack, frame->origin_begin_main_frame_args);
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h index 2ae154e1..b6faedc 100644 --- a/cc/trees/layer_tree_host_impl.h +++ b/cc/trees/layer_tree_host_impl.h
@@ -1293,6 +1293,11 @@ // not we are in that state. bool pending_tree_fully_painted_ = false; +#if DCHECK_IS_ON() + // Use to track when doing a synchronous draw. + bool doing_sync_draw_ = false; +#endif + // Provides support for PaintWorklets which depend on input properties that // are being animated by the compositor (aka 'animated' PaintWorklets). // Responsible for storing animated custom property values and for
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc index 9784156e..fb8bf14f 100644 --- a/cc/trees/layer_tree_host_impl_unittest.cc +++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -600,9 +600,13 @@ void DrawFrame() { PrepareForUpdateDrawProperties(host_impl_->active_tree()); TestFrameData frame; + host_impl_->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1, + base::TimeTicks() + base::TimeDelta::FromMilliseconds(1))); EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); + host_impl_->DidFinishImplFrame(); } RenderFrameMetadata StartDrawAndProduceRenderFrameMetadata() { @@ -4621,6 +4625,9 @@ { TestFrameData frame; + host_impl_->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1, + base::TimeTicks() + base::TimeDelta::FromMilliseconds(1))); EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); EXPECT_FALSE(frame.has_no_damage); @@ -4631,6 +4638,7 @@ EXPECT_NE(total_quad_count, 0u); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); + host_impl_->DidFinishImplFrame(); } // Stops the child layer from drawing. We should have damage from this but @@ -4646,6 +4654,9 @@ { TestFrameData frame; + host_impl_->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1, + base::TimeTicks() + base::TimeDelta::FromMilliseconds(1))); EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); EXPECT_FALSE(frame.has_no_damage); @@ -4656,12 +4667,16 @@ EXPECT_EQ(total_quad_count, 0u); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); + host_impl_->DidFinishImplFrame(); } // Now tries to draw again. Nothing changes, so should have no damage, no // render pass, and no quad. { TestFrameData frame; + host_impl_->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1, + base::TimeTicks() + base::TimeDelta::FromMilliseconds(1))); EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); EXPECT_TRUE(frame.has_no_damage); @@ -4672,6 +4687,7 @@ EXPECT_EQ(total_quad_count, 0u); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); + host_impl_->DidFinishImplFrame(); } } @@ -4965,9 +4981,13 @@ host_impl_->SetRequiresHighResToDraw(); TestFrameData frame; + host_impl_->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1, + base::TimeTicks() + base::TimeDelta::FromMilliseconds(1))); EXPECT_EQ(testcase.expected_result, host_impl_->PrepareToDraw(&frame)); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); + host_impl_->DidFinishImplFrame(); } } @@ -7111,9 +7131,13 @@ // Check scroll delta reflected in layer. TestFrameData frame; + host_impl_->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1, + base::TimeTicks() + base::TimeDelta::FromMilliseconds(1))); EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); + host_impl_->DidFinishImplFrame(); EXPECT_FALSE(frame.has_no_damage); CheckLayerScrollDelta(scroll_layer, gfx::ScrollOffsetToVector2dF(scroll_offset)); @@ -8306,9 +8330,13 @@ static bool MayContainVideoBitSetOnFrameData(LayerTreeHostImpl* host_impl) { host_impl->active_tree()->set_needs_update_draw_properties(); TestFrameData frame; + host_impl->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1, + base::TimeTicks() + base::TimeDelta::FromMilliseconds(1))); EXPECT_EQ(DRAW_SUCCESS, host_impl->PrepareToDraw(&frame)); host_impl->DrawLayers(&frame); host_impl->DidDrawAllLayers(frame); + host_impl->DidFinishImplFrame(); return frame.may_contain_video; } @@ -8645,8 +8673,6 @@ nullptr); layer_tree_host_impl->SetVisible(true); layer_tree_host_impl->InitializeFrameSink(layer_tree_frame_sink.get()); - layer_tree_host_impl->WillBeginImplFrame( - viz::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 2)); LayerImpl* root = SetupRootLayer<LayerImpl>( layer_tree_host_impl->active_tree(), gfx::Size(500, 500)); @@ -8664,9 +8690,13 @@ TestFrameData frame; // First frame, the entire screen should get swapped. + layer_tree_host_impl->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1, + base::TimeTicks() + base::TimeDelta::FromMilliseconds(1))); EXPECT_EQ(DRAW_SUCCESS, layer_tree_host_impl->PrepareToDraw(&frame)); layer_tree_host_impl->DrawLayers(&frame); layer_tree_host_impl->DidDrawAllLayers(frame); + layer_tree_host_impl->DidFinishImplFrame(); gfx::Rect expected_swap_rect(500, 500); EXPECT_EQ(expected_swap_rect.ToString(), fake_layer_tree_frame_sink->last_swap_rect().ToString()); @@ -8675,9 +8705,13 @@ // the union of old and new child rects: gfx::Rect(26, 28). child->SetOffsetToTransformParent(gfx::Vector2dF()); child->NoteLayerPropertyChanged(); + layer_tree_host_impl->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1, + base::TimeTicks() + base::TimeDelta::FromMilliseconds(1))); EXPECT_EQ(DRAW_SUCCESS, layer_tree_host_impl->PrepareToDraw(&frame)); layer_tree_host_impl->DrawLayers(&frame); - host_impl_->DidDrawAllLayers(frame); + layer_tree_host_impl->DidDrawAllLayers(frame); + layer_tree_host_impl->DidFinishImplFrame(); expected_swap_rect = gfx::Rect(26, 28); EXPECT_EQ(expected_swap_rect.ToString(), @@ -8686,9 +8720,13 @@ layer_tree_host_impl->active_tree()->SetDeviceViewportRect(gfx::Rect(10, 10)); // This will damage everything. root->SetBackgroundColor(SK_ColorBLACK); + layer_tree_host_impl->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1, + base::TimeTicks() + base::TimeDelta::FromMilliseconds(1))); EXPECT_EQ(DRAW_SUCCESS, layer_tree_host_impl->PrepareToDraw(&frame)); layer_tree_host_impl->DrawLayers(&frame); - host_impl_->DidDrawAllLayers(frame); + layer_tree_host_impl->DidDrawAllLayers(frame); + layer_tree_host_impl->DidFinishImplFrame(); expected_swap_rect = gfx::Rect(10, 10); EXPECT_EQ(expected_swap_rect.ToString(), @@ -8783,6 +8821,9 @@ // Verify one quad is drawn when transparent background set is not set. TestFrameData frame; + host_impl_->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1, + base::TimeTicks() + base::TimeDelta::FromMilliseconds(1))); EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); { const auto& root_pass = frame.render_passes.back(); @@ -8792,6 +8833,7 @@ } host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); + host_impl_->DidFinishImplFrame(); // Cause damage so we would draw something if possible. host_impl_->SetFullViewportDamage(); @@ -8799,6 +8841,9 @@ // Verify no quads are drawn when transparent background is set. host_impl_->active_tree()->set_background_color(SK_ColorTRANSPARENT); host_impl_->SetFullViewportDamage(); + host_impl_->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1, + base::TimeTicks() + base::TimeDelta::FromMilliseconds(1))); EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); { const auto& root_pass = frame.render_passes.back(); @@ -8806,6 +8851,7 @@ } host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); + host_impl_->DidFinishImplFrame(); // Cause damage so we would draw something if possible. host_impl_->SetFullViewportDamage(); @@ -8813,6 +8859,9 @@ // Verify no quads are drawn when semi-transparent background is set. host_impl_->active_tree()->set_background_color(SkColorSetARGB(5, 255, 0, 0)); host_impl_->SetFullViewportDamage(); + host_impl_->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1, + base::TimeTicks() + base::TimeDelta::FromMilliseconds(1))); EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); { const auto& root_pass = frame.render_passes.back(); @@ -8820,6 +8869,7 @@ } host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); + host_impl_->DidFinishImplFrame(); } class LayerTreeHostImplTestDrawAndTestDamage : public LayerTreeHostImplTest { @@ -8833,6 +8883,9 @@ bool expect_to_draw = !expected_damage.IsEmpty(); TestFrameData frame; + host_impl_->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1, + base::TimeTicks() + base::TimeDelta::FromMilliseconds(1))); EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); if (!expect_to_draw) { @@ -8862,6 +8915,7 @@ EXPECT_EQ(expect_to_draw, host_impl_->DrawLayers(&frame)); host_impl_->DidDrawAllLayers(frame); + host_impl_->DidFinishImplFrame(); } }; @@ -8943,6 +8997,9 @@ ASSERT_EQ(1u, host_impl_->active_tree()->GetRenderSurfaceList().size()); TestFrameData frame; + host_impl_->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1, + base::TimeTicks() + base::TimeDelta::FromMilliseconds(1))); EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); ASSERT_EQ(1u, frame.render_passes.size()); @@ -8962,6 +9019,7 @@ host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); + host_impl_->DidFinishImplFrame(); } class CompositorFrameMetadataTest : public LayerTreeHostImplTest { @@ -9122,12 +9180,16 @@ gfx::Rect full_frame_damage( host_impl->active_tree()->GetDeviceViewport().size()); TestFrameData frame; + host_impl->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1, + base::TimeTicks() + base::TimeDelta::FromMilliseconds(1))); EXPECT_EQ(DRAW_SUCCESS, host_impl->PrepareToDraw(&frame)); ASSERT_EQ(1u, frame.render_passes.size()); const viz::RenderPass* root_render_pass = frame.render_passes.back().get(); EXPECT_EQ(full_frame_damage, root_render_pass->damage_rect); EXPECT_TRUE(host_impl->DrawLayers(&frame)); host_impl->DidDrawAllLayers(frame); + host_impl->DidFinishImplFrame(); } } // namespace @@ -11477,8 +11539,6 @@ scrolling_layer->SetBounds(new_content_size); GetScrollNode(scrolling_layer)->bounds = new_content_size; - DrawFrame(); - begin_frame_args.frame_time = start_time + base::TimeDelta::FromMilliseconds(200); begin_frame_args.sequence_number++;
diff --git a/chrome/VERSION b/chrome/VERSION index e6e3473ed..bdd94ae 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=80 MINOR=0 -BUILD=3963 +BUILD=3964 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index 25b9be88..2acc3cb 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -1116,6 +1116,7 @@ "java/res_template/xml/file_paths.xml", "java/res_template/xml/launchershortcuts.xml", "java/res_template/xml/searchable.xml", + "java/res_template/xml/syncadapter.xml", ] res_dir = "java/res_template" variables = [ "manifest_package=$chrome_public_manifest_package" ]
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni index 9b7b8d70..dda43d25 100644 --- a/chrome/android/chrome_java_sources.gni +++ b/chrome/android/chrome_java_sources.gni
@@ -854,6 +854,8 @@ "java/src/org/chromium/chrome/browser/instantapps/InstantAppsBannerData.java", "java/src/org/chromium/chrome/browser/instantapps/InstantAppsHandler.java", "java/src/org/chromium/chrome/browser/instantapps/InstantAppsSettings.java", + "java/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapter.java", + "java/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapterService.java", "java/src/org/chromium/chrome/browser/invalidation/ResumableDelayedTaskRunner.java", "java/src/org/chromium/chrome/browser/invalidation/SessionsInvalidationManager.java", "java/src/org/chromium/chrome/browser/invalidation/UniqueIdInvalidationClientNameGenerator.java",
diff --git a/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrShellDelegate.java b/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrShellDelegate.java index f536b0f..9a379a0 100644 --- a/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrShellDelegate.java +++ b/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrShellDelegate.java
@@ -165,10 +165,6 @@ private boolean mRestoreSystemUiVisibility; private Integer mRestoreOrientation; private boolean mRequestedWebVr; - private boolean mListeningForWebVrActivate; - private boolean mMaybeActivateAfterHeadsetInsertion; - private Handler mClearMaybeActivateHandler = new Handler(); - private boolean mActivateFromHeadsetInsertion; private boolean mStartedFromVrIntent; private boolean mInternalIntentUsedToStartVr; @@ -252,11 +248,6 @@ VrModuleProvider.getDelegate().addBlackOverlayViewForActivity(sInstance.mActivity); } - // For headset insertion handling it should be impossible in practice to receive this - // broadcast after being resumed. However, with VR entry flows skipped, these events - // can happen out of order. See https://crbug.com/762724. - sInstance.mActivateFromHeadsetInsertion = sInstance.mMaybeActivateAfterHeadsetInsertion; - if (sInstance.mPaused) { if (activity instanceof ChromeTabbedActivity) { // We can special case singleInstance activities like CTA to avoid having to use @@ -1067,19 +1058,7 @@ if (mNativeVrShellDelegate == 0) return false; if (!canEnterVr()) return false; - // If headset insertion was performed while a page was listening for vrdisplayactivate, - // we assume it wants to request presentation. Go into WebVR mode tentatively. If the page - // doesn't request presentation in the vrdisplayactivate handler we will exit presentation - // later. - if (mActivateFromHeadsetInsertion) { - assert !mRequestedWebVr; - assert !mStartedFromVrIntent; - } - enterVr(mActivateFromHeadsetInsertion); - if (mActivateFromHeadsetInsertion && mListeningForWebVrActivate) { - VrShellDelegateJni.get().displayActivate(mNativeVrShellDelegate, VrShellDelegate.this); - mActivateFromHeadsetInsertion = false; - } + enterVr(); // The user has successfully completed a DON flow. RecordUserAction.record("VR.DON"); @@ -1087,7 +1066,7 @@ return true; } - private void enterVr(final boolean tentativeWebVrMode) { + private void enterVr() { // We should only enter VR when we're the resumed Activity or our changes to things like // system UI flags might get lost. assert !mPaused; @@ -1116,12 +1095,11 @@ if (!sRegisteredVrAssetsComponent) { registerVrAssetsComponentIfDaydreamUser(isDaydreamCurrentViewer()); } - boolean webVrMode = mRequestedWebVr || tentativeWebVrMode; - mVrShell.initializeNative(webVrMode, VrModuleProvider.getDelegate().bootsToVr()); - mVrShell.setWebVrModeEnabled(webVrMode); + mVrShell.initializeNative(mRequestedWebVr, VrModuleProvider.getDelegate().bootsToVr()); + mVrShell.setWebVrModeEnabled(mRequestedWebVr); // We're entering VR, but not in WebVr mode. - mVrBrowserUsed = !webVrMode; + mVrBrowserUsed = !mRequestedWebVr; // resume needs to be called on GvrLayout after initialization to make sure DON flow works // properly. @@ -1298,8 +1276,7 @@ if (getVrSupportLevel() <= VrSupportLevel.VR_NEEDS_UPDATE) return false; // If VR browsing is not enabled and this is not a WebXR request, then return false. - boolean presenting = mRequestedWebVr || mActivateFromHeadsetInsertion; - if (!isVrBrowsingEnabled() && !presenting) return false; + if (!isVrBrowsingEnabled() && !mRequestedWebVr) return false; return true; } @@ -1354,7 +1331,7 @@ getVrDaydreamApi().launchInVr(getEnterVrPendingIntent(mActivity)); mProbablyInDon = true; } else { - enterVr(false); + enterVr(); } return EnterVRResult.REQUESTED; } @@ -1430,9 +1407,6 @@ @VisibleForTesting protected void onResume() { if (VrDelegate.DEBUG_LOGS) Log.i(TAG, "onResume"); - if (!mTestWorkaroundDontCancelVrEntryOnResume) { - mMaybeActivateAfterHeadsetInsertion = false; - } if (mNeedsAnimationCancel) { // At least on some devices, like the Samsung S8+, a Window animation is run after our // Activity is shown that fades between a stale screenshot from before pausing to the @@ -1520,7 +1494,6 @@ if (mInVr) { maybeSetPresentResult(true); mDonSucceeded = false; - assert !mActivateFromHeadsetInsertion; return; } if (maybeExitVrToUpdateVrServices()) return; @@ -1556,10 +1529,6 @@ unregisterDaydreamIntent(); if (getVrSupportLevel() <= VrSupportLevel.VR_NEEDS_UPDATE) return; - if (mMaybeActivateAfterHeadsetInsertion) { - mClearMaybeActivateHandler.removeCallbacksAndMessages(null); - } - if (mInVr) mVrShell.pause(); if (mNativeVrShellDelegate != 0) { VrShellDelegateJni.get().onPause(mNativeVrShellDelegate, VrShellDelegate.this); @@ -1569,7 +1538,6 @@ } private void onStart() { - mMaybeActivateAfterHeadsetInsertion = false; if (mDonSucceeded) setWindowModeForVr(); // This handles the case where Chrome was paused in VR (ie the user navigated to DD home or @@ -1658,47 +1626,10 @@ return mIsDaydreamCurrentViewer; } - @CalledByNative - private void setListeningForWebVrActivate(boolean listening) { - if (VrDelegate.DEBUG_LOGS) { - Log.i(TAG, "WebVR page listening for vrdisplayactivate: " + listening); - } - // Non-Daydream devices do not have the concept of activation. - if (getVrSupportLevel() != VrSupportLevel.VR_DAYDREAM) return; - if (mListeningForWebVrActivate == listening) return; - mListeningForWebVrActivate = listening; - if (mListeningForWebVrActivate) { - registerDaydreamIntent(mActivity); - if (mNeedsAnimationCancel || mCancellingEntryAnimation) return; - if (mActivateFromHeadsetInsertion) { - // Dispatch vrdisplayactivate so that the WebVr page can call requestPresent - // to start presentation. - VrShellDelegateJni.get().displayActivate( - mNativeVrShellDelegate, VrShellDelegate.this); - mActivateFromHeadsetInsertion = false; - } - } else { - if (!canEnterVr()) unregisterDaydreamIntent(); - // When the active web page has a vrdisplayactivate event handler, and the phone is - // inserted into the headset, a vrdisplayactive event should be fired once DON flow - // is finished. However, the DON flow will pause our activity, which makes the active - // page lose focus and report that it can't handle displayActivate. - // Because of the order of onPause events running, we can't check for - // mListeningForWebVrActivate in onPause() as we may or may not already have lost focus. - // We need to remember that - mMaybeActivateAfterHeadsetInsertion = !mInVr && !mRequestedWebVr; - if (!mPaused) { - mClearMaybeActivateHandler.post( - () -> { mMaybeActivateAfterHeadsetInsertion = false; }); - } - } - } - private void cancelPendingVrEntry() { if (VrDelegate.DEBUG_LOGS) Log.i(TAG, "cancelPendingVrEntry"); VrModuleProvider.getDelegate().removeBlackOverlayView(mActivity, false /* animate */); mDonSucceeded = false; - mActivateFromHeadsetInsertion = false; maybeSetPresentResult(false); if (!mShowingDaydreamDoff) { setVrModeEnabled(mActivity, false); @@ -1923,11 +1854,6 @@ } @VisibleForTesting - protected boolean isListeningForWebVrActivate() { - return mListeningForWebVrActivate; - } - - @VisibleForTesting protected boolean isVrEntryComplete() { return mInVr && !mProbablyInDon && getVrShell().hasUiFinishedLoading(); } @@ -1973,7 +1899,6 @@ void onLibraryAvailable(); void setPresentResult(long nativeVrShellDelegate, VrShellDelegate caller, boolean result); void recordVrStartAction(long nativeVrShellDelegate, int startAction); - void displayActivate(long nativeVrShellDelegate, VrShellDelegate caller); void onPause(long nativeVrShellDelegate, VrShellDelegate caller); void onResume(long nativeVrShellDelegate, VrShellDelegate caller); void destroy(long nativeVrShellDelegate, VrShellDelegate caller);
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml index 3728cbf3..fd759c44 100644 --- a/chrome/android/java/AndroidManifest.xml +++ b/chrome/android/java/AndroidManifest.xml
@@ -978,6 +978,16 @@ android:resource="@xml/file_paths" /> </provider> + <!-- Sync adapter for browser invalidation. --> + <service android:name="org.chromium.chrome.browser.invalidation.ChromeBrowserSyncAdapterService" + android:exported="false"> + <intent-filter> + <action android:name="android.content.SyncAdapter" /> + </intent-filter> + <meta-data android:name="android.content.SyncAdapter" + android:resource="@xml/syncadapter" /> + </service> + <!-- Broadcast receiver that will be notified of account changes --> <receiver android:name="org.chromium.chrome.browser.services.AccountsChangedReceiver"> <intent-filter>
diff --git a/chrome/android/java/monochrome_public_bundle__base_bundle_module.AndroidManifest.expected b/chrome/android/java/monochrome_public_bundle__base_bundle_module.AndroidManifest.expected index fc9c4544..a004f967 100644 --- a/chrome/android/java/monochrome_public_bundle__base_bundle_module.AndroidManifest.expected +++ b/chrome/android/java/monochrome_public_bundle__base_bundle_module.AndroidManifest.expected
@@ -1554,6 +1554,14 @@ android:name="org.chromium.chrome.browser.incognito.IncognitoNotificationService"/> <service android:exported="false" + android:name="org.chromium.chrome.browser.invalidation.ChromeBrowserSyncAdapterService"> + <intent-filter> + <action android:name="android.content.SyncAdapter"/> + </intent-filter> + <meta-data android:name="android.content.SyncAdapter" android:resource="@xml/syncadapter"/> + </service> + <service + android:exported="false" android:name="org.chromium.chrome.browser.media.MediaCaptureNotificationService"/> <service android:exported="false"
diff --git a/chrome/android/java/res/layout/contacts_list_item_view.xml b/chrome/android/java/res/layout/contacts_list_item_view.xml index c613b059..c65a178 100644 --- a/chrome/android/java/res/layout/contacts_list_item_view.xml +++ b/chrome/android/java/res/layout/contacts_list_item_view.xml
@@ -14,6 +14,7 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" + android:layout_marginEnd="12dp" android:orientation="vertical" android:layout_gravity="center_vertical" > @@ -26,14 +27,39 @@ android:textAppearance="@style/TextAppearance.BlackTitle1" /> <LinearLayout - android:layout_width="match_parent" + android:layout_width="wrap_content" android:layout_height="wrap_content" - android:orientation="horizontal" > + android:orientation="horizontal"> + + <TextView + android:id="@+id/address" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:maxLines="1" + android:ellipsize="end" + android:textAppearance="@style/TextAppearance.BlackBody" /> + + <TextView + android:id="@+id/address_overflow_count" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingStart="4dp" + android:clickable="true" + android:maxLines="1" + android:textAppearance="@style/TextAppearance.BlueLink2" /> + </LinearLayout> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="horizontal"> <TextView android:id="@+id/email" - android:layout_width="wrap_content" + android:layout_width="0dp" android:layout_height="wrap_content" + android:layout_weight="1" android:maxLines="1" android:ellipsize="end" android:textAppearance="@style/TextAppearance.BlackBody" /> @@ -42,22 +68,22 @@ android:id="@+id/email_overflow_count" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:paddingStart="4dp" android:clickable="true" android:maxLines="1" - android:paddingStart="4dp" - android:ellipsize="end" - android:textAppearance="@style/TextAppearance.ContactsPickerMoreDetails" /> + android:textAppearance="@style/TextAppearance.BlueLink2" /> </LinearLayout> <LinearLayout - android:layout_width="match_parent" + android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" > <TextView android:id="@+id/telephone_number" - android:layout_width="wrap_content" + android:layout_width="0dp" android:layout_height="wrap_content" + android:layout_weight="1" android:maxLines="1" android:ellipsize="end" android:textAppearance="@style/TextAppearance.BlackBody" /> @@ -66,11 +92,10 @@ android:id="@+id/telephone_number_overflow_count" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:paddingStart="4dp" android:clickable="true" android:maxLines="1" - android:paddingStart="4dp" - android:ellipsize="end" - android:textAppearance="@style/TextAppearance.ContactsPickerMoreDetails" /> + android:textAppearance="@style/TextAppearance.BlueLink2" /> </LinearLayout> </LinearLayout> @@ -78,7 +103,7 @@ android:id="@+id/star" android:layout_width="32dp" android:layout_height="32dp" - android:layout_marginEnd="20dp" + android:layout_marginEnd="10dp" android:src="@drawable/btn_star_filled" android:visibility="gone" /> </merge>
diff --git a/chrome/android/java/res/layout/top_view.xml b/chrome/android/java/res/layout/top_view.xml index ea425b3c..801176f 100644 --- a/chrome/android/java/res/layout/top_view.xml +++ b/chrome/android/java/res/layout/top_view.xml
@@ -36,6 +36,13 @@ style="@style/SuggestionChip" /> <org.chromium.ui.widget.ChipView + android:id="@+id/address_filter" + android:gravity="center" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + style="@style/SuggestionChip" /> + + <org.chromium.ui.widget.ChipView android:id="@+id/email_filter" android:gravity="center" android:layout_height="wrap_content"
diff --git a/chrome/android/java/res/values/styles.xml b/chrome/android/java/res/values/styles.xml index 9a5624d..4b99217 100644 --- a/chrome/android/java/res/values/styles.xml +++ b/chrome/android/java/res/values/styles.xml
@@ -758,9 +758,6 @@ <item name="android:textColor">@color/default_text_color</item> <item name="android:textSize">@dimen/text_size_large</item> </style> - <style name="TextAppearance.ContactsPickerMoreDetails" parent="TextAppearance.BlackBody"> - <item name="android:textColor">@color/default_text_color_link</item> - </style> <style name="TextAppearance.PageInfoPermissionSubtitle" parent="TextAppearance.BlackBody"> <item name="android:textColor">@color/secondary_text_default_material_light</item> </style>
diff --git a/chrome/android/java/res_template/xml/syncadapter.xml b/chrome/android/java/res_template/xml/syncadapter.xml new file mode 100644 index 0000000..e69dfa9 --- /dev/null +++ b/chrome/android/java/res_template/xml/syncadapter.xml
@@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2015 The Chromium Authors. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. --> + +<!-- The attributes in this XML file provide configuration information --> +<!-- for the SyncAdapter. --> + +<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android" + android:contentAuthority="{{manifest_package}}" + android:accountType="com.google" /> +
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactDetails.java b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactDetails.java index edad68f..6068900b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactDetails.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactDetails.java
@@ -34,6 +34,8 @@ public String overflowEmailCount; public String primaryTelephoneNumber; public String overflowTelephoneNumberCount; + public String primaryAddress; + public String overflowAddressCount; } // The unique id for the contact. @@ -151,16 +153,38 @@ return displayChars; } + private String ensureSingleLine(String address) { + String returnValue = address.replaceAll("\n\n", "\n"); + // The string might have multiple consecutive new-lines, which means \n\n\n -> \n\n, so + // we'll perform the conversion until we've caught them all. + while (returnValue.length() < address.length()) { + address = returnValue; + returnValue = address.replaceAll("\n\n", "\n"); + } + + return returnValue.replaceAll("\n", ", "); + } + /** * Accessor for the list of contact details (emails and phone numbers). Returned as strings * separated by newline). + * @param includeAddresses Whether to include addresses in the returned results. * @param includeEmails Whether to include emails in the returned results. * @param includeTels Whether to include telephones in the returned results. * @return A string containing all the contact details registered for this contact. */ - public String getContactDetailsAsString(boolean includeEmails, boolean includeTels) { + public String getContactDetailsAsString( + boolean includeAddresses, boolean includeEmails, boolean includeTels) { int count = 0; StringBuilder builder = new StringBuilder(); + if (includeAddresses) { + for (PaymentAddress address : mAddresses) { + if (count++ > 0) { + builder.append("\n"); + } + builder.append(ensureSingleLine(address.addressLine[0])); + } + } if (includeEmails) { for (String email : mEmails) { if (count++ > 0) { @@ -183,15 +207,29 @@ /** * Accessor for the list of contact details (emails and phone numbers). + * @param includeAddresses Whether to include addresses in the returned results. * @param includeEmails Whether to include emails in the returned results. * @param includeTels Whether to include telephones in the returned results. * @param resources The resources to use for fetching the string. Must be provided. * @return The contact details registered for this contact. */ - public AbbreviatedContactDetails getAbbreviatedContactDetails( + public AbbreviatedContactDetails getAbbreviatedContactDetails(boolean includeAddresses, boolean includeEmails, boolean includeTels, @Nullable Resources resources) { AbbreviatedContactDetails results = new AbbreviatedContactDetails(); + results.overflowAddressCount = ""; + if (!includeAddresses || mAddresses.size() == 0) { + results.primaryAddress = ""; + } else { + results.primaryAddress = ensureSingleLine(mAddresses.get(0).addressLine[0]); + int totalAddresses = mAddresses.size(); + if (totalAddresses > 1) { + int hiddenAddresses = totalAddresses - 1; + results.overflowAddressCount = resources.getQuantityString( + R.plurals.contacts_picker_more_details, hiddenAddresses, hiddenAddresses); + } + } + results.overflowEmailCount = ""; if (!includeEmails || mEmails.size() == 0) { results.primaryEmail = "";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactView.java b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactView.java index b901f393..0298678 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactView.java
@@ -45,6 +45,8 @@ private TextView mDisplayName; // The contact details for the contact. + private TextView mAddress; + private TextView mAddressOverflowCount; private TextView mEmail; private TextView mEmailOverflowCount; private TextView mPhoneNumber; @@ -74,12 +76,15 @@ super.onFinishInflate(); mDisplayName = findViewById(R.id.title); + mAddress = findViewById(R.id.address); + mAddressOverflowCount = findViewById(R.id.address_overflow_count); mEmail = findViewById(R.id.email); mEmailOverflowCount = findViewById(R.id.email_overflow_count); mPhoneNumber = findViewById(R.id.telephone_number); mPhoneNumberOverflowCount = findViewById(R.id.telephone_number_overflow_count); mStar = findViewById(R.id.star); + mAddressOverflowCount.setOnClickListener(this); mEmailOverflowCount.setOnClickListener(this); mPhoneNumberOverflowCount.setOnClickListener(this); } @@ -87,7 +92,8 @@ @Override public void onClick(View view) { int id = view.getId(); - if (id == R.id.email_overflow_count || id == R.id.telephone_number_overflow_count) { + if (id == R.id.address_overflow_count || id == R.id.email_overflow_count + || id == R.id.telephone_number_overflow_count) { onLongClick(this); } else { super.onClick(view); @@ -119,6 +125,7 @@ .with(ModalDialogProperties.TITLE, mContactDetails.getDisplayName()) .with(ModalDialogProperties.MESSAGE, mContactDetails.getContactDetailsAsString( + PickerAdapter.includesAddresses(), PickerAdapter.includesEmails(), PickerAdapter.includesTelephones())) .with(ModalDialogProperties.POSITIVE_BUTTON_TEXT, mContext.getResources(), @@ -176,10 +183,13 @@ ContactDetails.AbbreviatedContactDetails details = contactDetails.getAbbreviatedContactDetails( + /*includeAddresses=*/PickerAdapter.includesAddresses(), /*includeEmails=*/PickerAdapter.includesEmails(), /*includeTels=*/PickerAdapter.includesTelephones(), mContext.getResources()); + updateTextViewVisibilityAndContent(mAddress, details.primaryAddress); + updateTextViewVisibilityAndContent(mAddressOverflowCount, details.overflowAddressCount); updateTextViewVisibilityAndContent(mEmail, details.primaryEmail); updateTextViewVisibilityAndContent(mEmailOverflowCount, details.overflowEmailCount); updateTextViewVisibilityAndContent(mPhoneNumber, details.primaryTelephoneNumber); @@ -215,6 +225,8 @@ private void resetTile() { setIconDrawable(null); mDisplayName.setText(""); + mAddress.setText(""); + mAddressOverflowCount.setText(""); mEmail.setText(""); mEmailOverflowCount.setText(""); mPhoneNumber.setText("");
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/PickerAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/PickerAdapter.java index fdfabbf..68eb2ef 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/PickerAdapter.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/PickerAdapter.java
@@ -65,11 +65,12 @@ * The types of filters supported. */ @Retention(RetentionPolicy.SOURCE) - @IntDef({FilterType.NAMES, FilterType.EMAILS, FilterType.TELEPHONES}) + @IntDef({FilterType.NAMES, FilterType.EMAILS, FilterType.TELEPHONES, FilterType.ADDRESSES}) public @interface FilterType { int NAMES = 0; int EMAILS = 1; int TELEPHONES = 2; + int ADDRESSES = 3; } /** @@ -122,6 +123,9 @@ // A list of search result indices into the larger data set. private ArrayList<Integer> mSearchResults; + // Whether to include addresses in the returned results. + private static boolean sIncludeAddresses; + // Whether to include names in the returned results. private static boolean sIncludeNames; @@ -148,6 +152,7 @@ mCategoryView = categoryView; mContentResolver = context.getContentResolver(); mFormattedOrigin = formattedOrigin; + sIncludeAddresses = true; sIncludeNames = true; sIncludeEmails = true; sIncludeTelephones = true; @@ -188,7 +193,8 @@ String query_lower = query.toLowerCase(Locale.getDefault()); for (ContactDetails contact : mContactDetails) { if (contact.getDisplayName().toLowerCase(Locale.getDefault()).contains(query_lower) - || contact.getContactDetailsAsString(includesEmails(), includesTelephones()) + || contact.getContactDetailsAsString(includesAddresses(), includesEmails(), + includesTelephones()) .toLowerCase(Locale.getDefault()) .contains(query_lower)) { mSearchResults.add(count); @@ -277,7 +283,8 @@ mTopView.registerChipToggledCallback(this); mTopView.updateCheckboxVisibility(mCategoryView.multiSelectionAllowed()); mTopView.updateChipVisibility(mCategoryView.includeNames, - mCategoryView.includeEmails, mCategoryView.includeTel); + mCategoryView.includeAddresses, mCategoryView.includeEmails, + mCategoryView.includeTel); mCategoryView.setTopView(mTopView); if (mContactDetails != null) mTopView.updateContactCount(mContactDetails.size()); return new TopViewHolder(mTopView); @@ -334,6 +341,9 @@ case FilterType.NAMES: sIncludeNames = !sIncludeNames; break; + case FilterType.ADDRESSES: + sIncludeAddresses = !sIncludeAddresses; + break; case FilterType.EMAILS: sIncludeEmails = !sIncludeEmails; break; @@ -348,6 +358,13 @@ } /** + * Returns true unless the adapter is filtering out addresses. + */ + public static boolean includesAddresses() { + return sIncludeAddresses; + } + + /** * Returns true unless the adapter is filtering out names. */ public static boolean includesNames() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/TopView.java b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/TopView.java index 291a284..b3979880 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/TopView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/TopView.java
@@ -64,6 +64,9 @@ // A Chip for filtering out names. private ChipView mNamesFilterChip; + // A Chip for filtering out addresses. + private ChipView mAddressFilterChip; + // A Chip for filtering out emails. private ChipView mEmailFilterChip; @@ -101,6 +104,12 @@ mNamesFilterChip.setSelected(true); mNamesFilterChip.setOnClickListener(this); + mAddressFilterChip = findViewById(R.id.address_filter); + textView = mAddressFilterChip.getPrimaryTextView(); + textView.setText(R.string.top_view_address_filter_label); + mAddressFilterChip.setSelected(true); + mAddressFilterChip.setOnClickListener(this); + mEmailFilterChip = findViewById(R.id.email_filter); textView = mEmailFilterChip.getPrimaryTextView(); textView.setText(R.string.top_view_email_filter_label); @@ -119,6 +128,8 @@ int id = view.getId(); if (id == R.id.names_filter) { notifyChipToggled(PickerAdapter.FilterType.NAMES); + } else if (id == R.id.address_filter) { + notifyChipToggled(PickerAdapter.FilterType.ADDRESSES); } else if (id == R.id.email_filter) { notifyChipToggled(PickerAdapter.FilterType.EMAILS); } else if (id == R.id.tel_filter) { @@ -137,6 +148,9 @@ case PickerAdapter.FilterType.NAMES: chipView = mNamesFilterChip; break; + case PickerAdapter.FilterType.ADDRESSES: + chipView = mAddressFilterChip; + break; case PickerAdapter.FilterType.EMAILS: chipView = mEmailFilterChip; break; @@ -194,12 +208,14 @@ /** * Updates which chips should be displayed as part of the top view. * @param shouldDisplayNames Whether the names chip should be displayed. + * @param shouldDisplayAddresses Whether the addresses chip should be displayed. * @param shouldDisplayEmails Whether the emails chip should be displayed. * @param shouldDisplayTel Whether the telephone chip should be displayed. */ - public void updateChipVisibility( - boolean shouldDisplayNames, boolean shouldDisplayEmails, boolean shouldDisplayTel) { + public void updateChipVisibility(boolean shouldDisplayNames, boolean shouldDisplayAddresses, + boolean shouldDisplayEmails, boolean shouldDisplayTel) { mNamesFilterChip.setVisibility(shouldDisplayNames ? View.VISIBLE : View.GONE); + mAddressFilterChip.setVisibility(shouldDisplayAddresses ? View.VISIBLE : View.GONE); mEmailFilterChip.setVisibility(shouldDisplayEmails ? View.VISIBLE : View.GONE); mTelephonesFilterChip.setVisibility(shouldDisplayTel ? View.VISIBLE : View.GONE); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapter.java new file mode 100644 index 0000000..1d40fcd --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapter.java
@@ -0,0 +1,44 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.invalidation; + +import android.accounts.Account; +import android.content.AbstractThreadedSyncAdapter; +import android.content.ContentProviderClient; +import android.content.ContentResolver; +import android.content.Context; +import android.content.SyncResult; +import android.os.Bundle; + +import org.chromium.components.signin.ChromeSigninController; + +/** + * A Sync adapter that integrates with Android's OS-level Sync settings. + */ +public class ChromeBrowserSyncAdapter extends AbstractThreadedSyncAdapter { + public ChromeBrowserSyncAdapter(Context context) { + super(context, false); + } + + @Override + public void onPerformSync(Account account, Bundle extras, String authority, + ContentProviderClient provider, SyncResult syncResult) { + // Make sure to only report Chrome as "syncable" if the given account matches our + // signed-in account. + if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE)) { + Account signedInAccount = ChromeSigninController.get().getSignedInUser(); + if (account.equals(signedInAccount)) { + ContentResolver.setIsSyncable(account, authority, 1); + } else { + ContentResolver.setIsSyncable(account, authority, 0); + } + return; + } + + // Else: Nothing to do; we ignore explicit requests to perform a sync, since Chrome Sync + // knows when it should perform a sync. We could consider calling + // ProfileSyncService.triggerRefresh() to honor explicit requests. + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapterService.java b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapterService.java new file mode 100644 index 0000000..1326932 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapterService.java
@@ -0,0 +1,41 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.invalidation; + +import android.annotation.SuppressLint; +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.os.IBinder; + +import org.chromium.base.ContextUtils; +import org.chromium.chrome.browser.init.ProcessInitializationHandler; + +/** + * A Service that provides access to {@link ChromeBrowserSyncAdapter}. + */ +public class ChromeBrowserSyncAdapterService extends Service { + @SuppressLint("StaticFieldLeak") + private static ChromeBrowserSyncAdapter sSyncAdapter; + private static final Object LOCK = new Object(); + + /** + * Get the sync adapter reference, creating an instance if necessary. + */ + private ChromeBrowserSyncAdapter getOrCreateSyncAdapter(Context applicationContext) { + synchronized (LOCK) { + if (sSyncAdapter == null) { + ProcessInitializationHandler.getInstance().initializePreNative(); + sSyncAdapter = new ChromeBrowserSyncAdapter(applicationContext); + } + } + return sSyncAdapter; + } + + @Override + public IBinder onBind(Intent intent) { + return getOrCreateSyncAdapter(ContextUtils.getApplicationContext()).getSyncAdapterBinder(); + } +}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contacts_picker/ContactDetailsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contacts_picker/ContactDetailsTest.java index 564c351..6219c8f 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contacts_picker/ContactDetailsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contacts_picker/ContactDetailsTest.java
@@ -52,6 +52,8 @@ Assert.assertEquals(expected.primaryTelephoneNumber, actual.primaryTelephoneNumber); Assert.assertEquals( expected.overflowTelephoneNumberCount, actual.overflowTelephoneNumberCount); + Assert.assertEquals(expected.primaryAddress, actual.primaryAddress); + Assert.assertEquals(expected.overflowAddressCount, actual.overflowAddressCount); } @Test @@ -117,11 +119,18 @@ Assert.assertEquals(true, contact.isSelf()); Assert.assertTrue(null != contact.getSelfIcon()); - Assert.assertEquals("", contact.getContactDetailsAsString(false, false)); + Assert.assertEquals("", + contact.getContactDetailsAsString(/*includeAddresses=*/false, + /*includeEmails=*/false, /*includeTels=*/false)); Assert.assertEquals("email@example.com\nemail2@example.com", - contact.getContactDetailsAsString(true, false)); - Assert.assertEquals( - "555 123-4567\n555 765-4321", contact.getContactDetailsAsString(false, true)); + contact.getContactDetailsAsString( + /*includeAddresses=*/false, /*includeEmails=*/true, /*includeTels=*/false)); + Assert.assertEquals("555 123-4567\n555 765-4321", + contact.getContactDetailsAsString( + /*includeAddresses=*/false, /*includeEmails=*/false, /*includeTels=*/true)); + Assert.assertEquals("formattedAddress1\nformattedAddress2", + contact.getContactDetailsAsString( + /*includeAddresses=*/true, /*includeEmails=*/false, /*includeTels=*/false)); Resources resources = mContext.getResources(); ContactDetails.AbbreviatedContactDetails expected = @@ -130,28 +139,98 @@ expected.overflowEmailCount = "(+ 1 more)"; expected.primaryTelephoneNumber = "555 123-4567"; expected.overflowTelephoneNumberCount = "(+ 1 more)"; + expected.primaryAddress = "formattedAddress1"; + expected.overflowAddressCount = "(+ 1 more)"; // Test with full details. ContactDetails.AbbreviatedContactDetails actual = contact.getAbbreviatedContactDetails( - /*includeEmails=*/true, /*includeTels=*/true, resources); + /*includeAddresses=*/true, /*includeEmails=*/true, /*includeTels=*/true, resources); compareAbbreviatedContactDetails(expected, actual); + // Test with only email details. actual = contact.getAbbreviatedContactDetails( - /*includeEmails=*/true, /*includeTels=*/false, resources); + /*includeAddresses=*/false, /*includeEmails=*/true, /*includeTels=*/false, + resources); expected.primaryTelephoneNumber = ""; expected.overflowTelephoneNumberCount = ""; + expected.primaryAddress = ""; + expected.overflowAddressCount = ""; compareAbbreviatedContactDetails(expected, actual); + // Test with no details. actual = contact.getAbbreviatedContactDetails( - /*includeEmails=*/false, /*includeTels=*/false, resources); + /*includeAddresses=*/false, /*includeEmails=*/false, /*includeTels=*/false, + resources); expected.primaryEmail = ""; expected.overflowEmailCount = ""; compareAbbreviatedContactDetails(expected, actual); + // Test with only telephone details. actual = contact.getAbbreviatedContactDetails( - /*includeEmails=*/false, /*includeTels=*/true, resources); + /*includeAddresses=*/false, /*includeEmails=*/false, /*includeTels=*/true, + resources); expected.primaryTelephoneNumber = "555 123-4567"; expected.overflowTelephoneNumberCount = "(+ 1 more)"; compareAbbreviatedContactDetails(expected, actual); + + // Test with only address details. + actual = contact.getAbbreviatedContactDetails( + /*includeAddresses=*/true, /*includeEmails=*/false, /*includeTels=*/false, + resources); + expected.primaryTelephoneNumber = ""; + expected.overflowTelephoneNumberCount = ""; + expected.primaryAddress = "formattedAddress1"; + expected.overflowAddressCount = "(+ 1 more)"; + compareAbbreviatedContactDetails(expected, actual); + } + + @Test + @SmallTest + public void testEnsureSingleLine() { + PaymentAddress address = new PaymentAddress(); + address.city = "city"; + address.country = "country"; + address.addressLine = new String[] {"Street\n\n\nCity\n\n\nCountry"}; + address.postalCode = "postalCode"; + address.region = "region"; + address.dependentLocality = ""; + address.sortingCode = ""; + address.organization = ""; + address.recipient = ""; + address.phone = ""; + + Resources resources = mContext.getResources(); + + // Odd number of multiple consecutive new-lines. + ContactDetails contact = + new ContactDetails("id", "Display Name", null, null, Arrays.asList(address)); + ContactDetails.AbbreviatedContactDetails abbreviated = contact.getAbbreviatedContactDetails( + /*includeAddresses=*/true, /*includeEmails=*/false, /*includeTels=*/false, + resources); + Assert.assertEquals("Street, City, Country", abbreviated.primaryAddress); + + // Even number of multiple consecutive new-lines. + address.addressLine = new String[] {"Street\n\n\n\nCity\n\n\n\nCountry"}; + contact = new ContactDetails("id", "Display Name", null, null, Arrays.asList(address)); + abbreviated = contact.getAbbreviatedContactDetails( + /*includeAddresses=*/true, /*includeEmails=*/false, /*includeTels=*/false, + resources); + Assert.assertEquals("Street, City, Country", abbreviated.primaryAddress); + + // New lines included, but none consecutive. + address.addressLine = new String[] {"Street\nCity\nCountry"}; + contact = new ContactDetails("id", "Display Name", null, null, Arrays.asList(address)); + abbreviated = contact.getAbbreviatedContactDetails( + /*includeAddresses=*/true, /*includeEmails=*/false, /*includeTels=*/false, + resources); + Assert.assertEquals("Street, City, Country", abbreviated.primaryAddress); + + // No new-lines. + address.addressLine = new String[] {"Street City Country"}; + contact = new ContactDetails("id", "Display Name", null, null, Arrays.asList(address)); + abbreviated = contact.getAbbreviatedContactDetails( + /*includeAddresses=*/true, /*includeEmails=*/false, /*includeTels=*/false, + resources); + Assert.assertEquals("Street City Country", abbreviated.primaryAddress); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contacts_picker/ContactsPickerDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contacts_picker/ContactsPickerDialogTest.java index 878eab79..7fc5bb78 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contacts_picker/ContactsPickerDialogTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contacts_picker/ContactsPickerDialogTest.java
@@ -361,13 +361,45 @@ Assert.assertNotNull(emailFilter); View telFilter = topView.findViewById(R.id.tel_filter); Assert.assertNotNull(telFilter); + View addrFilter = topView.findViewById(R.id.address_filter); + Assert.assertNotNull(addrFilter); // Per configuration given in the createDialog() call, the names and telephone filters - // should be visible, but the e-mail filter should be gone. + // should be visible, but the e-mail and address filter should be gone. Assert.assertEquals(namesFilter.getVisibility(), View.VISIBLE); Assert.assertEquals(emailFilter.getVisibility(), View.GONE); Assert.assertEquals(telFilter.getVisibility(), View.VISIBLE); - // TODO(crbug.com/1016870): Add a false test for the filter chip, when added. + Assert.assertEquals(addrFilter.getVisibility(), View.GONE); + } + + @Test + @LargeTest + public void testFilterVisibilityReverseForDataInclusion() throws Throwable { + setTestContacts(/*ownerEmail=*/null); + createDialog(/* multiselect = */ false, /* includeNames = */ false, + /* includeEmails = */ true, + /* includeTel = */ false, + /* includeAddresses = */ true); + Assert.assertTrue(mDialog.isShowing()); + + TopView topView = getTopView(); + Assert.assertNotNull(topView); + + View namesFilter = topView.findViewById(R.id.names_filter); + Assert.assertNotNull(namesFilter); + View emailFilter = topView.findViewById(R.id.email_filter); + Assert.assertNotNull(emailFilter); + View telFilter = topView.findViewById(R.id.tel_filter); + Assert.assertNotNull(telFilter); + View addrFilter = topView.findViewById(R.id.address_filter); + Assert.assertNotNull(addrFilter); + + // Per configuration given in the createDialog() call, the names and telephone filters + // should be hidden, but the e-mail and address filter should be visible. + Assert.assertEquals(namesFilter.getVisibility(), View.GONE); + Assert.assertEquals(emailFilter.getVisibility(), View.VISIBLE); + Assert.assertEquals(telFilter.getVisibility(), View.GONE); + Assert.assertEquals(addrFilter.getVisibility(), View.VISIBLE); } @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/TestVrShellDelegate.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/TestVrShellDelegate.java index abdf035..db453ab7 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/TestVrShellDelegate.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/TestVrShellDelegate.java
@@ -83,11 +83,6 @@ } @Override - public boolean isListeningForWebVrActivate() { - return super.isListeningForWebVrActivate(); - } - - @Override public boolean isVrEntryComplete() { return super.isVrEntryComplete(); } @@ -191,4 +186,4 @@ public void setAllow2dIntents(boolean allow) { mAllow2dIntents = allow; } -} \ No newline at end of file +}
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 69807cd..487508e 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -4134,6 +4134,11 @@ flag_descriptions::kMediaSessionNotificationsDescription, kOsCrOS, FEATURE_VALUE_TYPE(ash::features::kMediaSessionNotification)}, + {"enable-neural-stylus-palm-rejection", + flag_descriptions::kEnableNeuralStylusPalmRejectionName, + flag_descriptions::kEnableNeuralStylusPalmRejectionDescription, kOsCrOS, + FEATURE_VALUE_TYPE(ui::kEnableNeuralPalmDetectionFilter)}, + {"enable-heuristic-stylus-palm-rejection", flag_descriptions::kEnableHeuristicStylusPalmRejectionName, flag_descriptions::kEnableHeuristicStylusPalmRejectionDescription, kOsCrOS,
diff --git a/chrome/browser/android/vr/arcore_device/arcore_gl.cc b/chrome/browser/android/vr/arcore_device/arcore_gl.cc index 7ee8cae..399a807 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_gl.cc +++ b/chrome/browser/android/vr/arcore_device/arcore_gl.cc
@@ -413,15 +413,14 @@ frame_data->detected_planes_data = arcore_->GetDetectedPlanesData(); } - frame_data->anchors_data = arcore_->GetAnchorsData(); - fps_meter_.AddFrame(base::TimeTicks::Now()); TRACE_COUNTER1("gpu", "WebXR FPS", fps_meter_.GetFPS()); // Post a task to finish processing the frame so any calls to // RequestHitTest() that were made during this function, which can block // on the arcore_->Update() call above, can be processed in this frame. - // Additionally, this gives a chance for OnScreenTouch() tasks to run. + // Additionally, this gives a chance for OnScreenTouch() tasks to run + // and added anchors to be registered. gl_thread_task_runner_->PostTask( FROM_HERE, base::BindOnce(&ArCoreGl::ProcessFrame, weak_ptr_factory_.GetWeakPtr(), @@ -767,6 +766,9 @@ arcore_->GetHitTestSubscriptionResults(frame_data->pose); } + // Get anchors data, including anchors created this frame. + frame_data->anchors_data = arcore_->GetAnchorsData(); + // The timing requirements for hit-test are documented here: // https://github.com/immersive-web/hit-test/blob/master/explainer.md#timing // The current implementation of frame generation on the renderer side is
diff --git a/chrome/browser/android/vr/vr_shell_delegate.cc b/chrome/browser/android/vr/vr_shell_delegate.cc index 6f7824a..18a386f4 100644 --- a/chrome/browser/android/vr/vr_shell_delegate.cc +++ b/chrome/browser/android/vr/vr_shell_delegate.cc
@@ -211,23 +211,6 @@ std::move(request_present_response_callback_).Run(std::move(session)); } -void VrShellDelegate::DisplayActivate(JNIEnv* env, - const JavaParamRef<jobject>& obj) { - device::GvrDevice* gvr_device = GetGvrDevice(); - if (gvr_device) { - // The only possible source for DisplayActivate is HeadsetActivation. - possible_presentation_start_action_ = - PresentationStartAction::kHeadsetActivation; - - gvr_device->Activate( - device::mojom::VRDisplayEventReason::MOUNTED, - base::BindRepeating(&VrShellDelegate::OnActivateDisplayHandled, - weak_ptr_factory_.GetWeakPtr())); - } else { - OnActivateDisplayHandled(true /* will_not_present */); - } -} - void VrShellDelegate::OnPause(JNIEnv* env, const JavaParamRef<jobject>& obj) { if (vr_shell_) return; @@ -289,22 +272,6 @@ Java_VrShellDelegate_getVrCoreInfo(env, j_vr_shell_delegate_))); } -void VrShellDelegate::OnActivateDisplayHandled(bool will_not_present) { - if (will_not_present) { - // WebVR page didn't request presentation in the vrdisplayactivate handler. - // Tell VrShell that we are in VR Browsing Mode. - ExitWebVRPresent(); - // Reset possible_presentation_start_action_ as it may have been set. - possible_presentation_start_action_ = base::nullopt; - } -} - -void VrShellDelegate::OnListeningForActivateChanged(bool listening) { - JNIEnv* env = AttachCurrentThread(); - Java_VrShellDelegate_setListeningForWebVrActivate(env, j_vr_shell_delegate_, - listening); -} - void VrShellDelegate::OnRuntimeAdded(vr::BrowserXRRuntime* runtime) { if (vr_shell_) { // See comment in VrShellDelegate::SetDelegate. This handles the case where
diff --git a/chrome/browser/android/vr/vr_shell_delegate.h b/chrome/browser/android/vr/vr_shell_delegate.h index 55b2e9a5f..23c26fa 100644 --- a/chrome/browser/android/vr/vr_shell_delegate.h +++ b/chrome/browser/android/vr/vr_shell_delegate.h
@@ -59,8 +59,6 @@ jboolean success); void RecordVrStartAction(JNIEnv* env, jint start_action); - void DisplayActivate(JNIEnv* env, - const base::android::JavaParamRef<jobject>& obj); void OnPause(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj); void OnResume(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj); bool IsClearActivatePending(JNIEnv* env, @@ -81,7 +79,6 @@ device::mojom::VRDisplayInfoPtr display_info, device::mojom::XRRuntimeSessionOptionsPtr options, base::OnceCallback<void(device::mojom::XRSessionPtr)> callback) override; - void OnListeningForActivateChanged(bool listening) override; // vr::XRRuntimeManagerObserver implementation. // VrShellDelegate implements XRRuntimeManagerObserver to turn off poses (by @@ -91,9 +88,6 @@ // VrShell got created, their poses will be turned off too on its // creation. void OnRuntimeAdded(vr::BrowserXRRuntime* runtime) override; - - void OnActivateDisplayHandled(bool will_not_present); - void SetListeningForActivate(bool listening); void OnPresentResult( device::mojom::VRDisplayInfoPtr display_info, device::mojom::XRRuntimeSessionOptionsPtr options,
diff --git a/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc b/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc index cecdbeb..e0d7db6 100644 --- a/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc +++ b/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc
@@ -1451,7 +1451,7 @@ ui::CompositionText composition; composition.text = base::UTF8ToUTF16("InputTest456"); text_input_client->SetCompositionText(composition); - text_input_client->ConfirmCompositionText(); + text_input_client->ConfirmCompositionText(/* keep_selection */ false); EXPECT_TRUE(content::ExecuteScript( embedder_web_contents, "window.runCommand('testInputMethodRunNextStep', 2);"));
diff --git a/chrome/browser/apps/intent_helper/intent_picker_auto_display_pref.cc b/chrome/browser/apps/intent_helper/intent_picker_auto_display_pref.cc index 4d4be30..91c47897 100644 --- a/chrome/browser/apps/intent_helper/intent_picker_auto_display_pref.cc +++ b/chrome/browser/apps/intent_helper/intent_picker_auto_display_pref.cc
@@ -17,6 +17,7 @@ constexpr int kDismissThreshold = 2; constexpr char kAutoDisplayKey[] = "picker_auto_display_key"; +constexpr char kPlatformKey[] = "picker_platform_key"; // Retrieves or creates a new dictionary for the specific |origin|. std::unique_ptr<base::DictionaryValue> GetAutoDisplayDictForSettings( @@ -60,11 +61,28 @@ return ui_dismissed_counter_ < kDismissThreshold; } +IntentPickerAutoDisplayPref::Platform +IntentPickerAutoDisplayPref::GetPlatform() { + return platform_; +} + +void IntentPickerAutoDisplayPref::UpdatePlatform(Platform platform) { + if (!pref_dict_) + return; + + DCHECK_GE(static_cast<int>(platform), static_cast<int>(Platform::kNone)); + DCHECK_LE(static_cast<int>(platform), static_cast<int>(Platform::kMaxValue)); + platform_ = platform; + pref_dict_->SetInteger(kPlatformKey, static_cast<int>(platform_)); + Commit(); +} + IntentPickerAutoDisplayPref::IntentPickerAutoDisplayPref( const GURL& origin, std::unique_ptr<base::DictionaryValue> pref_dict) : origin_(origin), pref_dict_(pref_dict.release()) { ui_dismissed_counter_ = QueryDismissedCounter(); + platform_ = QueryPlatform(); } int IntentPickerAutoDisplayPref::QueryDismissedCounter() { @@ -73,6 +91,8 @@ int counter = 0; pref_dict_->GetInteger(kAutoDisplayKey, &counter); + DCHECK_GE(counter, static_cast<int>(Platform::kNone)); + DCHECK_LE(counter, static_cast<int>(Platform::kMaxValue)); return counter; } @@ -87,6 +107,19 @@ pref_dict_->SetInteger(kAutoDisplayKey, ui_dismissed_counter_); } +IntentPickerAutoDisplayPref::Platform +IntentPickerAutoDisplayPref::QueryPlatform() { + if (!pref_dict_) + return Platform::kNone; + + int platform = 0; + pref_dict_->GetInteger(kPlatformKey, &platform); + DCHECK_GE(platform, static_cast<int>(Platform::kNone)); + DCHECK_LT(platform, static_cast<int>(Platform::kMaxValue)); + + return static_cast<Platform>(platform); +} + void IntentPickerAutoDisplayPref::Commit() { settings_map_->SetWebsiteSettingDefaultScope( origin_, origin_, ContentSettingsType::INTENT_PICKER_DISPLAY,
diff --git a/chrome/browser/apps/intent_helper/intent_picker_auto_display_pref.h b/chrome/browser/apps/intent_helper/intent_picker_auto_display_pref.h index bdebc09a..319c9df 100644 --- a/chrome/browser/apps/intent_helper/intent_picker_auto_display_pref.h +++ b/chrome/browser/apps/intent_helper/intent_picker_auto_display_pref.h
@@ -17,6 +17,10 @@ // UI for a given origin. class IntentPickerAutoDisplayPref final { public: + // The platform selected by the user to handle this URL for devices of tablet + // form factor. + enum class Platform { kNone = 0, kArc = 1, kChrome = 2, kMaxValue = kChrome }; + IntentPickerAutoDisplayPref(const GURL& origin, HostContentSettingsMap* settings); ~IntentPickerAutoDisplayPref(); @@ -25,6 +29,10 @@ bool HasExceededThreshold(); + Platform GetPlatform(); + + void UpdatePlatform(Platform platform); + private: // Creates and keep track of the dictionary for this specific origin. IntentPickerAutoDisplayPref(const GURL& origin, @@ -34,6 +42,8 @@ void SetDismissedCounter(int new_counter); + Platform QueryPlatform(); + void Commit(); // Origin associated to this preference. @@ -41,6 +51,10 @@ int ui_dismissed_counter_; + // The platform selected by the user to handle link navigations with. + // This is only for devices of tablet form factor. + Platform platform_; + // Dictionary for this particular preference. std::unique_ptr<base::DictionaryValue> pref_dict_;
diff --git a/chrome/browser/apps/intent_helper/intent_picker_auto_display_service.cc b/chrome/browser/apps/intent_helper/intent_picker_auto_display_service.cc index 632806e..d57ade46 100644 --- a/chrome/browser/apps/intent_helper/intent_picker_auto_display_service.cc +++ b/chrome/browser/apps/intent_helper/intent_picker_auto_display_service.cc
@@ -6,7 +6,6 @@ #include <memory> -#include "chrome/browser/apps/intent_helper/intent_picker_auto_display_pref.h" #include "chrome/browser/apps/intent_helper/intent_picker_auto_display_service_factory.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" @@ -41,3 +40,14 @@ void IntentPickerAutoDisplayService::IncrementCounter(const GURL& url) { CreateLocalPreference(profile_, url)->IncrementCounter(); } + +IntentPickerAutoDisplayPref::Platform +IntentPickerAutoDisplayService::GetLastUsedPlatformForTablets(const GURL& url) { + return CreateLocalPreference(profile_, url)->GetPlatform(); +} + +void IntentPickerAutoDisplayService::UpdatePlatformForTablets( + const GURL& url, + IntentPickerAutoDisplayPref::Platform platform) { + CreateLocalPreference(profile_, url)->UpdatePlatform(platform); +}
diff --git a/chrome/browser/apps/intent_helper/intent_picker_auto_display_service.h b/chrome/browser/apps/intent_helper/intent_picker_auto_display_service.h index 4070c14..a198cc2 100644 --- a/chrome/browser/apps/intent_helper/intent_picker_auto_display_service.h +++ b/chrome/browser/apps/intent_helper/intent_picker_auto_display_service.h
@@ -6,6 +6,7 @@ #define CHROME_BROWSER_APPS_INTENT_HELPER_INTENT_PICKER_AUTO_DISPLAY_SERVICE_H_ #include "base/macros.h" +#include "chrome/browser/apps/intent_helper/intent_picker_auto_display_pref.h" #include "components/keyed_service/core/keyed_service.h" #include "url/gurl.h" @@ -28,6 +29,17 @@ // Keep track of the |url| repetitions. void IncrementCounter(const GURL& url); + // Returns the last platform selected by the user to handle |url|. + // If it has not been checked then it will return |Platform::kNone| + // for devices of tablet form factor. + IntentPickerAutoDisplayPref::Platform GetLastUsedPlatformForTablets( + const GURL& url); + + // Updates the Platform to |platform| for |url| for devices of + // tablet form factor. + void UpdatePlatformForTablets(const GURL& url, + IntentPickerAutoDisplayPref::Platform platform); + private: Profile* profile_;
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc index 74335c50..cd3a18c 100644 --- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc +++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
@@ -865,6 +865,9 @@ password_store->RemoveLeakedCredentialsByUrlAndTime( nullable_filter, delete_begin_, delete_end_, CreateTaskCompletionClosure(TracingDataType::kLeakedCredentials)); + password_store->RemoveFieldInfoByTime( + delete_begin_, delete_end_, + CreateTaskCompletionClosure(TracingDataType::kFieldInfo)); } }
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h index 56a73802..ae53976 100644 --- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h +++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h
@@ -227,7 +227,8 @@ kTpmAttestationKeys = 30, kStrikes = 31, kLeakedCredentials = 32, - kMaxValue = kLeakedCredentials, + kFieldInfo = 33, + kMaxValue = kFieldInfo, }; // Called by CreateTaskCompletionClosure().
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 737ae4e..8dc95a1 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -3655,6 +3655,23 @@ render_frame_host); } +#if defined(OS_WIN) || defined(OS_MACOSX) || \ + (defined(OS_LINUX) && !defined(OS_CHROMEOS)) +bool ShouldEnableAudioSandbox(const policy::PolicyMap& policies) { + const base::Value* audio_sandbox_enabled_policy_value = + policies.GetValue(policy::key::kAudioSandboxEnabled); + if (audio_sandbox_enabled_policy_value) { + bool force_enable_audio_sandbox; + audio_sandbox_enabled_policy_value->GetAsBoolean( + &force_enable_audio_sandbox); + return force_enable_audio_sandbox; + } + + return base::FeatureList::IsEnabled( + service_manager::features::kAudioServiceSandbox); +} +#endif + void ChromeContentBrowserClient::WillStartServiceManager() { #if defined(OS_WIN) || defined(OS_MACOSX) || \ (defined(OS_LINUX) && !defined(OS_CHROMEOS)) @@ -3679,14 +3696,9 @@ #endif bool enable_audio_process = base::FeatureList::IsEnabled(features::kAudioServiceOutOfProcess); - bool enable_audio_sandbox = base::FeatureList::IsEnabled( - service_manager::features::kAudioServiceSandbox); - const base::Value* audio_sandbox_enabled_policy_value = - policies.GetValue(policy::key::kAudioSandboxEnabled); - if (audio_sandbox_enabled_policy_value) - audio_sandbox_enabled_policy_value->GetAsBoolean(&enable_audio_sandbox); - service_manager::EnableAudioSandbox(enable_audio_sandbox); - if (!enable_audio_sandbox || !enable_audio_process) { + + service_manager::EnableAudioSandbox(ShouldEnableAudioSandbox(policies)); + if (!service_manager::IsAudioSandboxEnabled() || !enable_audio_process) { // Disabling the audio process or audio sandbox implies disabling APM in // the audio service for security reasons. Append a switch so that this // is communicated to the audio and renderer processes.
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index 7e6d1fb..8e200cf 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -2337,7 +2337,7 @@ } } -copy("dbus_service_files") { +action("dbus_service_files") { sources = [ "dbus/org.chromium.ChromeFeaturesService.conf", "dbus/org.chromium.ComponentUpdaterService.conf", @@ -2353,9 +2353,14 @@ "dbus/org.chromium.VirtualFileRequestService.conf", "dbus/org.chromium.VmApplicationsService.conf", ] + output_conf_file = "$root_out_dir/dbus/chrome_dbus_services.conf" outputs = [ - "$root_out_dir/dbus/{{source_file_part}}", + output_conf_file, ] + + script = "//chromeos/tools/concat_dbus_conf_files.py" + args = [ rebase_path(output_conf_file, root_build_dir) ] + args += rebase_path(sources, root_build_dir) } static_library("arc_test_support") { @@ -2930,32 +2935,13 @@ "../ui/webui/settings/chromeos/device_keyboard_handler_unittest.cc", "../ui/webui/settings/chromeos/internet_handler_unittest.cc", "../ui/webui/settings/chromeos/multidevice_handler_unittest.cc", - "//components/drive/about_resource_loader_unittest.cc", - "//components/drive/change_list_loader_unittest.cc", "//components/drive/change_list_processor_unittest.cc", "//components/drive/chromeos/file_cache_unittest.cc", - "//components/drive/directory_loader_unittest.cc", "//components/drive/drive_file_util_unittest.cc", "//components/drive/drive_notification_manager_unittest.cc", "//components/drive/drive_operation_queue_unittest.cc", - "//components/drive/fake_file_system_unittest.cc", "//components/drive/file_change_unittest.cc", - "//components/drive/file_system/copy_operation_unittest.cc", - "//components/drive/file_system/create_directory_operation_unittest.cc", - "//components/drive/file_system/create_file_operation_unittest.cc", - "//components/drive/file_system/download_operation_unittest.cc", - "//components/drive/file_system/get_file_for_saving_operation_unittest.cc", - "//components/drive/file_system/move_operation_unittest.cc", - "//components/drive/file_system/open_file_operation_unittest.cc", - "//components/drive/file_system/operation_test_base.cc", - "//components/drive/file_system/operation_test_base.h", - "//components/drive/file_system/remove_operation_unittest.cc", - "//components/drive/file_system/search_operation_unittest.cc", - "//components/drive/file_system/set_property_operation_unittest.cc", - "//components/drive/file_system/touch_operation_unittest.cc", - "//components/drive/file_system/truncate_operation_unittest.cc", "//components/drive/file_system_core_util_unittest.cc", - "//components/drive/file_system_unittest.cc", "//components/drive/file_write_watcher_unittest.cc", "//components/drive/job_queue_unittest.cc", "//components/drive/job_scheduler_unittest.cc", @@ -2965,13 +2951,6 @@ "//components/drive/resource_metadata_storage_unittest.cc", "//components/drive/resource_metadata_unittest.cc", "//components/drive/search_metadata_unittest.cc", - "//components/drive/start_page_token_loader_unittest.cc", - "//components/drive/sync/entry_revert_performer_unittest.cc", - "//components/drive/sync/entry_update_performer_unittest.cc", - "//components/drive/sync/remove_performer_unittest.cc", - "//components/drive/sync_client_unittest.cc", - "//components/drive/team_drive_change_list_loader_unittest.cc", - "//components/drive/team_drive_list_loader_unittest.cc", ] public_deps = [
diff --git a/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.cc b/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.cc index be1516b..97bfc26 100644 --- a/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.cc +++ b/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.cc
@@ -18,6 +18,7 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_window.h" +#include "chromeos/constants/chromeos_switches.h" #include "components/arc/intent_helper/arc_intent_helper_bridge.h" #include "components/arc/metrics/arc_metrics_constants.h" #include "content/public/browser/browser_context.h" @@ -66,6 +67,21 @@ apps::PickerEntryType entry_type, apps::IntentPickerCloseReason close_reason, bool should_persist) { + if (chromeos::switches::IsTabletFormFactor() && should_persist) { + // On devices of tablet form factor, until the user has decided to persist + // the setting, the browser-side intent picker should always be seen. + auto platform = IntentPickerAutoDisplayPref::Platform::kNone; + if (entry_type == apps::PickerEntryType::kArc) { + platform = IntentPickerAutoDisplayPref::Platform::kArc; + } else if (entry_type == apps::PickerEntryType::kUnknown && + close_reason == apps::IntentPickerCloseReason::STAY_IN_CHROME) { + platform = IntentPickerAutoDisplayPref::Platform::kChrome; + } + IntentPickerAutoDisplayService::Get( + Profile::FromBrowserContext(web_contents->GetBrowserContext())) + ->UpdatePlatformForTablets(url, platform); + } + const bool should_launch_app = close_reason == apps::IntentPickerCloseReason::OPEN_APP; switch (entry_type) { @@ -217,14 +233,17 @@ bool ChromeOsAppsNavigationThrottle::ShouldDeferNavigationForArc( content::NavigationHandle* handle) { // Query for ARC apps, and if we are handling a link navigation, allow the - // preferred app (if it exists) to be launched. + // preferred app (if it exists) to be launched unless we are on a device + // of tablet form factor, which will only launch the app if the user has + // explicitly set that app as preferred and persisted that setting via the + // intent picker previously. if (arc_enabled_ && arc::ArcIntentPickerAppFetcher::WillGetArcAppsForNavigation( handle, base::BindOnce( &ChromeOsAppsNavigationThrottle::OnDeferredNavigationProcessed, weak_factory_.GetWeakPtr()), - /*should_launch_preferred_app=*/navigate_from_link())) { + ShouldLaunchPreferredApp(handle->GetURL()))) { return true; } return false; @@ -260,6 +279,14 @@ const std::vector<apps::IntentPickerAppInfo>& apps_for_picker, content::WebContents* web_contents, const GURL& url) { + // On devices with tablet form factor we should not pop out the intent + // picker if Chrome has been chosen by the user as the platform for this URL. + if (chromeos::switches::IsTabletFormFactor()) { + if (ui_auto_display_service_->GetLastUsedPlatformForTablets(url) == + IntentPickerAutoDisplayPref::Platform::kChrome) { + return PickerShowState::kOmnibox; + } + } return ShouldAutoDisplayUi(apps_for_picker, web_contents, url) && navigate_from_link() ? PickerShowState::kPopOut @@ -299,4 +326,18 @@ DCHECK(ui_auto_display_service_); return ui_auto_display_service_->ShouldAutoDisplayUi(url); } + +bool ChromeOsAppsNavigationThrottle::ShouldLaunchPreferredApp(const GURL& url) { + DCHECK(ui_auto_display_service_); + // Devices of tablet form factor should only launch a preferred app + // from Chrome if it has been explicitly set and persisted by the user in the + // intent picker previously. + if (chromeos::switches::IsTabletFormFactor() && + ui_auto_display_service_->GetLastUsedPlatformForTablets(url) != + IntentPickerAutoDisplayPref::Platform::kArc) { + return false; + } + return navigate_from_link(); +} + } // namespace chromeos
diff --git a/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.h b/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.h index ce344e4b..8d01621 100644 --- a/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.h +++ b/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.h
@@ -122,6 +122,9 @@ content::WebContents* web_contents, const GURL& url); + // Whether or not we should launch preferred ARC apps. + bool ShouldLaunchPreferredApp(const GURL& url); + // True if ARC is enabled, false otherwise. const bool arc_enabled_;
diff --git a/chrome/browser/chromeos/login/lock/views_screen_locker.cc b/chrome/browser/chromeos/login/lock/views_screen_locker.cc index 6907dd1..6f276365 100644 --- a/chrome/browser/chromeos/login/lock/views_screen_locker.cc +++ b/chrome/browser/chromeos/login/lock/views_screen_locker.cc
@@ -227,25 +227,18 @@ focused_pod_account_id_ = base::Optional<AccountId>(account_id); - const user_manager::User* user = - user_manager::UserManager::Get()->FindUser(account_id); - // |user| may be null in kiosk mode or unit tests. - if (user && user->is_logged_in() && !user->is_active()) { - SessionControllerClientImpl::DoSwitchActiveUser(account_id); - } else { - lock_screen_utils::SetUserInputMethod(account_id.GetUserEmail(), - ime_state_.get()); - lock_screen_utils::SetKeyboardSettings(account_id); - WallpaperControllerClient::Get()->ShowUserWallpaper(account_id); + lock_screen_utils::SetUserInputMethod(account_id.GetUserEmail(), + ime_state_.get()); + lock_screen_utils::SetKeyboardSettings(account_id); + WallpaperControllerClient::Get()->ShowUserWallpaper(account_id); - bool use_24hour_clock = false; - if (user_manager::known_user::GetBooleanPref( - account_id, prefs::kUse24HourClock, &use_24hour_clock)) { - g_browser_process->platform_part() - ->GetSystemClock() - ->SetLastFocusedPodHourClockType( - use_24hour_clock ? base::k24HourClock : base::k12HourClock); - } + bool use_24hour_clock = false; + if (user_manager::known_user::GetBooleanPref( + account_id, prefs::kUse24HourClock, &use_24hour_clock)) { + g_browser_process->platform_part() + ->GetSystemClock() + ->SetLastFocusedPodHourClockType(use_24hour_clock ? base::k24HourClock + : base::k12HourClock); } }
diff --git a/chrome/browser/chromeos/login/ui/login_web_dialog.cc b/chrome/browser/chromeos/login/ui/login_web_dialog.cc index 312ce17..7cc30bb 100644 --- a/chrome/browser/chromeos/login/ui/login_web_dialog.cc +++ b/chrome/browser/chromeos/login/ui/login_web_dialog.cc
@@ -114,8 +114,7 @@ return stack.empty() ? nullptr : stack.front(); } -void LoginWebDialog::OnDialogShown(content::WebUI* webui, - content::RenderViewHost* render_view_host) { +void LoginWebDialog::OnDialogShown(content::WebUI* webui) { g_web_contents_stack.Pointer()->push_front(webui->GetWebContents()); }
diff --git a/chrome/browser/chromeos/login/ui/login_web_dialog.h b/chrome/browser/chromeos/login/ui/login_web_dialog.h index 10bfcb7..fb831ae 100644 --- a/chrome/browser/chromeos/login/ui/login_web_dialog.h +++ b/chrome/browser/chromeos/login/ui/login_web_dialog.h
@@ -66,8 +66,7 @@ void GetDialogSize(gfx::Size* size) const override; void GetMinimumDialogSize(gfx::Size* size) const override; std::string GetDialogArgs() const override; - void OnDialogShown(content::WebUI* webui, - content::RenderViewHost* render_view_host) override; + void OnDialogShown(content::WebUI* webui) override; // NOTE: This function deletes this object at the end. void OnDialogClosed(const std::string& json_retval) override; void OnCloseContents(content::WebContents* source,
diff --git a/chrome/browser/chromeos/policy/system_log_uploader_unittest.cc b/chrome/browser/chromeos/policy/system_log_uploader_unittest.cc index a3d8a82..49488980b 100644 --- a/chrome/browser/chromeos/policy/system_log_uploader_unittest.cc +++ b/chrome/browser/chromeos/policy/system_log_uploader_unittest.cc
@@ -295,10 +295,11 @@ base::HistogramTester histogram_tester_; }; +// TODO(crbug.com/1022591) Disabled because of flakiness. // Verify log throttling. Try successive kLogThrottleCount log uploads by // creating a new task. First kLogThrottleCount logs should have 0 delay. // Successive logs should have approx. kLogThrottleWindowDuration delay. -TEST_P(SystemLogUploaderTest, LogThrottleTest) { +TEST_P(SystemLogUploaderTest, DISABLED_LogThrottleTest) { for (int upload_num = 0; upload_num < SystemLogUploader::kLogThrottleCount + 3; upload_num++) { EXPECT_FALSE(task_runner_->HasPendingTask());
diff --git a/chrome/browser/extensions/api/identity/gaia_web_auth_flow.cc b/chrome/browser/extensions/api/identity/gaia_web_auth_flow.cc index f8677cb1..94e82cb 100644 --- a/chrome/browser/extensions/api/identity/gaia_web_auth_flow.cc +++ b/chrome/browser/extensions/api/identity/gaia_web_auth_flow.cc
@@ -90,8 +90,7 @@ account_id_, base::BindOnce(&GaiaWebAuthFlow::OnUbertokenFetchComplete, base::Unretained(this)), - gaia::GaiaSource::kChrome, profile_->GetURLLoaderFactory(), - /*bound_to_channel_id=*/false); + gaia::GaiaSource::kChrome, profile_->GetURLLoaderFactory()); } void GaiaWebAuthFlow::OnUbertokenFetchComplete(GoogleServiceAuthError error,
diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc index c56489c..3941291f 100644 --- a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc +++ b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
@@ -712,6 +712,18 @@ } ExtensionFunction::ResponseAction +InputMethodPrivateFinishComposingTextFunction::Run() { + InputMethodEngine* engine = GetEngineIfActive( + Profile::FromBrowserContext(browser_context()), extension_id()); + if (!engine) + return RespondNow(Error(kInputImeApiChromeOSErrorEngineNotAvailable)); + + engine->ConfirmCompositionText(/* reset_engine */ false, + /* keep_selection */ true); + return RespondNow(NoArguments()); +} + +ExtensionFunction::ResponseAction InputMethodPrivateNotifyImeMenuItemActivatedFunction::Run() { chromeos::input_method::InputMethodDescriptor current_input_method = chromeos::input_method::InputMethodManager::Get()
diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.h b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.h index 12a8e009..e717357 100644 --- a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.h +++ b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.h
@@ -114,6 +114,26 @@ ResponseAction Run() override; }; +class InputMethodPrivateFinishComposingTextFunction : public ExtensionFunction { + public: + InputMethodPrivateFinishComposingTextFunction( + const InputMethodPrivateFinishComposingTextFunction&) = delete; + InputMethodPrivateFinishComposingTextFunction& operator=( + const InputMethodPrivateFinishComposingTextFunction&) = delete; + + InputMethodPrivateFinishComposingTextFunction() = default; + + protected: + ~InputMethodPrivateFinishComposingTextFunction() override = default; + + // ExtensionFunction: + ResponseAction Run() override; + + private: + DECLARE_EXTENSION_FUNCTION("inputMethodPrivate.finishComposingText", + INPUTMETHODPRIVATE_FINISHCOMPOSINGTEXT) +}; + class InputMethodPrivateNotifyImeMenuItemActivatedFunction : public ExtensionFunction { public:
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 21ac126..8fbe1df 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -1549,6 +1549,13 @@ "expiry_milestone": -1 }, { + "name": "enable-neural-stylus-palm-rejection", + "owners": ["robsc", "napper", "adlr"], + // We add a neural net to change how fingers are handled. We set a milestone + // deep into the future to allow for experiments. + "expiry_milestone": 90 + }, + { "name": "enable-new-download-backend", "owners": [ "shaktisahu", "dtrainor" ], "expiry_milestone": 80
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index f356d98..b36de73 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -3497,6 +3497,12 @@ const char kEnableHomeLauncherDescription[] = "Enable home launcher in tablet mode."; +const char kEnableNeuralStylusPalmRejectionName[] = + "Enable Neural Palm Detection"; +const char kEnableNeuralStylusPalmRejectionDescription[] = + "Experimental: Enable Neural Palm detection. Not compatible with all " + "devices."; + const char kEnableParentalControlsSettingsName[] = "Enable Parental controls settings"; const char kEnableParentalControlsSettingsDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 99073a74..411e4a1 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -2068,6 +2068,9 @@ extern const char kEnableHomeLauncherName[]; extern const char kEnableHomeLauncherDescription[]; +extern const char kEnableNeuralStylusPalmRejectionName[]; +extern const char kEnableNeuralStylusPalmRejectionDescription[]; + extern const char kEnableParentalControlsSettingsName[]; extern const char kEnableParentalControlsSettingsDescription[];
diff --git a/chrome/browser/offline_pages/offline_page_request_handler_unittest.cc b/chrome/browser/offline_pages/offline_page_request_handler_unittest.cc index 69b55ac..53716127 100644 --- a/chrome/browser/offline_pages/offline_page_request_handler_unittest.cc +++ b/chrome/browser/offline_pages/offline_page_request_handler_unittest.cc
@@ -43,6 +43,7 @@ #include "content/public/common/previews_state.h" #include "content/public/common/resource_type.h" #include "content/public/test/browser_task_environment.h" +#include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/system/wait.h" #include "net/base/filename_util.h" #include "net/http/http_request_headers.h" @@ -154,8 +155,7 @@ virtual ~Observer() {} }; - explicit TestURLLoaderClient(Observer* observer) - : observer_(observer), binding_(this) {} + explicit TestURLLoaderClient(Observer* observer) : observer_(observer) {} ~TestURLLoaderClient() override {} void OnReceiveResponse( @@ -190,9 +190,9 @@ network::mojom::URLLoaderClientPtr CreateInterfacePtr() { network::mojom::URLLoaderClientPtr client_ptr; - binding_.Bind(mojo::MakeRequest(&client_ptr)); - binding_.set_connection_error_handler(base::BindOnce( - &TestURLLoaderClient::OnConnectionError, base::Unretained(this))); + receiver_.Bind(mojo::MakeRequest(&client_ptr)); + receiver_.set_disconnect_handler(base::BindOnce( + &TestURLLoaderClient::OnMojoDisconnect, base::Unretained(this))); return client_ptr; } @@ -203,10 +203,10 @@ } private: - void OnConnectionError() {} + void OnMojoDisconnect() {} Observer* observer_ = nullptr; - mojo::Binding<network::mojom::URLLoaderClient> binding_; + mojo::Receiver<network::mojom::URLLoaderClient> receiver_{this}; mojo::ScopedDataPipeConsumerHandle response_body_; network::URLLoaderCompletionStatus completion_status_;
diff --git a/chrome/browser/optimization_guide/optimization_guide_hints_manager.cc b/chrome/browser/optimization_guide/optimization_guide_hints_manager.cc index 541df95b..517b626 100644 --- a/chrome/browser/optimization_guide/optimization_guide_hints_manager.cc +++ b/chrome/browser/optimization_guide/optimization_guide_hints_manager.cc
@@ -848,11 +848,16 @@ // If we do not have a hint already loaded and we do not have one in the // cache, we do not know what to do with the URL so just return. // Otherwise, we do have information, but we just do not know it yet. - *optimization_type_decision = - has_hint_in_cache - ? optimization_guide::OptimizationTypeDecision:: - kHadHintButNotLoadedInTime - : optimization_guide::OptimizationTypeDecision::kNoHintAvailable; + if (has_hint_in_cache) { + *optimization_type_decision = optimization_guide:: + OptimizationTypeDecision::kHadHintButNotLoadedInTime; + } else if (IsHintBeingFetched(url.host())) { + *optimization_type_decision = optimization_guide:: + OptimizationTypeDecision::kHintFetchStartedButNotAvailableInTime; + } else { + *optimization_type_decision = + optimization_guide::OptimizationTypeDecision::kNoHintAvailable; + } return; } if (!matched_page_hint) { @@ -930,7 +935,8 @@ return; } - if (IsAllowedToFetchNavigationHints(navigation_handle->GetURL())) { + if (IsAllowedToFetchNavigationHints(navigation_handle->GetURL()) && + !hint_cache_->HasHint(navigation_handle->GetURL().host())) { std::vector<std::string> hosts{navigation_handle->GetURL().host()}; navigation_hosts_last_fetched_real_time_.clear(); navigation_hosts_last_fetched_real_time_.push_back( @@ -956,3 +962,10 @@ optimization_guide::HintsFetcher::ClearHostsSuccessfullyFetched( pref_service_); } + +bool OptimizationGuideHintsManager::IsHintBeingFetched( + const std::string& host) const { + return std::find(navigation_hosts_last_fetched_real_time_.begin(), + navigation_hosts_last_fetched_real_time_.end(), + host) != navigation_hosts_last_fetched_real_time_.end(); +}
diff --git a/chrome/browser/optimization_guide/optimization_guide_hints_manager.h b/chrome/browser/optimization_guide/optimization_guide_hints_manager.h index 118ac516..2855b73d 100644 --- a/chrome/browser/optimization_guide/optimization_guide_hints_manager.h +++ b/chrome/browser/optimization_guide/optimization_guide_hints_manager.h
@@ -270,6 +270,10 @@ const base::Optional<NavigationPredictorKeyedService::Prediction>& prediction) override; + // Returns whether a hint for |host| is currently being fetched from the + // remote Optimization Guide Service. + bool IsHintBeingFetched(const std::string& host) const; + // The OptimizationGuideService that this guide is listening to. Not owned. optimization_guide::OptimizationGuideService* const optimization_guide_service_;
diff --git a/chrome/browser/optimization_guide/optimization_guide_hints_manager_unittest.cc b/chrome/browser/optimization_guide/optimization_guide_hints_manager_unittest.cc index cd4c53d3..b0879e8 100644 --- a/chrome/browser/optimization_guide/optimization_guide_hints_manager_unittest.cc +++ b/chrome/browser/optimization_guide/optimization_guide_hints_manager_unittest.cc
@@ -1942,6 +1942,30 @@ } TEST_F(OptimizationGuideHintsManagerTest, + HintsFetchedAtNavigationTime_HasComponentHintButNotFetched) { + hints_manager()->RegisterOptimizationTypes( + {optimization_guide::proto::DEFER_ALL_SCRIPT}); + base::test::ScopedFeatureList scoped_list; + scoped_list.InitAndEnableFeature( + optimization_guide::features::kOptimizationHintsFetching); + InitializeWithDefaultConfig("1.0.0.0"); + + // Set ECT estimate so hint is activated. + hints_manager()->OnEffectiveConnectionTypeChanged( + net::EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_SLOW_2G); + std::unique_ptr<content::MockNavigationHandle> navigation_handle = + CreateMockNavigationHandleWithOptimizationGuideWebContentsObserver( + url_with_hints()); + base::RunLoop run_loop; + base::HistogramTester histogram_tester; + hints_manager()->OnNavigationStartOrRedirect(navigation_handle.get(), + run_loop.QuitClosure()); + run_loop.Run(); + histogram_tester.ExpectTotalCount( + "OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 0); +} + +TEST_F(OptimizationGuideHintsManagerTest, HintsNotFetchedAtNavigationTime_ECT_4G) { hints_manager()->RegisterOptimizationTypes( {optimization_guide::proto::DEFER_ALL_SCRIPT}); @@ -1965,6 +1989,35 @@ "OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 0); } +TEST_F(OptimizationGuideHintsManagerTest, CanApplyOptimizationCalledMidFetch) { + hints_manager()->RegisterOptimizationTypes( + {optimization_guide::proto::DEFER_ALL_SCRIPT}); + base::test::ScopedFeatureList scoped_list; + scoped_list.InitAndEnableFeature( + optimization_guide::features::kOptimizationHintsFetching); + InitializeWithDefaultConfig("1.0.0.0"); + + // Set ECT estimate so hint will attempt to be fetched. + hints_manager()->OnEffectiveConnectionTypeChanged( + net::EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_2G); + std::unique_ptr<content::MockNavigationHandle> navigation_handle = + CreateMockNavigationHandleWithOptimizationGuideWebContentsObserver( + url_without_hints()); + hints_manager()->OnNavigationStartOrRedirect(navigation_handle.get(), + base::DoNothing()); + optimization_guide::OptimizationTargetDecision unused_target_decision; + optimization_guide::OptimizationTypeDecision optimization_type_decision; + hints_manager()->CanApplyOptimization( + navigation_handle.get(), + optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD, + optimization_guide::proto::DEFER_ALL_SCRIPT, &unused_target_decision, + &optimization_type_decision, /*optimization_metadata=*/nullptr); + + EXPECT_EQ(optimization_type_decision, + optimization_guide::OptimizationTypeDecision:: + kHintFetchStartedButNotAvailableInTime); +} + TEST_F(OptimizationGuideHintsManagerTest, CanApplyOptimizationNoMatchingPageHint) { InitializeWithDefaultConfig("1.0.0.0");
diff --git a/chrome/browser/optimization_guide/optimization_guide_keyed_service.cc b/chrome/browser/optimization_guide/optimization_guide_keyed_service.cc index f3cdee9..be6b6d7 100644 --- a/chrome/browser/optimization_guide/optimization_guide_keyed_service.cc +++ b/chrome/browser/optimization_guide/optimization_guide_keyed_service.cc
@@ -90,22 +90,16 @@ switch (optimization_target_decision) { case optimization_guide::OptimizationTargetDecision::kPageLoadDoesNotMatch: case optimization_guide::OptimizationTargetDecision:: - kModelNotAvailableOnClient: - case optimization_guide::OptimizationTargetDecision:: kModelPredictionHoldback: return optimization_guide::OptimizationGuideDecision::kFalse; case optimization_guide::OptimizationTargetDecision::kPageLoadMatches: return optimization_guide::OptimizationGuideDecision::kTrue; + case optimization_guide::OptimizationTargetDecision:: + kModelNotAvailableOnClient: + case optimization_guide::OptimizationTargetDecision::kUnknown: case optimization_guide::OptimizationTargetDecision::kDeciderNotInitialized: - default: return optimization_guide::OptimizationGuideDecision::kUnknown; } - static_assert( - optimization_guide::OptimizationTargetDecision::kMaxValue == - optimization_guide::OptimizationTargetDecision:: - kDeciderNotInitialized, - "This function should be updated when a new OptimizationTargetDecision " - "is added"); } // Returns the OptimizationGuideDecision from |optimization_type_decision|. @@ -122,16 +116,17 @@ kHadOptimizationFilterButNotLoadedInTime: case optimization_guide::OptimizationTypeDecision:: kHadHintButNotLoadedInTime: + case optimization_guide::OptimizationTypeDecision:: + kHintFetchStartedButNotAvailableInTime: case optimization_guide::OptimizationTypeDecision::kDeciderNotInitialized: return optimization_guide::OptimizationGuideDecision::kUnknown; - default: + case optimization_guide::OptimizationTypeDecision::kNotAllowedByHint: + case optimization_guide::OptimizationTypeDecision::kNoMatchingPageHint: + case optimization_guide::OptimizationTypeDecision::kNoHintAvailable: + case optimization_guide::OptimizationTypeDecision:: + kNotAllowedByOptimizationFilter: return optimization_guide::OptimizationGuideDecision::kFalse; } - static_assert( - optimization_guide::OptimizationTypeDecision::kMaxValue == - optimization_guide::OptimizationTypeDecision::kDeciderNotInitialized, - "This function should be updated when a new OptimizationTypeDecision is " - "added"); } // Returns the OptimizationGuideDecision based on |decisions| @@ -139,19 +134,26 @@ // 2) If all decisions are true, return true. // 3) Otherwise, return unknown. optimization_guide::OptimizationGuideDecision ResolveOptimizationGuideDecisions( - std::vector<optimization_guide::OptimizationGuideDecision> decisions) { - bool has_unknown_decision = false; + const std::vector<optimization_guide::OptimizationGuideDecision>& + decisions) { + bool has_all_true_decisions = true; for (const auto decision : decisions) { if (decision == optimization_guide::OptimizationGuideDecision::kFalse) return optimization_guide::OptimizationGuideDecision::kFalse; - if (decision == optimization_guide::OptimizationGuideDecision::kUnknown) - has_unknown_decision = true; + if (decision != optimization_guide::OptimizationGuideDecision::kTrue) { + has_all_true_decisions = false; + break; + } } - return has_unknown_decision - ? optimization_guide::OptimizationGuideDecision::kUnknown - : optimization_guide::OptimizationGuideDecision::kTrue; + return has_all_true_decisions + ? optimization_guide::OptimizationGuideDecision::kTrue + : optimization_guide::OptimizationGuideDecision::kUnknown; + static_assert(optimization_guide::OptimizationGuideDecision::kMaxValue == + optimization_guide::OptimizationGuideDecision::kFalse, + "This function should be updated when a new " + "OptimizationGuideDecision is added"); } } // namespace
diff --git a/chrome/browser/optimization_guide/optimization_guide_keyed_service_browsertest.cc b/chrome/browser/optimization_guide/optimization_guide_keyed_service_browsertest.cc index 24bd717..260da5f 100644 --- a/chrome/browser/optimization_guide/optimization_guide_keyed_service_browsertest.cc +++ b/chrome/browser/optimization_guide/optimization_guide_keyed_service_browsertest.cc
@@ -666,6 +666,9 @@ cmd->AppendSwitch("enable-spdy-proxy-auth"); // Add switch to avoid having to see the infobar in the test. cmd->AppendSwitch(previews::switches::kDoNotRequireLitePageRedirectInfoBar); + // Add switch to avoid racing navigations in the test. + cmd->AppendSwitch(optimization_guide::switches:: + kDisableFetchingHintsAtNavigationStartForTesting); } private: @@ -802,11 +805,11 @@ // There should be a hint that matches this URL. histogram_tester.ExpectUniqueSample("OptimizationGuide.LoadedHint.Result", true, 1); - EXPECT_EQ(optimization_guide::OptimizationGuideDecision::kFalse, + EXPECT_EQ(optimization_guide::OptimizationGuideDecision::kUnknown, last_should_target_navigation_decision()); EXPECT_EQ(optimization_guide::OptimizationGuideDecision::kTrue, last_can_apply_optimization_decision()); - EXPECT_EQ(optimization_guide::OptimizationGuideDecision::kFalse, + EXPECT_EQ(optimization_guide::OptimizationGuideDecision::kUnknown, last_consumer_decision()); histogram_tester.ExpectUniqueSample( "OptimizationGuide.TargetDecision.PainfulPageLoad",
diff --git a/chrome/browser/previews/previews_lite_page_redirect_serving_url_loader.cc b/chrome/browser/previews/previews_lite_page_redirect_serving_url_loader.cc index c713caf..5619d32 100644 --- a/chrome/browser/previews/previews_lite_page_redirect_serving_url_loader.cc +++ b/chrome/browser/previews/previews_lite_page_redirect_serving_url_loader.cc
@@ -205,9 +205,7 @@ PreviewsLitePageRedirectServingURLLoader:: PreviewsLitePageRedirectServingURLLoader(ResultCallback result_callback) - : url_loader_binding_(this), - result_callback_(std::move(result_callback)), - binding_(this) {} + : result_callback_(std::move(result_callback)), binding_(this) {} void PreviewsLitePageRedirectServingURLLoader::StartNetworkRequest( const network::ResourceRequest& request, @@ -218,10 +216,10 @@ previews_url_ = request.url; network::mojom::URLLoaderClientPtr client; - url_loader_binding_.Bind(mojo::MakeRequest(&client), - base::ThreadTaskRunnerHandle::Get()); - url_loader_binding_.set_connection_error_handler(base::BindOnce( - &PreviewsLitePageRedirectServingURLLoader::OnConnectionError, + url_loader_receiver_.Bind(mojo::MakeRequest(&client), + base::ThreadTaskRunnerHandle::Get()); + url_loader_receiver_.set_disconnect_handler(base::BindOnce( + &PreviewsLitePageRedirectServingURLLoader::OnMojoDisconnect, base::Unretained(this))); // Create a network service URL loader with passed in params. @@ -274,7 +272,7 @@ DCHECK(!binding_.is_bound()); binding_.Bind(std::move(receiver)); binding_.set_connection_error_handler(base::BindOnce( - &PreviewsLitePageRedirectServingURLLoader::OnConnectionError, + &PreviewsLitePageRedirectServingURLLoader::OnMojoDisconnect, weak_ptr_factory_.GetWeakPtr())); forwarding_client_ = std::move(forwarding_client); @@ -290,7 +288,7 @@ forwarding_client_->OnReceiveResponse(resource_response_->head); // Resume previously paused network service URLLoader. - url_loader_binding_.ResumeIncomingMethodCallProcessing(); + url_loader_receiver_.Resume(); } void PreviewsLitePageRedirectServingURLLoader::OnReceiveResponse( @@ -359,7 +357,7 @@ GURL(original_url).host(), frame_tree_node_id_); } - url_loader_binding_.PauseIncomingMethodCallProcessing(); + url_loader_receiver_.Pause(); std::move(result_callback_) .Run(ServingLoaderResult::kSuccess, base::nullopt, nullptr); } @@ -492,7 +490,7 @@ network_url_loader_->ResumeReadingBodyFromNet(); } -void PreviewsLitePageRedirectServingURLLoader::OnConnectionError() { +void PreviewsLitePageRedirectServingURLLoader::OnMojoDisconnect() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // When we are not yet bound to the navigation code, fallback, which will // destroy this object. @@ -505,7 +503,7 @@ } network_url_loader_.reset(); - url_loader_binding_.Close(); + url_loader_receiver_.reset(); if (binding_.is_bound()) { binding_.Close();
diff --git a/chrome/browser/previews/previews_lite_page_redirect_serving_url_loader.h b/chrome/browser/previews/previews_lite_page_redirect_serving_url_loader.h index aca4f58..adeac94 100644 --- a/chrome/browser/previews/previews_lite_page_redirect_serving_url_loader.h +++ b/chrome/browser/previews/previews_lite_page_redirect_serving_url_loader.h
@@ -16,6 +16,7 @@ #include "content/public/browser/url_loader_request_interceptor.h" #include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/bindings/pending_receiver.h" +#include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/system/data_pipe.h" #include "services/network/public/cpp/resource_response.h" #include "services/network/public/cpp/shared_url_loader_factory.h" @@ -89,9 +90,9 @@ mojo::ScopedDataPipeConsumerHandle body) override; void OnComplete(const network::URLLoaderCompletionStatus& status) override; - // When a connection error occurs in either mojo pipe, this objects lifetime + // When a disconnection occurs in either mojo pipe, this object's lifetime // needs to be managed and the connections need to be closed. - void OnConnectionError(); + void OnMojoDisconnect(); // Calls |result_callback_| with kFallback and cleans up. void Fallback(); @@ -110,9 +111,9 @@ mojo::PendingReceiver<network::mojom::URLLoader> receiver, network::mojom::URLLoaderClientPtr forwarding_client); - // The network URLLoader that fetches the LitePage URL and its binding. + // The network URLLoader that fetches the LitePage URL and its receiver. network::mojom::URLLoaderPtr network_url_loader_; - mojo::Binding<network::mojom::URLLoaderClient> url_loader_binding_; + mojo::Receiver<network::mojom::URLLoaderClient> url_loader_receiver_{this}; // When a result is determined, this callback should be run with the // appropriate ServingLoaderResult.
diff --git a/chrome/browser/resources/chromeos/camera/src/views/main.html b/chrome/browser/resources/chromeos/camera/src/views/main.html index 81200bf..f5e88e6 100644 --- a/chrome/browser/resources/chromeos/camera/src/views/main.html +++ b/chrome/browser/resources/chromeos/camera/src/views/main.html
@@ -201,7 +201,7 @@ <button class="icon" tabindex="0" i18n-aria="back_button"></button> <div i18n-content="settings_button"></div> </div> - <button class="menu-item circle" id="settings-gridtype" tabindex="0" + <button class="menu-item" id="settings-gridtype" tabindex="0" aria-describedby="gridtype-desc"> <div class="icon"></div> <div> @@ -214,7 +214,7 @@ </div> <div class="icon end"></div> </button> - <button class="menu-item circle" id="settings-timerdur" tabindex="0" + <button class="menu-item" id="settings-timerdur" tabindex="0" aria-describedby="timerdur-desc"> <div class="icon"></div> <div> @@ -226,23 +226,23 @@ </div> <div class="icon end"></div> </button> - <button class="menu-item circle" id="settings-resolution" tabindex="0"> + <button class="menu-item" id="settings-resolution" tabindex="0"> <div class="icon"></div> <div i18n-content="camera_resolution_button"> </div> <div class="icon end"></div> </button> - <button class="menu-item circle" id="settings-expert" tabindex="0"> + <button class="menu-item" id="settings-expert" tabindex="0"> <div class="icon"></div> <div i18n-content="expert_mode_button"> </div> <div class="icon end"></div> </button> - <button class="menu-item circle" id="settings-feedback" tabindex="0"> + <button class="menu-item" id="settings-feedback" tabindex="0"> <div class="icon"></div> <div i18n-content="feedback_button"></div> </button> - <button class="menu-item circle" id="settings-help" tabindex="0"> + <button class="menu-item" id="settings-help" tabindex="0"> <div class="icon"></div> <div i18n-content="help_button"></div> </button> @@ -298,7 +298,7 @@ </div> <div id="builtin-photo-header" class="menu-item" i18n-content="label_switch_take_photo_button"></div> - <button class="menu-item resol-item circle" + <button class="menu-item resol-item" id="settings-front-photores" tabindex="0" aria-describedby="front-photores-desc"> <div> @@ -310,7 +310,7 @@ </div> <div class="icon end"></div> </button> - <button class="menu-item resol-item circle" + <button class="menu-item resol-item" id="settings-back-photores" tabindex="0" aria-describedby="back-photores-desc"> <div> @@ -323,7 +323,7 @@ </button> <div id="builtin-video-header" class="menu-item" i18n-content="label_switch_record_video_button"></div> - <button class="menu-item resol-item circle" + <button class="menu-item resol-item" id="settings-front-videores" tabindex="0" aria-describedby="front-videores-desc"> <div> @@ -334,7 +334,7 @@ </div> <div class="icon end"></div> </button> - <button class="menu-item resol-item circle" + <button class="menu-item resol-item" id="settings-back-videores" tabindex="0" aria-describedby="back-videores-desc"> <div> @@ -369,13 +369,13 @@ <button class="icon" tabindex="0" i18n-aria="back_button"></button> <div i18n-content="expert_mode_button"></div> </div> - <label class="menu-item circle" for="expert-show-metadata"> + <label class="menu-item" for="expert-show-metadata"> <input class="icon" id="expert-show-metadata" type="checkbox" tabindex="0" data-state="show-metadata" data-key="showMetadata"> <span i18n-content="expert_preview_metadata"></span> </label> - <label class="menu-item circle" for="expert-save-metadata"> + <label class="menu-item" for="expert-save-metadata"> <input class="icon" id="expert-save-metadata" type="checkbox" tabindex="0" data-state="save-metadata" data-key="saveMetadata"> @@ -444,7 +444,7 @@ </div> <div class="icon end"></div> </button> - <button class="menu-item resol-item circle external-camera" + <button class="menu-item resol-item external-camera" tabindex="0"> <div> <div i18n-content="video_resolution_button"></div>
diff --git a/chrome/browser/resources/chromeos/switch_access/focus_ring_manager.js b/chrome/browser/resources/chromeos/switch_access/focus_ring_manager.js index e8fc5cf..d2ea4aa4 100644 --- a/chrome/browser/resources/chromeos/switch_access/focus_ring_manager.js +++ b/chrome/browser/resources/chromeos/switch_access/focus_ring_manager.js
@@ -87,6 +87,11 @@ if (this.rings_.size === 0) { return; } + if (!primary.location || !group.location) { + throw SwitchAccess.error( + SAConstants.ErrorType.MISSING_LOCATION, + 'Cannot set focus rings if node location is undefined'); + } if (primary instanceof BackButtonNode) { // TODO(anastasi): Use standard focus rings.
diff --git a/chrome/browser/resources/chromeos/switch_access/navigation_manager.js b/chrome/browser/resources/chromeos/switch_access/navigation_manager.js index f5a0c97..dca1625 100644 --- a/chrome/browser/resources/chromeos/switch_access/navigation_manager.js +++ b/chrome/browser/resources/chromeos/switch_access/navigation_manager.js
@@ -355,11 +355,10 @@ } } - const desktop = RootNodeWrapper.buildDesktopTree(this.desktop_); - const nextNode = desktop.firstChild.automationNode; - if (nextNode) { - this.moveTo_(nextNode); - } + // If there is no valid node in the group stack, go to the desktop. + this.group_ = RootNodeWrapper.buildDesktopTree(this.desktop_); + this.node_ = this.group_.firstChild; + this.groupStack_ = []; } /**
diff --git a/chrome/browser/resources/chromeos/switch_access/switch_access_constants.js b/chrome/browser/resources/chromeos/switch_access/switch_access_constants.js index de67581..9470ffb 100644 --- a/chrome/browser/resources/chromeos/switch_access/switch_access_constants.js +++ b/chrome/browser/resources/chromeos/switch_access/switch_access_constants.js
@@ -190,6 +190,7 @@ NULL_CHILD: 6, NO_CHILDREN: 7, MALFORMED_DESKTOP: 8, + MISSING_LOCATION: 9, }; /**
diff --git a/chrome/browser/resources/chromeos/switch_access/switch_access_predicate.js b/chrome/browser/resources/chromeos/switch_access/switch_access_predicate.js index f6c0f9c..0866606 100644 --- a/chrome/browser/resources/chromeos/switch_access/switch_access_predicate.js +++ b/chrome/browser/resources/chromeos/switch_access/switch_access_predicate.js
@@ -39,7 +39,7 @@ const state = node.state; // Skip things that are offscreen or invisible. - if (state[StateType.OFFSCREEN] || loc.top < 0 || loc.left < 0 || + if (state[StateType.OFFSCREEN] || !loc || loc.top < 0 || loc.left < 0 || state[StateType.INVISIBLE]) { return false; }
diff --git a/chrome/browser/resources/extensions/activity_log/BUILD.gn b/chrome/browser/resources/extensions/activity_log/BUILD.gn index 70ade218..d562aa8 100644 --- a/chrome/browser/resources/extensions/activity_log/BUILD.gn +++ b/chrome/browser/resources/extensions/activity_log/BUILD.gn
@@ -1,6 +1,6 @@ -# 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. +#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. import("//third_party/closure_compiler/compile_js.gni") import("//tools/polymer/polymer.gni")
diff --git a/chrome/browser/resources/extensions/activity_log/activity_log.js b/chrome/browser/resources/extensions/activity_log/activity_log.js index c0cee3fd..6bf480f 100644 --- a/chrome/browser/resources/extensions/activity_log/activity_log.js +++ b/chrome/browser/resources/extensions/activity_log/activity_log.js
@@ -37,140 +37,140 @@ STREAM: 1 }; +/** + * A struct used as a placeholder for chrome.developerPrivate.ExtensionInfo + * for this component if the extensionId from the URL does not correspond to + * installed extension. + * @typedef {{ + * id: string, + * isPlaceholder: boolean, + * }} + */ +export let ActivityLogExtensionPlaceholder; + +Polymer({ + is: 'extensions-activity-log', + + _template: html`{__html_template__}`, + + behaviors: [ + CrContainerShadowBehavior, + I18nBehavior, + ItemBehavior, + ], + + properties: { + /** + * The underlying ExtensionInfo for the details being displayed. + * @type {!chrome.developerPrivate.ExtensionInfo| + * !ActivityLogExtensionPlaceholder} + */ + extensionInfo: Object, + + /** @type {!ActivityLogDelegate} */ + delegate: Object, + + /** @private {!ActivityLogSubpage} */ + selectedSubpage_: { + type: Number, + value: ActivityLogSubpage.NONE, + observer: 'onSelectedSubpageChanged_', + }, + + /** @private {Array<string>} */ + tabNames_: { + type: Array, + value: () => ([ + loadTimeData.getString('activityLogHistoryTabHeading'), + loadTimeData.getString('activityLogStreamTabHeading'), + ]), + } + }, + + listeners: { + 'view-enter-start': 'onViewEnterStart_', + 'view-exit-finish': 'onViewExitFinish_', + }, + /** - * A struct used as a placeholder for chrome.developerPrivate.ExtensionInfo - * for this component if the extensionId from the URL does not correspond to - * installed extension. - * @typedef {{ - * id: string, - * isPlaceholder: boolean, - * }} + * Focuses the back button when page is loaded and set the activie view to + * be HISTORY when we navigate to the page. + * @private */ - export let ActivityLogExtensionPlaceholder; + onViewEnterStart_: function() { + this.selectedSubpage_ = ActivityLogSubpage.HISTORY; + afterNextRender(this, () => focusWithoutInk(this.$.closeButton)); + }, - Polymer({ - is: 'extensions-activity-log', + /** + * Set |selectedSubpage_| to NONE to remove the active view from the DOM. + * @private + */ + onViewExitFinish_: function() { + this.selectedSubpage_ = ActivityLogSubpage.NONE; + // clear the stream if the user is exiting the activity log page. + const activityLogStream = this.$$('activity-log-stream'); + if (activityLogStream) { + activityLogStream.clearStream(); + } + }, - _template: html`{__html_template__}`, + /** + * @private + * @return {string} + */ + getActivityLogHeading_: function() { + const headingName = this.extensionInfo.isPlaceholder ? + this.i18n('missingOrUninstalledExtension') : + this.extensionInfo.name; + return this.i18n('activityLogPageHeading', headingName); + }, - behaviors: [ - CrContainerShadowBehavior, - I18nBehavior, - ItemBehavior, - ], + /** + * @private + * @return {boolean} + */ + isHistoryTabSelected_: function() { + return this.selectedSubpage_ === ActivityLogSubpage.HISTORY; + }, - properties: { - /** - * The underlying ExtensionInfo for the details being displayed. - * @type {!chrome.developerPrivate.ExtensionInfo| - * !ActivityLogExtensionPlaceholder} - */ - extensionInfo: Object, + /** + * @private + * @return {boolean} + */ + isStreamTabSelected_: function() { + return this.selectedSubpage_ === ActivityLogSubpage.STREAM; + }, - /** @type {!ActivityLogDelegate} */ - delegate: Object, - - /** @private {!ActivityLogSubpage} */ - selectedSubpage_: { - type: Number, - value: ActivityLogSubpage.NONE, - observer: 'onSelectedSubpageChanged_', - }, - - /** @private {Array<string>} */ - tabNames_: { - type: Array, - value: () => ([ - loadTimeData.getString('activityLogHistoryTabHeading'), - loadTimeData.getString('activityLogStreamTabHeading'), - ]), + /** + * @private + * @param {!ActivityLogSubpage} newTab + * @param {!ActivityLogSubpage} oldTab + */ + onSelectedSubpageChanged_: function(newTab, oldTab) { + const activityLogStream = this.$$('activity-log-stream'); + if (activityLogStream) { + if (newTab === ActivityLogSubpage.STREAM) { + // Start the stream if the user is switching to the real-time tab. + // This will not handle the first tab switch to the real-time tab as + // the stream has not been attached to the DOM yet, and is handled + // instead by the stream's |attached| method. + activityLogStream.startStream(); + } else if (oldTab === ActivityLogSubpage.STREAM) { + // Pause the stream if the user is navigating away from the real-time + // tab. + activityLogStream.pauseStream(); } - }, + } + }, - listeners: { - 'view-enter-start': 'onViewEnterStart_', - 'view-exit-finish': 'onViewExitFinish_', - }, - - /** - * Focuses the back button when page is loaded and set the activie view to - * be HISTORY when we navigate to the page. - * @private - */ - onViewEnterStart_: function() { - this.selectedSubpage_ = ActivityLogSubpage.HISTORY; - afterNextRender(this, () => focusWithoutInk(this.$.closeButton)); - }, - - /** - * Set |selectedSubpage_| to NONE to remove the active view from the DOM. - * @private - */ - onViewExitFinish_: function() { - this.selectedSubpage_ = ActivityLogSubpage.NONE; - // clear the stream if the user is exiting the activity log page. - const activityLogStream = this.$$('activity-log-stream'); - if (activityLogStream) { - activityLogStream.clearStream(); - } - }, - - /** - * @private - * @return {string} - */ - getActivityLogHeading_: function() { - const headingName = this.extensionInfo.isPlaceholder ? - this.i18n('missingOrUninstalledExtension') : - this.extensionInfo.name; - return this.i18n('activityLogPageHeading', headingName); - }, - - /** - * @private - * @return {boolean} - */ - isHistoryTabSelected_: function() { - return this.selectedSubpage_ === ActivityLogSubpage.HISTORY; - }, - - /** - * @private - * @return {boolean} - */ - isStreamTabSelected_: function() { - return this.selectedSubpage_ === ActivityLogSubpage.STREAM; - }, - - /** - * @private - * @param {!ActivityLogSubpage} newTab - * @param {!ActivityLogSubpage} oldTab - */ - onSelectedSubpageChanged_: function(newTab, oldTab) { - const activityLogStream = this.$$('activity-log-stream'); - if (activityLogStream) { - if (newTab === ActivityLogSubpage.STREAM) { - // Start the stream if the user is switching to the real-time tab. - // This will not handle the first tab switch to the real-time tab as - // the stream has not been attached to the DOM yet, and is handled - // instead by the stream's |attached| method. - activityLogStream.startStream(); - } else if (oldTab === ActivityLogSubpage.STREAM) { - // Pause the stream if the user is navigating away from the real-time - // tab. - activityLogStream.pauseStream(); - } - } - }, - - /** @private */ - onCloseButtonTap_: function() { - if (this.extensionInfo.isPlaceholder) { - navigation.navigateTo({page: Page.LIST}); - } else { - navigation.navigateTo( - {page: Page.DETAILS, extensionId: this.extensionInfo.id}); - } - }, - }); + /** @private */ + onCloseButtonTap_: function() { + if (this.extensionInfo.isPlaceholder) { + navigation.navigateTo({page: Page.LIST}); + } else { + navigation.navigateTo( + {page: Page.DETAILS, extensionId: this.extensionInfo.id}); + } + }, +});
diff --git a/chrome/browser/resources/extensions/activity_log/activity_log_history.js b/chrome/browser/resources/extensions/activity_log/activity_log_history.js index 3be47fc..a28281e 100644 --- a/chrome/browser/resources/extensions/activity_log/activity_log_history.js +++ b/chrome/browser/resources/extensions/activity_log/activity_log_history.js
@@ -14,410 +14,410 @@ import {ActivityGroup} from './activity_log_history_item.js'; +/** + * The different states the activity log page can be in. Initial state is + * LOADING because we call the activity log API whenever a user navigates to + * the page. LOADED is the state where the API call has returned a successful + * result. + * @enum {string} + */ +export const ActivityLogPageState = { + LOADING: 'loading', + LOADED: 'loaded' +}; + +/** @interface */ +export class ActivityLogDelegate { /** - * The different states the activity log page can be in. Initial state is - * LOADING because we call the activity log API whenever a user navigates to - * the page. LOADED is the state where the API call has returned a successful - * result. - * @enum {string} + * @param {string} extensionId + * @return {!Promise<!chrome.activityLogPrivate.ActivityResultSet>} */ - export const ActivityLogPageState = { - LOADING: 'loading', - LOADED: 'loaded' - }; + getExtensionActivityLog(extensionId) {} - /** @interface */ - export class ActivityLogDelegate { - /** - * @param {string} extensionId - * @return {!Promise<!chrome.activityLogPrivate.ActivityResultSet>} - */ - getExtensionActivityLog(extensionId) {} + /** + * @param {string} extensionId + * @param {string} searchTerm + * @return {!Promise<!chrome.activityLogPrivate.ActivityResultSet>} + */ + getFilteredExtensionActivityLog(extensionId, searchTerm) {} - /** - * @param {string} extensionId - * @param {string} searchTerm - * @return {!Promise<!chrome.activityLogPrivate.ActivityResultSet>} - */ - getFilteredExtensionActivityLog(extensionId, searchTerm) {} + /** + * @param {!Array<string>} activityIds + * @return {!Promise<void>} + */ + deleteActivitiesById(activityIds) {} - /** - * @param {!Array<string>} activityIds - * @return {!Promise<void>} - */ - deleteActivitiesById(activityIds) {} + /** + * @param {string} extensionId + * @return {!Promise<void>} + */ + deleteActivitiesFromExtension(extensionId) {} - /** - * @param {string} extensionId - * @return {!Promise<void>} - */ - deleteActivitiesFromExtension(extensionId) {} + /** + * @param {string} rawActivityData + * @param {string} fileName + */ + downloadActivities(rawActivityData, fileName) {} +} - /** - * @param {string} rawActivityData - * @param {string} fileName - */ - downloadActivities(rawActivityData, fileName) {} +/** + * Content scripts activities do not have an API call, so we use the names of + * the scripts executed (specified as a stringified JSON array in the args + * field) as the keys for an activity group instead. + * @private + * @param {!chrome.activityLogPrivate.ExtensionActivity} activity + * @return {!Array<string>} + */ +function getActivityGroupKeysForContentScript_(activity) { + assert( + activity.activityType === + chrome.activityLogPrivate.ExtensionActivityType.CONTENT_SCRIPT); + + if (!activity.args) { + return []; } - /** - * Content scripts activities do not have an API call, so we use the names of - * the scripts executed (specified as a stringified JSON array in the args - * field) as the keys for an activity group instead. - * @private - * @param {!chrome.activityLogPrivate.ExtensionActivity} activity - * @return {!Array<string>} - */ - function getActivityGroupKeysForContentScript_(activity) { - assert( - activity.activityType === - chrome.activityLogPrivate.ExtensionActivityType.CONTENT_SCRIPT); + const parsedArgs = JSON.parse(activity.args); + assert(Array.isArray(parsedArgs), 'Invalid API data.'); + return /** @type {!Array<string>} */ (parsedArgs); +} - if (!activity.args) { - return []; +/** + * Web request activities can have extra information which describes what the + * web request does in more detail than just the api_call. This information + * is in activity.other.webRequest and we use this to generate more activity + * group keys if possible. + * @private + * @param {!chrome.activityLogPrivate.ExtensionActivity} activity + * @return {!Array<string>} + */ +function getActivityGroupKeysForWebRequest_(activity) { + assert( + activity.activityType === + chrome.activityLogPrivate.ExtensionActivityType.WEB_REQUEST); + + const apiCall = activity.apiCall; + const other = activity.other; + + if (!other || !other.webRequest) { + return [apiCall]; + } + + const webRequest = /** @type {!Object} */ (JSON.parse(other.webRequest)); + assert(typeof webRequest === 'object', 'Invalid API data'); + + // If there is extra information in the other.webRequest object, + // construct a group for each consisting of the API call and each object key + // in other.webRequest. Otherwise we default to just the API call. + return Object.keys(webRequest).length === 0 ? + [apiCall] : + Object.keys(webRequest).map(field => `${apiCall} (${field})`); +} + +/** + * Group activity log entries by a key determined from each entry. Usually + * this would be the activity's API call though content script and web + * requests have different keys. We currently assume that every API call + * matches to one activity type. + * @param {!Array<!chrome.activityLogPrivate.ExtensionActivity>} + * activityData + * @return {!Map<string, !ActivityGroup>} + */ +function groupActivities(activityData) { + const groupedActivities = new Map(); + + for (const activity of activityData) { + const activityId = activity.activityId; + const activityType = activity.activityType; + const count = activity.count; + const pageUrl = activity.pageUrl; + + const isContentScript = activityType === + chrome.activityLogPrivate.ExtensionActivityType.CONTENT_SCRIPT; + const isWebRequest = activityType === + chrome.activityLogPrivate.ExtensionActivityType.WEB_REQUEST; + + let activityGroupKeys = [activity.apiCall]; + if (isContentScript) { + activityGroupKeys = getActivityGroupKeysForContentScript_(activity); + } else if (isWebRequest) { + activityGroupKeys = getActivityGroupKeysForWebRequest_(activity); } - const parsedArgs = JSON.parse(activity.args); - assert(Array.isArray(parsedArgs), 'Invalid API data.'); - return /** @type {!Array<string>} */ (parsedArgs); - } + for (const key of activityGroupKeys) { + if (!groupedActivities.has(key)) { + const activityGroup = { + activityIds: new Set([activityId]), + key, + count, + activityType, + countsByUrl: pageUrl ? new Map([[pageUrl, count]]) : new Map(), + expanded: false, + }; + groupedActivities.set(key, activityGroup); + } else { + const activityGroup = groupedActivities.get(key); + activityGroup.activityIds.add(activityId); + activityGroup.count += count; - /** - * Web request activities can have extra information which describes what the - * web request does in more detail than just the api_call. This information - * is in activity.other.webRequest and we use this to generate more activity - * group keys if possible. - * @private - * @param {!chrome.activityLogPrivate.ExtensionActivity} activity - * @return {!Array<string>} - */ - function getActivityGroupKeysForWebRequest_(activity) { - assert( - activity.activityType === - chrome.activityLogPrivate.ExtensionActivityType.WEB_REQUEST); - - const apiCall = activity.apiCall; - const other = activity.other; - - if (!other || !other.webRequest) { - return [apiCall]; + if (pageUrl) { + const currentCount = activityGroup.countsByUrl.get(pageUrl) || 0; + activityGroup.countsByUrl.set(pageUrl, currentCount + count); + } + } } - - const webRequest = /** @type {!Object} */ (JSON.parse(other.webRequest)); - assert(typeof webRequest === 'object', 'Invalid API data'); - - // If there is extra information in the other.webRequest object, - // construct a group for each consisting of the API call and each object key - // in other.webRequest. Otherwise we default to just the API call. - return Object.keys(webRequest).length === 0 ? - [apiCall] : - Object.keys(webRequest).map(field => `${apiCall} (${field})`); } + return groupedActivities; +} + +/** + * Sort activities by the total count for each activity group key. Resolve + * ties by the alphabetical order of the key. + * @param {!Map<string, !ActivityGroup>} groupedActivities + * @return {!Array<!ActivityGroup>} + */ +function sortActivitiesByCallCount(groupedActivities) { + return Array.from(groupedActivities.values()).sort((a, b) => { + if (a.count != b.count) { + return b.count - a.count; + } + if (a.key < b.key) { + return -1; + } + if (a.key > b.key) { + return 1; + } + return 0; + }); +} + +Polymer({ + is: 'activity-log-history', + + _template: html`{__html_template__}`, + + properties: { + /** @type {!string} */ + extensionId: String, + + /** @type {!ActivityLogDelegate} */ + delegate: Object, + + /** + * An array representing the activity log. Stores activities grouped by + * API call or content script name sorted in descending order of the call + * count. + * @private {!Array<!ActivityGroup>} + */ + activityData_: { + type: Array, + value: () => [], + }, + + /** @private {ActivityLogPageState} */ + pageState_: { + type: String, + value: ActivityLogPageState.LOADING, + }, + + /** @private */ + lastSearch_: { + type: String, + value: '', + }, + }, + + listeners: { + 'delete-activity-log-item': 'deleteItem_', + }, + /** - * Group activity log entries by a key determined from each entry. Usually - * this would be the activity's API call though content script and web - * requests have different keys. We currently assume that every API call - * matches to one activity type. + * A promise resolver for any external files waiting for the + * GetExtensionActivity API call to finish. + * Currently only used for extension_settings_browsertest.cc + * @private {PromiseResolver} + */ + dataFetchedResolver_: null, + + /** + * The stringified API response from the activityLogPrivate API with + * individual activities sorted in ascending order by timestamp; used for + * exporting the activity log. + * @private {string} + */ + rawActivities_: '', + + /** + * Expose only the promise of dataFetchedResolver_. + * @return {!Promise<void>} + */ + whenDataFetched: function() { + return this.dataFetchedResolver_.promise; + }, + + /** @override */ + attached: function() { + this.dataFetchedResolver_ = new PromiseResolver(); + this.refreshActivities_(); + }, + + /** + * @private + * @return {boolean} + */ + shouldShowEmptyActivityLogMessage_: function() { + return this.pageState_ === ActivityLogPageState.LOADED && + this.activityData_.length === 0; + }, + + /** + * @private + * @return {boolean} + */ + shouldShowLoadingMessage_: function() { + return this.pageState_ === ActivityLogPageState.LOADING; + }, + + /** + * @private + * @return {boolean} + */ + shouldShowActivities_: function() { + return this.pageState_ === ActivityLogPageState.LOADED && + this.activityData_.length > 0; + }, + + /** @private */ + onClearActivitiesClick_: function() { + this.delegate.deleteActivitiesFromExtension(this.extensionId).then(() => { + this.processActivities_([]); + }); + }, + + /** @private */ + onMoreActionsClick_: function() { + this.$$('cr-action-menu').showAt(assert(this.$$('cr-icon-button'))); + }, + + /** + * @private + * @param {boolean} expanded + */ + expandItems_: function(expanded) { + // Do not use .filter here as we need the original index of the item + // in |activityData_|. + this.activityData_.forEach((item, index) => { + if (item.countsByUrl.size > 0) { + this.set(`activityData_.${index}.expanded`, expanded); + } + }); + this.$$('cr-action-menu').close(); + }, + + /** @private */ + onExpandAllClick_: function() { + this.expandItems_(true); + }, + + /** @private */ + onCollapseAllClick_: function() { + this.expandItems_(false); + }, + + /** @private */ + onExportClick_: function() { + const fileName = `exported_activity_log_${this.extensionId}.json`; + this.delegate.downloadActivities(this.rawActivities_, fileName); + }, + + /** + * @private + * @param {!CustomEvent<!Array<string>>} e + */ + deleteItem_: function(e) { + const activityIds = e.detail; + this.delegate.deleteActivitiesById(activityIds).then(() => { + // It is possible for multiple activities displayed to have the same + // underlying activity ID. This happens when we split content script and + // web request activities by fields other than their API call. For + // consistency, we will re-fetch the activity log. + this.refreshActivities_(); + }); + }, + + /** + * @private * @param {!Array<!chrome.activityLogPrivate.ExtensionActivity>} * activityData - * @return {!Map<string, !ActivityGroup>} */ - function groupActivities(activityData) { - const groupedActivities = new Map(); + processActivities_: function(activityData) { + this.pageState_ = ActivityLogPageState.LOADED; - for (const activity of activityData) { - const activityId = activity.activityId; - const activityType = activity.activityType; - const count = activity.count; - const pageUrl = activity.pageUrl; + // Sort |activityData| in ascending order based on the activity's + // timestamp; Used for |this.encodedRawActivities|. + activityData.sort((a, b) => a.time - b.time); + this.rawActivities_ = JSON.stringify(activityData); - const isContentScript = activityType === - chrome.activityLogPrivate.ExtensionActivityType.CONTENT_SCRIPT; - const isWebRequest = activityType === - chrome.activityLogPrivate.ExtensionActivityType.WEB_REQUEST; - - let activityGroupKeys = [activity.apiCall]; - if (isContentScript) { - activityGroupKeys = getActivityGroupKeysForContentScript_(activity); - } else if (isWebRequest) { - activityGroupKeys = getActivityGroupKeysForWebRequest_(activity); - } - - for (const key of activityGroupKeys) { - if (!groupedActivities.has(key)) { - const activityGroup = { - activityIds: new Set([activityId]), - key, - count, - activityType, - countsByUrl: pageUrl ? new Map([[pageUrl, count]]) : new Map(), - expanded: false, - }; - groupedActivities.set(key, activityGroup); - } else { - const activityGroup = groupedActivities.get(key); - activityGroup.activityIds.add(activityId); - activityGroup.count += count; - - if (pageUrl) { - const currentCount = activityGroup.countsByUrl.get(pageUrl) || 0; - activityGroup.countsByUrl.set(pageUrl, currentCount + count); - } - } - } + this.activityData_ = + sortActivitiesByCallCount(groupActivities(activityData)); + if (!this.dataFetchedResolver_.isFulfilled) { + this.dataFetchedResolver_.resolve(); } - - return groupedActivities; - } + }, /** - * Sort activities by the total count for each activity group key. Resolve - * ties by the alphabetical order of the key. - * @param {!Map<string, !ActivityGroup>} groupedActivities - * @return {!Array<!ActivityGroup>} + * @private + * @return {!Promise<void>} */ - function sortActivitiesByCallCount(groupedActivities) { - return Array.from(groupedActivities.values()).sort((a, b) => { - if (a.count != b.count) { - return b.count - a.count; - } - if (a.key < b.key) { - return -1; - } - if (a.key > b.key) { - return 1; - } - return 0; - }); - } + refreshActivities_: function() { + if (this.lastSearch_ === '') { + return this.getActivityLog_(); + } - Polymer({ - is: 'activity-log-history', + return this.getFilteredActivityLog_(this.lastSearch_); + }, - _template: html`{__html_template__}`, + /** + * @private + * @return {!Promise<void>} + */ + getActivityLog_: function() { + this.pageState_ = ActivityLogPageState.LOADING; + return this.delegate.getExtensionActivityLog(this.extensionId) + .then(result => { + this.processActivities_(result.activities); + }); + }, - properties: { - /** @type {!string} */ - extensionId: String, + /** + * @private + * @param {string} searchTerm + * @return {!Promise<void>} + */ + getFilteredActivityLog_: function(searchTerm) { + this.pageState_ = ActivityLogPageState.LOADING; + return this.delegate + .getFilteredExtensionActivityLog(this.extensionId, searchTerm) + .then(result => { + this.processActivities_(result.activities); + }); + }, - /** @type {!ActivityLogDelegate} */ - delegate: Object, + /** + * @private + * @param {!CustomEvent<string>} e + */ + onSearchChanged_: function(e) { + // Remove all whitespaces from the search term, as API call names and + // urls should not contain any whitespace. As of now, only single term + // search queries are allowed. + const searchTerm = e.detail.replace(/\s+/g, ''); + if (searchTerm === this.lastSearch_) { + return; + } - /** - * An array representing the activity log. Stores activities grouped by - * API call or content script name sorted in descending order of the call - * count. - * @private {!Array<!ActivityGroup>} - */ - activityData_: { - type: Array, - value: () => [], - }, - - /** @private {ActivityLogPageState} */ - pageState_: { - type: String, - value: ActivityLogPageState.LOADING, - }, - - /** @private */ - lastSearch_: { - type: String, - value: '', - }, - }, - - listeners: { - 'delete-activity-log-item': 'deleteItem_', - }, - - /** - * A promise resolver for any external files waiting for the - * GetExtensionActivity API call to finish. - * Currently only used for extension_settings_browsertest.cc - * @private {PromiseResolver} - */ - dataFetchedResolver_: null, - - /** - * The stringified API response from the activityLogPrivate API with - * individual activities sorted in ascending order by timestamp; used for - * exporting the activity log. - * @private {string} - */ - rawActivities_: '', - - /** - * Expose only the promise of dataFetchedResolver_. - * @return {!Promise<void>} - */ - whenDataFetched: function() { - return this.dataFetchedResolver_.promise; - }, - - /** @override */ - attached: function() { - this.dataFetchedResolver_ = new PromiseResolver(); - this.refreshActivities_(); - }, - - /** - * @private - * @return {boolean} - */ - shouldShowEmptyActivityLogMessage_: function() { - return this.pageState_ === ActivityLogPageState.LOADED && - this.activityData_.length === 0; - }, - - /** - * @private - * @return {boolean} - */ - shouldShowLoadingMessage_: function() { - return this.pageState_ === ActivityLogPageState.LOADING; - }, - - /** - * @private - * @return {boolean} - */ - shouldShowActivities_: function() { - return this.pageState_ === ActivityLogPageState.LOADED && - this.activityData_.length > 0; - }, - - /** @private */ - onClearActivitiesClick_: function() { - this.delegate.deleteActivitiesFromExtension(this.extensionId).then(() => { - this.processActivities_([]); - }); - }, - - /** @private */ - onMoreActionsClick_: function() { - this.$$('cr-action-menu').showAt(assert(this.$$('cr-icon-button'))); - }, - - /** - * @private - * @param {boolean} expanded - */ - expandItems_: function(expanded) { - // Do not use .filter here as we need the original index of the item - // in |activityData_|. - this.activityData_.forEach((item, index) => { - if (item.countsByUrl.size > 0) { - this.set(`activityData_.${index}.expanded`, expanded); - } - }); - this.$$('cr-action-menu').close(); - }, - - /** @private */ - onExpandAllClick_: function() { - this.expandItems_(true); - }, - - /** @private */ - onCollapseAllClick_: function() { - this.expandItems_(false); - }, - - /** @private */ - onExportClick_: function() { - const fileName = `exported_activity_log_${this.extensionId}.json`; - this.delegate.downloadActivities(this.rawActivities_, fileName); - }, - - /** - * @private - * @param {!CustomEvent<!Array<string>>} e - */ - deleteItem_: function(e) { - const activityIds = e.detail; - this.delegate.deleteActivitiesById(activityIds).then(() => { - // It is possible for multiple activities displayed to have the same - // underlying activity ID. This happens when we split content script and - // web request activities by fields other than their API call. For - // consistency, we will re-fetch the activity log. - this.refreshActivities_(); - }); - }, - - /** - * @private - * @param {!Array<!chrome.activityLogPrivate.ExtensionActivity>} - * activityData - */ - processActivities_: function(activityData) { - this.pageState_ = ActivityLogPageState.LOADED; - - // Sort |activityData| in ascending order based on the activity's - // timestamp; Used for |this.encodedRawActivities|. - activityData.sort((a, b) => a.time - b.time); - this.rawActivities_ = JSON.stringify(activityData); - - this.activityData_ = - sortActivitiesByCallCount(groupActivities(activityData)); - if (!this.dataFetchedResolver_.isFulfilled) { - this.dataFetchedResolver_.resolve(); - } - }, - - /** - * @private - * @return {!Promise<void>} - */ - refreshActivities_: function() { - if (this.lastSearch_ === '') { - return this.getActivityLog_(); - } - - return this.getFilteredActivityLog_(this.lastSearch_); - }, - - /** - * @private - * @return {!Promise<void>} - */ - getActivityLog_: function() { - this.pageState_ = ActivityLogPageState.LOADING; - return this.delegate.getExtensionActivityLog(this.extensionId) - .then(result => { - this.processActivities_(result.activities); - }); - }, - - /** - * @private - * @param {string} searchTerm - * @return {!Promise<void>} - */ - getFilteredActivityLog_: function(searchTerm) { - this.pageState_ = ActivityLogPageState.LOADING; - return this.delegate - .getFilteredExtensionActivityLog(this.extensionId, searchTerm) - .then(result => { - this.processActivities_(result.activities); - }); - }, - - /** - * @private - * @param {!CustomEvent<string>} e - */ - onSearchChanged_: function(e) { - // Remove all whitespaces from the search term, as API call names and - // urls should not contain any whitespace. As of now, only single term - // search queries are allowed. - const searchTerm = e.detail.replace(/\s+/g, ''); - if (searchTerm === this.lastSearch_) { - return; - } - - this.lastSearch_ = searchTerm; - this.refreshActivities_(); - }, - }); + this.lastSearch_ = searchTerm; + this.refreshActivities_(); + }, +});
diff --git a/chrome/browser/resources/extensions/activity_log/activity_log_history_item.js b/chrome/browser/resources/extensions/activity_log/activity_log_history_item.js index 1c172fba..1ed2d728 100644 --- a/chrome/browser/resources/extensions/activity_log/activity_log_history_item.js +++ b/chrome/browser/resources/extensions/activity_log/activity_log_history_item.js
@@ -11,96 +11,95 @@ import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; - /** - * @typedef {{ - * activityIds: !Set<string>, - * key: string, - * count: number, - * activityType: !chrome.activityLogPrivate.ExtensionActivityFilter, - * countsByUrl: !Map<string, number>, - * expanded: boolean - * }} - */ - export let ActivityGroup; +/** + * @typedef {{ + * activityIds: !Set<string>, + * key: string, + * count: number, + * activityType: !chrome.activityLogPrivate.ExtensionActivityFilter, + * countsByUrl: !Map<string, number>, + * expanded: boolean + * }} + */ +export let ActivityGroup; - /** - * A struct used to describe each url and its associated counts. The id is - * unique for each item in the list of URLs and is used for the tooltip. - * @typedef {{ - * page: string, - * count: number - * }} - */ - let PageUrlItem; +/** + * A struct used to describe each url and its associated counts. The id is + * unique for each item in the list of URLs and is used for the tooltip. + * @typedef {{ + * page: string, + * count: number + * }} + */ +let PageUrlItem; - Polymer({ - is: 'activity-log-history-item', +Polymer({ + is: 'activity-log-history-item', - _template: html`{__html_template__}`, + _template: html`{__html_template__}`, - properties: { - /** - * The underlying ActivityGroup that provides data for the - * ActivityLogItem displayed. - * @type {!ActivityGroup} - */ - data: Object, - - /** @private */ - isExpandable_: { - type: Boolean, - computed: 'computeIsExpandable_(data.countsByUrl)', - }, - }, - + properties: { /** - * @private - * @return {boolean} + * The underlying ActivityGroup that provides data for the + * ActivityLogItem displayed. + * @type {!ActivityGroup} */ - computeIsExpandable_: function() { - return this.data.countsByUrl.size > 0; - }, - - /** - * Sort the page URLs by the number of times it was associated with the key - * for this ActivityGroup (API call or content script invocation.) Resolve - * ties by the alphabetical order of the page URL. - * @private - * @return {!Array<PageUrlItem>} - */ - getPageUrls_: function() { - return Array.from(this.data.countsByUrl.entries()) - .map(e => ({page: e[0], count: e[1]})) - .sort(function(a, b) { - if (a.count != b.count) { - return b.count - a.count; - } - return a.page < b.page ? -1 : (a.page > b.page ? 1 : 0); - }); - }, + data: Object, /** @private */ - onDeleteTap_: function(e) { - e.stopPropagation(); - this.fire( - 'delete-activity-log-item', - Array.from(this.data.activityIds.values())); + isExpandable_: { + type: Boolean, + computed: 'computeIsExpandable_(data.countsByUrl)', }, + }, - /** @private */ - onExpandTap_: function() { - if (this.isExpandable_) { - this.set('data.expanded', !this.data.expanded); - } - }, + /** + * @private + * @return {boolean} + */ + computeIsExpandable_: function() { + return this.data.countsByUrl.size > 0; + }, - /** - * Show the call count for a particular page URL if more than one page - * URL is associated with the key for this ActivityGroup. - * @private - * @return {boolean} - */ - shouldShowPageUrlCount_: function() { - return this.data.countsByUrl.size > 1; - }, - }); + /** + * Sort the page URLs by the number of times it was associated with the key + * for this ActivityGroup (API call or content script invocation.) Resolve + * ties by the alphabetical order of the page URL. + * @private + * @return {!Array<PageUrlItem>} + */ + getPageUrls_: function() { + return Array.from(this.data.countsByUrl.entries()) + .map(e => ({page: e[0], count: e[1]})) + .sort(function(a, b) { + if (a.count != b.count) { + return b.count - a.count; + } + return a.page < b.page ? -1 : (a.page > b.page ? 1 : 0); + }); + }, + + /** @private */ + onDeleteTap_: function(e) { + e.stopPropagation(); + this.fire( + 'delete-activity-log-item', Array.from(this.data.activityIds.values())); + }, + + /** @private */ + onExpandTap_: function() { + if (this.isExpandable_) { + this.set('data.expanded', !this.data.expanded); + } + }, + + /** + * Show the call count for a particular page URL if more than one page + * URL is associated with the key for this ActivityGroup. + * @private + * @return {boolean} + */ + shouldShowPageUrlCount_: function() { + return this.data.countsByUrl.size > 1; + }, +});
diff --git a/chrome/browser/resources/extensions/activity_log/activity_log_stream.js b/chrome/browser/resources/extensions/activity_log/activity_log_stream.js index 1a62539..7b74faf 100644 --- a/chrome/browser/resources/extensions/activity_log/activity_log_stream.js +++ b/chrome/browser/resources/extensions/activity_log/activity_log_stream.js
@@ -13,223 +13,221 @@ import {StreamArgItem, StreamItem} from './activity_log_stream_item.js'; - /** @interface */ - export class ActivityLogEventDelegate { - /** @return {!ChromeEvent} */ - getOnExtensionActivity() {} +/** @interface */ +export class ActivityLogEventDelegate { + /** @return {!ChromeEvent} */ + getOnExtensionActivity() {} +} + +/** + * Process activity for the stream. In the case of content scripts, we split + * the activity for every script invoked. + * @param {!chrome.activityLogPrivate.ExtensionActivity} + * activity + * @return {!Array<!StreamItem>} + */ +function processActivityForStream(activity) { + const activityType = activity.activityType; + const timestamp = activity.time; + const isContentScript = activityType === + chrome.activityLogPrivate.ExtensionActivityType.CONTENT_SCRIPT; + + const args = isContentScript ? JSON.stringify([]) : activity.args; + + let streamItemNames = [activity.apiCall]; + + // TODO(kelvinjiang): Reuse logic from activity_log_history and refactor + // some of the processing code into a separate file in a follow up CL. + if (isContentScript) { + streamItemNames = activity.args ? JSON.parse(activity.args) : []; + assert(Array.isArray(streamItemNames), 'Invalid data for script names.'); } + const other = activity.other; + const webRequestInfo = other && other.webRequest; + + return streamItemNames.map(name => ({ + args, + argUrl: activity.argUrl, + activityType, + name, + pageUrl: activity.pageUrl, + timestamp, + webRequestInfo, + expanded: false, + })); +} + +Polymer({ + is: 'activity-log-stream', + + _template: html`{__html_template__}`, + + properties: { + /** @type {string} */ + extensionId: String, + + /** @type {!ActivityLogEventDelegate} */ + delegate: Object, + + /** @private */ + isStreamOn_: { + type: Boolean, + value: false, + }, + + /** @private {!Array<!StreamItem>} */ + activityStream_: { + type: Array, + value: () => [], + }, + + /** @private {!Array<!StreamItem>} */ + filteredActivityStream_: { + type: Array, + computed: + 'computeFilteredActivityStream_(activityStream_.*, lastSearch_)', + }, + + /** @private */ + lastSearch_: { + type: String, + value: '', + }, + }, + + listeners: { + 'resize-stream': 'onResizeStream_', + }, + /** - * Process activity for the stream. In the case of content scripts, we split - * the activity for every script invoked. - * @param {!chrome.activityLogPrivate.ExtensionActivity} - * activity - * @return {!Array<!StreamItem>} + * Instance of |extensionActivityListener_| bound to |this|. + * @private {!Function} */ - function processActivityForStream(activity) { - const activityType = activity.activityType; - const timestamp = activity.time; - const isContentScript = activityType === - chrome.activityLogPrivate.ExtensionActivityType.CONTENT_SCRIPT; + listenerInstance_: () => {}, - const args = isContentScript ? JSON.stringify([]) : activity.args; + /** @override */ + attached: function() { + // Since this component is not restamped, this will only be called once + // in its lifecycle. + this.listenerInstance_ = this.extensionActivityListener_.bind(this); + this.startStream(); + }, - let streamItemNames = [activity.apiCall]; + /** @private */ + onResizeStream_: function(e) { + this.$$('iron-list').notifyResize(); + }, - // TODO(kelvinjiang): Reuse logic from activity_log_history and refactor - // some of the processing code into a separate file in a follow up CL. - if (isContentScript) { - streamItemNames = activity.args ? JSON.parse(activity.args) : []; - assert(Array.isArray(streamItemNames), 'Invalid data for script names.'); + clearStream: function() { + this.splice('activityStream_', 0, this.activityStream_.length); + }, + + startStream: function() { + if (this.isStreamOn_) { + return; } - const other = activity.other; - const webRequestInfo = other && other.webRequest; + this.isStreamOn_ = true; + this.delegate.getOnExtensionActivity().addListener(this.listenerInstance_); + }, - return streamItemNames.map(name => ({ - args, - argUrl: activity.argUrl, - activityType, - name, - pageUrl: activity.pageUrl, - timestamp, - webRequestInfo, - expanded: false, - })); - } + pauseStream: function() { + if (!this.isStreamOn_) { + return; + } - Polymer({ - is: 'activity-log-stream', + this.delegate.getOnExtensionActivity().removeListener( + this.listenerInstance_); + this.isStreamOn_ = false; + }, - _template: html`{__html_template__}`, - - properties: { - /** @type {string} */ - extensionId: String, - - /** @type {!ActivityLogEventDelegate} */ - delegate: Object, - - /** @private */ - isStreamOn_: { - type: Boolean, - value: false, - }, - - /** @private {!Array<!StreamItem>} */ - activityStream_: { - type: Array, - value: () => [], - }, - - /** @private {!Array<!StreamItem>} */ - filteredActivityStream_: { - type: Array, - computed: - 'computeFilteredActivityStream_(activityStream_.*, lastSearch_)', - }, - - /** @private */ - lastSearch_: { - type: String, - value: '', - }, - }, - - listeners: { - 'resize-stream': 'onResizeStream_', - }, - - /** - * Instance of |extensionActivityListener_| bound to |this|. - * @private {!Function} - */ - listenerInstance_: () => {}, - - /** @override */ - attached: function() { - // Since this component is not restamped, this will only be called once - // in its lifecycle. - this.listenerInstance_ = this.extensionActivityListener_.bind(this); + /** @private */ + onToggleButtonClick_: function() { + if (this.isStreamOn_) { + this.pauseStream(); + } else { this.startStream(); - }, + } + }, - /** @private */ - onResizeStream_: function(e) { - this.$$('iron-list').notifyResize(); - }, + /** + * @private + * @return {boolean} + */ + isStreamEmpty_: function() { + return this.activityStream_.length == 0; + }, - clearStream: function() { - this.splice('activityStream_', 0, this.activityStream_.length); - }, + /** + * @private + * @return {boolean} + */ + isFilteredStreamEmpty_: function() { + return this.filteredActivityStream_.length == 0; + }, - startStream: function() { - if (this.isStreamOn_) { - return; - } + /** + * @private + * @return {boolean} + */ + shouldShowEmptySearchMessage_: function() { + return !this.isStreamEmpty_() && this.isFilteredStreamEmpty_(); + }, - this.isStreamOn_ = true; - this.delegate.getOnExtensionActivity().addListener( - this.listenerInstance_); - }, + /** + * @private + * @param {!chrome.activityLogPrivate.ExtensionActivity} activity + */ + extensionActivityListener_: function(activity) { + if (activity.extensionId != this.extensionId) { + return; + } - pauseStream: function() { - if (!this.isStreamOn_) { - return; - } + this.splice( + 'activityStream_', this.activityStream_.length, 0, + ...processActivityForStream(activity)); - this.delegate.getOnExtensionActivity().removeListener( - this.listenerInstance_); - this.isStreamOn_ = false; - }, + // Used to update the scrollbar. + this.$$('iron-list').notifyResize(); + }, - /** @private */ - onToggleButtonClick_: function() { - if (this.isStreamOn_) { - this.pauseStream(); - } else { - this.startStream(); - } - }, + /** + * @private + * @param {!CustomEvent<string>} e + */ + onSearchChanged_: function(e) { + // Remove all whitespaces from the search term, as API call names and + // URLs should not contain any whitespace. As of now, only single term + // search queries are allowed. + const searchTerm = e.detail.replace(/\s+/g, '').toLowerCase(); + if (searchTerm === this.lastSearch_) { + return; + } - /** - * @private - * @return {boolean} - */ - isStreamEmpty_: function() { - return this.activityStream_.length == 0; - }, + this.lastSearch_ = searchTerm; + }, - /** - * @private - * @return {boolean} - */ - isFilteredStreamEmpty_: function() { - return this.filteredActivityStream_.length == 0; - }, + /** + * @private + * @return {!Array<!StreamItem>} + */ + computeFilteredActivityStream_: function() { + if (!this.lastSearch_) { + return this.activityStream_.slice(); + } - /** - * @private - * @return {boolean} - */ - shouldShowEmptySearchMessage_: function() { - return !this.isStreamEmpty_() && this.isFilteredStreamEmpty_(); - }, + // Match on these properties for each activity. + const propNames = [ + 'name', + 'pageUrl', + 'activityType', + ]; - /** - * @private - * @param {!chrome.activityLogPrivate.ExtensionActivity} activity - */ - extensionActivityListener_: function(activity) { - if (activity.extensionId != this.extensionId) { - return; - } - - this.splice( - 'activityStream_', this.activityStream_.length, 0, - ...processActivityForStream(activity)); - - // Used to update the scrollbar. - this.$$('iron-list').notifyResize(); - }, - - /** - * @private - * @param {!CustomEvent<string>} e - */ - onSearchChanged_: function(e) { - // Remove all whitespaces from the search term, as API call names and - // URLs should not contain any whitespace. As of now, only single term - // search queries are allowed. - const searchTerm = e.detail.replace(/\s+/g, '').toLowerCase(); - if (searchTerm === this.lastSearch_) { - return; - } - - this.lastSearch_ = searchTerm; - }, - - /** - * @private - * @return {!Array<!StreamItem>} - */ - computeFilteredActivityStream_: function() { - if (!this.lastSearch_) { - return this.activityStream_.slice(); - } - - // Match on these properties for each activity. - const propNames = [ - 'name', - 'pageUrl', - 'activityType', - ]; - - return this.activityStream_.filter(act => { - return propNames.some(prop => { - return act[prop] && - act[prop].toLowerCase().includes(this.lastSearch_); - }); + return this.activityStream_.filter(act => { + return propNames.some(prop => { + return act[prop] && act[prop].toLowerCase().includes(this.lastSearch_); }); - }, - }); + }); + }, +});
diff --git a/chrome/browser/resources/extensions/activity_log/activity_log_stream_item.js b/chrome/browser/resources/extensions/activity_log/activity_log_stream_item.js index daf175a..e702507 100644 --- a/chrome/browser/resources/extensions/activity_log/activity_log_stream_item.js +++ b/chrome/browser/resources/extensions/activity_log/activity_log_stream_item.js
@@ -10,152 +10,152 @@ import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; - /** - * @typedef {{ - * name: string, - * timestamp: number, - * activityType: !chrome.activityLogPrivate.ExtensionActivityFilter, - * pageUrl: string, - * argUrl: string, - * args: string, - * webRequestInfo: (string|undefined), - * expanded: boolean - * }} - */ - export let StreamItem; +/** + * @typedef {{ + * name: string, + * timestamp: number, + * activityType: !chrome.activityLogPrivate.ExtensionActivityFilter, + * pageUrl: string, + * argUrl: string, + * args: string, + * webRequestInfo: (string|undefined), + * expanded: boolean + * }} + */ +export let StreamItem; - /** - * A struct used to describe each argument for an activity (each item in - * the parsed version of |data.args|). Contains the argument's value itself - * and its index. - * @typedef {{ - * arg: string, - * index: number - * }} - */ - export let StreamArgItem; +/** + * A struct used to describe each argument for an activity (each item in + * the parsed version of |data.args|). Contains the argument's value itself + * and its index. + * @typedef {{ + * arg: string, + * index: number + * }} + */ +export let StreamArgItem; - /** - * Placeholder for arg_url that can occur in |StreamItem.args|. Sometimes we - * see this as '\u003Carg_url>' (opening arrow is unicode converted) but - * string comparison with the non-unicode value still returns true so we - * don't need to convert. - * @type {string} - */ - export const ARG_URL_PLACEHOLDER = '<arg_url>'; +/** + * Placeholder for arg_url that can occur in |StreamItem.args|. Sometimes we + * see this as '\u003Carg_url>' (opening arrow is unicode converted) but + * string comparison with the non-unicode value still returns true so we + * don't need to convert. + * @type {string} + */ +export const ARG_URL_PLACEHOLDER = '<arg_url>'; - /** - * Regex pattern for |ARG_URL_PLACEHOLDER| for String.replace. A regex of the - * exact string with a global search flag is needed to replace all - * occurrences. - * @type {!RegExp} - */ - const ARG_URL_PLACEHOLDER_REGEX = /"<arg_url>"/g; +/** + * Regex pattern for |ARG_URL_PLACEHOLDER| for String.replace. A regex of the + * exact string with a global search flag is needed to replace all + * occurrences. + * @type {!RegExp} + */ +const ARG_URL_PLACEHOLDER_REGEX = /"<arg_url>"/g; - Polymer({ - is: 'activity-log-stream-item', +Polymer({ + is: 'activity-log-stream-item', - _template: html`{__html_template__}`, + _template: html`{__html_template__}`, - properties: { - /** - * The underlying ActivityGroup that provides data for the - * ActivityLogItem displayed. - * @type {!StreamItem} - */ - data: Object, - - /** @private {!Array<!StreamArgItem>} */ - argsList_: { - type: Array, - computed: 'computeArgsList_(data.args)', - }, - - /** @private */ - isExpandable_: { - type: Boolean, - computed: 'computeIsExpandable_(data)', - }, - }, - + properties: { /** - * @private - * @return {boolean} + * The underlying ActivityGroup that provides data for the + * ActivityLogItem displayed. + * @type {!StreamItem} */ - computeIsExpandable_: function() { - return this.hasPageUrl_() || this.hasArgs_() || this.hasWebRequestInfo_(); - }, + data: Object, - /** - * @private - * @return {string} - */ - getFormattedTime_: function() { - // Format the activity's time to HH:MM:SS.mmm format. Use ToLocaleString - // for HH:MM:SS and padLeft for milliseconds. - const activityDate = new Date(this.data.timestamp); - const timeString = activityDate.toLocaleTimeString(undefined, { - hour12: false, - hour: '2-digit', - minute: '2-digit', - second: '2-digit', - }); - - const ms = activityDate.getMilliseconds().toString().padStart(3, '0'); - return `${timeString}.${ms}`; - }, - - /** - * @private - * @return {boolean} - */ - hasPageUrl_: function() { - return !!this.data.pageUrl; - }, - - /** - * @private - * @return {boolean} - */ - hasArgs_: function() { - return this.argsList_.length > 0; - }, - - /** - * @private - * @return {boolean} - */ - hasWebRequestInfo_: function() { - return !!this.data.webRequestInfo && this.data.webRequestInfo != '{}'; - }, - - /** - * @private - * @return {!Array<!StreamArgItem>} - */ - computeArgsList_: function() { - const parsedArgs = JSON.parse(this.data.args); - if (!Array.isArray(parsedArgs)) { - return []; - } - - // Replace occurrences AFTER parsing then stringifying as the JSON - // serializer on the C++ side escapes certain characters such as '<' and - // parsing un-escapes these characters. - // See EscapeSpecialCodePoint in base/json/string_escape.cc. - return parsedArgs.map( - (arg, i) => ({ - arg: JSON.stringify(arg).replace( - ARG_URL_PLACEHOLDER_REGEX, `"${this.data.argUrl}"`), - index: i + 1, - })); + /** @private {!Array<!StreamArgItem>} */ + argsList_: { + type: Array, + computed: 'computeArgsList_(data.args)', }, /** @private */ - onExpandClick_: function() { - if (this.isExpandable_) { - this.set('data.expanded', !this.data.expanded); - this.fire('resize-stream'); - } + isExpandable_: { + type: Boolean, + computed: 'computeIsExpandable_(data)', }, - }); + }, + + /** + * @private + * @return {boolean} + */ + computeIsExpandable_: function() { + return this.hasPageUrl_() || this.hasArgs_() || this.hasWebRequestInfo_(); + }, + + /** + * @private + * @return {string} + */ + getFormattedTime_: function() { + // Format the activity's time to HH:MM:SS.mmm format. Use ToLocaleString + // for HH:MM:SS and padLeft for milliseconds. + const activityDate = new Date(this.data.timestamp); + const timeString = activityDate.toLocaleTimeString(undefined, { + hour12: false, + hour: '2-digit', + minute: '2-digit', + second: '2-digit', + }); + + const ms = activityDate.getMilliseconds().toString().padStart(3, '0'); + return `${timeString}.${ms}`; + }, + + /** + * @private + * @return {boolean} + */ + hasPageUrl_: function() { + return !!this.data.pageUrl; + }, + + /** + * @private + * @return {boolean} + */ + hasArgs_: function() { + return this.argsList_.length > 0; + }, + + /** + * @private + * @return {boolean} + */ + hasWebRequestInfo_: function() { + return !!this.data.webRequestInfo && this.data.webRequestInfo != '{}'; + }, + + /** + * @private + * @return {!Array<!StreamArgItem>} + */ + computeArgsList_: function() { + const parsedArgs = JSON.parse(this.data.args); + if (!Array.isArray(parsedArgs)) { + return []; + } + + // Replace occurrences AFTER parsing then stringifying as the JSON + // serializer on the C++ side escapes certain characters such as '<' and + // parsing un-escapes these characters. + // See EscapeSpecialCodePoint in base/json/string_escape.cc. + return parsedArgs.map( + (arg, i) => ({ + arg: JSON.stringify(arg).replace( + ARG_URL_PLACEHOLDER_REGEX, `"${this.data.argUrl}"`), + index: i + 1, + })); + }, + + /** @private */ + onExpandClick_: function() { + if (this.isExpandable_) { + this.set('data.expanded', !this.data.expanded); + this.fire('resize-stream'); + } + }, +});
diff --git a/chrome/browser/resources/extensions/code_section.js b/chrome/browser/resources/extensions/code_section.js index c8406113..9a24dd3 100644 --- a/chrome/browser/resources/extensions/code_section.js +++ b/chrome/browser/resources/extensions/code_section.js
@@ -12,192 +12,192 @@ import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +/** + * @param {number} totalCount + * @param {number} oppositeCount + * @return {number} + */ +function visibleLineCount(totalCount, oppositeCount) { + // We limit the number of lines shown for DOM performance. + const MAX_VISIBLE_LINES = 1000; + const max = + Math.max(MAX_VISIBLE_LINES / 2, MAX_VISIBLE_LINES - oppositeCount); + return Math.min(max, totalCount); +} + +Polymer({ + is: 'extensions-code-section', + + _template: html`{__html_template__}`, + + behaviors: [I18nBehavior], + + properties: { + /** + * The code this object is displaying. + * @type {?chrome.developerPrivate.RequestFileSourceResponse} + */ + code: { + type: Object, + value: null, + }, + + isActive: Boolean, + + /** @private Highlighted code. */ + highlighted_: String, + + /** @private Code before the highlighted section. */ + before_: String, + + /** @private Code after the highlighted section. */ + after_: String, + + /** @private */ + showNoCode_: { + type: Boolean, + computed: 'computeShowNoCode_(isActive, highlighted_)', + }, + + /** @private Description for the highlighted section. */ + highlightDescription_: String, + + /** @private */ + lineNumbers_: String, + + /** @private */ + truncatedBefore_: Number, + + /** @private */ + truncatedAfter_: Number, + + /** + * The string to display if no |code| is set (e.g. because we couldn't + * load the relevant source file). + * @type {string} + */ + couldNotDisplayCode: String, + }, + + observers: [ + 'onCodeChanged_(code.*)', + ], + /** - * @param {number} totalCount - * @param {number} oppositeCount - * @return {number} + * @private */ - function visibleLineCount(totalCount, oppositeCount) { - // We limit the number of lines shown for DOM performance. - const MAX_VISIBLE_LINES = 1000; - const max = - Math.max(MAX_VISIBLE_LINES / 2, MAX_VISIBLE_LINES - oppositeCount); - return Math.min(max, totalCount); - } + onCodeChanged_: function() { + if (!this.code || + (!this.code.beforeHighlight && !this.code.highlight && + !this.code.afterHighlight)) { + this.highlighted_ = ''; + this.highlightDescription_ = ''; + this.before_ = ''; + this.after_ = ''; + this.lineNumbers_ = ''; + return; + } - Polymer({ - is: 'extensions-code-section', + const before = this.code.beforeHighlight; + const highlight = this.code.highlight; + const after = this.code.afterHighlight; - _template: html`{__html_template__}`, + const linesBefore = before ? before.split('\n') : []; + const linesAfter = after ? after.split('\n') : []; + const visibleLineCountBefore = + visibleLineCount(linesBefore.length, linesAfter.length); + const visibleLineCountAfter = + visibleLineCount(linesAfter.length, linesBefore.length); - behaviors: [I18nBehavior], + const visibleBefore = + linesBefore.slice(linesBefore.length - visibleLineCountBefore) + .join('\n'); + let visibleAfter = linesAfter.slice(0, visibleLineCountAfter).join('\n'); + // If the last character is a \n, force it to be rendered. + if (visibleAfter.charAt(visibleAfter.length - 1) == '\n') { + visibleAfter += ' '; + } - properties: { - /** - * The code this object is displaying. - * @type {?chrome.developerPrivate.RequestFileSourceResponse} - */ - code: { - type: Object, - value: null, - }, + this.highlighted_ = highlight; + this.highlightDescription_ = this.getAccessibilityHighlightDescription_( + linesBefore.length, highlight.split('\n').length); + this.before_ = visibleBefore; + this.after_ = visibleAfter; + this.truncatedBefore_ = linesBefore.length - visibleLineCountBefore; + this.truncatedAfter_ = linesAfter.length - visibleLineCountAfter; - isActive: Boolean, + const visibleCode = visibleBefore + highlight + visibleAfter; - /** @private Highlighted code. */ - highlighted_: String, + this.setLineNumbers_( + this.truncatedBefore_ + 1, + this.truncatedBefore_ + visibleCode.split('\n').length); + this.scrollToHighlight_(visibleLineCountBefore); + }, - /** @private Code before the highlighted section. */ - before_: String, + /** + * @param {number} lineCount + * @param {string} stringSingular + * @param {string} stringPluralTemplate + * @return {string} + * @private + */ + getLinesNotShownLabel_(lineCount, stringSingular, stringPluralTemplate) { + return lineCount == 1 ? + stringSingular : + loadTimeData.substituteString(stringPluralTemplate, lineCount); + }, - /** @private Code after the highlighted section. */ - after_: String, + /** + * @param {number} start + * @param {number} end + * @private + */ + setLineNumbers_: function(start, end) { + let lineNumbers = ''; + for (let i = start; i <= end; ++i) { + lineNumbers += i + '\n'; + } - /** @private */ - showNoCode_: { - type: Boolean, - computed: 'computeShowNoCode_(isActive, highlighted_)', - }, + this.lineNumbers_ = lineNumbers; + }, - /** @private Description for the highlighted section. */ - highlightDescription_: String, + /** + * @param {number} linesBeforeHighlight + * @private + */ + scrollToHighlight_: function(linesBeforeHighlight) { + const CSS_LINE_HEIGHT = 20; - /** @private */ - lineNumbers_: String, + // Count how many pixels is above the highlighted code. + const highlightTop = linesBeforeHighlight * CSS_LINE_HEIGHT; - /** @private */ - truncatedBefore_: Number, + // Find the position to show the highlight roughly in the middle. + const targetTop = highlightTop - this.clientHeight * 0.5; - /** @private */ - truncatedAfter_: Number, + this.$['scroll-container'].scrollTo({top: targetTop}); + }, - /** - * The string to display if no |code| is set (e.g. because we couldn't - * load the relevant source file). - * @type {string} - */ - couldNotDisplayCode: String, - }, + /** + * @param {number} lineStart + * @param {number} numLines + * @return {string} + * @private + */ + getAccessibilityHighlightDescription_: function(lineStart, numLines) { + if (numLines > 1) { + return this.i18n( + 'accessibilityErrorMultiLine', lineStart.toString(), + (lineStart + numLines - 1).toString()); + } else { + return this.i18n('accessibilityErrorLine', lineStart.toString()); + } + }, - observers: [ - 'onCodeChanged_(code.*)', - ], - - /** - * @private - */ - onCodeChanged_: function() { - if (!this.code || - (!this.code.beforeHighlight && !this.code.highlight && - !this.code.afterHighlight)) { - this.highlighted_ = ''; - this.highlightDescription_ = ''; - this.before_ = ''; - this.after_ = ''; - this.lineNumbers_ = ''; - return; - } - - const before = this.code.beforeHighlight; - const highlight = this.code.highlight; - const after = this.code.afterHighlight; - - const linesBefore = before ? before.split('\n') : []; - const linesAfter = after ? after.split('\n') : []; - const visibleLineCountBefore = - visibleLineCount(linesBefore.length, linesAfter.length); - const visibleLineCountAfter = - visibleLineCount(linesAfter.length, linesBefore.length); - - const visibleBefore = - linesBefore.slice(linesBefore.length - visibleLineCountBefore) - .join('\n'); - let visibleAfter = linesAfter.slice(0, visibleLineCountAfter).join('\n'); - // If the last character is a \n, force it to be rendered. - if (visibleAfter.charAt(visibleAfter.length - 1) == '\n') { - visibleAfter += ' '; - } - - this.highlighted_ = highlight; - this.highlightDescription_ = this.getAccessibilityHighlightDescription_( - linesBefore.length, highlight.split('\n').length); - this.before_ = visibleBefore; - this.after_ = visibleAfter; - this.truncatedBefore_ = linesBefore.length - visibleLineCountBefore; - this.truncatedAfter_ = linesAfter.length - visibleLineCountAfter; - - const visibleCode = visibleBefore + highlight + visibleAfter; - - this.setLineNumbers_( - this.truncatedBefore_ + 1, - this.truncatedBefore_ + visibleCode.split('\n').length); - this.scrollToHighlight_(visibleLineCountBefore); - }, - - /** - * @param {number} lineCount - * @param {string} stringSingular - * @param {string} stringPluralTemplate - * @return {string} - * @private - */ - getLinesNotShownLabel_(lineCount, stringSingular, stringPluralTemplate) { - return lineCount == 1 ? - stringSingular : - loadTimeData.substituteString(stringPluralTemplate, lineCount); - }, - - /** - * @param {number} start - * @param {number} end - * @private - */ - setLineNumbers_: function(start, end) { - let lineNumbers = ''; - for (let i = start; i <= end; ++i) { - lineNumbers += i + '\n'; - } - - this.lineNumbers_ = lineNumbers; - }, - - /** - * @param {number} linesBeforeHighlight - * @private - */ - scrollToHighlight_: function(linesBeforeHighlight) { - const CSS_LINE_HEIGHT = 20; - - // Count how many pixels is above the highlighted code. - const highlightTop = linesBeforeHighlight * CSS_LINE_HEIGHT; - - // Find the position to show the highlight roughly in the middle. - const targetTop = highlightTop - this.clientHeight * 0.5; - - this.$['scroll-container'].scrollTo({top: targetTop}); - }, - - /** - * @param {number} lineStart - * @param {number} numLines - * @return {string} - * @private - */ - getAccessibilityHighlightDescription_: function(lineStart, numLines) { - if (numLines > 1) { - return this.i18n( - 'accessibilityErrorMultiLine', lineStart.toString(), - (lineStart + numLines - 1).toString()); - } else { - return this.i18n('accessibilityErrorLine', lineStart.toString()); - } - }, - - /** - * @private - * @return {boolean} - */ - computeShowNoCode_: function() { - return this.isActive && !this.highlighted_; - }, - }); + /** + * @private + * @return {boolean} + */ + computeShowNoCode_: function() { + return this.isActive && !this.highlighted_; + }, +});
diff --git a/chrome/browser/resources/extensions/detail_view.js b/chrome/browser/resources/extensions/detail_view.js index 1c33c0e..65dfba4 100644 --- a/chrome/browser/resources/extensions/detail_view.js +++ b/chrome/browser/resources/extensions/detail_view.js
@@ -34,354 +34,351 @@ import {computeInspectableViewLabel, getItemSource, getItemSourceString, isControlled, isEnabled, userCanChangeEnablement} from './item_util.js'; import {navigation, Page} from './navigation_helper.js'; - Polymer({ - is: 'extensions-detail-view', +Polymer({ + is: 'extensions-detail-view', - _template: html`{__html_template__}`, + _template: html`{__html_template__}`, - behaviors: [ - CrContainerShadowBehavior, - ItemBehavior, - ], + behaviors: [ + CrContainerShadowBehavior, + ItemBehavior, + ], - properties: { - /** - * The underlying ExtensionInfo for the details being displayed. - * @type {!chrome.developerPrivate.ExtensionInfo} - */ - data: Object, - - /** @private */ - size_: String, - - /** @type {!ItemDelegate} */ - delegate: Object, - - /** Whether the user has enabled the UI's developer mode. */ - inDevMode: Boolean, - - /** Whether "allow in incognito" option should be shown. */ - incognitoAvailable: Boolean, - - /** Whether "View Activity Log" link should be shown. */ - showActivityLog: Boolean, - - /** Whether the user navigated to this page from the activity log page. */ - fromActivityLog: Boolean, - }, - - observers: [ - 'onItemIdChanged_(data.id, delegate)', - ], - - listeners: { - 'view-enter-start': 'onViewEnterStart_', - }, - + properties: { /** - * Focuses the extensions options button. This should be used after the - * dialog closes. + * The underlying ExtensionInfo for the details being displayed. + * @type {!chrome.developerPrivate.ExtensionInfo} */ - focusOptionsButton: function() { - this.$$('#extensions-options').focus(); - }, - - /** - * Focuses the back button when page is loaded. - * @private - */ - onViewEnterStart_: function() { - const elementToFocus = this.fromActivityLog ? - this.$.extensionsActivityLogLink : - this.$.closeButton; - - afterNextRender(this, () => focusWithoutInk(elementToFocus)); - }, + data: Object, /** @private */ - onItemIdChanged_: function() { - // Clear the size, since this view is reused, such that no obsolete size - // is displayed.: - this.size_ = ''; - this.delegate.getExtensionSize(this.data.id).then(size => { - this.size_ = size; - }); - }, + size_: String, - /** @private */ - onActivityLogTap_: function() { - navigation.navigateTo( - {page: Page.ACTIVITY_LOG, extensionId: this.data.id}); - }, + /** @type {!ItemDelegate} */ + delegate: Object, - /** - * @param {string} description - * @param {string} fallback - * @return {string} - * @private - */ - getDescription_: function(description, fallback) { - return description || fallback; - }, + /** Whether the user has enabled the UI's developer mode. */ + inDevMode: Boolean, - /** @private */ - onCloseButtonTap_: function() { - navigation.navigateTo({page: Page.LIST}); - }, + /** Whether "allow in incognito" option should be shown. */ + incognitoAvailable: Boolean, - /** - * @return {boolean} - * @private - */ - isControlled_: function() { - return isControlled(this.data); - }, + /** Whether "View Activity Log" link should be shown. */ + showActivityLog: Boolean, - /** - * @return {boolean} - * @private - */ - isEnabled_: function() { - return isEnabled(this.data.state); - }, + /** Whether the user navigated to this page from the activity log page. */ + fromActivityLog: Boolean, + }, - /** - * @return {boolean} - * @private - */ - isEnableToggleEnabled_: function() { - return userCanChangeEnablement(this.data); - }, + observers: [ + 'onItemIdChanged_(data.id, delegate)', + ], - /** - * Returns true if the extension is in the terminated state. - * @return {boolean} - * @private - */ - isTerminated_: function() { - return this.data.state == - chrome.developerPrivate.ExtensionState.TERMINATED; - }, + listeners: { + 'view-enter-start': 'onViewEnterStart_', + }, - /** - * @return {boolean} - * @private - */ - hasDependentExtensions_: function() { - return this.data.dependentExtensions.length > 0; - }, + /** + * Focuses the extensions options button. This should be used after the + * dialog closes. + */ + focusOptionsButton: function() { + this.$$('#extensions-options').focus(); + }, - /** - * @return {boolean} - * @private - */ - hasWarnings_: function() { - return this.data.disableReasons.corruptInstall || - this.data.disableReasons.suspiciousInstall || - this.data.disableReasons.updateRequired || - !!this.data.blacklistText || this.data.runtimeWarnings.length > 0; - }, + /** + * Focuses the back button when page is loaded. + * @private + */ + onViewEnterStart_: function() { + const elementToFocus = this.fromActivityLog ? + this.$.extensionsActivityLogLink : + this.$.closeButton; - /** - * @return {string} - * @private - */ - computeEnabledStyle_: function() { - return this.isEnabled_() ? 'enabled-text' : ''; - }, + afterNextRender(this, () => focusWithoutInk(elementToFocus)); + }, - /** - * @param {!chrome.developerPrivate.ExtensionState} state - * @param {string} onText - * @param {string} offText - * @return {string} - * @private - */ - computeEnabledText_: function(state, onText, offText) { - // TODO(devlin): Get the full spectrum of these strings from bettes. - return isEnabled(state) ? onText : offText; - }, + /** @private */ + onItemIdChanged_: function() { + // Clear the size, since this view is reused, such that no obsolete size + // is displayed.: + this.size_ = ''; + this.delegate.getExtensionSize(this.data.id).then(size => { + this.size_ = size; + }); + }, - /** - * @param {!chrome.developerPrivate.ExtensionView} view - * @return {string} - * @private - */ - computeInspectLabel_: function(view) { - return computeInspectableViewLabel(view); - }, + /** @private */ + onActivityLogTap_: function() { + navigation.navigateTo({page: Page.ACTIVITY_LOG, extensionId: this.data.id}); + }, - /** - * @return {boolean} - * @private - */ - shouldShowOptionsLink_: function() { - return !!this.data.optionsPage; - }, + /** + * @param {string} description + * @param {string} fallback + * @return {string} + * @private + */ + getDescription_: function(description, fallback) { + return description || fallback; + }, - /** - * @return {boolean} - * @private - */ - shouldShowOptionsSection_: function() { - return this.data.incognitoAccess.isEnabled || - this.data.fileAccess.isEnabled || this.data.errorCollection.isEnabled; - }, + /** @private */ + onCloseButtonTap_: function() { + navigation.navigateTo({page: Page.LIST}); + }, - /** - * @return {boolean} - * @private - */ - shouldShowIncognitoOption_: function() { - return this.data.incognitoAccess.isEnabled && this.incognitoAvailable; - }, + /** + * @return {boolean} + * @private + */ + isControlled_: function() { + return isControlled(this.data); + }, - /** @private */ - onEnableChange_: function() { - this.delegate.setItemEnabled( - this.data.id, this.$['enable-toggle'].checked); - }, + /** + * @return {boolean} + * @private + */ + isEnabled_: function() { + return isEnabled(this.data.state); + }, - /** - * @param {!{model: !{item: !chrome.developerPrivate.ExtensionView}}} e - * @private - */ - onInspectTap_: function(e) { - this.delegate.inspectItemView(this.data.id, e.model.item); - }, + /** + * @return {boolean} + * @private + */ + isEnableToggleEnabled_: function() { + return userCanChangeEnablement(this.data); + }, - /** @private */ - onExtensionOptionsTap_: function() { - this.delegate.showItemOptionsPage(this.data); - }, + /** + * Returns true if the extension is in the terminated state. + * @return {boolean} + * @private + */ + isTerminated_: function() { + return this.data.state == chrome.developerPrivate.ExtensionState.TERMINATED; + }, - /** @private */ - onReloadTap_: function() { - this.delegate.reloadItem(this.data.id).catch(loadError => { - this.fire('load-error', loadError); - }); - }, + /** + * @return {boolean} + * @private + */ + hasDependentExtensions_: function() { + return this.data.dependentExtensions.length > 0; + }, - /** @private */ - onRemoveTap_: function() { - this.delegate.deleteItem(this.data.id); - }, + /** + * @return {boolean} + * @private + */ + hasWarnings_: function() { + return this.data.disableReasons.corruptInstall || + this.data.disableReasons.suspiciousInstall || + this.data.disableReasons.updateRequired || !!this.data.blacklistText || + this.data.runtimeWarnings.length > 0; + }, - /** @private */ - onRepairTap_: function() { - this.delegate.repairItem(this.data.id); - }, + /** + * @return {string} + * @private + */ + computeEnabledStyle_: function() { + return this.isEnabled_() ? 'enabled-text' : ''; + }, - /** @private */ - onLoadPathTap_: function() { - this.delegate.showInFolder(this.data.id); - }, + /** + * @param {!chrome.developerPrivate.ExtensionState} state + * @param {string} onText + * @param {string} offText + * @return {string} + * @private + */ + computeEnabledText_: function(state, onText, offText) { + // TODO(devlin): Get the full spectrum of these strings from bettes. + return isEnabled(state) ? onText : offText; + }, - /** @private */ - onAllowIncognitoChange_: function() { - this.delegate.setItemAllowedIncognito( - this.data.id, this.$$('#allow-incognito').checked); - }, + /** + * @param {!chrome.developerPrivate.ExtensionView} view + * @return {string} + * @private + */ + computeInspectLabel_: function(view) { + return computeInspectableViewLabel(view); + }, - /** @private */ - onAllowOnFileUrlsChange_: function() { - this.delegate.setItemAllowedOnFileUrls( - this.data.id, this.$$('#allow-on-file-urls').checked); - }, + /** + * @return {boolean} + * @private + */ + shouldShowOptionsLink_: function() { + return !!this.data.optionsPage; + }, - /** @private */ - onCollectErrorsChange_: function() { - this.delegate.setItemCollectsErrors( - this.data.id, this.$$('#collect-errors').checked); - }, + /** + * @return {boolean} + * @private + */ + shouldShowOptionsSection_: function() { + return this.data.incognitoAccess.isEnabled || + this.data.fileAccess.isEnabled || this.data.errorCollection.isEnabled; + }, - /** @private */ - onExtensionWebSiteTap_: function() { - this.delegate.openUrl(this.data.manifestHomePageUrl); - }, + /** + * @return {boolean} + * @private + */ + shouldShowIncognitoOption_: function() { + return this.data.incognitoAccess.isEnabled && this.incognitoAvailable; + }, - /** @private */ - onViewInStoreTap_: function() { - this.delegate.openUrl(this.data.webStoreUrl); - }, + /** @private */ + onEnableChange_: function() { + this.delegate.setItemEnabled(this.data.id, this.$['enable-toggle'].checked); + }, - /** - * @param {!chrome.developerPrivate.DependentExtension} item - * @return {string} - * @private - */ - computeDependentEntry_: function(item) { - return loadTimeData.getStringF('itemDependentEntry', item.name, item.id); - }, + /** + * @param {!{model: !{item: !chrome.developerPrivate.ExtensionView}}} e + * @private + */ + onInspectTap_: function(e) { + this.delegate.inspectItemView(this.data.id, e.model.item); + }, - /** - * @return {string} - * @private - */ - computeSourceString_: function() { - return this.data.locationText || - getItemSourceString(getItemSource(this.data)); - }, + /** @private */ + onExtensionOptionsTap_: function() { + this.delegate.showItemOptionsPage(this.data); + }, - /** - * @param {chrome.developerPrivate.ControllerType} type - * @return {string} - * @private - */ - getIndicatorIcon_: function(type) { - switch (type) { - case 'POLICY': - return 'cr20:domain'; - case 'CHILD_CUSTODIAN': - return 'cr:account-child-invert'; - case 'SUPERVISED_USER_CUSTODIAN': - return 'cr:supervisor-account'; - default: - return ''; - } - }, + /** @private */ + onReloadTap_: function() { + this.delegate.reloadItem(this.data.id).catch(loadError => { + this.fire('load-error', loadError); + }); + }, - /** - * @return {boolean} - * @private - */ - hasPermissions_: function() { - return this.data.permissions.simplePermissions.length > 0 || - this.hasRuntimeHostPermissions_(); - }, + /** @private */ + onRemoveTap_: function() { + this.delegate.deleteItem(this.data.id); + }, - /** - * @return {boolean} - * @private - */ - hasRuntimeHostPermissions_: function() { - return !!this.data.permissions.runtimeHostPermissions; - }, + /** @private */ + onRepairTap_: function() { + this.delegate.repairItem(this.data.id); + }, - /** - * @return {boolean} - * @private - */ - showSiteAccessContent_: function() { - return this.showFreeformRuntimeHostPermissions_() || - this.showHostPermissionsToggleList_(); - }, + /** @private */ + onLoadPathTap_: function() { + this.delegate.showInFolder(this.data.id); + }, - /** - * @return {boolean} - * @private - */ - showFreeformRuntimeHostPermissions_: function() { - return this.hasRuntimeHostPermissions_() && - this.data.permissions.runtimeHostPermissions.hasAllHosts; - }, + /** @private */ + onAllowIncognitoChange_: function() { + this.delegate.setItemAllowedIncognito( + this.data.id, this.$$('#allow-incognito').checked); + }, - /** - * @return {boolean} - * @private - */ - showHostPermissionsToggleList_: function() { - return this.hasRuntimeHostPermissions_() && - !this.data.permissions.runtimeHostPermissions.hasAllHosts; - }, - }); + /** @private */ + onAllowOnFileUrlsChange_: function() { + this.delegate.setItemAllowedOnFileUrls( + this.data.id, this.$$('#allow-on-file-urls').checked); + }, + + /** @private */ + onCollectErrorsChange_: function() { + this.delegate.setItemCollectsErrors( + this.data.id, this.$$('#collect-errors').checked); + }, + + /** @private */ + onExtensionWebSiteTap_: function() { + this.delegate.openUrl(this.data.manifestHomePageUrl); + }, + + /** @private */ + onViewInStoreTap_: function() { + this.delegate.openUrl(this.data.webStoreUrl); + }, + + /** + * @param {!chrome.developerPrivate.DependentExtension} item + * @return {string} + * @private + */ + computeDependentEntry_: function(item) { + return loadTimeData.getStringF('itemDependentEntry', item.name, item.id); + }, + + /** + * @return {string} + * @private + */ + computeSourceString_: function() { + return this.data.locationText || + getItemSourceString(getItemSource(this.data)); + }, + + /** + * @param {chrome.developerPrivate.ControllerType} type + * @return {string} + * @private + */ + getIndicatorIcon_: function(type) { + switch (type) { + case 'POLICY': + return 'cr20:domain'; + case 'CHILD_CUSTODIAN': + return 'cr:account-child-invert'; + case 'SUPERVISED_USER_CUSTODIAN': + return 'cr:supervisor-account'; + default: + return ''; + } + }, + + /** + * @return {boolean} + * @private + */ + hasPermissions_: function() { + return this.data.permissions.simplePermissions.length > 0 || + this.hasRuntimeHostPermissions_(); + }, + + /** + * @return {boolean} + * @private + */ + hasRuntimeHostPermissions_: function() { + return !!this.data.permissions.runtimeHostPermissions; + }, + + /** + * @return {boolean} + * @private + */ + showSiteAccessContent_: function() { + return this.showFreeformRuntimeHostPermissions_() || + this.showHostPermissionsToggleList_(); + }, + + /** + * @return {boolean} + * @private + */ + showFreeformRuntimeHostPermissions_: function() { + return this.hasRuntimeHostPermissions_() && + this.data.permissions.runtimeHostPermissions.hasAllHosts; + }, + + /** + * @return {boolean} + * @private + */ + showHostPermissionsToggleList_: function() { + return this.hasRuntimeHostPermissions_() && + !this.data.permissions.runtimeHostPermissions.hasAllHosts; + }, +});
diff --git a/chrome/browser/resources/extensions/drag_and_drop_handler.js b/chrome/browser/resources/extensions/drag_and_drop_handler.js index b05bbbf9..a6bfab3 100644 --- a/chrome/browser/resources/extensions/drag_and_drop_handler.js +++ b/chrome/browser/resources/extensions/drag_and_drop_handler.js
@@ -7,100 +7,98 @@ import {Service} from './service.js'; - /** @implements DragWrapperDelegate */ - export class DragAndDropHandler { - /** - * @param {boolean} dragEnabled - * @param {!EventTarget} target - */ - constructor(dragEnabled, target) { - this.dragEnabled = dragEnabled; +/** @implements DragWrapperDelegate */ +export class DragAndDropHandler { + /** + * @param {boolean} dragEnabled + * @param {!EventTarget} target + */ + constructor(dragEnabled, target) { + this.dragEnabled = dragEnabled; - /** @private {!EventTarget} */ - this.eventTarget_ = target; + /** @private {!EventTarget} */ + this.eventTarget_ = target; + } + + /** @override */ + shouldAcceptDrag(e) { + // External Extension installation can be disabled globally, e.g. while a + // different overlay is already showing. + if (!this.dragEnabled) { + return false; } - /** @override */ - shouldAcceptDrag(e) { - // External Extension installation can be disabled globally, e.g. while a - // different overlay is already showing. - if (!this.dragEnabled) { - return false; - } + // We can't access filenames during the 'dragenter' event, so we have to + // wait until 'drop' to decide whether to do something with the file or + // not. + // See: http://www.w3.org/TR/2011/WD-html5-20110113/dnd.html#concept-dnd-p + return !!e.dataTransfer.types && e.dataTransfer.types.indexOf('Files') > -1; + } - // We can't access filenames during the 'dragenter' event, so we have to - // wait until 'drop' to decide whether to do something with the file or - // not. - // See: http://www.w3.org/TR/2011/WD-html5-20110113/dnd.html#concept-dnd-p - return !!e.dataTransfer.types && - e.dataTransfer.types.indexOf('Files') > -1; + /** @override */ + doDragEnter() { + Service.getInstance().notifyDragInstallInProgress(); + this.eventTarget_.dispatchEvent(new CustomEvent('extension-drag-started')); + } + + /** @override */ + doDragLeave() { + this.fireDragEnded_(); + } + + /** @override */ + doDragOver(e) { + e.preventDefault(); + } + + /** @override */ + doDrop(e) { + this.fireDragEnded_(); + if (e.dataTransfer.files.length != 1) { + return; } - /** @override */ - doDragEnter() { - Service.getInstance().notifyDragInstallInProgress(); - this.eventTarget_.dispatchEvent( - new CustomEvent('extension-drag-started')); + let handled = false; + + // Files lack a check if they're a directory, but we can find out through + // its item entry. + const item = e.dataTransfer.items[0]; + if (item.kind === 'file' && item.webkitGetAsEntry().isDirectory) { + handled = true; + this.handleDirectoryDrop_(); + } else if (/\.(crx|user\.js|zip)$/i.test(e.dataTransfer.files[0].name)) { + // Only process files that look like extensions. Other files should + // navigate the browser normally. + handled = true; + this.handleFileDrop_(); } - /** @override */ - doDragLeave() { - this.fireDragEnded_(); - } - - /** @override */ - doDragOver(e) { + if (handled) { e.preventDefault(); } - - /** @override */ - doDrop(e) { - this.fireDragEnded_(); - if (e.dataTransfer.files.length != 1) { - return; - } - - let handled = false; - - // Files lack a check if they're a directory, but we can find out through - // its item entry. - const item = e.dataTransfer.items[0]; - if (item.kind === 'file' && item.webkitGetAsEntry().isDirectory) { - handled = true; - this.handleDirectoryDrop_(); - } else if (/\.(crx|user\.js|zip)$/i.test(e.dataTransfer.files[0].name)) { - // Only process files that look like extensions. Other files should - // navigate the browser normally. - handled = true; - this.handleFileDrop_(); - } - - if (handled) { - e.preventDefault(); - } - } - - /** - * Handles a dropped file. - * @private - */ - handleFileDrop_() { - Service.getInstance().installDroppedFile(); - } - - /** - * Handles a dropped directory. - * @private - */ - handleDirectoryDrop_() { - Service.getInstance().loadUnpackedFromDrag().catch(loadError => { - this.eventTarget_.dispatchEvent(new CustomEvent( - 'drag-and-drop-load-error', {detail: loadError})); - }); - } - - /** @private */ - fireDragEnded_() { - this.eventTarget_.dispatchEvent(new CustomEvent('extension-drag-ended')); - } } + + /** + * Handles a dropped file. + * @private + */ + handleFileDrop_() { + Service.getInstance().installDroppedFile(); + } + + /** + * Handles a dropped directory. + * @private + */ + handleDirectoryDrop_() { + Service.getInstance().loadUnpackedFromDrag().catch(loadError => { + this.eventTarget_.dispatchEvent( + new CustomEvent('drag-and-drop-load-error', {detail: loadError})); + }); + } + + /** @private */ + fireDragEnded_() { + this.eventTarget_.dispatchEvent(new CustomEvent('extension-drag-ended')); + } +}
diff --git a/chrome/browser/resources/extensions/error_page.js b/chrome/browser/resources/extensions/error_page.js index a1d876b..1da980e 100644 --- a/chrome/browser/resources/extensions/error_page.js +++ b/chrome/browser/resources/extensions/error_page.js
@@ -28,415 +28,414 @@ /** @typedef {chrome.developerPrivate.RuntimeError} */ let RuntimeError; - /** @interface */ - export class ErrorPageDelegate { - /** - * @param {string} extensionId - * @param {!Array<number>=} errorIds - * @param {chrome.developerPrivate.ErrorType=} type - */ - deleteErrors(extensionId, errorIds, type) {} - - /** - * @param {chrome.developerPrivate.RequestFileSourceProperties} args - * @return {!Promise<!chrome.developerPrivate.RequestFileSourceResponse>} - */ - requestFileSource(args) {} - } - +/** @interface */ +export class ErrorPageDelegate { /** - * Get the URL relative to the main extension url. If the url is - * unassociated with the extension, this will be the full url. - * @param {string} url - * @param {?(ManifestError|RuntimeError)} error - * @return {string} + * @param {string} extensionId + * @param {!Array<number>=} errorIds + * @param {chrome.developerPrivate.ErrorType=} type */ - function getRelativeUrl(url, error) { - const fullUrl = 'chrome-extension://' + error.extensionId + '/'; - return url.startsWith(fullUrl) ? url.substring(fullUrl.length) : url; - } + deleteErrors(extensionId, errorIds, type) {} /** - * Given 3 strings, this function returns the correct one for the type of - * error that |item| is. - * @param {!ManifestError|!RuntimeError} item - * @param {string} log - * @param {string} warn - * @param {string} error + * @param {chrome.developerPrivate.RequestFileSourceProperties} args + * @return {!Promise<!chrome.developerPrivate.RequestFileSourceResponse>} + */ + requestFileSource(args) {} +} + +/** + * Get the URL relative to the main extension url. If the url is + * unassociated with the extension, this will be the full url. + * @param {string} url + * @param {?(ManifestError|RuntimeError)} error + * @return {string} + */ +function getRelativeUrl(url, error) { + const fullUrl = 'chrome-extension://' + error.extensionId + '/'; + return url.startsWith(fullUrl) ? url.substring(fullUrl.length) : url; +} + +/** + * Given 3 strings, this function returns the correct one for the type of + * error that |item| is. + * @param {!ManifestError|!RuntimeError} item + * @param {string} log + * @param {string} warn + * @param {string} error + * @return {string} + * @private + */ +function getErrorSeverityText_(item, log, warn, error) { + if (item.type == chrome.developerPrivate.ErrorType.RUNTIME) { + switch (item.severity) { + case chrome.developerPrivate.ErrorLevel.LOG: + return log; + case chrome.developerPrivate.ErrorLevel.WARN: + return warn; + case chrome.developerPrivate.ErrorLevel.ERROR: + return error; + } + assertNotReached(); + } + assert(item.type == chrome.developerPrivate.ErrorType.MANIFEST); + return warn; +} + +Polymer({ + is: 'extensions-error-page', + + _template: html`{__html_template__}`, + + behaviors: [CrContainerShadowBehavior], + + properties: { + /** @type {!chrome.developerPrivate.ExtensionInfo|undefined} */ + data: Object, + + /** @type {!ErrorPageDelegate|undefined} */ + delegate: Object, + + // Whether or not dev mode is enabled. + inDevMode: { + type: Boolean, + value: false, + observer: 'onInDevModeChanged_', + }, + + /** @private {!Array<!(ManifestError|RuntimeError)>} */ + entries_: Array, + + /** @private {?chrome.developerPrivate.RequestFileSourceResponse} */ + code_: Object, + + /** + * Index into |entries_|. + * @private + */ + selectedEntry_: { + type: Number, + observer: 'onSelectedErrorChanged_', + }, + + /** @private {?chrome.developerPrivate.StackFrame}*/ + selectedStackFrame_: { + type: Object, + value: function() { + return null; + }, + }, + }, + + observers: [ + 'observeDataChanges_(data.*)', + ], + + listeners: { + 'view-enter-start': 'onViewEnterStart_', + }, + + /** @override */ + ready: function() { + FocusOutlineManager.forDocument(document); + }, + + /** @return {!ManifestError|!RuntimeError} */ + getSelectedError: function() { + return this.entries_[this.selectedEntry_]; + }, + + /** + * Focuses the back button when page is loaded. + * @private + */ + onViewEnterStart_: function() { + afterNextRender(this, () => focusWithoutInk(this.$.closeButton)); + chrome.metricsPrivate.recordUserAction('Options_ViewExtensionErrors'); + }, + + /** + * @param {!ManifestError|!RuntimeError} error + * @param {string} unknown * @return {string} * @private */ - function getErrorSeverityText_(item, log, warn, error) { - if (item.type == chrome.developerPrivate.ErrorType.RUNTIME) { - switch (item.severity) { - case chrome.developerPrivate.ErrorLevel.LOG: - return log; - case chrome.developerPrivate.ErrorLevel.WARN: - return warn; - case chrome.developerPrivate.ErrorLevel.ERROR: - return error; - } - assertNotReached(); + getContextUrl_: function(error, unknown) { + return error.contextUrl ? getRelativeUrl(error.contextUrl, error) : unknown; + }, + + /** + * Watches for changes to |data| in order to fetch the corresponding + * file source. + * @private + */ + observeDataChanges_: function() { + const errors = this.data.manifestErrors.concat(this.data.runtimeErrors); + this.entries_ = errors; + this.selectedEntry_ = -1; // This also help reset code-section content. + if (this.entries_.length) { + this.selectedEntry_ = 0; } - assert(item.type == chrome.developerPrivate.ErrorType.MANIFEST); - return warn; - } + }, - Polymer({ - is: 'extensions-error-page', + /** @private */ + onCloseButtonTap_: function() { + navigation.navigateTo({page: Page.LIST}); + }, - _template: html`{__html_template__}`, + /** @private */ + onClearAllTap_: function() { + const ids = this.entries_.map(entry => entry.id); + this.delegate.deleteErrors(this.data.id, ids); + }, - behaviors: [CrContainerShadowBehavior], + /** + * @param {!ManifestError|!RuntimeError} error + * @return {string} + * @private + */ + computeErrorIcon_: function(error) { + // Do not i18n these strings, they're CSS classes. + return getErrorSeverityText_(error, 'info', 'warning', 'error'); + }, - properties: { - /** @type {!chrome.developerPrivate.ExtensionInfo|undefined} */ - data: Object, + /** + * @param {!ManifestError|!RuntimeError} error + * @return {string} + * @private + */ + computeErrorTypeLabel_: function(error) { + return getErrorSeverityText_( + error, loadTimeData.getString('logLevel'), + loadTimeData.getString('warnLevel'), + loadTimeData.getString('errorLevel')); + }, - /** @type {!ErrorPageDelegate|undefined} */ - delegate: Object, + /** + * @param {!Event} e + * @private + */ + onDeleteErrorAction_: function(e) { + this.delegate.deleteErrors( + this.data.id, [(/** @type {!{model:Object}} */ (e)).model.item.id]); + e.stopPropagation(); + }, - // Whether or not dev mode is enabled. - inDevMode: { - type: Boolean, - value: false, - observer: 'onInDevModeChanged_', - }, + /** private */ + onInDevModeChanged_: function() { + if (!this.inDevMode) { + // Wait until next render cycle in case error page is loading. + this.async(() => { + this.onCloseButtonTap_(); + }); + } + }, - /** @private {!Array<!(ManifestError|RuntimeError)>} */ - entries_: Array, + /** + * Fetches the source for the selected error and populates the code section. + * @private + */ + onSelectedErrorChanged_: function() { + this.code_ = null; - /** @private {?chrome.developerPrivate.RequestFileSourceResponse} */ - code_: Object, + if (this.selectedEntry_ < 0) { + return; + } - /** - * Index into |entries_|. - * @private - */ - selectedEntry_: { - type: Number, - observer: 'onSelectedErrorChanged_', - }, + const error = this.getSelectedError(); + const args = { + extensionId: error.extensionId, + message: error.message, + }; + switch (error.type) { + case chrome.developerPrivate.ErrorType.MANIFEST: + args.pathSuffix = error.source; + args.manifestKey = error.manifestKey; + args.manifestSpecific = error.manifestSpecific; + break; + case chrome.developerPrivate.ErrorType.RUNTIME: + // slice(1) because pathname starts with a /. + args.pathSuffix = new URL(error.source).pathname.slice(1); + args.lineNumber = error.stackTrace && error.stackTrace[0] ? + error.stackTrace[0].lineNumber : + 0; + this.selectedStackFrame_ = error.stackTrace && error.stackTrace[0] ? + error.stackTrace[0] : + null; + break; + } + this.delegate.requestFileSource(args).then(code => this.code_ = code); + }, - /** @private {?chrome.developerPrivate.StackFrame}*/ - selectedStackFrame_: { - type: Object, - value: function() { - return null; - }, - }, - }, + /** + * @return {boolean} + * @private + */ + computeIsRuntimeError_: function(item) { + return item.type == chrome.developerPrivate.ErrorType.RUNTIME; + }, - observers: [ - 'observeDataChanges_(data.*)', - ], + /** + * The description is a human-readable summation of the frame, in the + * form "<relative_url>:<line_number> (function)", e.g. + * "myfile.js:25 (myFunction)". + * @param {!chrome.developerPrivate.StackFrame} frame + * @return {string} + * @private + */ + getStackTraceLabel_: function(frame) { + let description = getRelativeUrl(frame.url, this.getSelectedError()) + ':' + + frame.lineNumber; - listeners: { - 'view-enter-start': 'onViewEnterStart_', - }, + if (frame.functionName) { + const functionName = frame.functionName == '(anonymous function)' ? + loadTimeData.getString('anonymousFunction') : + frame.functionName; + description += ' (' + functionName + ')'; + } - /** @override */ - ready: function() { - FocusOutlineManager.forDocument(document); - }, + return description; + }, - /** @return {!ManifestError|!RuntimeError} */ - getSelectedError: function() { - return this.entries_[this.selectedEntry_]; - }, + /** + * @param {chrome.developerPrivate.StackFrame} frame + * @return {string} + * @private + */ + getStackFrameClass_: function(frame) { + return frame == this.selectedStackFrame_ ? 'selected' : ''; + }, - /** - * Focuses the back button when page is loaded. - * @private - */ - onViewEnterStart_: function() { - afterNextRender(this, () => focusWithoutInk(this.$.closeButton)); - chrome.metricsPrivate.recordUserAction('Options_ViewExtensionErrors'); - }, + /** + * @param {!chrome.developerPrivate.StackFrame} frame + * @return {number} + * @private + */ + getStackFrameTabIndex_: function(frame) { + return frame == this.selectedStackFrame_ ? 0 : -1; + }, - /** - * @param {!ManifestError|!RuntimeError} error - * @param {string} unknown - * @return {string} - * @private - */ - getContextUrl_: function(error, unknown) { - return error.contextUrl ? getRelativeUrl(error.contextUrl, error) : - unknown; - }, + /** + * This function is used to determine whether or not we want to show a + * stack frame. We don't want to show code from internal scripts. + * @param {string} url + * @return {boolean} + * @private + */ + shouldDisplayFrame_: function(url) { + // All our internal scripts are in the 'extensions::' namespace. + return !/^extensions::/.test(url); + }, - /** - * Watches for changes to |data| in order to fetch the corresponding - * file source. - * @private - */ - observeDataChanges_: function() { - const errors = this.data.manifestErrors.concat(this.data.runtimeErrors); - this.entries_ = errors; - this.selectedEntry_ = -1; // This also help reset code-section content. - if (this.entries_.length) { - this.selectedEntry_ = 0; - } - }, + /** + * @param {!chrome.developerPrivate.StackFrame} frame + * @private + */ + updateSelected_: function(frame) { + this.selectedStackFrame_ = assert(frame); - /** @private */ - onCloseButtonTap_: function() { - navigation.navigateTo({page: Page.LIST}); - }, + const selectedError = this.getSelectedError(); + this.delegate + .requestFileSource({ + extensionId: selectedError.extensionId, + message: selectedError.message, + pathSuffix: getRelativeUrl(frame.url, selectedError), + lineNumber: frame.lineNumber, + }) + .then(code => this.code_ = code); + }, - /** @private */ - onClearAllTap_: function() { - const ids = this.entries_.map(entry => entry.id); - this.delegate.deleteErrors(this.data.id, ids); - }, + /** + * @param {!Event} e + * @private + */ + onStackFrameTap_: function(e) { + const frame = /** @type {!{model:Object}} */ (e).model.item; + this.updateSelected_(frame); + }, - /** - * @param {!ManifestError|!RuntimeError} error - * @return {string} - * @private - */ - computeErrorIcon_: function(error) { - // Do not i18n these strings, they're CSS classes. - return getErrorSeverityText_(error, 'info', 'warning', 'error'); - }, + /** + * @param {!Event} e + * @private + */ + onStackKeydown_: function(e) { + let direction = 0; - /** - * @param {!ManifestError|!RuntimeError} error - * @return {string} - * @private - */ - computeErrorTypeLabel_: function(error) { - return getErrorSeverityText_( - error, loadTimeData.getString('logLevel'), - loadTimeData.getString('warnLevel'), - loadTimeData.getString('errorLevel')); - }, + if (e.key == 'ArrowDown') { + direction = 1; + } else if (e.key == 'ArrowUp') { + direction = -1; + } else { + return; + } - /** - * @param {!Event} e - * @private - */ - onDeleteErrorAction_: function(e) { - this.delegate.deleteErrors( - this.data.id, [(/** @type {!{model:Object}} */ (e)).model.item.id]); - e.stopPropagation(); - }, + e.preventDefault(); - /** private */ - onInDevModeChanged_: function() { - if (!this.inDevMode) { - // Wait until next render cycle in case error page is loading. - this.async(() => { - this.onCloseButtonTap_(); - }); - } - }, + const list = e.target.parentElement.querySelectorAll('li'); - /** - * Fetches the source for the selected error and populates the code section. - * @private - */ - onSelectedErrorChanged_: function() { - this.code_ = null; - - if (this.selectedEntry_ < 0) { - return; - } - - const error = this.getSelectedError(); - const args = { - extensionId: error.extensionId, - message: error.message, - }; - switch (error.type) { - case chrome.developerPrivate.ErrorType.MANIFEST: - args.pathSuffix = error.source; - args.manifestKey = error.manifestKey; - args.manifestSpecific = error.manifestSpecific; - break; - case chrome.developerPrivate.ErrorType.RUNTIME: - // slice(1) because pathname starts with a /. - args.pathSuffix = new URL(error.source).pathname.slice(1); - args.lineNumber = error.stackTrace && error.stackTrace[0] ? - error.stackTrace[0].lineNumber : - 0; - this.selectedStackFrame_ = error.stackTrace && error.stackTrace[0] ? - error.stackTrace[0] : - null; - break; - } - this.delegate.requestFileSource(args).then(code => this.code_ = code); - }, - - /** - * @return {boolean} - * @private - */ - computeIsRuntimeError_: function(item) { - return item.type == chrome.developerPrivate.ErrorType.RUNTIME; - }, - - /** - * The description is a human-readable summation of the frame, in the - * form "<relative_url>:<line_number> (function)", e.g. - * "myfile.js:25 (myFunction)". - * @param {!chrome.developerPrivate.StackFrame} frame - * @return {string} - * @private - */ - getStackTraceLabel_: function(frame) { - let description = getRelativeUrl(frame.url, this.getSelectedError()) + - ':' + frame.lineNumber; - - if (frame.functionName) { - const functionName = frame.functionName == '(anonymous function)' ? - loadTimeData.getString('anonymousFunction') : - frame.functionName; - description += ' (' + functionName + ')'; - } - - return description; - }, - - /** - * @param {chrome.developerPrivate.StackFrame} frame - * @return {string} - * @private - */ - getStackFrameClass_: function(frame) { - return frame == this.selectedStackFrame_ ? 'selected' : ''; - }, - - /** - * @param {!chrome.developerPrivate.StackFrame} frame - * @return {number} - * @private - */ - getStackFrameTabIndex_: function(frame) { - return frame == this.selectedStackFrame_ ? 0 : -1; - }, - - /** - * This function is used to determine whether or not we want to show a - * stack frame. We don't want to show code from internal scripts. - * @param {string} url - * @return {boolean} - * @private - */ - shouldDisplayFrame_: function(url) { - // All our internal scripts are in the 'extensions::' namespace. - return !/^extensions::/.test(url); - }, - - /** - * @param {!chrome.developerPrivate.StackFrame} frame - * @private - */ - updateSelected_: function(frame) { - this.selectedStackFrame_ = assert(frame); - - const selectedError = this.getSelectedError(); - this.delegate - .requestFileSource({ - extensionId: selectedError.extensionId, - message: selectedError.message, - pathSuffix: getRelativeUrl(frame.url, selectedError), - lineNumber: frame.lineNumber, - }) - .then(code => this.code_ = code); - }, - - /** - * @param {!Event} e - * @private - */ - onStackFrameTap_: function(e) { - const frame = /** @type {!{model:Object}} */ (e).model.item; - this.updateSelected_(frame); - }, - - /** - * @param {!Event} e - * @private - */ - onStackKeydown_: function(e) { - let direction = 0; - - if (e.key == 'ArrowDown') { - direction = 1; - } else if (e.key == 'ArrowUp') { - direction = -1; - } else { - return; - } - - e.preventDefault(); - - const list = e.target.parentElement.querySelectorAll('li'); - - for (let i = 0; i < list.length; ++i) { - if (list[i].classList.contains('selected')) { - const polymerEvent = /** @type {!{model: !Object}} */ (e); - const frame = polymerEvent.model.item.stackTrace[i + direction]; - if (frame) { - this.updateSelected_(frame); - list[i + direction].focus(); // Preserve focus. - } - return; + for (let i = 0; i < list.length; ++i) { + if (list[i].classList.contains('selected')) { + const polymerEvent = /** @type {!{model: !Object}} */ (e); + const frame = polymerEvent.model.item.stackTrace[i + direction]; + if (frame) { + this.updateSelected_(frame); + list[i + direction].focus(); // Preserve focus. } - } - }, - - /** - * Computes the class name for the error item depending on whether its - * the currently selected error. - * @param {number} index - * @return {string} - * @private - */ - computeErrorClass_: function(index) { - return index == this.selectedEntry_ ? 'selected' : ''; - }, - - /** @private */ - iconName_: function(index) { - return index == this.selectedEntry_ ? 'icon-expand-less' : - 'icon-expand-more'; - }, - - /** - * Determine if the iron-collapse should be opened (expanded). - * @param {number} index - * @return {boolean} - * @private - */ - isOpened_: function(index) { - return index == this.selectedEntry_; - }, - - - /** - * @param {number} index - * @return {string} The aria-expanded value as a string. - * @private - */ - isAriaExpanded_: function(index) { - return this.isOpened_(index).toString(); - }, - - /** - * @param {!{type: string, code: string, model: !{index: number}}} e - * @private - */ - onErrorItemAction_: function(e) { - if (e.type == 'keydown' && !((e.code == 'Space' || e.code == 'Enter'))) { return; } + } + }, - // Call preventDefault() to avoid the browser scrolling when the space key - // is pressed. - e.preventDefault(); - this.selectedEntry_ = - this.selectedEntry_ == e.model.index ? -1 : e.model.index; - }, - }); + /** + * Computes the class name for the error item depending on whether its + * the currently selected error. + * @param {number} index + * @return {string} + * @private + */ + computeErrorClass_: function(index) { + return index == this.selectedEntry_ ? 'selected' : ''; + }, + + /** @private */ + iconName_: function(index) { + return index == this.selectedEntry_ ? 'icon-expand-less' : + 'icon-expand-more'; + }, + + /** + * Determine if the iron-collapse should be opened (expanded). + * @param {number} index + * @return {boolean} + * @private + */ + isOpened_: function(index) { + return index == this.selectedEntry_; + }, + + + /** + * @param {number} index + * @return {string} The aria-expanded value as a string. + * @private + */ + isAriaExpanded_: function(index) { + return this.isOpened_(index).toString(); + }, + + /** + * @param {!{type: string, code: string, model: !{index: number}}} e + * @private + */ + onErrorItemAction_: function(e) { + if (e.type == 'keydown' && !((e.code == 'Space' || e.code == 'Enter'))) { + return; + } + + // Call preventDefault() to avoid the browser scrolling when the space key + // is pressed. + e.preventDefault(); + this.selectedEntry_ = + this.selectedEntry_ == e.model.index ? -1 : e.model.index; + }, +});
diff --git a/chrome/browser/resources/extensions/host_permissions_toggle_list.js b/chrome/browser/resources/extensions/host_permissions_toggle_list.js index 44594ebc..b8a3e49 100644 --- a/chrome/browser/resources/extensions/host_permissions_toggle_list.js +++ b/chrome/browser/resources/extensions/host_permissions_toggle_list.js
@@ -14,78 +14,78 @@ import {ItemDelegate} from './item.js'; - Polymer({ - is: 'extensions-host-permissions-toggle-list', +Polymer({ + is: 'extensions-host-permissions-toggle-list', - _template: html`{__html_template__}`, + _template: html`{__html_template__}`, - properties: { - /** - * The underlying permissions data. - * @type {chrome.developerPrivate.RuntimeHostPermissions} - */ - permissions: Object, - - /** @private */ - itemId: String, - - /** @type {!ItemDelegate} */ - delegate: Object, - }, - + properties: { /** - * @return {boolean} Whether the item is allowed to execute on all of its - * requested sites. - * @private + * The underlying permissions data. + * @type {chrome.developerPrivate.RuntimeHostPermissions} */ - allowedOnAllHosts_: function() { - return this.permissions.hostAccess == - chrome.developerPrivate.HostAccess.ON_ALL_SITES; - }, - - /** - * Returns a lexicographically-sorted list of the hosts associated with this - * item. - * @return {!Array<!chrome.developerPrivate.SiteControl>} - * @private - */ - getSortedHosts_: function() { - return this.permissions.hosts.sort((a, b) => { - if (a.host < b.host) { - return -1; - } - if (a.host > b.host) { - return 1; - } - return 0; - }); - }, + permissions: Object, /** @private */ - onAllHostsToggleChanged_: function() { - // TODO(devlin): In the case of going from all sites to specific sites, - // we'll withhold all sites (i.e., all specific site toggles will move to - // unchecked, and the user can check them individually). This is slightly - // different than the sync page, where disabling the "sync everything" - // switch leaves everything synced, and user can uncheck them - // individually. It could be nice to align on behavior, but probably not - // super high priority. - this.delegate.setItemHostAccess( - this.itemId, - this.$.allHostsToggle.checked ? - chrome.developerPrivate.HostAccess.ON_ALL_SITES : - chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES); - }, + itemId: String, - /** @private */ - onHostAccessChanged_: function(e) { - const host = e.target.host; - const checked = e.target.checked; + /** @type {!ItemDelegate} */ + delegate: Object, + }, - if (checked) { - this.delegate.addRuntimeHostPermission(this.itemId, host); - } else { - this.delegate.removeRuntimeHostPermission(this.itemId, host); + /** + * @return {boolean} Whether the item is allowed to execute on all of its + * requested sites. + * @private + */ + allowedOnAllHosts_: function() { + return this.permissions.hostAccess == + chrome.developerPrivate.HostAccess.ON_ALL_SITES; + }, + + /** + * Returns a lexicographically-sorted list of the hosts associated with this + * item. + * @return {!Array<!chrome.developerPrivate.SiteControl>} + * @private + */ + getSortedHosts_: function() { + return this.permissions.hosts.sort((a, b) => { + if (a.host < b.host) { + return -1; } - }, - }); + if (a.host > b.host) { + return 1; + } + return 0; + }); + }, + + /** @private */ + onAllHostsToggleChanged_: function() { + // TODO(devlin): In the case of going from all sites to specific sites, + // we'll withhold all sites (i.e., all specific site toggles will move to + // unchecked, and the user can check them individually). This is slightly + // different than the sync page, where disabling the "sync everything" + // switch leaves everything synced, and user can uncheck them + // individually. It could be nice to align on behavior, but probably not + // super high priority. + this.delegate.setItemHostAccess( + this.itemId, + this.$.allHostsToggle.checked ? + chrome.developerPrivate.HostAccess.ON_ALL_SITES : + chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES); + }, + + /** @private */ + onHostAccessChanged_: function(e) { + const host = e.target.host; + const checked = e.target.checked; + + if (checked) { + this.delegate.addRuntimeHostPermission(this.itemId, host); + } else { + this.delegate.removeRuntimeHostPermission(this.itemId, host); + } + }, +});
diff --git a/chrome/browser/resources/extensions/install_warnings_dialog.js b/chrome/browser/resources/extensions/install_warnings_dialog.js index a882800..b333dca 100644 --- a/chrome/browser/resources/extensions/install_warnings_dialog.js +++ b/chrome/browser/resources/extensions/install_warnings_dialog.js
@@ -10,23 +10,23 @@ import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; - Polymer({ - is: 'extensions-install-warnings-dialog', +Polymer({ + is: 'extensions-install-warnings-dialog', - _template: html`{__html_template__}`, + _template: html`{__html_template__}`, - properties: { - /** @type {!Array<string>} */ - installWarnings: Array, - }, + properties: { + /** @type {!Array<string>} */ + installWarnings: Array, + }, - /** @override */ - attached: function() { - this.$.dialog.showModal(); - }, + /** @override */ + attached: function() { + this.$.dialog.showModal(); + }, - /** @private */ - onOkTap_: function() { - this.$.dialog.close(); - }, - }); + /** @private */ + onOkTap_: function() { + this.$.dialog.close(); + }, +});
diff --git a/chrome/browser/resources/extensions/item.js b/chrome/browser/resources/extensions/item.js index 0cea8365..4abc178 100644 --- a/chrome/browser/resources/extensions/item.js +++ b/chrome/browser/resources/extensions/item.js
@@ -29,418 +29,414 @@ import {computeInspectableViewLabel, getItemSource, getItemSourceString, isControlled, isEnabled, SourceType, userCanChangeEnablement} from './item_util.js'; import {navigation, Page} from './navigation_helper.js'; - /** @interface */ - export class ItemDelegate { - /** @param {string} id */ - deleteItem(id) {} +/** @interface */ +export class ItemDelegate { + /** @param {string} id */ + deleteItem(id) {} - /** - * @param {string} id - * @param {boolean} isEnabled - */ - setItemEnabled(id, isEnabled) {} + /** + * @param {string} id + * @param {boolean} isEnabled + */ + setItemEnabled(id, isEnabled) {} - /** - * @param {string} id - * @param {boolean} isAllowedIncognito - */ - setItemAllowedIncognito(id, isAllowedIncognito) {} + /** + * @param {string} id + * @param {boolean} isAllowedIncognito + */ + setItemAllowedIncognito(id, isAllowedIncognito) {} - /** - * @param {string} id - * @param {boolean} isAllowedOnFileUrls - */ - setItemAllowedOnFileUrls(id, isAllowedOnFileUrls) {} + /** + * @param {string} id + * @param {boolean} isAllowedOnFileUrls + */ + setItemAllowedOnFileUrls(id, isAllowedOnFileUrls) {} - /** - * @param {string} id - * @param {!chrome.developerPrivate.HostAccess} hostAccess - */ - setItemHostAccess(id, hostAccess) {} + /** + * @param {string} id + * @param {!chrome.developerPrivate.HostAccess} hostAccess + */ + setItemHostAccess(id, hostAccess) {} - /** - * @param {string} id - * @param {boolean} collectsErrors - */ - setItemCollectsErrors(id, collectsErrors) {} + /** + * @param {string} id + * @param {boolean} collectsErrors + */ + setItemCollectsErrors(id, collectsErrors) {} - /** - * @param {string} id - * @param {chrome.developerPrivate.ExtensionView} view - */ - inspectItemView(id, view) {} + /** + * @param {string} id + * @param {chrome.developerPrivate.ExtensionView} view + */ + inspectItemView(id, view) {} - /** - * @param {string} url - */ - openUrl(url) {} + /** + * @param {string} url + */ + openUrl(url) {} - /** - * @param {string} id - * @return {!Promise} - */ - reloadItem(id) {} + /** + * @param {string} id + * @return {!Promise} + */ + reloadItem(id) {} - /** @param {string} id */ - repairItem(id) {} + /** @param {string} id */ + repairItem(id) {} - /** @param {!chrome.developerPrivate.ExtensionInfo} extension */ - showItemOptionsPage(extension) {} + /** @param {!chrome.developerPrivate.ExtensionInfo} extension */ + showItemOptionsPage(extension) {} - /** @param {string} id */ - showInFolder(id) {} + /** @param {string} id */ + showInFolder(id) {} - /** - * @param {string} id - * @return {!Promise<string>} - */ - getExtensionSize(id) {} + /** + * @param {string} id + * @return {!Promise<string>} + */ + getExtensionSize(id) {} - /** - * @param {string} id - * @param {string} host - * @return {!Promise<void>} - */ - addRuntimeHostPermission(id, host) {} + /** + * @param {string} id + * @param {string} host + * @return {!Promise<void>} + */ + addRuntimeHostPermission(id, host) {} - /** - * @param {string} id - * @param {string} host - * @return {!Promise<void>} - */ - removeRuntimeHostPermission(id, host) {} - } + /** + * @param {string} id + * @param {string} host + * @return {!Promise<void>} + */ + removeRuntimeHostPermission(id, host) {} +} - Polymer({ - is: 'extensions-item', +Polymer({ + is: 'extensions-item', - _template: html`{__html_template__}`, + _template: html`{__html_template__}`, - behaviors: [I18nBehavior, ItemBehavior], + behaviors: [I18nBehavior, ItemBehavior], - properties: { - // The item's delegate, or null. - delegate: { - type: Object, - }, - - // Whether or not dev mode is enabled. - inDevMode: { - type: Boolean, - value: false, - }, - - // The underlying ExtensionInfo itself. Public for use in declarative - // bindings. - /** @type {chrome.developerPrivate.ExtensionInfo} */ - data: { - type: Object, - }, - - // Whether or not the expanded view of the item is shown. - /** @private */ - showingDetails_: { - type: Boolean, - value: false, - }, + properties: { + // The item's delegate, or null. + delegate: { + type: Object, }, - /** Prevents reloading the same item while it's already being reloaded. */ - isReloading_: false, - - observers: [ - 'observeIdVisibility_(inDevMode, showingDetails_, data.id)', - ], - - /** @return {!HTMLElement} The "Details" button. */ - getDetailsButton: function() { - return /** @type {!HTMLElement} */ (this.$.detailsButton); + // Whether or not dev mode is enabled. + inDevMode: { + type: Boolean, + value: false, }, - /** @return {?HTMLElement} The "Errors" button, if it exists. */ - getErrorsButton: function() { - return /** @type {?HTMLElement} */ (this.$$('#errors-button')); + // The underlying ExtensionInfo itself. Public for use in declarative + // bindings. + /** @type {chrome.developerPrivate.ExtensionInfo} */ + data: { + type: Object, }, - /** @private string */ - a11yAssociation_: function() { - // Don't use I18nBehavior.i18n because of additional checks it performs. - // Polymer ensures that this string is not stamped into arbitrary HTML. - // |this.data.name| can contain any data including html tags. - // ex: "My <video> download extension!" - return loadTimeData.getStringF( - 'extensionA11yAssociation', this.data.name); - }, - + // Whether or not the expanded view of the item is shown. /** @private */ - observeIdVisibility_: function(inDevMode, showingDetails, id) { - flush(); - const idElement = this.$$('#extension-id'); - if (idElement) { - assert(this.data); - idElement.innerHTML = this.i18n('itemId', this.data.id); - } + showingDetails_: { + type: Boolean, + value: false, }, + }, - /** - * @return {boolean} - * @private - */ - shouldShowErrorsButton_: function() { - // When the error console is disabled (happens when - // --disable-error-console command line flag is used or when in the - // Stable/Beta channel), |installWarnings| is populated. - if (this.data.installWarnings && this.data.installWarnings.length > 0) { - return true; - } + /** Prevents reloading the same item while it's already being reloaded. */ + isReloading_: false, - // When error console is enabled |installedWarnings| is not populated. - // Instead |manifestErrors| and |runtimeErrors| are used. - return this.data.manifestErrors.length > 0 || - this.data.runtimeErrors.length > 0; - }, + observers: [ + 'observeIdVisibility_(inDevMode, showingDetails_, data.id)', + ], - /** @private */ - onRemoveTap_: function() { - this.delegate.deleteItem(this.data.id); - }, + /** @return {!HTMLElement} The "Details" button. */ + getDetailsButton: function() { + return /** @type {!HTMLElement} */ (this.$.detailsButton); + }, - /** @private */ - onEnableChange_: function() { - this.delegate.setItemEnabled( - this.data.id, this.$['enable-toggle'].checked); - }, + /** @return {?HTMLElement} The "Errors" button, if it exists. */ + getErrorsButton: function() { + return /** @type {?HTMLElement} */ (this.$$('#errors-button')); + }, - /** @private */ - onErrorsTap_: function() { - if (this.data.installWarnings && this.data.installWarnings.length > 0) { - this.fire('show-install-warnings', this.data.installWarnings); - return; - } + /** @private string */ + a11yAssociation_: function() { + // Don't use I18nBehavior.i18n because of additional checks it performs. + // Polymer ensures that this string is not stamped into arbitrary HTML. + // |this.data.name| can contain any data including html tags. + // ex: "My <video> download extension!" + return loadTimeData.getStringF('extensionA11yAssociation', this.data.name); + }, - navigation.navigateTo({page: Page.ERRORS, extensionId: this.data.id}); - }, + /** @private */ + observeIdVisibility_: function(inDevMode, showingDetails, id) { + flush(); + const idElement = this.$$('#extension-id'); + if (idElement) { + assert(this.data); + idElement.innerHTML = this.i18n('itemId', this.data.id); + } + }, - /** @private */ - onDetailsTap_: function() { - navigation.navigateTo({page: Page.DETAILS, extensionId: this.data.id}); - }, + /** + * @return {boolean} + * @private + */ + shouldShowErrorsButton_: function() { + // When the error console is disabled (happens when + // --disable-error-console command line flag is used or when in the + // Stable/Beta channel), |installWarnings| is populated. + if (this.data.installWarnings && this.data.installWarnings.length > 0) { + return true; + } - /** - * @param {!{model: !{item: !chrome.developerPrivate.ExtensionView}}} e - * @private - */ - onInspectTap_: function(e) { - this.delegate.inspectItemView(this.data.id, this.data.views[0]); - }, + // When error console is enabled |installedWarnings| is not populated. + // Instead |manifestErrors| and |runtimeErrors| are used. + return this.data.manifestErrors.length > 0 || + this.data.runtimeErrors.length > 0; + }, - /** @private */ - onExtraInspectTap_: function() { - navigation.navigateTo({page: Page.DETAILS, extensionId: this.data.id}); - }, + /** @private */ + onRemoveTap_: function() { + this.delegate.deleteItem(this.data.id); + }, - /** @private */ - onReloadTap_: function() { - // Don't reload if in the middle of an update. - if (this.isReloading_) { - return; - } + /** @private */ + onEnableChange_: function() { + this.delegate.setItemEnabled(this.data.id, this.$['enable-toggle'].checked); + }, - this.isReloading_ = true; + /** @private */ + onErrorsTap_: function() { + if (this.data.installWarnings && this.data.installWarnings.length > 0) { + this.fire('show-install-warnings', this.data.installWarnings); + return; + } - const toastManager = getInstance(); - // Keep the toast open indefinitely. - toastManager.duration = 0; - toastManager.show(this.i18n('itemReloading'), false); - this.delegate.reloadItem(this.data.id) - .then( - () => { - toastManager.hide(); - toastManager.duration = 3000; - toastManager.show(this.i18n('itemReloaded'), false); - this.isReloading_ = false; - }, - loadError => { - this.fire('load-error', loadError); - toastManager.hide(); - this.isReloading_ = false; - }); - }, + navigation.navigateTo({page: Page.ERRORS, extensionId: this.data.id}); + }, - /** @private */ - onRepairTap_: function() { - this.delegate.repairItem(this.data.id); - }, + /** @private */ + onDetailsTap_: function() { + navigation.navigateTo({page: Page.DETAILS, extensionId: this.data.id}); + }, - /** - * @return {boolean} - * @private - */ - isControlled_: function() { - return isControlled(this.data); - }, + /** + * @param {!{model: !{item: !chrome.developerPrivate.ExtensionView}}} e + * @private + */ + onInspectTap_: function(e) { + this.delegate.inspectItemView(this.data.id, this.data.views[0]); + }, - /** - * @return {boolean} - * @private - */ - isEnabled_: function() { - return isEnabled(this.data.state); - }, + /** @private */ + onExtraInspectTap_: function() { + navigation.navigateTo({page: Page.DETAILS, extensionId: this.data.id}); + }, - /** - * @return {boolean} - * @private - */ - isEnableToggleEnabled_: function() { - return userCanChangeEnablement(this.data); - }, + /** @private */ + onReloadTap_: function() { + // Don't reload if in the middle of an update. + if (this.isReloading_) { + return; + } - /** - * Returns true if the enable toggle should be shown. - * @return {boolean} - * @private - */ - showEnableToggle_: function() { - return !this.isTerminated_() && !this.data.disableReasons.corruptInstall; - }, + this.isReloading_ = true; - /** - * Returns true if the extension is in the terminated state. - * @return {boolean} - * @private - */ - isTerminated_: function() { - return this.data.state == - chrome.developerPrivate.ExtensionState.TERMINATED; - }, + const toastManager = getInstance(); + // Keep the toast open indefinitely. + toastManager.duration = 0; + toastManager.show(this.i18n('itemReloading'), false); + this.delegate.reloadItem(this.data.id) + .then( + () => { + toastManager.hide(); + toastManager.duration = 3000; + toastManager.show(this.i18n('itemReloaded'), false); + this.isReloading_ = false; + }, + loadError => { + this.fire('load-error', loadError); + toastManager.hide(); + this.isReloading_ = false; + }); + }, - /** - * return {string} - * @private - */ - computeClasses_: function() { - let classes = this.isEnabled_() ? 'enabled' : 'disabled'; - if (this.inDevMode) { - classes += ' dev-mode'; - } - return classes; - }, + /** @private */ + onRepairTap_: function() { + this.delegate.repairItem(this.data.id); + }, - /** - * @return {string} - * @private - */ - computeSourceIndicatorIcon_: function() { - switch (getItemSource(this.data)) { - case SourceType.POLICY: - return 'extensions-icons:business'; - case SourceType.SIDELOADED: - return 'extensions-icons:input'; - case SourceType.UNKNOWN: - // TODO(dpapad): Ask UX for a better icon for this case. - return 'extensions-icons:input'; - case SourceType.UNPACKED: - return 'extensions-icons:unpacked'; - case SourceType.WEBSTORE: - return ''; - } - assertNotReached(); - }, + /** + * @return {boolean} + * @private + */ + isControlled_: function() { + return isControlled(this.data); + }, - /** - * @return {string} - * @private - */ - computeSourceIndicatorText_: function() { - if (this.data.locationText) { - return this.data.locationText; - } + /** + * @return {boolean} + * @private + */ + isEnabled_: function() { + return isEnabled(this.data.state); + }, - const sourceType = getItemSource(this.data); - return sourceType == SourceType.WEBSTORE ? - '' : - getItemSourceString(sourceType); - }, + /** + * @return {boolean} + * @private + */ + isEnableToggleEnabled_: function() { + return userCanChangeEnablement(this.data); + }, - /** - * @return {boolean} - * @private - */ - computeInspectViewsHidden_: function() { - return !this.data.views || this.data.views.length == 0; - }, + /** + * Returns true if the enable toggle should be shown. + * @return {boolean} + * @private + */ + showEnableToggle_: function() { + return !this.isTerminated_() && !this.data.disableReasons.corruptInstall; + }, - /** - * @return {string} - * @private - */ - computeFirstInspectTitle_: function() { - // Note: theoretically, this wouldn't be called without any inspectable - // views (because it's in a dom-if="!computeInspectViewsHidden_()"). - // However, due to the recycling behavior of iron list, it seems that - // sometimes it can. Even when it is, the UI behaves properly, but we - // need to handle the case gracefully. - return this.data.views.length > 0 ? - computeInspectableViewLabel(this.data.views[0]) : - ''; - }, + /** + * Returns true if the extension is in the terminated state. + * @return {boolean} + * @private + */ + isTerminated_: function() { + return this.data.state == chrome.developerPrivate.ExtensionState.TERMINATED; + }, - /** - * @return {string} - * @private - */ - computeFirstInspectLabel_: function() { - const label = this.computeFirstInspectTitle_(); - return label && this.data.views.length > 1 ? label + ',' : label; - }, + /** + * return {string} + * @private + */ + computeClasses_: function() { + let classes = this.isEnabled_() ? 'enabled' : 'disabled'; + if (this.inDevMode) { + classes += ' dev-mode'; + } + return classes; + }, - /** - * @return {boolean} - * @private - */ - computeExtraViewsHidden_: function() { - return this.data.views.length <= 1; - }, + /** + * @return {string} + * @private + */ + computeSourceIndicatorIcon_: function() { + switch (getItemSource(this.data)) { + case SourceType.POLICY: + return 'extensions-icons:business'; + case SourceType.SIDELOADED: + return 'extensions-icons:input'; + case SourceType.UNKNOWN: + // TODO(dpapad): Ask UX for a better icon for this case. + return 'extensions-icons:input'; + case SourceType.UNPACKED: + return 'extensions-icons:unpacked'; + case SourceType.WEBSTORE: + return ''; + } + assertNotReached(); + }, - /** - * @return {boolean} - * @private - */ - computeDevReloadButtonHidden_: function() { - // Only display the reload spinner if the extension is unpacked and - // enabled. There's no point in reloading a disabled extension, and we'll - // show a crashed reload button if it's terminated. - const showIcon = - this.data.location == chrome.developerPrivate.Location.UNPACKED && - this.data.state == chrome.developerPrivate.ExtensionState.ENABLED; - return !showIcon; - }, + /** + * @return {string} + * @private + */ + computeSourceIndicatorText_: function() { + if (this.data.locationText) { + return this.data.locationText; + } - /** - * @return {string} - * @private - */ - computeExtraInspectLabel_: function() { - return this.i18n( - 'itemInspectViewsExtra', (this.data.views.length - 1).toString()); - }, + const sourceType = getItemSource(this.data); + return sourceType == SourceType.WEBSTORE ? '' : + getItemSourceString(sourceType); + }, - /** - * @return {boolean} - * @private - */ - hasWarnings_: function() { - return this.data.disableReasons.corruptInstall || - this.data.disableReasons.suspiciousInstall || - this.data.runtimeWarnings.length > 0 || !!this.data.blacklistText; - }, + /** + * @return {boolean} + * @private + */ + computeInspectViewsHidden_: function() { + return !this.data.views || this.data.views.length == 0; + }, - /** - * @return {string} - * @private - */ - computeWarningsClasses_: function() { - return this.data.blacklistText ? 'severe' : 'mild'; - }, - }); + /** + * @return {string} + * @private + */ + computeFirstInspectTitle_: function() { + // Note: theoretically, this wouldn't be called without any inspectable + // views (because it's in a dom-if="!computeInspectViewsHidden_()"). + // However, due to the recycling behavior of iron list, it seems that + // sometimes it can. Even when it is, the UI behaves properly, but we + // need to handle the case gracefully. + return this.data.views.length > 0 ? + computeInspectableViewLabel(this.data.views[0]) : + ''; + }, + + /** + * @return {string} + * @private + */ + computeFirstInspectLabel_: function() { + const label = this.computeFirstInspectTitle_(); + return label && this.data.views.length > 1 ? label + ',' : label; + }, + + /** + * @return {boolean} + * @private + */ + computeExtraViewsHidden_: function() { + return this.data.views.length <= 1; + }, + + /** + * @return {boolean} + * @private + */ + computeDevReloadButtonHidden_: function() { + // Only display the reload spinner if the extension is unpacked and + // enabled. There's no point in reloading a disabled extension, and we'll + // show a crashed reload button if it's terminated. + const showIcon = + this.data.location == chrome.developerPrivate.Location.UNPACKED && + this.data.state == chrome.developerPrivate.ExtensionState.ENABLED; + return !showIcon; + }, + + /** + * @return {string} + * @private + */ + computeExtraInspectLabel_: function() { + return this.i18n( + 'itemInspectViewsExtra', (this.data.views.length - 1).toString()); + }, + + /** + * @return {boolean} + * @private + */ + hasWarnings_: function() { + return this.data.disableReasons.corruptInstall || + this.data.disableReasons.suspiciousInstall || + this.data.runtimeWarnings.length > 0 || !!this.data.blacklistText; + }, + + /** + * @return {string} + * @private + */ + computeWarningsClasses_: function() { + return this.data.blacklistText ? 'severe' : 'mild'; + }, +});
diff --git a/chrome/browser/resources/extensions/item_behavior.js b/chrome/browser/resources/extensions/item_behavior.js index 07c7794..c1e368a 100644 --- a/chrome/browser/resources/extensions/item_behavior.js +++ b/chrome/browser/resources/extensions/item_behavior.js
@@ -4,25 +4,25 @@ import {assertNotReached} from 'chrome://resources/js/assert.m.js'; - /** @polymerBehavior */ - export const ItemBehavior = { - /** - * @param {chrome.developerPrivate.ExtensionType} type - * @param {string} appLabel - * @param {string} extensionLabel - * @return {string} The app or extension label depending on |type|. - */ - appOrExtension: function(type, appLabel, extensionLabel) { - const ExtensionType = chrome.developerPrivate.ExtensionType; - switch (type) { - case ExtensionType.HOSTED_APP: - case ExtensionType.LEGACY_PACKAGED_APP: - case ExtensionType.PLATFORM_APP: - return appLabel; - case ExtensionType.EXTENSION: - case ExtensionType.SHARED_MODULE: - return extensionLabel; - } - assertNotReached('Item type is not App or Extension.'); - }, - }; +/** @polymerBehavior */ +export const ItemBehavior = { + /** + * @param {chrome.developerPrivate.ExtensionType} type + * @param {string} appLabel + * @param {string} extensionLabel + * @return {string} The app or extension label depending on |type|. + */ + appOrExtension: function(type, appLabel, extensionLabel) { + const ExtensionType = chrome.developerPrivate.ExtensionType; + switch (type) { + case ExtensionType.HOSTED_APP: + case ExtensionType.LEGACY_PACKAGED_APP: + case ExtensionType.PLATFORM_APP: + return appLabel; + case ExtensionType.EXTENSION: + case ExtensionType.SHARED_MODULE: + return extensionLabel; + } + assertNotReached('Item type is not App or Extension.'); + }, +};
diff --git a/chrome/browser/resources/extensions/item_list.js b/chrome/browser/resources/extensions/item_list.js index b11d8be2..f24ce18 100644 --- a/chrome/browser/resources/extensions/item_list.js +++ b/chrome/browser/resources/extensions/item_list.js
@@ -12,121 +12,121 @@ import {ItemDelegate} from './item.js'; - Polymer({ - is: 'extensions-item-list', +Polymer({ + is: 'extensions-item-list', - _template: html`{__html_template__}`, + _template: html`{__html_template__}`, - behaviors: [CrContainerShadowBehavior, I18nBehavior], + behaviors: [CrContainerShadowBehavior, I18nBehavior], - properties: { - /** @type {!Array<!chrome.developerPrivate.ExtensionInfo>} */ - apps: Array, + properties: { + /** @type {!Array<!chrome.developerPrivate.ExtensionInfo>} */ + apps: Array, - /** @type {!Array<!chrome.developerPrivate.ExtensionInfo>} */ - extensions: Array, + /** @type {!Array<!chrome.developerPrivate.ExtensionInfo>} */ + extensions: Array, - /** @type {ItemDelegate} */ - delegate: Object, + /** @type {ItemDelegate} */ + delegate: Object, - inDevMode: { - type: Boolean, - value: false, - }, - - filter: { - type: String, - }, - - /** @private */ - computedFilter_: { - type: String, - computed: 'computeFilter_(filter)', - observer: 'announceSearchResults_', - }, - - /** @private */ - shownExtensionsCount_: { - type: Number, - value: 0, - }, - - /** @private */ - shownAppsCount_: { - type: Number, - value: 0, - }, + inDevMode: { + type: Boolean, + value: false, }, - /** - * @param {string} id - * @return {?Element} - */ - getDetailsButton: function(id) { - const item = this.$$(`#${id}`); - return item && item.getDetailsButton(); - }, - - /** - * @param {string} id - * @return {?Element} - */ - getErrorsButton: function(id) { - const item = this.$$(`#${id}`); - return item && item.getErrorsButton(); - }, - - /** - * Computes the filter function to be used for determining which items - * should be shown. A |null| value indicates that everything should be - * shown. - * return {?Function} - * @private - */ - computeFilter_: function() { - const formattedFilter = this.filter.trim().toLowerCase(); - return formattedFilter ? - i => i.name.toLowerCase().includes(formattedFilter) : - null; + filter: { + type: String, }, /** @private */ - shouldShowEmptyItemsMessage_: function() { - if (!this.apps || !this.extensions) { - return; - } - - return this.apps.length === 0 && this.extensions.length === 0; + computedFilter_: { + type: String, + computed: 'computeFilter_(filter)', + observer: 'announceSearchResults_', }, /** @private */ - shouldShowEmptySearchMessage_: function() { - return !this.shouldShowEmptyItemsMessage_() && - this.shownAppsCount_ === 0 && this.shownExtensionsCount_ === 0; + shownExtensionsCount_: { + type: Number, + value: 0, }, /** @private */ - onNoExtensionsTap_: function(e) { - if (e.target.tagName == 'A') { - chrome.metricsPrivate.recordUserAction('Options_GetMoreExtensions'); - } + shownAppsCount_: { + type: Number, + value: 0, }, + }, - /** @private */ - announceSearchResults_: function() { - if (this.computedFilter_) { - IronA11yAnnouncer.requestAvailability(); - this.async(() => { // Async to allow list to update. - const total = this.shownAppsCount_ + this.shownExtensionsCount_; - this.fire('iron-announce', { - text: this.shouldShowEmptySearchMessage_() ? - this.i18n('noSearchResults') : - (total == 1 ? - this.i18n('searchResultsSingular', this.filter) : - this.i18n( - 'searchResultsPlural', total.toString(), this.filter)), - }); + /** + * @param {string} id + * @return {?Element} + */ + getDetailsButton: function(id) { + const item = this.$$(`#${id}`); + return item && item.getDetailsButton(); + }, + + /** + * @param {string} id + * @return {?Element} + */ + getErrorsButton: function(id) { + const item = this.$$(`#${id}`); + return item && item.getErrorsButton(); + }, + + /** + * Computes the filter function to be used for determining which items + * should be shown. A |null| value indicates that everything should be + * shown. + * return {?Function} + * @private + */ + computeFilter_: function() { + const formattedFilter = this.filter.trim().toLowerCase(); + return formattedFilter ? + i => i.name.toLowerCase().includes(formattedFilter) : + null; + }, + + /** @private */ + shouldShowEmptyItemsMessage_: function() { + if (!this.apps || !this.extensions) { + return; + } + + return this.apps.length === 0 && this.extensions.length === 0; + }, + + /** @private */ + shouldShowEmptySearchMessage_: function() { + return !this.shouldShowEmptyItemsMessage_() && this.shownAppsCount_ === 0 && + this.shownExtensionsCount_ === 0; + }, + + /** @private */ + onNoExtensionsTap_: function(e) { + if (e.target.tagName == 'A') { + chrome.metricsPrivate.recordUserAction('Options_GetMoreExtensions'); + } + }, + + /** @private */ + announceSearchResults_: function() { + if (this.computedFilter_) { + IronA11yAnnouncer.requestAvailability(); + this.async(() => { // Async to allow list to update. + const total = this.shownAppsCount_ + this.shownExtensionsCount_; + this.fire('iron-announce', { + text: this.shouldShowEmptySearchMessage_() ? + this.i18n('noSearchResults') : + (total == 1 ? + this.i18n('searchResultsSingular', this.filter) : + this.i18n( + 'searchResultsPlural', total.toString(), this.filter)), }); - } - }, - }); + }); + } + }, +});
diff --git a/chrome/browser/resources/extensions/item_util.js b/chrome/browser/resources/extensions/item_util.js index dccf05dba..b137f5d8 100644 --- a/chrome/browser/resources/extensions/item_util.js +++ b/chrome/browser/resources/extensions/item_util.js
@@ -8,144 +8,144 @@ import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js'; - // Closure compiler won't let this be declared inside cr.define(). - /** @enum {string} */ - export const SourceType = { - WEBSTORE: 'webstore', - POLICY: 'policy', - SIDELOADED: 'sideloaded', - UNPACKED: 'unpacked', - UNKNOWN: 'unknown', - }; +// Closure compiler won't let this be declared inside cr.define(). +/** @enum {string} */ +export const SourceType = { + WEBSTORE: 'webstore', + POLICY: 'policy', + SIDELOADED: 'sideloaded', + UNPACKED: 'unpacked', + UNKNOWN: 'unknown', +}; - /** - * Returns true if the extension is enabled, including terminated - * extensions. - * @param {!chrome.developerPrivate.ExtensionState} state - * @return {boolean} - */ - export function isEnabled(state) { - switch (state) { - case chrome.developerPrivate.ExtensionState.ENABLED: - case chrome.developerPrivate.ExtensionState.TERMINATED: - return true; - case chrome.developerPrivate.ExtensionState.BLACKLISTED: - case chrome.developerPrivate.ExtensionState.DISABLED: - return false; - } - assertNotReached(); - } - - /** - * @param {!chrome.developerPrivate.ExtensionInfo} extensionInfo - * @return {boolean} Whether the extension is controlled. - */ - export function isControlled(extensionInfo) { - return !!extensionInfo.controlledInfo; - } - - /** - * Returns true if the user can change whether or not the extension is - * enabled. - * @param {!chrome.developerPrivate.ExtensionInfo} item - * @return {boolean} - */ - export function userCanChangeEnablement(item) { - // User doesn't have permission. - if (!item.userMayModify) { +/** + * Returns true if the extension is enabled, including terminated + * extensions. + * @param {!chrome.developerPrivate.ExtensionState} state + * @return {boolean} + */ +export function isEnabled(state) { + switch (state) { + case chrome.developerPrivate.ExtensionState.ENABLED: + case chrome.developerPrivate.ExtensionState.TERMINATED: + return true; + case chrome.developerPrivate.ExtensionState.BLACKLISTED: + case chrome.developerPrivate.ExtensionState.DISABLED: return false; - } - // Item is forcefully disabled. - if (item.disableReasons.corruptInstall || - item.disableReasons.suspiciousInstall || - item.disableReasons.updateRequired) { - return false; - } - // An item with dependent extensions can't be disabled (it would bork the - // dependents). - if (item.dependentExtensions.length > 0) { - return false; - } - // Blacklisted can't be enabled, either. - if (item.state == chrome.developerPrivate.ExtensionState.BLACKLISTED) { - return false; - } + } + assertNotReached(); +} - return true; +/** + * @param {!chrome.developerPrivate.ExtensionInfo} extensionInfo + * @return {boolean} Whether the extension is controlled. + */ +export function isControlled(extensionInfo) { + return !!extensionInfo.controlledInfo; +} + +/** + * Returns true if the user can change whether or not the extension is + * enabled. + * @param {!chrome.developerPrivate.ExtensionInfo} item + * @return {boolean} + */ +export function userCanChangeEnablement(item) { + // User doesn't have permission. + if (!item.userMayModify) { + return false; + } + // Item is forcefully disabled. + if (item.disableReasons.corruptInstall || + item.disableReasons.suspiciousInstall || + item.disableReasons.updateRequired) { + return false; + } + // An item with dependent extensions can't be disabled (it would bork the + // dependents). + if (item.dependentExtensions.length > 0) { + return false; + } + // Blacklisted can't be enabled, either. + if (item.state == chrome.developerPrivate.ExtensionState.BLACKLISTED) { + return false; } - /** - * @param {!chrome.developerPrivate.ExtensionInfo} item - * @return {SourceType} - */ - export function getItemSource(item) { - if (item.controlledInfo && - item.controlledInfo.type == - chrome.developerPrivate.ControllerType.POLICY) { - return SourceType.POLICY; - } + return true; +} - switch (item.location) { - case chrome.developerPrivate.Location.THIRD_PARTY: - return SourceType.SIDELOADED; - case chrome.developerPrivate.Location.UNPACKED: - return SourceType.UNPACKED; - case chrome.developerPrivate.Location.UNKNOWN: - return SourceType.UNKNOWN; - case chrome.developerPrivate.Location.FROM_STORE: - return SourceType.WEBSTORE; - } - - assertNotReached(item.location); +/** + * @param {!chrome.developerPrivate.ExtensionInfo} item + * @return {SourceType} + */ +export function getItemSource(item) { + if (item.controlledInfo && + item.controlledInfo.type == + chrome.developerPrivate.ControllerType.POLICY) { + return SourceType.POLICY; } - /** - * @param {SourceType} source - * @return {string} - */ - export function getItemSourceString(source) { - switch (source) { - case SourceType.POLICY: - return loadTimeData.getString('itemSourcePolicy'); - case SourceType.SIDELOADED: - return loadTimeData.getString('itemSourceSideloaded'); - case SourceType.UNPACKED: - return loadTimeData.getString('itemSourceUnpacked'); - case SourceType.WEBSTORE: - return loadTimeData.getString('itemSourceWebstore'); - case SourceType.UNKNOWN: - // Nothing to return. Calling code should use - // chrome.developerPrivate.ExtensionInfo's |locationText| instead. - return ''; - } - assertNotReached(); + switch (item.location) { + case chrome.developerPrivate.Location.THIRD_PARTY: + return SourceType.SIDELOADED; + case chrome.developerPrivate.Location.UNPACKED: + return SourceType.UNPACKED; + case chrome.developerPrivate.Location.UNKNOWN: + return SourceType.UNKNOWN; + case chrome.developerPrivate.Location.FROM_STORE: + return SourceType.WEBSTORE; } - /** - * Computes the human-facing label for the given inspectable view. - * @param {!chrome.developerPrivate.ExtensionView} view - * @return {string} - */ - export function computeInspectableViewLabel(view) { - // Trim the "chrome-extension://<id>/". - const url = new URL(view.url); - let label = view.url; - if (url.protocol == 'chrome-extension:') { - label = url.pathname.substring(1); - } - if (label == '_generated_background_page.html') { - label = loadTimeData.getString('viewBackgroundPage'); - } - // Add any qualifiers. - if (view.incognito) { - label += ' ' + loadTimeData.getString('viewIncognito'); - } - if (view.renderProcessId == -1) { - label += ' ' + loadTimeData.getString('viewInactive'); - } - if (view.isIframe) { - label += ' ' + loadTimeData.getString('viewIframe'); - } + assertNotReached(item.location); +} - return label; +/** + * @param {SourceType} source + * @return {string} + */ +export function getItemSourceString(source) { + switch (source) { + case SourceType.POLICY: + return loadTimeData.getString('itemSourcePolicy'); + case SourceType.SIDELOADED: + return loadTimeData.getString('itemSourceSideloaded'); + case SourceType.UNPACKED: + return loadTimeData.getString('itemSourceUnpacked'); + case SourceType.WEBSTORE: + return loadTimeData.getString('itemSourceWebstore'); + case SourceType.UNKNOWN: + // Nothing to return. Calling code should use + // chrome.developerPrivate.ExtensionInfo's |locationText| instead. + return ''; } + assertNotReached(); +} + +/** + * Computes the human-facing label for the given inspectable view. + * @param {!chrome.developerPrivate.ExtensionView} view + * @return {string} + */ +export function computeInspectableViewLabel(view) { + // Trim the "chrome-extension://<id>/". + const url = new URL(view.url); + let label = view.url; + if (url.protocol == 'chrome-extension:') { + label = url.pathname.substring(1); + } + if (label == '_generated_background_page.html') { + label = loadTimeData.getString('viewBackgroundPage'); + } + // Add any qualifiers. + if (view.incognito) { + label += ' ' + loadTimeData.getString('viewIncognito'); + } + if (view.renderProcessId == -1) { + label += ' ' + loadTimeData.getString('viewInactive'); + } + if (view.isIframe) { + label += ' ' + loadTimeData.getString('viewIframe'); + } + + return label; +}
diff --git a/chrome/browser/resources/extensions/keyboard_shortcut_delegate.js b/chrome/browser/resources/extensions/keyboard_shortcut_delegate.js index 4c4a293..4281304e 100644 --- a/chrome/browser/resources/extensions/keyboard_shortcut_delegate.js +++ b/chrome/browser/resources/extensions/keyboard_shortcut_delegate.js
@@ -4,32 +4,32 @@ 'use strict'; - /** @interface */ - export class KeyboardShortcutDelegate { - /** - * Called when shortcut capturing changes in order to suspend or re-enable - * global shortcut handling. This is important so that the shortcuts aren't - * processed normally as the user types them. - * TODO(devlin): From very brief experimentation, it looks like preventing - * the default handling on the event also does this. Investigate more in the - * future. - * @param {boolean} isCapturing - */ - setShortcutHandlingSuspended(isCapturing) {} +/** @interface */ +export class KeyboardShortcutDelegate { + /** + * Called when shortcut capturing changes in order to suspend or re-enable + * global shortcut handling. This is important so that the shortcuts aren't + * processed normally as the user types them. + * TODO(devlin): From very brief experimentation, it looks like preventing + * the default handling on the event also does this. Investigate more in the + * future. + * @param {boolean} isCapturing + */ + setShortcutHandlingSuspended(isCapturing) {} - /** - * Updates an extension command's keybinding. - * @param {string} extensionId - * @param {string} commandName - * @param {string} keybinding - */ - updateExtensionCommandKeybinding(extensionId, commandName, keybinding) {} + /** + * Updates an extension command's keybinding. + * @param {string} extensionId + * @param {string} commandName + * @param {string} keybinding + */ + updateExtensionCommandKeybinding(extensionId, commandName, keybinding) {} - /** - * Updates an extension command's scope. - * @param {string} extensionId - * @param {string} commandName - * @param {chrome.developerPrivate.CommandScope} scope - */ - updateExtensionCommandScope(extensionId, commandName, scope) {} - } + /** + * Updates an extension command's scope. + * @param {string} extensionId + * @param {string} commandName + * @param {chrome.developerPrivate.CommandScope} scope + */ + updateExtensionCommandScope(extensionId, commandName, scope) {} +}
diff --git a/chrome/browser/resources/extensions/keyboard_shortcuts.js b/chrome/browser/resources/extensions/keyboard_shortcuts.js index 6a92974d..92d8663 100644 --- a/chrome/browser/resources/extensions/keyboard_shortcuts.js +++ b/chrome/browser/resources/extensions/keyboard_shortcuts.js
@@ -14,95 +14,95 @@ import {ItemBehavior} from './item_behavior.js'; import {KeyboardShortcutDelegate} from './keyboard_shortcut_delegate.js'; - // The UI to display and manage keyboard shortcuts set for extension commands. - Polymer({ - is: 'extensions-keyboard-shortcuts', +// The UI to display and manage keyboard shortcuts set for extension commands. +Polymer({ + is: 'extensions-keyboard-shortcuts', - _template: html`{__html_template__}`, + _template: html`{__html_template__}`, - behaviors: [CrContainerShadowBehavior, ItemBehavior], + behaviors: [CrContainerShadowBehavior, ItemBehavior], - properties: { - /** @type {!KeyboardShortcutDelegate} */ - delegate: Object, + properties: { + /** @type {!KeyboardShortcutDelegate} */ + delegate: Object, - /** @type {Array<!chrome.developerPrivate.ExtensionInfo>} */ - items: Array, - - /** - * Proxying the enum to be used easily by the html template. - * @private - */ - CommandScope_: { - type: Object, - value: chrome.developerPrivate.CommandScope, - }, - }, - - listeners: { - 'view-enter-start': 'onViewEnter_', - }, - - /** @private */ - onViewEnter_: function() { - chrome.metricsPrivate.recordUserAction('Options_ExtensionCommands'); - }, + /** @type {Array<!chrome.developerPrivate.ExtensionInfo>} */ + items: Array, /** - * @return {!Array<!chrome.developerPrivate.ExtensionInfo>} + * Proxying the enum to be used easily by the html template. * @private */ - calculateShownItems_: function() { - return this.items.filter(function(item) { - return item.commands.length > 0; - }); + CommandScope_: { + type: Object, + value: chrome.developerPrivate.CommandScope, }, + }, - /** - * A polymer bug doesn't allow for databinding of a string property as a - * boolean, but it is correctly interpreted from a function. - * Bug: https://github.com/Polymer/polymer/issues/3669 - * @param {string} keybinding - * @return {boolean} - * @private - */ - hasKeybinding_: function(keybinding) { - return !!keybinding; - }, + listeners: { + 'view-enter-start': 'onViewEnter_', + }, - /** - * Determines whether to disable the dropdown menu for the command's scope. - * @param {!chrome.developerPrivate.Command} command - * @return {boolean} - * @private - */ - computeScopeDisabled_: function(command) { - return command.isExtensionAction || !command.isActive; - }, + /** @private */ + onViewEnter_: function() { + chrome.metricsPrivate.recordUserAction('Options_ExtensionCommands'); + }, - /** - * This function exists to force trigger an update when CommandScope_ - * becomes available. - * @param {string} scope - * @return {string} - */ - triggerScopeChange_: function(scope) { - return scope; - }, + /** + * @return {!Array<!chrome.developerPrivate.ExtensionInfo>} + * @private + */ + calculateShownItems_: function() { + return this.items.filter(function(item) { + return item.commands.length > 0; + }); + }, - /** @private */ - onCloseButtonClick_: function() { - this.fire('close'); - }, + /** + * A polymer bug doesn't allow for databinding of a string property as a + * boolean, but it is correctly interpreted from a function. + * Bug: https://github.com/Polymer/polymer/issues/3669 + * @param {string} keybinding + * @return {boolean} + * @private + */ + hasKeybinding_: function(keybinding) { + return !!keybinding; + }, - /** - * @param {!{target: HTMLSelectElement, model: Object}} event - * @private - */ - onScopeChanged_: function(event) { - this.delegate.updateExtensionCommandScope( - event.model.get('item.id'), event.model.get('command.name'), - /** @type {chrome.developerPrivate.CommandScope} */ - (event.target.value)); - }, - }); + /** + * Determines whether to disable the dropdown menu for the command's scope. + * @param {!chrome.developerPrivate.Command} command + * @return {boolean} + * @private + */ + computeScopeDisabled_: function(command) { + return command.isExtensionAction || !command.isActive; + }, + + /** + * This function exists to force trigger an update when CommandScope_ + * becomes available. + * @param {string} scope + * @return {string} + */ + triggerScopeChange_: function(scope) { + return scope; + }, + + /** @private */ + onCloseButtonClick_: function() { + this.fire('close'); + }, + + /** + * @param {!{target: HTMLSelectElement, model: Object}} event + * @private + */ + onScopeChanged_: function(event) { + this.delegate.updateExtensionCommandScope( + event.model.get('item.id'), event.model.get('command.name'), + /** @type {chrome.developerPrivate.CommandScope} */ + (event.target.value)); + }, +});
diff --git a/chrome/browser/resources/extensions/kiosk_browser_proxy.js b/chrome/browser/resources/extensions/kiosk_browser_proxy.js index 1316bb6..2a00b9e 100644 --- a/chrome/browser/resources/extensions/kiosk_browser_proxy.js +++ b/chrome/browser/resources/extensions/kiosk_browser_proxy.js
@@ -37,66 +37,66 @@ */ export let KioskAppSettings; - /** @interface */ - export class KioskBrowserProxy { - /** @param {string} appId */ - addKioskApp(appId) {} +/** @interface */ +export class KioskBrowserProxy { + /** @param {string} appId */ + addKioskApp(appId) {} - /** @param {string} appId */ - disableKioskAutoLaunch(appId) {} + /** @param {string} appId */ + disableKioskAutoLaunch(appId) {} - /** @param {string} appId */ - enableKioskAutoLaunch(appId) {} + /** @param {string} appId */ + enableKioskAutoLaunch(appId) {} - /** @return {!Promise<!KioskAppSettings>} */ - getKioskAppSettings() {} + /** @return {!Promise<!KioskAppSettings>} */ + getKioskAppSettings() {} - /** @return {!Promise<!KioskSettings>} */ - initializeKioskAppSettings() {} + /** @return {!Promise<!KioskSettings>} */ + initializeKioskAppSettings() {} - /** @param {string} appId */ - removeKioskApp(appId) {} + /** @param {string} appId */ + removeKioskApp(appId) {} - /** @param {boolean} disableBailout */ - setDisableBailoutShortcut(disableBailout) {} + /** @param {boolean} disableBailout */ + setDisableBailoutShortcut(disableBailout) {} +} + +/** @implements {KioskBrowserProxy} */ +export class KioskBrowserProxyImpl { + /** @override */ + initializeKioskAppSettings() { + return sendWithPromise('initializeKioskAppSettings'); } - /** @implements {KioskBrowserProxy} */ - export class KioskBrowserProxyImpl { - /** @override */ - initializeKioskAppSettings() { - return sendWithPromise('initializeKioskAppSettings'); - } - - /** @override */ - getKioskAppSettings() { - return sendWithPromise('getKioskAppSettings'); - } - - /** @override */ - addKioskApp(appId) { - chrome.send('addKioskApp', [appId]); - } - - /** @override */ - disableKioskAutoLaunch(appId) { - chrome.send('disableKioskAutoLaunch', [appId]); - } - - /** @override */ - enableKioskAutoLaunch(appId) { - chrome.send('enableKioskAutoLaunch', [appId]); - } - - /** @override */ - removeKioskApp(appId) { - chrome.send('removeKioskApp', [appId]); - } - - /** @override */ - setDisableBailoutShortcut(disableBailout) { - chrome.send('setDisableBailoutShortcut', [disableBailout]); - } + /** @override */ + getKioskAppSettings() { + return sendWithPromise('getKioskAppSettings'); } - addSingletonGetter(KioskBrowserProxyImpl); + /** @override */ + addKioskApp(appId) { + chrome.send('addKioskApp', [appId]); + } + + /** @override */ + disableKioskAutoLaunch(appId) { + chrome.send('disableKioskAutoLaunch', [appId]); + } + + /** @override */ + enableKioskAutoLaunch(appId) { + chrome.send('enableKioskAutoLaunch', [appId]); + } + + /** @override */ + removeKioskApp(appId) { + chrome.send('removeKioskApp', [appId]); + } + + /** @override */ + setDisableBailoutShortcut(disableBailout) { + chrome.send('setDisableBailoutShortcut', [disableBailout]); + } +} + +addSingletonGetter(KioskBrowserProxyImpl);
diff --git a/chrome/browser/resources/extensions/kiosk_dialog.js b/chrome/browser/resources/extensions/kiosk_dialog.js index bfae0a1..04bc4cb 100644 --- a/chrome/browser/resources/extensions/kiosk_dialog.js +++ b/chrome/browser/resources/extensions/kiosk_dialog.js
@@ -18,179 +18,179 @@ import {KioskApp, KioskAppSettings, KioskBrowserProxy, KioskBrowserProxyImpl} from './kiosk_browser_proxy.js'; - Polymer({ - is: 'extensions-kiosk-dialog', +Polymer({ + is: 'extensions-kiosk-dialog', - _template: html`{__html_template__}`, + _template: html`{__html_template__}`, - behaviors: [WebUIListenerBehavior, ItemBehavior], + behaviors: [WebUIListenerBehavior, ItemBehavior], - properties: { - /** @private {?string} */ - addAppInput_: { - type: String, - value: null, - }, - - /** @private {!Array<!KioskApp>} */ - apps_: Array, - - /** @private */ - bailoutDisabled_: Boolean, - - /** @private */ - canEditAutoLaunch_: Boolean, - - /** @private */ - canEditBailout_: Boolean, - - /** @private {?string} */ - errorAppId_: String, + properties: { + /** @private {?string} */ + addAppInput_: { + type: String, + value: null, }, - /** @private {?KioskBrowserProxy} */ - kioskBrowserProxy_: null, - - /** @override */ - ready: function() { - this.kioskBrowserProxy_ = KioskBrowserProxyImpl.getInstance(); - }, - - /** @override */ - attached: function() { - this.kioskBrowserProxy_.initializeKioskAppSettings() - .then(params => { - this.canEditAutoLaunch_ = params.autoLaunchEnabled; - return this.kioskBrowserProxy_.getKioskAppSettings(); - }) - .then(this.setSettings_.bind(this)); - - this.addWebUIListener( - 'kiosk-app-settings-changed', this.setSettings_.bind(this)); - this.addWebUIListener('kiosk-app-updated', this.updateApp_.bind(this)); - this.addWebUIListener('kiosk-app-error', this.showError_.bind(this)); - - this.$.dialog.showModal(); - }, - - /** - * @param {!KioskAppSettings} settings - * @private - */ - setSettings_: function(settings) { - this.apps_ = settings.apps; - this.bailoutDisabled_ = settings.disableBailout; - this.canEditBailout_ = settings.hasAutoLaunchApp; - }, - - /** - * @param {!KioskApp} app - * @private - */ - updateApp_: function(app) { - const index = this.apps_.findIndex(a => a.id == app.id); - assert(index < this.apps_.length); - this.set('apps_.' + index, app); - }, - - /** - * @param {string} appId - * @private - */ - showError_: function(appId) { - this.errorAppId_ = appId; - }, - - /** - * @param {string} errorMessage - * @return {string} - * @private - */ - getErrorMessage_: function(errorMessage) { - return this.errorAppId_ + ' ' + errorMessage; - }, + /** @private {!Array<!KioskApp>} */ + apps_: Array, /** @private */ - onAddAppTap_: function() { - assert(this.addAppInput_); - this.kioskBrowserProxy_.addKioskApp(this.addAppInput_); - this.addAppInput_ = null; - }, + bailoutDisabled_: Boolean, /** @private */ - clearInputInvalid_: function() { - this.errorAppId_ = null; - }, - - /** - * @param {{model: {item: !KioskApp}}} event - * @private - */ - onAutoLaunchButtonTap_: function(event) { - const app = event.model.item; - if (app.autoLaunch) { // If the app is originally set to - // auto-launch. - this.kioskBrowserProxy_.disableKioskAutoLaunch(app.id); - } else { - this.kioskBrowserProxy_.enableKioskAutoLaunch(app.id); - } - }, - - /** - * @param {!Event} event - * @private - */ - onBailoutChanged_: function(event) { - event.preventDefault(); - if (this.$.bailout.checked) { - this.$['confirm-dialog'].showModal(); - } else { - this.kioskBrowserProxy_.setDisableBailoutShortcut(false); - this.$['confirm-dialog'].close(); - } - }, + canEditAutoLaunch_: Boolean, /** @private */ - onBailoutDialogCancelTap_: function() { - this.$.bailout.checked = false; - this.$['confirm-dialog'].cancel(); - }, + canEditBailout_: Boolean, - /** @private */ - onBailoutDialogConfirmTap_: function() { - this.kioskBrowserProxy_.setDisableBailoutShortcut(true); + /** @private {?string} */ + errorAppId_: String, + }, + + /** @private {?KioskBrowserProxy} */ + kioskBrowserProxy_: null, + + /** @override */ + ready: function() { + this.kioskBrowserProxy_ = KioskBrowserProxyImpl.getInstance(); + }, + + /** @override */ + attached: function() { + this.kioskBrowserProxy_.initializeKioskAppSettings() + .then(params => { + this.canEditAutoLaunch_ = params.autoLaunchEnabled; + return this.kioskBrowserProxy_.getKioskAppSettings(); + }) + .then(this.setSettings_.bind(this)); + + this.addWebUIListener( + 'kiosk-app-settings-changed', this.setSettings_.bind(this)); + this.addWebUIListener('kiosk-app-updated', this.updateApp_.bind(this)); + this.addWebUIListener('kiosk-app-error', this.showError_.bind(this)); + + this.$.dialog.showModal(); + }, + + /** + * @param {!KioskAppSettings} settings + * @private + */ + setSettings_: function(settings) { + this.apps_ = settings.apps; + this.bailoutDisabled_ = settings.disableBailout; + this.canEditBailout_ = settings.hasAutoLaunchApp; + }, + + /** + * @param {!KioskApp} app + * @private + */ + updateApp_: function(app) { + const index = this.apps_.findIndex(a => a.id == app.id); + assert(index < this.apps_.length); + this.set('apps_.' + index, app); + }, + + /** + * @param {string} appId + * @private + */ + showError_: function(appId) { + this.errorAppId_ = appId; + }, + + /** + * @param {string} errorMessage + * @return {string} + * @private + */ + getErrorMessage_: function(errorMessage) { + return this.errorAppId_ + ' ' + errorMessage; + }, + + /** @private */ + onAddAppTap_: function() { + assert(this.addAppInput_); + this.kioskBrowserProxy_.addKioskApp(this.addAppInput_); + this.addAppInput_ = null; + }, + + /** @private */ + clearInputInvalid_: function() { + this.errorAppId_ = null; + }, + + /** + * @param {{model: {item: !KioskApp}}} event + * @private + */ + onAutoLaunchButtonTap_: function(event) { + const app = event.model.item; + if (app.autoLaunch) { // If the app is originally set to + // auto-launch. + this.kioskBrowserProxy_.disableKioskAutoLaunch(app.id); + } else { + this.kioskBrowserProxy_.enableKioskAutoLaunch(app.id); + } + }, + + /** + * @param {!Event} event + * @private + */ + onBailoutChanged_: function(event) { + event.preventDefault(); + if (this.$.bailout.checked) { + this.$['confirm-dialog'].showModal(); + } else { + this.kioskBrowserProxy_.setDisableBailoutShortcut(false); this.$['confirm-dialog'].close(); - }, + } + }, - /** @private */ - onDoneTap_: function() { - this.$.dialog.close(); - }, + /** @private */ + onBailoutDialogCancelTap_: function() { + this.$.bailout.checked = false; + this.$['confirm-dialog'].cancel(); + }, - /** - * @param {{model: {item: !KioskApp}}} event - * @private - */ - onDeleteAppTap_: function(event) { - this.kioskBrowserProxy_.removeKioskApp(event.model.item.id); - }, + /** @private */ + onBailoutDialogConfirmTap_: function() { + this.kioskBrowserProxy_.setDisableBailoutShortcut(true); + this.$['confirm-dialog'].close(); + }, - /** - * @param {boolean} autoLaunched - * @param {string} disableStr - * @param {string} enableStr - * @return {string} - * @private - */ - getAutoLaunchButtonLabel_: function(autoLaunched, disableStr, enableStr) { - return autoLaunched ? disableStr : enableStr; - }, + /** @private */ + onDoneTap_: function() { + this.$.dialog.close(); + }, - /** - * @param {!Event} e - * @private - */ - stopPropagation_: function(e) { - e.stopPropagation(); - }, - }); + /** + * @param {{model: {item: !KioskApp}}} event + * @private + */ + onDeleteAppTap_: function(event) { + this.kioskBrowserProxy_.removeKioskApp(event.model.item.id); + }, + + /** + * @param {boolean} autoLaunched + * @param {string} disableStr + * @param {string} enableStr + * @return {string} + * @private + */ + getAutoLaunchButtonLabel_: function(autoLaunched, disableStr, enableStr) { + return autoLaunched ? disableStr : enableStr; + }, + + /** + * @param {!Event} e + * @private + */ + stopPropagation_: function(e) { + e.stopPropagation(); + }, +});
diff --git a/chrome/browser/resources/extensions/load_error.js b/chrome/browser/resources/extensions/load_error.js index c8c6588..ff678ac 100644 --- a/chrome/browser/resources/extensions/load_error.js +++ b/chrome/browser/resources/extensions/load_error.js
@@ -12,76 +12,75 @@ import {assert} from 'chrome://resources/js/assert.m.js'; import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; - /** @interface */ - export class LoadErrorDelegate { - /** - * Attempts to load the previously-attempted unpacked extension. - * @param {string} retryId - * @return {!Promise} - */ - retryLoadUnpacked(retryId) {} - } +/** @interface */ +export class LoadErrorDelegate { + /** + * Attempts to load the previously-attempted unpacked extension. + * @param {string} retryId + * @return {!Promise} + */ + retryLoadUnpacked(retryId) {} +} - Polymer({ - is: 'extensions-load-error', +Polymer({ + is: 'extensions-load-error', - _template: html`{__html_template__}`, + _template: html`{__html_template__}`, - properties: { - /** @type {LoadErrorDelegate} */ - delegate: Object, + properties: { + /** @type {LoadErrorDelegate} */ + delegate: Object, - /** @type {chrome.developerPrivate.LoadError} */ - loadError: Object, - - /** @private */ - retrying_: Boolean, - }, - - observers: [ - 'observeLoadErrorChanges_(loadError)', - ], - - show: function() { - /** @type {!CrDialogElement} */ (this.$.dialog).showModal(); - }, - - close: function() { - /** @type {!CrDialogElement} */ (this.$.dialog).close(); - }, + /** @type {chrome.developerPrivate.LoadError} */ + loadError: Object, /** @private */ - onRetryTap_: function() { - this.retrying_ = true; - this.delegate.retryLoadUnpacked(this.loadError.retryGuid) - .then( - () => { - this.close(); - }, - loadError => { - this.loadError = - /** @type {chrome.developerPrivate.LoadError} */ ( - loadError); - this.retrying_ = false; - }); - }, + retrying_: Boolean, + }, - /** @private */ - observeLoadErrorChanges_: function() { - assert(this.loadError); - const source = this.loadError.source; - // CodeSection expects a RequestFileSourceResponse, rather than an - // ErrorFileSource. Massage into place. - // TODO(devlin): Make RequestFileSourceResponse use ErrorFileSource. - /** @type {!chrome.developerPrivate.RequestFileSourceResponse} */ - const codeSectionProperties = { - beforeHighlight: source ? source.beforeHighlight : '', - highlight: source ? source.highlight : '', - afterHighlight: source ? source.afterHighlight : '', - title: '', - message: this.loadError.error, - }; + observers: [ + 'observeLoadErrorChanges_(loadError)', + ], - this.$.code.code = codeSectionProperties; - }, - }); + show: function() { + /** @type {!CrDialogElement} */ (this.$.dialog).showModal(); + }, + + close: function() { + /** @type {!CrDialogElement} */ (this.$.dialog).close(); + }, + + /** @private */ + onRetryTap_: function() { + this.retrying_ = true; + this.delegate.retryLoadUnpacked(this.loadError.retryGuid) + .then( + () => { + this.close(); + }, + loadError => { + this.loadError = + /** @type {chrome.developerPrivate.LoadError} */ (loadError); + this.retrying_ = false; + }); + }, + + /** @private */ + observeLoadErrorChanges_: function() { + assert(this.loadError); + const source = this.loadError.source; + // CodeSection expects a RequestFileSourceResponse, rather than an + // ErrorFileSource. Massage into place. + // TODO(devlin): Make RequestFileSourceResponse use ErrorFileSource. + /** @type {!chrome.developerPrivate.RequestFileSourceResponse} */ + const codeSectionProperties = { + beforeHighlight: source ? source.beforeHighlight : '', + highlight: source ? source.highlight : '', + afterHighlight: source ? source.afterHighlight : '', + title: '', + message: this.loadError.error, + }; + + this.$.code.code = codeSectionProperties; + }, +});
diff --git a/chrome/browser/resources/extensions/manager.js b/chrome/browser/resources/extensions/manager.js index e73a0f2..b1df5c6 100644 --- a/chrome/browser/resources/extensions/manager.js +++ b/chrome/browser/resources/extensions/manager.js
@@ -35,626 +35,625 @@ import {Dialog, navigation, Page, PageState} from './navigation_helper.js'; import {Service} from './service.js'; - /** - * Compares two extensions to determine which should come first in the list. - * @param {chrome.developerPrivate.ExtensionInfo} a - * @param {chrome.developerPrivate.ExtensionInfo} b - * @return {number} - */ - const compareExtensions = function(a, b) { - function compare(x, y) { - return x < y ? -1 : (x > y ? 1 : 0); - } - function compareLocation(x, y) { - if (x.location == y.location) { - return 0; - } - if (x.location == chrome.developerPrivate.Location.UNPACKED) { - return -1; - } - if (y.location == chrome.developerPrivate.Location.UNPACKED) { - return 1; - } +/** + * Compares two extensions to determine which should come first in the list. + * @param {chrome.developerPrivate.ExtensionInfo} a + * @param {chrome.developerPrivate.ExtensionInfo} b + * @return {number} + */ +const compareExtensions = function(a, b) { + function compare(x, y) { + return x < y ? -1 : (x > y ? 1 : 0); + } + function compareLocation(x, y) { + if (x.location == y.location) { return 0; } - return compareLocation(a, b) || - compare(a.name.toLowerCase(), b.name.toLowerCase()) || - compare(a.id, b.id); - }; + if (x.location == chrome.developerPrivate.Location.UNPACKED) { + return -1; + } + if (y.location == chrome.developerPrivate.Location.UNPACKED) { + return 1; + } + return 0; + } + return compareLocation(a, b) || + compare(a.name.toLowerCase(), b.name.toLowerCase()) || + compare(a.id, b.id); +}; - Polymer({ - is: 'extensions-manager', +Polymer({ + is: 'extensions-manager', - _template: html`{__html_template__}`, + _template: html`{__html_template__}`, - properties: { - canLoadUnpacked: { - type: Boolean, - value: false, - }, - - /** @type {!Service} */ - delegate: { - type: Object, - value: function() { - return Service.getInstance(); - }, - }, - - inDevMode: { - type: Boolean, - value: () => loadTimeData.getBoolean('inDevMode'), - }, - - showActivityLog: { - type: Boolean, - value: () => loadTimeData.getBoolean('showActivityLog'), - }, - - devModeControlledByPolicy: { - type: Boolean, - value: false, - }, - - /** @private */ - isSupervised_: { - type: Boolean, - value: false, - }, - - incognitoAvailable_: { - type: Boolean, - value: false, - }, - - filter: { - type: String, - value: '', - }, - - /** - * The item currently displayed in the error subpage. We use a separate - * item for different pages (rather than a single subpageItem_ property) - * so that hidden subpages don't update when an item updates. That is, we - * don't want the details view subpage to update when the item shown in - * the errors page updates, and vice versa. - * @private {!chrome.developerPrivate.ExtensionInfo|undefined} - */ - errorPageItem_: Object, - - /** - * The item currently displayed in the details view subpage. See also - * errorPageItem_. - * @private {!chrome.developerPrivate.ExtensionInfo|undefined} - */ - detailViewItem_: Object, - - /** - * The item that provides some information about the current extension - * for the activity log view subpage. See also errorPageItem_. - * @private {!chrome.developerPrivate.ExtensionInfo|undefined| - * !ActivityLogExtensionPlaceholder} - */ - activityLogItem_: Object, - - /** @private {!Array<!chrome.developerPrivate.ExtensionInfo>} */ - extensions_: Array, - - /** @private {!Array<!chrome.developerPrivate.ExtensionInfo>} */ - apps_: Array, - - /** - * Prevents page content from showing before data is first loaded. - * @private - */ - didInitPage_: { - type: Boolean, - value: false, - }, - - /** @private */ - showDrawer_: Boolean, - - /** @private */ - showLoadErrorDialog_: Boolean, - - /** @private */ - showInstallWarningsDialog_: Boolean, - - /** @private {?Array<string>} */ - installWarnings_: Array, - - /** @private */ - showOptionsDialog_: Boolean, - - /** - * Whether the last page the user navigated from was the activity log - * page. - * @private - */ - fromActivityLog_: Boolean, - - // <if expr="chromeos"> - /** @private */ - kioskEnabled_: { - type: Boolean, - value: false, - }, - - /** @private */ - showKioskDialog_: { - type: Boolean, - value: false, - }, - // </if> + properties: { + canLoadUnpacked: { + type: Boolean, + value: false, }, - listeners: { - 'load-error': 'onLoadError_', - 'view-enter-start': 'onViewEnterStart_', - 'view-exit-start': 'onViewExitStart_', - 'view-exit-finish': 'onViewExitFinish_', + /** @type {!Service} */ + delegate: { + type: Object, + value: function() { + return Service.getInstance(); + }, }, - /** - * The current page being shown. Default to null, and initPage_ will figure - * out the initial page based on url. - * @private {?PageState} - */ - currentPage_: null, - - /** - * The ID of the listener on |navigation|. Stored so that the - * listener can be removed when this element is detached (happens in tests). - * @private {?number} - */ - navigationListener_: null, - - /** @override */ - ready: function() { - const service = Service.getInstance(); - - const onProfileStateChanged = profileInfo => { - this.isSupervised_ = profileInfo.isSupervised; - this.incognitoAvailable_ = profileInfo.isIncognitoAvailable; - this.devModeControlledByPolicy = - profileInfo.isDeveloperModeControlledByPolicy; - this.inDevMode = profileInfo.inDeveloperMode; - this.canLoadUnpacked = profileInfo.canLoadUnpacked; - }; - service.getProfileStateChangedTarget().addListener(onProfileStateChanged); - service.getProfileConfiguration().then(onProfileStateChanged); - - service.getExtensionsInfo().then(extensionsAndApps => { - this.initExtensionsAndApps_(extensionsAndApps); - this.initPage_(); - - service.getItemStateChangedTarget().addListener( - this.onItemStateChanged_.bind(this)); - }); - - // <if expr="chromeos"> - KioskBrowserProxyImpl.getInstance() - .initializeKioskAppSettings() - .then(params => { - this.kioskEnabled_ = params.kioskEnabled; - }); - // </if> + inDevMode: { + type: Boolean, + value: () => loadTimeData.getBoolean('inDevMode'), }, - /** @override */ - attached: function() { - document.documentElement.classList.remove('loading'); - document.fonts.load('bold 12px Roboto'); - - this.navigationListener_ = navigation.addListener(newPage => { - this.changePage_(newPage); - }); + showActivityLog: { + type: Boolean, + value: () => loadTimeData.getBoolean('showActivityLog'), }, - /** @override */ - detached: function() { - assert(navigation.removeListener( - /** @type {number} */ (this.navigationListener_))); - this.navigationListener_ = null; - }, - - /** - * Initializes the page to reflect what's specified in the url so that if - * the user visits chrome://extensions/?id=..., we land on the proper page. - * @private - */ - initPage_: function() { - this.didInitPage_ = true; - this.changePage_(navigation.getCurrentPage()); - }, - - /** - * @param {!chrome.developerPrivate.EventData} eventData - * @private - */ - onItemStateChanged_: function(eventData) { - const EventType = chrome.developerPrivate.EventType; - switch (eventData.event_type) { - case EventType.VIEW_REGISTERED: - case EventType.VIEW_UNREGISTERED: - case EventType.INSTALLED: - case EventType.LOADED: - case EventType.UNLOADED: - case EventType.ERROR_ADDED: - case EventType.ERRORS_REMOVED: - case EventType.PREFS_CHANGED: - case EventType.WARNINGS_CHANGED: - case EventType.COMMAND_ADDED: - case EventType.COMMAND_REMOVED: - case EventType.PERMISSIONS_CHANGED: - // |extensionInfo| can be undefined in the case of an extension - // being unloaded right before uninstallation. There's nothing to do - // here. - if (!eventData.extensionInfo) { - break; - } - - if (this.delegate.shouldIgnoreUpdate( - eventData.extensionInfo.id, eventData.event_type)) { - break; - } - - const listId = this.getListId_(eventData.extensionInfo); - const currentIndex = this[listId].findIndex( - item => item.id == eventData.extensionInfo.id); - - if (currentIndex >= 0) { - this.updateItem_(listId, currentIndex, eventData.extensionInfo); - } else { - this.addItem_(listId, eventData.extensionInfo); - } - break; - case EventType.UNINSTALLED: - this.removeItem_(eventData.item_id); - break; - default: - assertNotReached(); - } - }, - - /** - * @param {!CustomEvent<string>} event - * @private - */ - onFilterChanged_: function(event) { - if (this.currentPage_.page !== Page.LIST) { - navigation.navigateTo({page: Page.LIST}); - } - this.filter = event.detail; + devModeControlledByPolicy: { + type: Boolean, + value: false, }, /** @private */ - onMenuButtonTap_: function() { - this.showDrawer_ = true; - this.async(() => { - this.$$('#drawer').openDrawer(); - }); + isSupervised_: { + type: Boolean, + value: false, + }, + + incognitoAvailable_: { + type: Boolean, + value: false, + }, + + filter: { + type: String, + value: '', }, /** - * @param {!chrome.developerPrivate.ExtensionInfo} item - * @return {string} The ID of the list that the item belongs in. - * @private + * The item currently displayed in the error subpage. We use a separate + * item for different pages (rather than a single subpageItem_ property) + * so that hidden subpages don't update when an item updates. That is, we + * don't want the details view subpage to update when the item shown in + * the errors page updates, and vice versa. + * @private {!chrome.developerPrivate.ExtensionInfo|undefined} */ - getListId_: function(item) { - const ExtensionType = chrome.developerPrivate.ExtensionType; - switch (item.type) { - case ExtensionType.HOSTED_APP: - case ExtensionType.LEGACY_PACKAGED_APP: - case ExtensionType.PLATFORM_APP: - return 'apps_'; - case ExtensionType.EXTENSION: - case ExtensionType.SHARED_MODULE: - return 'extensions_'; - case ExtensionType.THEME: - assertNotReached('Don\'t send themes to the chrome://extensions page'); - break; - } - assertNotReached(); - }, + errorPageItem_: Object, /** - * @param {string} listId The list to look for the item in. - * @param {string} itemId The id of the item to look for. - * @return {number} The index of the item in the list, or -1 if not found. - * @private + * The item currently displayed in the details view subpage. See also + * errorPageItem_. + * @private {!chrome.developerPrivate.ExtensionInfo|undefined} */ - getIndexInList_: function(listId, itemId) { - return this[listId].findIndex(function(item) { - return item.id == itemId; - }); - }, + detailViewItem_: Object, /** - * @return {?chrome.developerPrivate.ExtensionInfo} - * @private + * The item that provides some information about the current extension + * for the activity log view subpage. See also errorPageItem_. + * @private {!chrome.developerPrivate.ExtensionInfo|undefined| + * !ActivityLogExtensionPlaceholder} */ - getData_: function(id) { - return this.extensions_[this.getIndexInList_('extensions_', id)] || - this.apps_[this.getIndexInList_('apps_', id)]; - }, + activityLogItem_: Object, + + /** @private {!Array<!chrome.developerPrivate.ExtensionInfo>} */ + extensions_: Array, + + /** @private {!Array<!chrome.developerPrivate.ExtensionInfo>} */ + apps_: Array, /** - * Categorizes |extensionsAndApps| to apps and extensions and initializes - * those lists. - * @param {!Array<!chrome.developerPrivate.ExtensionInfo>} extensionsAndApps + * Prevents page content from showing before data is first loaded. * @private */ - initExtensionsAndApps_: function(extensionsAndApps) { - extensionsAndApps.sort(compareExtensions); - const apps = []; - const extensions = []; - for (const i of extensionsAndApps) { - const list = this.getListId_(i) === 'apps_' ? apps : extensions; - list.push(i); - } - - this.apps_ = apps; - this.extensions_ = extensions; - }, - - /** - * Creates and adds a new extensions-item element to the list, inserting it - * into its sorted position in the relevant section. - * @param {!chrome.developerPrivate.ExtensionInfo} item The extension - * the new element is representing. - * @private - */ - addItem_: function(listId, item) { - // We should never try and add an existing item. - assert(this.getIndexInList_(listId, item.id) == -1); - let insertBeforeChild = this[listId].findIndex(function(listEl) { - return compareExtensions(listEl, item) > 0; - }); - if (insertBeforeChild == -1) { - insertBeforeChild = this[listId].length; - } - this.splice(listId, insertBeforeChild, 0, item); - }, - - /** - * @param {!chrome.developerPrivate.ExtensionInfo} item The data for the - * item to update. - * @private - */ - updateItem_: function(listId, index, item) { - // We should never try and update a non-existent item. - assert(index >= 0); - this.set([listId, index], item); - - // Update the subpage if it is open and displaying the item. If it's not - // open, we don't update the data even if it's displaying that item. We'll - // set the item correctly before opening the page. It's a little weird - // that the DOM will have stale data, but there's no point in causing the - // extra work. - if (this.detailViewItem_ && this.detailViewItem_.id == item.id && - this.currentPage_.page == Page.DETAILS) { - this.detailViewItem_ = item; - } else if ( - this.errorPageItem_ && this.errorPageItem_.id == item.id && - this.currentPage_.page == Page.ERRORS) { - this.errorPageItem_ = item; - } else if ( - this.activityLogItem_ && this.activityLogItem_.id == item.id && - this.currentPage_.page == Page.ACTIVITY_LOG) { - this.activityLogItem_ = item; - } - }, - - /** - * @param {string} itemId The id of item to remove. - * @private - */ - removeItem_: function(itemId) { - // Search for the item to be deleted in |extensions_|. - let listId = 'extensions_'; - let index = this.getIndexInList_(listId, itemId); - if (index == -1) { - // If not in |extensions_| it must be in |apps_|. - listId = 'apps_'; - index = this.getIndexInList_(listId, itemId); - } - - // We should never try and remove a non-existent item. - assert(index >= 0); - this.splice(listId, index, 1); - if ((this.currentPage_.page == Page.ACTIVITY_LOG || - this.currentPage_.page == Page.DETAILS || - this.currentPage_.page == Page.ERRORS) && - this.currentPage_.extensionId == itemId) { - // Leave the details page (the 'list' page is a fine choice). - navigation.replaceWith({page: Page.LIST}); - } - }, - - /** - * @param {!CustomEvent<!chrome.developerPrivate.LoadError>} e - * @private - */ - onLoadError_: function(e) { - this.showLoadErrorDialog_ = true; - this.async(() => { - const dialog = this.$$('#load-error'); - dialog.loadError = e.detail; - dialog.show(); - }); - }, - - /** - * Changes the active page selection. - * @param {PageState} newPage - * @private - */ - changePage_: function(newPage) { - this.onCloseDrawer_(); - - const optionsDialog = this.$$('#options-dialog'); - if (optionsDialog && optionsDialog.open) { - this.showOptionsDialog_ = false; - } - - const fromPage = this.currentPage_ ? this.currentPage_.page : null; - const toPage = newPage.page; - let data; - let activityLogPlaceholder; - if (newPage.extensionId) { - data = this.getData_(newPage.extensionId); - if (!data) { - // Allow the user to navigate to the activity log page even if the - // extension ID is not valid. This enables the use case of seeing an - // extension's install-time activities by navigating to an extension's - // activity log page, then installing the extension. - if (this.showActivityLog && toPage == Page.ACTIVITY_LOG) { - activityLogPlaceholder = { - id: newPage.extensionId, - isPlaceholder: true, - }; - } else { - // Attempting to view an invalid (removed?) app or extension ID. - navigation.replaceWith({page: Page.LIST}); - return; - } - } - } - - if (toPage == Page.DETAILS) { - this.detailViewItem_ = assert(data); - } else if (toPage == Page.ERRORS) { - this.errorPageItem_ = assert(data); - } else if (toPage == Page.ACTIVITY_LOG) { - if (!this.showActivityLog) { - // Redirect back to the details page if we try to view the - // activity log of an extension but the flag is not set. - navigation.replaceWith( - {page: Page.DETAILS, extensionId: newPage.extensionId}); - return; - } - - this.activityLogItem_ = data ? assert(data) : activityLogPlaceholder; - } - - if (fromPage != toPage) { - /** @type {CrViewManagerElement} */ (this.$.viewManager) - .switchView(/** @type {string} */ (toPage)); - } - - if (newPage.subpage) { - assert(newPage.subpage == Dialog.OPTIONS); - assert(newPage.extensionId); - this.showOptionsDialog_ = true; - this.async(() => { - this.$$('#options-dialog').show(data); - }); - } - - document.title = toPage == Page.DETAILS ? - `${loadTimeData.getString('title')} - ${this.detailViewItem_.name}` : - loadTimeData.getString('title'); - this.currentPage_ = newPage; - }, - - /** - * This method detaches the drawer dialog completely. Should only be - * triggered by the dialog's 'close' event. - * @private - */ - onDrawerClose_: function() { - this.showDrawer_ = false; - }, - - /** - * This method animates the closing of the drawer. - * @private - */ - onCloseDrawer_: function() { - const drawer = this.$$('#drawer'); - if (drawer && drawer.open) { - drawer.close(); - } + didInitPage_: { + type: Boolean, + value: false, }, /** @private */ - onLoadErrorDialogClose_: function() { - this.showLoadErrorDialog_ = false; - }, + showDrawer_: Boolean, /** @private */ - onOptionsDialogClose_: function() { - this.showOptionsDialog_ = false; - this.$$('extensions-detail-view').focusOptionsButton(); - }, + showLoadErrorDialog_: Boolean, /** @private */ - onViewEnterStart_: function() { - this.fromActivityLog_ = false; - }, + showInstallWarningsDialog_: Boolean, - /** - * @param {!Event} e - * @private - */ - onViewExitStart_: function(e) { - const viewType = e.composedPath()[0].tagName; - this.fromActivityLog_ = viewType == 'EXTENSIONS-ACTIVITY-LOG'; - }, - - /** - * @param {!Event} e - * @private - */ - onViewExitFinish_: function(e) { - const viewType = e.composedPath()[0].tagName; - if (viewType == 'EXTENSIONS-ITEM-LIST' || - viewType == 'EXTENSIONS-KEYBOARD-SHORTCUTS' || - viewType == 'EXTENSIONS-ACTIVITY-LOG') { - return; - } - - const extensionId = e.composedPath()[0].data.id; - const list = this.$$('extensions-item-list'); - const button = viewType == 'EXTENSIONS-DETAIL-VIEW' ? - list.getDetailsButton(extensionId) : - list.getErrorsButton(extensionId); - - // The button will not exist, when returning from a details page - // because the corresponding extension/app was deleted. - if (button) { - button.focus(); - } - }, - - /** - * @param {!CustomEvent<!Array<string>>} e - * @private - */ - onShowInstallWarnings_: function(e) { - // Leverage Polymer data bindings instead of just assigning the - // installWarnings on the dialog since the dialog hasn't been stamped - // in the DOM yet. - this.installWarnings_ = e.detail; - this.showInstallWarningsDialog_ = true; - }, + /** @private {?Array<string>} */ + installWarnings_: Array, /** @private */ - onInstallWarningsDialogClose_: function() { - this.installWarnings_ = null; - this.showInstallWarningsDialog_ = false; - }, + showOptionsDialog_: Boolean, + + /** + * Whether the last page the user navigated from was the activity log + * page. + * @private + */ + fromActivityLog_: Boolean, // <if expr="chromeos"> /** @private */ - onKioskTap_: function() { - this.showKioskDialog_ = true; + kioskEnabled_: { + type: Boolean, + value: false, }, - onKioskDialogClose_: function() { - this.showKioskDialog_ = false; + /** @private */ + showKioskDialog_: { + type: Boolean, + value: false, }, // </if> - }); + }, + + listeners: { + 'load-error': 'onLoadError_', + 'view-enter-start': 'onViewEnterStart_', + 'view-exit-start': 'onViewExitStart_', + 'view-exit-finish': 'onViewExitFinish_', + }, + + /** + * The current page being shown. Default to null, and initPage_ will figure + * out the initial page based on url. + * @private {?PageState} + */ + currentPage_: null, + + /** + * The ID of the listener on |navigation|. Stored so that the + * listener can be removed when this element is detached (happens in tests). + * @private {?number} + */ + navigationListener_: null, + + /** @override */ + ready: function() { + const service = Service.getInstance(); + + const onProfileStateChanged = profileInfo => { + this.isSupervised_ = profileInfo.isSupervised; + this.incognitoAvailable_ = profileInfo.isIncognitoAvailable; + this.devModeControlledByPolicy = + profileInfo.isDeveloperModeControlledByPolicy; + this.inDevMode = profileInfo.inDeveloperMode; + this.canLoadUnpacked = profileInfo.canLoadUnpacked; + }; + service.getProfileStateChangedTarget().addListener(onProfileStateChanged); + service.getProfileConfiguration().then(onProfileStateChanged); + + service.getExtensionsInfo().then(extensionsAndApps => { + this.initExtensionsAndApps_(extensionsAndApps); + this.initPage_(); + + service.getItemStateChangedTarget().addListener( + this.onItemStateChanged_.bind(this)); + }); + + // <if expr="chromeos"> + KioskBrowserProxyImpl.getInstance().initializeKioskAppSettings().then( + params => { + this.kioskEnabled_ = params.kioskEnabled; + }); + // </if> + }, + + /** @override */ + attached: function() { + document.documentElement.classList.remove('loading'); + document.fonts.load('bold 12px Roboto'); + + this.navigationListener_ = navigation.addListener(newPage => { + this.changePage_(newPage); + }); + }, + + /** @override */ + detached: function() { + assert(navigation.removeListener( + /** @type {number} */ (this.navigationListener_))); + this.navigationListener_ = null; + }, + + /** + * Initializes the page to reflect what's specified in the url so that if + * the user visits chrome://extensions/?id=..., we land on the proper page. + * @private + */ + initPage_: function() { + this.didInitPage_ = true; + this.changePage_(navigation.getCurrentPage()); + }, + + /** + * @param {!chrome.developerPrivate.EventData} eventData + * @private + */ + onItemStateChanged_: function(eventData) { + const EventType = chrome.developerPrivate.EventType; + switch (eventData.event_type) { + case EventType.VIEW_REGISTERED: + case EventType.VIEW_UNREGISTERED: + case EventType.INSTALLED: + case EventType.LOADED: + case EventType.UNLOADED: + case EventType.ERROR_ADDED: + case EventType.ERRORS_REMOVED: + case EventType.PREFS_CHANGED: + case EventType.WARNINGS_CHANGED: + case EventType.COMMAND_ADDED: + case EventType.COMMAND_REMOVED: + case EventType.PERMISSIONS_CHANGED: + // |extensionInfo| can be undefined in the case of an extension + // being unloaded right before uninstallation. There's nothing to do + // here. + if (!eventData.extensionInfo) { + break; + } + + if (this.delegate.shouldIgnoreUpdate( + eventData.extensionInfo.id, eventData.event_type)) { + break; + } + + const listId = this.getListId_(eventData.extensionInfo); + const currentIndex = this[listId].findIndex( + item => item.id == eventData.extensionInfo.id); + + if (currentIndex >= 0) { + this.updateItem_(listId, currentIndex, eventData.extensionInfo); + } else { + this.addItem_(listId, eventData.extensionInfo); + } + break; + case EventType.UNINSTALLED: + this.removeItem_(eventData.item_id); + break; + default: + assertNotReached(); + } + }, + + /** + * @param {!CustomEvent<string>} event + * @private + */ + onFilterChanged_: function(event) { + if (this.currentPage_.page !== Page.LIST) { + navigation.navigateTo({page: Page.LIST}); + } + this.filter = event.detail; + }, + + /** @private */ + onMenuButtonTap_: function() { + this.showDrawer_ = true; + this.async(() => { + this.$$('#drawer').openDrawer(); + }); + }, + + /** + * @param {!chrome.developerPrivate.ExtensionInfo} item + * @return {string} The ID of the list that the item belongs in. + * @private + */ + getListId_: function(item) { + const ExtensionType = chrome.developerPrivate.ExtensionType; + switch (item.type) { + case ExtensionType.HOSTED_APP: + case ExtensionType.LEGACY_PACKAGED_APP: + case ExtensionType.PLATFORM_APP: + return 'apps_'; + case ExtensionType.EXTENSION: + case ExtensionType.SHARED_MODULE: + return 'extensions_'; + case ExtensionType.THEME: + assertNotReached('Don\'t send themes to the chrome://extensions page'); + break; + } + assertNotReached(); + }, + + /** + * @param {string} listId The list to look for the item in. + * @param {string} itemId The id of the item to look for. + * @return {number} The index of the item in the list, or -1 if not found. + * @private + */ + getIndexInList_: function(listId, itemId) { + return this[listId].findIndex(function(item) { + return item.id == itemId; + }); + }, + + /** + * @return {?chrome.developerPrivate.ExtensionInfo} + * @private + */ + getData_: function(id) { + return this.extensions_[this.getIndexInList_('extensions_', id)] || + this.apps_[this.getIndexInList_('apps_', id)]; + }, + + /** + * Categorizes |extensionsAndApps| to apps and extensions and initializes + * those lists. + * @param {!Array<!chrome.developerPrivate.ExtensionInfo>} extensionsAndApps + * @private + */ + initExtensionsAndApps_: function(extensionsAndApps) { + extensionsAndApps.sort(compareExtensions); + const apps = []; + const extensions = []; + for (const i of extensionsAndApps) { + const list = this.getListId_(i) === 'apps_' ? apps : extensions; + list.push(i); + } + + this.apps_ = apps; + this.extensions_ = extensions; + }, + + /** + * Creates and adds a new extensions-item element to the list, inserting it + * into its sorted position in the relevant section. + * @param {!chrome.developerPrivate.ExtensionInfo} item The extension + * the new element is representing. + * @private + */ + addItem_: function(listId, item) { + // We should never try and add an existing item. + assert(this.getIndexInList_(listId, item.id) == -1); + let insertBeforeChild = this[listId].findIndex(function(listEl) { + return compareExtensions(listEl, item) > 0; + }); + if (insertBeforeChild == -1) { + insertBeforeChild = this[listId].length; + } + this.splice(listId, insertBeforeChild, 0, item); + }, + + /** + * @param {!chrome.developerPrivate.ExtensionInfo} item The data for the + * item to update. + * @private + */ + updateItem_: function(listId, index, item) { + // We should never try and update a non-existent item. + assert(index >= 0); + this.set([listId, index], item); + + // Update the subpage if it is open and displaying the item. If it's not + // open, we don't update the data even if it's displaying that item. We'll + // set the item correctly before opening the page. It's a little weird + // that the DOM will have stale data, but there's no point in causing the + // extra work. + if (this.detailViewItem_ && this.detailViewItem_.id == item.id && + this.currentPage_.page == Page.DETAILS) { + this.detailViewItem_ = item; + } else if ( + this.errorPageItem_ && this.errorPageItem_.id == item.id && + this.currentPage_.page == Page.ERRORS) { + this.errorPageItem_ = item; + } else if ( + this.activityLogItem_ && this.activityLogItem_.id == item.id && + this.currentPage_.page == Page.ACTIVITY_LOG) { + this.activityLogItem_ = item; + } + }, + + /** + * @param {string} itemId The id of item to remove. + * @private + */ + removeItem_: function(itemId) { + // Search for the item to be deleted in |extensions_|. + let listId = 'extensions_'; + let index = this.getIndexInList_(listId, itemId); + if (index == -1) { + // If not in |extensions_| it must be in |apps_|. + listId = 'apps_'; + index = this.getIndexInList_(listId, itemId); + } + + // We should never try and remove a non-existent item. + assert(index >= 0); + this.splice(listId, index, 1); + if ((this.currentPage_.page == Page.ACTIVITY_LOG || + this.currentPage_.page == Page.DETAILS || + this.currentPage_.page == Page.ERRORS) && + this.currentPage_.extensionId == itemId) { + // Leave the details page (the 'list' page is a fine choice). + navigation.replaceWith({page: Page.LIST}); + } + }, + + /** + * @param {!CustomEvent<!chrome.developerPrivate.LoadError>} e + * @private + */ + onLoadError_: function(e) { + this.showLoadErrorDialog_ = true; + this.async(() => { + const dialog = this.$$('#load-error'); + dialog.loadError = e.detail; + dialog.show(); + }); + }, + + /** + * Changes the active page selection. + * @param {PageState} newPage + * @private + */ + changePage_: function(newPage) { + this.onCloseDrawer_(); + + const optionsDialog = this.$$('#options-dialog'); + if (optionsDialog && optionsDialog.open) { + this.showOptionsDialog_ = false; + } + + const fromPage = this.currentPage_ ? this.currentPage_.page : null; + const toPage = newPage.page; + let data; + let activityLogPlaceholder; + if (newPage.extensionId) { + data = this.getData_(newPage.extensionId); + if (!data) { + // Allow the user to navigate to the activity log page even if the + // extension ID is not valid. This enables the use case of seeing an + // extension's install-time activities by navigating to an extension's + // activity log page, then installing the extension. + if (this.showActivityLog && toPage == Page.ACTIVITY_LOG) { + activityLogPlaceholder = { + id: newPage.extensionId, + isPlaceholder: true, + }; + } else { + // Attempting to view an invalid (removed?) app or extension ID. + navigation.replaceWith({page: Page.LIST}); + return; + } + } + } + + if (toPage == Page.DETAILS) { + this.detailViewItem_ = assert(data); + } else if (toPage == Page.ERRORS) { + this.errorPageItem_ = assert(data); + } else if (toPage == Page.ACTIVITY_LOG) { + if (!this.showActivityLog) { + // Redirect back to the details page if we try to view the + // activity log of an extension but the flag is not set. + navigation.replaceWith( + {page: Page.DETAILS, extensionId: newPage.extensionId}); + return; + } + + this.activityLogItem_ = data ? assert(data) : activityLogPlaceholder; + } + + if (fromPage != toPage) { + /** @type {CrViewManagerElement} */ (this.$.viewManager) + .switchView(/** @type {string} */ (toPage)); + } + + if (newPage.subpage) { + assert(newPage.subpage == Dialog.OPTIONS); + assert(newPage.extensionId); + this.showOptionsDialog_ = true; + this.async(() => { + this.$$('#options-dialog').show(data); + }); + } + + document.title = toPage == Page.DETAILS ? + `${loadTimeData.getString('title')} - ${this.detailViewItem_.name}` : + loadTimeData.getString('title'); + this.currentPage_ = newPage; + }, + + /** + * This method detaches the drawer dialog completely. Should only be + * triggered by the dialog's 'close' event. + * @private + */ + onDrawerClose_: function() { + this.showDrawer_ = false; + }, + + /** + * This method animates the closing of the drawer. + * @private + */ + onCloseDrawer_: function() { + const drawer = this.$$('#drawer'); + if (drawer && drawer.open) { + drawer.close(); + } + }, + + /** @private */ + onLoadErrorDialogClose_: function() { + this.showLoadErrorDialog_ = false; + }, + + /** @private */ + onOptionsDialogClose_: function() { + this.showOptionsDialog_ = false; + this.$$('extensions-detail-view').focusOptionsButton(); + }, + + /** @private */ + onViewEnterStart_: function() { + this.fromActivityLog_ = false; + }, + + /** + * @param {!Event} e + * @private + */ + onViewExitStart_: function(e) { + const viewType = e.composedPath()[0].tagName; + this.fromActivityLog_ = viewType == 'EXTENSIONS-ACTIVITY-LOG'; + }, + + /** + * @param {!Event} e + * @private + */ + onViewExitFinish_: function(e) { + const viewType = e.composedPath()[0].tagName; + if (viewType == 'EXTENSIONS-ITEM-LIST' || + viewType == 'EXTENSIONS-KEYBOARD-SHORTCUTS' || + viewType == 'EXTENSIONS-ACTIVITY-LOG') { + return; + } + + const extensionId = e.composedPath()[0].data.id; + const list = this.$$('extensions-item-list'); + const button = viewType == 'EXTENSIONS-DETAIL-VIEW' ? + list.getDetailsButton(extensionId) : + list.getErrorsButton(extensionId); + + // The button will not exist, when returning from a details page + // because the corresponding extension/app was deleted. + if (button) { + button.focus(); + } + }, + + /** + * @param {!CustomEvent<!Array<string>>} e + * @private + */ + onShowInstallWarnings_: function(e) { + // Leverage Polymer data bindings instead of just assigning the + // installWarnings on the dialog since the dialog hasn't been stamped + // in the DOM yet. + this.installWarnings_ = e.detail; + this.showInstallWarningsDialog_ = true; + }, + + /** @private */ + onInstallWarningsDialogClose_: function() { + this.installWarnings_ = null; + this.showInstallWarningsDialog_ = false; + }, + + // <if expr="chromeos"> + /** @private */ + onKioskTap_: function() { + this.showKioskDialog_ = true; + }, + + onKioskDialogClose_: function() { + this.showKioskDialog_ = false; + }, + // </if> +});
diff --git a/chrome/browser/resources/extensions/navigation_helper.js b/chrome/browser/resources/extensions/navigation_helper.js index f062024..b4bc143d 100644 --- a/chrome/browser/resources/extensions/navigation_helper.js +++ b/chrome/browser/resources/extensions/navigation_helper.js
@@ -5,225 +5,225 @@ import {assert} from 'chrome://resources/js/assert.m.js'; - /** - * The different pages that can be shown at a time. - * Note: This must remain in sync with the page ids in manager.html! - * @enum {string} - */ - export const Page = { - LIST: 'items-list', - DETAILS: 'details-view', - ACTIVITY_LOG: 'activity-log', - SHORTCUTS: 'keyboard-shortcuts', - ERRORS: 'error-page', - }; +/** + * The different pages that can be shown at a time. + * Note: This must remain in sync with the page ids in manager.html! + * @enum {string} + */ +export const Page = { + LIST: 'items-list', + DETAILS: 'details-view', + ACTIVITY_LOG: 'activity-log', + SHORTCUTS: 'keyboard-shortcuts', + ERRORS: 'error-page', +}; - /** @enum {string} */ - export const Dialog = { - OPTIONS: 'options', - }; +/** @enum {string} */ +export const Dialog = { + OPTIONS: 'options', +}; - /** - * @typedef {{page: Page, - * extensionId: (string|undefined), - * subpage: (!Dialog|undefined)}} - */ - export let PageState; +/** + * @typedef {{page: Page, + * extensionId: (string|undefined), + * subpage: (!Dialog|undefined)}} + */ +export let PageState; - /** - * @param {!PageState} a - * @param {!PageState} b - * @return {boolean} Whether a and b are equal. - */ - function isPageStateEqual(a, b) { - return a.page == b.page && a.subpage == b.subpage && - a.extensionId == b.extensionId; +/** + * @param {!PageState} a + * @param {!PageState} b + * @return {boolean} Whether a and b are equal. + */ +function isPageStateEqual(a, b) { + return a.page == b.page && a.subpage == b.subpage && + a.extensionId == b.extensionId; +} + +/** + * Regular expression that captures the leading slash, the content and the + * trailing slash in three different groups. + * @const {!RegExp} + */ +const CANONICAL_PATH_REGEX = /(^\/)([\/-\w]+)(\/$)/; + +/** + * A helper object to manage in-page navigations. Since the extensions page + * needs to support different urls for different subpages (like the details + * page), we use this object to manage the history and url conversions. + */ +export class NavigationHelper { + constructor() { + this.processRoute_(); + + /** @private {number} */ + this.nextListenerId_ = 1; + + /** @private {!Map<number, function(!PageState)>} */ + this.listeners_ = new Map(); + + /** @private {!PageState} */ + this.previousPage_; + + window.addEventListener('popstate', () => { + this.notifyRouteChanged_(this.getCurrentPage()); + }); + } + + /** @private */ + get currentPath_() { + return location.pathname.replace(CANONICAL_PATH_REGEX, '$1$2'); } /** - * Regular expression that captures the leading slash, the content and the - * trailing slash in three different groups. - * @const {!RegExp} + * Going to /configureCommands and /shortcuts should land you on /shortcuts. + * These are the only two supported routes, so all other cases will redirect + * you to root path if not already on it. + * @private */ - const CANONICAL_PATH_REGEX = /(^\/)([\/-\w]+)(\/$)/; - - /** - * A helper object to manage in-page navigations. Since the extensions page - * needs to support different urls for different subpages (like the details - * page), we use this object to manage the history and url conversions. - */ - export class NavigationHelper { - constructor() { - this.processRoute_(); - - /** @private {number} */ - this.nextListenerId_ = 1; - - /** @private {!Map<number, function(!PageState)>} */ - this.listeners_ = new Map(); - - /** @private {!PageState} */ - this.previousPage_; - - window.addEventListener('popstate', () => { - this.notifyRouteChanged_(this.getCurrentPage()); - }); - } - - /** @private */ - get currentPath_() { - return location.pathname.replace(CANONICAL_PATH_REGEX, '$1$2'); - } - - /** - * Going to /configureCommands and /shortcuts should land you on /shortcuts. - * These are the only two supported routes, so all other cases will redirect - * you to root path if not already on it. - * @private - */ - processRoute_() { - if (this.currentPath_ == '/configureCommands' || - this.currentPath_ == '/shortcuts') { - window.history.replaceState( - undefined /* stateObject */, '', '/shortcuts'); - } else if (this.currentPath_ !== '/') { - window.history.replaceState(undefined /* stateObject */, '', '/'); - } - } - - /** - * @return {!PageState} The page that should be displayed for the - * current URL. - */ - getCurrentPage() { - const search = new URLSearchParams(location.search); - let id = search.get('id'); - if (id) { - return {page: Page.DETAILS, extensionId: id}; - } - id = search.get('activity'); - if (id) { - return {page: Page.ACTIVITY_LOG, extensionId: id}; - } - id = search.get('options'); - if (id) { - return {page: Page.DETAILS, extensionId: id, subpage: Dialog.OPTIONS}; - } - id = search.get('errors'); - if (id) { - return {page: Page.ERRORS, extensionId: id}; - } - - if (this.currentPath_ == '/shortcuts') { - return {page: Page.SHORTCUTS}; - } - - return {page: Page.LIST}; - } - - /** - * Function to add subscribers. - * @param {!function(!PageState)} listener - * @return {number} A numerical ID to be used for removing the listener. - */ - addListener(listener) { - const nextListenerId = this.nextListenerId_++; - this.listeners_.set(nextListenerId, listener); - return nextListenerId; - } - - /** - * Remove a previously registered listener. - * @param {number} id - * @return {boolean} Whether a listener with the given ID was actually found - * and removed. - */ - removeListener(id) { - return this.listeners_.delete(id); - } - - /** - * Function to notify subscribers. - * @private - */ - notifyRouteChanged_(newPage) { - this.listeners_.forEach((listener, id) => { - listener(newPage); - }); - } - - /** - * @param {!PageState} newPage the page to navigate to. - */ - navigateTo(newPage) { - const currentPage = this.getCurrentPage(); - if (currentPage && isPageStateEqual(currentPage, newPage)) { - return; - } - - this.updateHistory(newPage, false /* replaceState */); - this.notifyRouteChanged_(newPage); - } - - /** - * @param {!PageState} newPage the page to replace the current - * page with. - */ - replaceWith(newPage) { - this.updateHistory(newPage, true /* replaceState */); - if (this.previousPage_ && isPageStateEqual(this.previousPage_, newPage)) { - // Skip the duplicate history entry. - history.back(); - return; - } - this.notifyRouteChanged_(newPage); - } - - /** - * Called when a page changes, and pushes state to history to reflect it. - * @param {!PageState} entry - * @param {boolean} replaceState - */ - updateHistory(entry, replaceState) { - let path; - switch (entry.page) { - case Page.LIST: - path = '/'; - break; - case Page.ACTIVITY_LOG: - path = '/?activity=' + entry.extensionId; - break; - case Page.DETAILS: - if (entry.subpage) { - assert(entry.subpage == Dialog.OPTIONS); - path = '/?options=' + entry.extensionId; - } else { - path = '/?id=' + entry.extensionId; - } - break; - case Page.SHORTCUTS: - path = '/shortcuts'; - break; - case Page.ERRORS: - path = '/?errors=' + entry.extensionId; - break; - } - assert(path); - const state = {url: path}; - const currentPage = this.getCurrentPage(); - const isDialogNavigation = currentPage.page == entry.page && - currentPage.extensionId == entry.extensionId; - // Navigating to a dialog doesn't visually change pages; it just opens - // a dialog. As such, we replace state rather than pushing a new state - // on the stack so that hitting the back button doesn't just toggle the - // dialog. - if (replaceState || isDialogNavigation) { - history.replaceState(state, '', path); - } else { - this.previousPage_ = currentPage; - history.pushState(state, '', path); - } + processRoute_() { + if (this.currentPath_ == '/configureCommands' || + this.currentPath_ == '/shortcuts') { + window.history.replaceState( + undefined /* stateObject */, '', '/shortcuts'); + } else if (this.currentPath_ !== '/') { + window.history.replaceState(undefined /* stateObject */, '', '/'); } } - export const navigation = new NavigationHelper(); + /** + * @return {!PageState} The page that should be displayed for the + * current URL. + */ + getCurrentPage() { + const search = new URLSearchParams(location.search); + let id = search.get('id'); + if (id) { + return {page: Page.DETAILS, extensionId: id}; + } + id = search.get('activity'); + if (id) { + return {page: Page.ACTIVITY_LOG, extensionId: id}; + } + id = search.get('options'); + if (id) { + return {page: Page.DETAILS, extensionId: id, subpage: Dialog.OPTIONS}; + } + id = search.get('errors'); + if (id) { + return {page: Page.ERRORS, extensionId: id}; + } + + if (this.currentPath_ == '/shortcuts') { + return {page: Page.SHORTCUTS}; + } + + return {page: Page.LIST}; + } + + /** + * Function to add subscribers. + * @param {!function(!PageState)} listener + * @return {number} A numerical ID to be used for removing the listener. + */ + addListener(listener) { + const nextListenerId = this.nextListenerId_++; + this.listeners_.set(nextListenerId, listener); + return nextListenerId; + } + + /** + * Remove a previously registered listener. + * @param {number} id + * @return {boolean} Whether a listener with the given ID was actually found + * and removed. + */ + removeListener(id) { + return this.listeners_.delete(id); + } + + /** + * Function to notify subscribers. + * @private + */ + notifyRouteChanged_(newPage) { + this.listeners_.forEach((listener, id) => { + listener(newPage); + }); + } + + /** + * @param {!PageState} newPage the page to navigate to. + */ + navigateTo(newPage) { + const currentPage = this.getCurrentPage(); + if (currentPage && isPageStateEqual(currentPage, newPage)) { + return; + } + + this.updateHistory(newPage, false /* replaceState */); + this.notifyRouteChanged_(newPage); + } + + /** + * @param {!PageState} newPage the page to replace the current + * page with. + */ + replaceWith(newPage) { + this.updateHistory(newPage, true /* replaceState */); + if (this.previousPage_ && isPageStateEqual(this.previousPage_, newPage)) { + // Skip the duplicate history entry. + history.back(); + return; + } + this.notifyRouteChanged_(newPage); + } + + /** + * Called when a page changes, and pushes state to history to reflect it. + * @param {!PageState} entry + * @param {boolean} replaceState + */ + updateHistory(entry, replaceState) { + let path; + switch (entry.page) { + case Page.LIST: + path = '/'; + break; + case Page.ACTIVITY_LOG: + path = '/?activity=' + entry.extensionId; + break; + case Page.DETAILS: + if (entry.subpage) { + assert(entry.subpage == Dialog.OPTIONS); + path = '/?options=' + entry.extensionId; + } else { + path = '/?id=' + entry.extensionId; + } + break; + case Page.SHORTCUTS: + path = '/shortcuts'; + break; + case Page.ERRORS: + path = '/?errors=' + entry.extensionId; + break; + } + assert(path); + const state = {url: path}; + const currentPage = this.getCurrentPage(); + const isDialogNavigation = currentPage.page == entry.page && + currentPage.extensionId == entry.extensionId; + // Navigating to a dialog doesn't visually change pages; it just opens + // a dialog. As such, we replace state rather than pushing a new state + // on the stack so that hitting the back button doesn't just toggle the + // dialog. + if (replaceState || isDialogNavigation) { + history.replaceState(state, '', path); + } else { + this.previousPage_ = currentPage; + history.pushState(state, '', path); + } + } +} + +export const navigation = new NavigationHelper();
diff --git a/chrome/browser/resources/extensions/options_dialog.js b/chrome/browser/resources/extensions/options_dialog.js index dfa0fba0..ce9aa267 100644 --- a/chrome/browser/resources/extensions/options_dialog.js +++ b/chrome/browser/resources/extensions/options_dialog.js
@@ -9,124 +9,123 @@ import {ItemBehavior} from './item_behavior.js'; import {navigation, Page} from './navigation_helper.js'; - /** - * @return {!Promise} A signal that the document is ready. Need to wait for - * this, otherwise the custom ExtensionOptions element might not have been - * registered yet. - */ - function whenDocumentReady() { - if (document.readyState == 'complete') { - return Promise.resolve(); - } - - return new Promise(function(resolve) { - document.addEventListener('readystatechange', function f() { - if (document.readyState == 'complete') { - document.removeEventListener('readystatechange', f); - resolve(); - } - }); - }); +/** + * @return {!Promise} A signal that the document is ready. Need to wait for + * this, otherwise the custom ExtensionOptions element might not have been + * registered yet. + */ +function whenDocumentReady() { + if (document.readyState == 'complete') { + return Promise.resolve(); } - // The minimum width in pixels for the options dialog. - export const OptionsDialogMinWidth = 400; - - // The maximum height in pixels for the options dialog. - export const OptionsDialogMaxHeight = 640; - - Polymer({ - is: 'extensions-options-dialog', - - _template: html`{__html_template__}`, - - behaviors: [ItemBehavior], - - properties: { - /** @private {Object} */ - extensionOptions_: Object, - - /** @private {chrome.developerPrivate.ExtensionInfo} */ - data_: Object, - }, - - /** @private {?Function} */ - boundUpdateDialogSize_: null, - - /** @private {?{height: number, width: number}} */ - preferredSize_: null, - - get open() { - return this.$.dialog.open; - }, - - /** - * Resizes the dialog to the width/height stored in |preferredSize_|, taking - * into account the window width/height. - * @private - */ - updateDialogSize_: function() { - const headerHeight = this.$.body.offsetTop; - const maxHeight = - Math.min(0.9 * window.innerHeight, OptionsDialogMaxHeight); - const effectiveHeight = - Math.min(maxHeight, headerHeight + this.preferredSize_.height); - const effectiveWidth = - Math.max(OptionsDialogMinWidth, this.preferredSize_.width); - - this.$.dialog.style.setProperty( - '--dialog-height', `${effectiveHeight}px`); - this.$.dialog.style.setProperty('--dialog-width', `${effectiveWidth}px`); - this.$.dialog.style.setProperty('--dialog-opacity', '1'); - }, - - /** @param {chrome.developerPrivate.ExtensionInfo} data */ - show: function(data) { - this.data_ = data; - whenDocumentReady().then(() => { - if (!this.extensionOptions_) { - this.extensionOptions_ = document.createElement('ExtensionOptions'); - } - this.extensionOptions_.extension = this.data_.id; - this.extensionOptions_.onclose = () => this.$.dialog.close(); - - const boundUpdateDialogSize = this.updateDialogSize_.bind(this); - this.boundUpdateDialogSize_ = boundUpdateDialogSize; - this.extensionOptions_.onpreferredsizechanged = e => { - if (!this.$.dialog.open) { - this.$.dialog.showModal(); - } - this.preferredSize_ = e; - this.debounce('updateDialogSize_', boundUpdateDialogSize, 50); - }; - - // Add a 'resize' such that the dialog is resized when window size - // changes. - window.addEventListener('resize', this.boundUpdateDialogSize_); - this.$.body.appendChild(/** @type {Node} */ (this.extensionOptions_)); - }); - }, - - /** @private */ - onClose_: function() { - this.extensionOptions_.onpreferredsizechanged = null; - - if (this.boundUpdateDialogSize_) { - window.removeEventListener('resize', this.boundUpdateDialogSize_); - this.boundUpdateDialogSize_ = null; + return new Promise(function(resolve) { + document.addEventListener('readystatechange', function f() { + if (document.readyState == 'complete') { + document.removeEventListener('readystatechange', f); + resolve(); } - - const currentPage = navigation.getCurrentPage(); - // We update the page when the options dialog closes, but only if we're - // still on the details page. We could be on a different page if the - // user hit back while the options dialog was visible; in that case, the - // new page is already correct. - if (currentPage && currentPage.page == Page.DETAILS) { - // This will update the currentPage_ and the NavigationHelper; since - // the active page is already the details page, no main page - // transition occurs. - navigation.navigateTo( - {page: Page.DETAILS, extensionId: currentPage.extensionId}); - } - }, + }); }); +} + +// The minimum width in pixels for the options dialog. +export const OptionsDialogMinWidth = 400; + +// The maximum height in pixels for the options dialog. +export const OptionsDialogMaxHeight = 640; + +Polymer({ + is: 'extensions-options-dialog', + + _template: html`{__html_template__}`, + + behaviors: [ItemBehavior], + + properties: { + /** @private {Object} */ + extensionOptions_: Object, + + /** @private {chrome.developerPrivate.ExtensionInfo} */ + data_: Object, + }, + + /** @private {?Function} */ + boundUpdateDialogSize_: null, + + /** @private {?{height: number, width: number}} */ + preferredSize_: null, + + get open() { + return this.$.dialog.open; + }, + + /** + * Resizes the dialog to the width/height stored in |preferredSize_|, taking + * into account the window width/height. + * @private + */ + updateDialogSize_: function() { + const headerHeight = this.$.body.offsetTop; + const maxHeight = + Math.min(0.9 * window.innerHeight, OptionsDialogMaxHeight); + const effectiveHeight = + Math.min(maxHeight, headerHeight + this.preferredSize_.height); + const effectiveWidth = + Math.max(OptionsDialogMinWidth, this.preferredSize_.width); + + this.$.dialog.style.setProperty('--dialog-height', `${effectiveHeight}px`); + this.$.dialog.style.setProperty('--dialog-width', `${effectiveWidth}px`); + this.$.dialog.style.setProperty('--dialog-opacity', '1'); + }, + + /** @param {chrome.developerPrivate.ExtensionInfo} data */ + show: function(data) { + this.data_ = data; + whenDocumentReady().then(() => { + if (!this.extensionOptions_) { + this.extensionOptions_ = document.createElement('ExtensionOptions'); + } + this.extensionOptions_.extension = this.data_.id; + this.extensionOptions_.onclose = () => this.$.dialog.close(); + + const boundUpdateDialogSize = this.updateDialogSize_.bind(this); + this.boundUpdateDialogSize_ = boundUpdateDialogSize; + this.extensionOptions_.onpreferredsizechanged = e => { + if (!this.$.dialog.open) { + this.$.dialog.showModal(); + } + this.preferredSize_ = e; + this.debounce('updateDialogSize_', boundUpdateDialogSize, 50); + }; + + // Add a 'resize' such that the dialog is resized when window size + // changes. + window.addEventListener('resize', this.boundUpdateDialogSize_); + this.$.body.appendChild(/** @type {Node} */ (this.extensionOptions_)); + }); + }, + + /** @private */ + onClose_: function() { + this.extensionOptions_.onpreferredsizechanged = null; + + if (this.boundUpdateDialogSize_) { + window.removeEventListener('resize', this.boundUpdateDialogSize_); + this.boundUpdateDialogSize_ = null; + } + + const currentPage = navigation.getCurrentPage(); + // We update the page when the options dialog closes, but only if we're + // still on the details page. We could be on a different page if the + // user hit back while the options dialog was visible; in that case, the + // new page is already correct. + if (currentPage && currentPage.page == Page.DETAILS) { + // This will update the currentPage_ and the NavigationHelper; since + // the active page is already the details page, no main page + // transition occurs. + navigation.navigateTo( + {page: Page.DETAILS, extensionId: currentPage.extensionId}); + } + }, +});
diff --git a/chrome/browser/resources/extensions/pack_dialog.js b/chrome/browser/resources/extensions/pack_dialog.js index 6ccfe322..4791d6b 100644 --- a/chrome/browser/resources/extensions/pack_dialog.js +++ b/chrome/browser/resources/extensions/pack_dialog.js
@@ -12,123 +12,122 @@ import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; - /** @interface */ - export class PackDialogDelegate { - /** - * Opens a file browser for the user to select the root directory. - * @return {Promise<string>} A promise that is resolved with the path the - * user selected. - */ - choosePackRootDirectory() {} +/** @interface */ +export class PackDialogDelegate { + /** + * Opens a file browser for the user to select the root directory. + * @return {Promise<string>} A promise that is resolved with the path the + * user selected. + */ + choosePackRootDirectory() {} - /** - * Opens a file browser for the user to select the private key file. - * @return {Promise<string>} A promise that is resolved with the path the - * user selected. - */ - choosePrivateKeyPath() {} + /** + * Opens a file browser for the user to select the private key file. + * @return {Promise<string>} A promise that is resolved with the path the + * user selected. + */ + choosePrivateKeyPath() {} - /** - * Packs the extension into a .crx. - * @param {string} rootPath - * @param {string} keyPath - * @param {number=} flag - * @param {function(chrome.developerPrivate.PackDirectoryResponse)=} - * callback - */ - packExtension(rootPath, keyPath, flag, callback) {} - } + /** + * Packs the extension into a .crx. + * @param {string} rootPath + * @param {string} keyPath + * @param {number=} flag + * @param {function(chrome.developerPrivate.PackDirectoryResponse)=} + * callback + */ + packExtension(rootPath, keyPath, flag, callback) {} +} - Polymer({ - is: 'extensions-pack-dialog', +Polymer({ + is: 'extensions-pack-dialog', - _template: html`{__html_template__}`, + _template: html`{__html_template__}`, - properties: { - /** @type {PackDialogDelegate} */ - delegate: Object, + properties: { + /** @type {PackDialogDelegate} */ + delegate: Object, - /** @private */ - packDirectory_: { - type: String, - value: '', // Initialized to trigger binding when attached. - }, - - /** @private */ - keyFile_: String, - - /** @private {?chrome.developerPrivate.PackDirectoryResponse} */ - lastResponse_: Object, - }, - - /** @override */ - attached: function() { - this.$.dialog.showModal(); + /** @private */ + packDirectory_: { + type: String, + value: '', // Initialized to trigger binding when attached. }, /** @private */ - onRootBrowse_: function() { - this.delegate.choosePackRootDirectory().then(path => { - if (path) { - this.set('packDirectory_', path); - } - }); - }, + keyFile_: String, - /** @private */ - onKeyBrowse_: function() { - this.delegate.choosePrivateKeyPath().then(path => { - if (path) { - this.set('keyFile_', path); - } - }); - }, + /** @private {?chrome.developerPrivate.PackDirectoryResponse} */ + lastResponse_: Object, + }, - /** @private */ - onCancelTap_: function() { - this.$.dialog.cancel(); - }, + /** @override */ + attached: function() { + this.$.dialog.showModal(); + }, - /** @private */ - onConfirmTap_: function() { + /** @private */ + onRootBrowse_: function() { + this.delegate.choosePackRootDirectory().then(path => { + if (path) { + this.set('packDirectory_', path); + } + }); + }, + + /** @private */ + onKeyBrowse_: function() { + this.delegate.choosePrivateKeyPath().then(path => { + if (path) { + this.set('keyFile_', path); + } + }); + }, + + /** @private */ + onCancelTap_: function() { + this.$.dialog.cancel(); + }, + + /** @private */ + onConfirmTap_: function() { + this.delegate.packExtension( + this.packDirectory_, this.keyFile_, 0, this.onPackResponse_.bind(this)); + }, + + /** + * @param {chrome.developerPrivate.PackDirectoryResponse} response the + * response from request to pack an extension. + * @private + */ + onPackResponse_: function(response) { + this.lastResponse_ = response; + }, + + /** + * In the case that the alert dialog was a success message, the entire + * pack-dialog should close. Otherwise, we detach the alert by setting + * lastResponse_ null. Additionally, if the user selected "proceed anyway" + * in the dialog, we pack the extension again with override flags. + * @param {!Event} e + * @private + */ + onAlertClose_: function(e) { + e.stopPropagation(); + + if (this.lastResponse_.status == + chrome.developerPrivate.PackStatus.SUCCESS) { + this.$.dialog.close(); + return; + } + + // This is only possible for a warning dialog. + if (this.$$('extensions-pack-dialog-alert').returnValue == 'success') { this.delegate.packExtension( - this.packDirectory_, this.keyFile_, 0, - this.onPackResponse_.bind(this)); - }, + this.lastResponse_.item_path, this.lastResponse_.pem_path, + this.lastResponse_.override_flags, this.onPackResponse_.bind(this)); + } - /** - * @param {chrome.developerPrivate.PackDirectoryResponse} response the - * response from request to pack an extension. - * @private - */ - onPackResponse_: function(response) { - this.lastResponse_ = response; - }, - - /** - * In the case that the alert dialog was a success message, the entire - * pack-dialog should close. Otherwise, we detach the alert by setting - * lastResponse_ null. Additionally, if the user selected "proceed anyway" - * in the dialog, we pack the extension again with override flags. - * @param {!Event} e - * @private - */ - onAlertClose_: function(e) { - e.stopPropagation(); - - if (this.lastResponse_.status == - chrome.developerPrivate.PackStatus.SUCCESS) { - this.$.dialog.close(); - return; - } - - // This is only possible for a warning dialog. - if (this.$$('extensions-pack-dialog-alert').returnValue == 'success') { - this.delegate.packExtension( - this.lastResponse_.item_path, this.lastResponse_.pem_path, - this.lastResponse_.override_flags, this.onPackResponse_.bind(this)); - } - - this.lastResponse_ = null; - }, - }); + this.lastResponse_ = null; + }, +});
diff --git a/chrome/browser/resources/extensions/pack_dialog_alert.js b/chrome/browser/resources/extensions/pack_dialog_alert.js index 913dafb..a39869e 100644 --- a/chrome/browser/resources/extensions/pack_dialog_alert.js +++ b/chrome/browser/resources/extensions/pack_dialog_alert.js
@@ -9,90 +9,89 @@ import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js'; import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; - Polymer({ - is: 'extensions-pack-dialog-alert', +Polymer({ + is: 'extensions-pack-dialog-alert', - _template: html`{__html_template__}`, + _template: html`{__html_template__}`, - properties: { - /** @private {chrome.developerPrivate.PackDirectoryResponse} */ - model: Object, + properties: { + /** @private {chrome.developerPrivate.PackDirectoryResponse} */ + model: Object, - /** @private */ - title_: String, + /** @private */ + title_: String, - /** @private */ - message_: String, + /** @private */ + message_: String, - /** @private {?string} */ - cancelLabel_: String, - - /** - * This needs to be initialized to trigger data-binding. - * @private {?string} - */ - confirmLabel_: { - type: String, - value: '', - } - }, - - /** @return {string} */ - get returnValue() { - return /** @type {!CrDialogElement} */ (this.$.dialog) - .getNative() - .returnValue; - }, - - /** @override */ - ready: function() { - // Initialize button label values for initial html binding. - this.cancelLabel_ = null; - this.confirmLabel_ = null; - - switch (this.model.status) { - case chrome.developerPrivate.PackStatus.WARNING: - this.title_ = loadTimeData.getString('packDialogWarningTitle'); - this.cancelLabel_ = loadTimeData.getString('cancel'); - this.confirmLabel_ = - loadTimeData.getString('packDialogProceedAnyway'); - break; - case chrome.developerPrivate.PackStatus.ERROR: - this.title_ = loadTimeData.getString('packDialogErrorTitle'); - this.cancelLabel_ = loadTimeData.getString('ok'); - break; - case chrome.developerPrivate.PackStatus.SUCCESS: - this.title_ = loadTimeData.getString('packDialogTitle'); - this.cancelLabel_ = loadTimeData.getString('ok'); - break; - default: - assertNotReached(); - return; - } - }, - - /** @override */ - attached: function() { - this.$.dialog.showModal(); - }, + /** @private {?string} */ + cancelLabel_: String, /** - * @return {string} - * @private + * This needs to be initialized to trigger data-binding. + * @private {?string} */ - getCancelButtonClass_: function() { - return this.confirmLabel_ ? 'cancel-button' : 'action-button'; - }, - - /** @private */ - onCancelTap_: function() { - this.$.dialog.cancel(); - }, - - /** @private */ - onConfirmTap_: function() { - // The confirm button should only be available in WARNING state. - assert(this.model.status === chrome.developerPrivate.PackStatus.WARNING); - this.$.dialog.close(); + confirmLabel_: { + type: String, + value: '', } - }); + }, + + /** @return {string} */ + get returnValue() { + return /** @type {!CrDialogElement} */ (this.$.dialog) + .getNative() + .returnValue; + }, + + /** @override */ + ready: function() { + // Initialize button label values for initial html binding. + this.cancelLabel_ = null; + this.confirmLabel_ = null; + + switch (this.model.status) { + case chrome.developerPrivate.PackStatus.WARNING: + this.title_ = loadTimeData.getString('packDialogWarningTitle'); + this.cancelLabel_ = loadTimeData.getString('cancel'); + this.confirmLabel_ = loadTimeData.getString('packDialogProceedAnyway'); + break; + case chrome.developerPrivate.PackStatus.ERROR: + this.title_ = loadTimeData.getString('packDialogErrorTitle'); + this.cancelLabel_ = loadTimeData.getString('ok'); + break; + case chrome.developerPrivate.PackStatus.SUCCESS: + this.title_ = loadTimeData.getString('packDialogTitle'); + this.cancelLabel_ = loadTimeData.getString('ok'); + break; + default: + assertNotReached(); + return; + } + }, + + /** @override */ + attached: function() { + this.$.dialog.showModal(); + }, + + /** + * @return {string} + * @private + */ + getCancelButtonClass_: function() { + return this.confirmLabel_ ? 'cancel-button' : 'action-button'; + }, + + /** @private */ + onCancelTap_: function() { + this.$.dialog.cancel(); + }, + + /** @private */ + onConfirmTap_: function() { + // The confirm button should only be available in WARNING state. + assert(this.model.status === chrome.developerPrivate.PackStatus.WARNING); + this.$.dialog.close(); + } +});
diff --git a/chrome/browser/resources/extensions/runtime_host_permissions.js b/chrome/browser/resources/extensions/runtime_host_permissions.js index 33624e4..1814e42 100644 --- a/chrome/browser/resources/extensions/runtime_host_permissions.js +++ b/chrome/browser/resources/extensions/runtime_host_permissions.js
@@ -23,245 +23,244 @@ import {ItemDelegate} from './item.js'; - Polymer({ - is: 'extensions-runtime-host-permissions', +Polymer({ + is: 'extensions-runtime-host-permissions', - _template: html`{__html_template__}`, + _template: html`{__html_template__}`, - properties: { - /** - * The underlying permissions data. - * @type {chrome.developerPrivate.RuntimeHostPermissions} - */ - permissions: Object, - - /** @private */ - itemId: String, - - /** @type {!ItemDelegate} */ - delegate: Object, - - /** - * Whether the dialog to add a new host permission is shown. - * @private - */ - showHostDialog_: Boolean, - - /** - * The current site of the entry that the host dialog is editing, if the - * dialog is open for editing. - * @type {?string} - * @private - */ - hostDialogModel_: { - type: String, - value: null, - }, - - /** - * The element to return focus to once the host dialog closes. - * @type {?HTMLElement} - * @private - */ - hostDialogAnchorElement_: { - type: Object, - value: null, - }, - - /** - * If the action menu is open, the site of the entry it is open for. - * Otherwise null. - * @type {?string} - * @private - */ - actionMenuModel_: { - type: String, - value: null, - }, - - /** - * The element that triggered the action menu, so that the page will - * return focus once the action menu (or dialog) closes. - * @type {?HTMLElement} - * @private - */ - actionMenuAnchorElement_: { - type: Object, - value: null, - }, - - /** - * The old host access setting; used when we don't immediately commit the - * change to host access so that we can reset it if the user cancels. - * @type {?string} - * @private - */ - oldHostAccess_: { - type: String, - value: null, - }, - - /** - * Proxying the enum to be used easily by the html template. - * @private - */ - HostAccess_: { - type: Object, - value: chrome.developerPrivate.HostAccess, - }, - }, - + properties: { /** - * @param {!Event} event - * @private + * The underlying permissions data. + * @type {chrome.developerPrivate.RuntimeHostPermissions} */ - onHostAccessChange_: function(event) { - const group = /** @type {!HTMLElement} */ (this.$['host-access']); - const access = group.selected; - - if (access == chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES && - this.permissions.hostAccess != - chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES) { - // If the user is transitioning to the "on specific sites" option, show - // the "add host" dialog. This serves two purposes: - // - The user is prompted to add a host immediately, since otherwise - // "on specific sites" is meaningless, and - // - The way the C++ code differentiates between "on click" and "on - // specific sites" is by checking if there are any specific sites. - // This ensures there will be at least one, so that the host access - // is properly calculated. - this.oldHostAccess_ = this.permissions.hostAccess; - this.doShowHostDialog_(group, null); - } else { - this.delegate.setItemHostAccess(this.itemId, access); - } - }, - - /** - * @return {boolean} - * @private - */ - showSpecificSites_: function() { - return this.permissions.hostAccess == - chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES; - }, - - /** - * Returns the granted host permissions as a sorted set of strings. - * @return {!Array<string>} - * @private - */ - getRuntimeHosts_: function() { - if (!this.permissions.hosts) { - return []; - } - - // Only show granted hosts in the list. - // TODO(devlin): For extensions that request a finite set of hosts, - // display them in a toggle list. https://crbug.com/891803. - return this.permissions.hosts.filter(control => control.granted) - .map(control => control.host) - .sort(); - }, - - /** - * @param {Event} e - * @private - */ - onAddHostClick_: function(e) { - const target = /** @type {!HTMLElement} */ (e.target); - this.doShowHostDialog_(target, null); - }, - - /** - * @param {!HTMLElement} anchorElement The element to return focus to once - * the dialog closes. - * @param {?string} currentSite The site entry currently being - * edited, or null if this is to add a new entry. - * @private - */ - doShowHostDialog_: function(anchorElement, currentSite) { - this.hostDialogAnchorElement_ = anchorElement; - this.hostDialogModel_ = currentSite; - this.showHostDialog_ = true; - }, + permissions: Object, /** @private */ - onHostDialogClose_: function() { - this.hostDialogModel_ = null; - this.showHostDialog_ = false; - focusWithoutInk(assert(this.hostDialogAnchorElement_, 'Host Anchor')); - this.hostDialogAnchorElement_ = null; + itemId: String, + + /** @type {!ItemDelegate} */ + delegate: Object, + + /** + * Whether the dialog to add a new host permission is shown. + * @private + */ + showHostDialog_: Boolean, + + /** + * The current site of the entry that the host dialog is editing, if the + * dialog is open for editing. + * @type {?string} + * @private + */ + hostDialogModel_: { + type: String, + value: null, + }, + + /** + * The element to return focus to once the host dialog closes. + * @type {?HTMLElement} + * @private + */ + hostDialogAnchorElement_: { + type: Object, + value: null, + }, + + /** + * If the action menu is open, the site of the entry it is open for. + * Otherwise null. + * @type {?string} + * @private + */ + actionMenuModel_: { + type: String, + value: null, + }, + + /** + * The element that triggered the action menu, so that the page will + * return focus once the action menu (or dialog) closes. + * @type {?HTMLElement} + * @private + */ + actionMenuAnchorElement_: { + type: Object, + value: null, + }, + + /** + * The old host access setting; used when we don't immediately commit the + * change to host access so that we can reset it if the user cancels. + * @type {?string} + * @private + */ + oldHostAccess_: { + type: String, + value: null, + }, + + /** + * Proxying the enum to be used easily by the html template. + * @private + */ + HostAccess_: { + type: Object, + value: chrome.developerPrivate.HostAccess, + }, + }, + + /** + * @param {!Event} event + * @private + */ + onHostAccessChange_: function(event) { + const group = /** @type {!HTMLElement} */ (this.$['host-access']); + const access = group.selected; + + if (access == chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES && + this.permissions.hostAccess != + chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES) { + // If the user is transitioning to the "on specific sites" option, show + // the "add host" dialog. This serves two purposes: + // - The user is prompted to add a host immediately, since otherwise + // "on specific sites" is meaningless, and + // - The way the C++ code differentiates between "on click" and "on + // specific sites" is by checking if there are any specific sites. + // This ensures there will be at least one, so that the host access + // is properly calculated. + this.oldHostAccess_ = this.permissions.hostAccess; + this.doShowHostDialog_(group, null); + } else { + this.delegate.setItemHostAccess(this.itemId, access); + } + }, + + /** + * @return {boolean} + * @private + */ + showSpecificSites_: function() { + return this.permissions.hostAccess == + chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES; + }, + + /** + * Returns the granted host permissions as a sorted set of strings. + * @return {!Array<string>} + * @private + */ + getRuntimeHosts_: function() { + if (!this.permissions.hosts) { + return []; + } + + // Only show granted hosts in the list. + // TODO(devlin): For extensions that request a finite set of hosts, + // display them in a toggle list. https://crbug.com/891803. + return this.permissions.hosts.filter(control => control.granted) + .map(control => control.host) + .sort(); + }, + + /** + * @param {Event} e + * @private + */ + onAddHostClick_: function(e) { + const target = /** @type {!HTMLElement} */ (e.target); + this.doShowHostDialog_(target, null); + }, + + /** + * @param {!HTMLElement} anchorElement The element to return focus to once + * the dialog closes. + * @param {?string} currentSite The site entry currently being + * edited, or null if this is to add a new entry. + * @private + */ + doShowHostDialog_: function(anchorElement, currentSite) { + this.hostDialogAnchorElement_ = anchorElement; + this.hostDialogModel_ = currentSite; + this.showHostDialog_ = true; + }, + + /** @private */ + onHostDialogClose_: function() { + this.hostDialogModel_ = null; + this.showHostDialog_ = false; + focusWithoutInk(assert(this.hostDialogAnchorElement_, 'Host Anchor')); + this.hostDialogAnchorElement_ = null; + this.oldHostAccess_ = null; + }, + + /** @private */ + onHostDialogCancel_: function() { + // The user canceled the dialog. Set host-access back to the old value, + // if the dialog was shown when just transitioning to a new state. + if (this.oldHostAccess_) { + assert(this.permissions.hostAccess == this.oldHostAccess_); + this.$['host-access'].selected = this.oldHostAccess_; this.oldHostAccess_ = null; - }, + } + }, - /** @private */ - onHostDialogCancel_: function() { - // The user canceled the dialog. Set host-access back to the old value, - // if the dialog was shown when just transitioning to a new state. - if (this.oldHostAccess_) { - assert(this.permissions.hostAccess == this.oldHostAccess_); - this.$['host-access'].selected = this.oldHostAccess_; - this.oldHostAccess_ = null; - } - }, + /** + * @return {boolean} + * @private + */ + dialogShouldUpdateHostAccess_: function() { + return !!this.oldHostAccess_; + }, - /** - * @return {boolean} - * @private - */ - dialogShouldUpdateHostAccess_: function() { - return !!this.oldHostAccess_; - }, + /** + * @param {!{ + * model: !{item: string}, + * target: !HTMLElement, + * }} e + * @private + */ + onEditHostClick_: function(e) { + this.actionMenuModel_ = e.model.item; + this.actionMenuAnchorElement_ = e.target; + const actionMenu = + /** @type {CrActionMenuElement} */ (this.$.hostActionMenu); + actionMenu.showAt(e.target); + }, - /** - * @param {!{ - * model: !{item: string}, - * target: !HTMLElement, - * }} e - * @private - */ - onEditHostClick_: function(e) { - this.actionMenuModel_ = e.model.item; - this.actionMenuAnchorElement_ = e.target; - const actionMenu = - /** @type {CrActionMenuElement} */ (this.$.hostActionMenu); - actionMenu.showAt(e.target); - }, + /** @private */ + onActionMenuEditClick_: function() { + // Cache the site before closing the action menu, since it's cleared. + const site = this.actionMenuModel_; - /** @private */ - onActionMenuEditClick_: function() { - // Cache the site before closing the action menu, since it's cleared. - const site = this.actionMenuModel_; + // Cache and reset actionMenuAnchorElement_ so focus is not returned + // to the action menu's trigger (since the dialog will be shown next). + // Instead, curry the element to the dialog, so once it closes, focus + // will be returned. + const anchorElement = assert(this.actionMenuAnchorElement_, 'Menu Anchor'); + this.actionMenuAnchorElement_ = null; + this.closeActionMenu_(); + this.doShowHostDialog_(anchorElement, site); + }, - // Cache and reset actionMenuAnchorElement_ so focus is not returned - // to the action menu's trigger (since the dialog will be shown next). - // Instead, curry the element to the dialog, so once it closes, focus - // will be returned. - const anchorElement = - assert(this.actionMenuAnchorElement_, 'Menu Anchor'); - this.actionMenuAnchorElement_ = null; - this.closeActionMenu_(); - this.doShowHostDialog_(anchorElement, site); - }, + /** @private */ + onActionMenuRemoveClick_: function() { + this.delegate.removeRuntimeHostPermission( + this.itemId, assert(this.actionMenuModel_, 'Action Menu Model')); + this.closeActionMenu_(); + }, - /** @private */ - onActionMenuRemoveClick_: function() { - this.delegate.removeRuntimeHostPermission( - this.itemId, assert(this.actionMenuModel_, 'Action Menu Model')); - this.closeActionMenu_(); - }, + /** @private */ + closeActionMenu_: function() { + const menu = this.$.hostActionMenu; + assert(menu.open); + menu.close(); + }, - /** @private */ - closeActionMenu_: function() { - const menu = this.$.hostActionMenu; - assert(menu.open); - menu.close(); - }, - - /** @private */ - onActionMenuClose_: function() { - this.actionMenuModel_ = null; - this.actionMenuAnchorElement_ = null; - }, - }); + /** @private */ + onActionMenuClose_: function() { + this.actionMenuModel_ = null; + this.actionMenuAnchorElement_ = null; + }, +});
diff --git a/chrome/browser/resources/extensions/runtime_hosts_dialog.js b/chrome/browser/resources/extensions/runtime_hosts_dialog.js index b37c1ae9..bbe15ac 100644 --- a/chrome/browser/resources/extensions/runtime_hosts_dialog.js +++ b/chrome/browser/resources/extensions/runtime_hosts_dialog.js
@@ -14,216 +14,216 @@ import {ItemDelegate} from './item.js'; - // A RegExp to roughly match acceptable patterns entered by the user. - // exec'ing() this RegExp will match the following groups: - // 0: Full matched string. - // 1: Scheme + scheme separator (e.g., 'https://'). - // 2: Scheme only (e.g., 'https'). - // 3: Match subdomains ('*.'). - // 4: Hostname (e.g., 'example.com'). - // 5: Port, including ':' separator (e.g., ':80'). - // 6: Path, include '/' separator (e.g., '/*'). - const patternRegExp = new RegExp( - '^' + - // Scheme; optional. - '((http|https|\\*)://)?' + - // Include subdomains specifier; optional. - '(\\*\\.)?' + - // Hostname, required. - '([a-z0-9\\.-]+\\.[a-z0-9]+)' + - // Port, optional. - '(:[0-9]+)?' + - // Path, optional but if present must be '/' or '/*'. - '(\\/\\*|\\/)?' + - '$'); +// A RegExp to roughly match acceptable patterns entered by the user. +// exec'ing() this RegExp will match the following groups: +// 0: Full matched string. +// 1: Scheme + scheme separator (e.g., 'https://'). +// 2: Scheme only (e.g., 'https'). +// 3: Match subdomains ('*.'). +// 4: Hostname (e.g., 'example.com'). +// 5: Port, including ':' separator (e.g., ':80'). +// 6: Path, include '/' separator (e.g., '/*'). +const patternRegExp = new RegExp( + '^' + + // Scheme; optional. + '((http|https|\\*)://)?' + + // Include subdomains specifier; optional. + '(\\*\\.)?' + + // Hostname, required. + '([a-z0-9\\.-]+\\.[a-z0-9]+)' + + // Port, optional. + '(:[0-9]+)?' + + // Path, optional but if present must be '/' or '/*'. + '(\\/\\*|\\/)?' + + '$'); - export function getPatternFromSite(site) { - const res = patternRegExp.exec(site); - assert(res); - const scheme = res[1] || '*://'; - const host = (res[3] || '') + res[4]; - const port = res[5] || ''; - const path = '/*'; - return scheme + host + port + path; - } +export function getPatternFromSite(site) { + const res = patternRegExp.exec(site); + assert(res); + const scheme = res[1] || '*://'; + const host = (res[3] || '') + res[4]; + const port = res[5] || ''; + const path = '/*'; + return scheme + host + port + path; +} - Polymer({ - is: 'extensions-runtime-hosts-dialog', +Polymer({ + is: 'extensions-runtime-hosts-dialog', - _template: html`{__html_template__}`, + _template: html`{__html_template__}`, - properties: { - /** @type {!ItemDelegate} */ - delegate: Object, + properties: { + /** @type {!ItemDelegate} */ + delegate: Object, - /** @type {string} */ - itemId: String, + /** @type {string} */ + itemId: String, - /** - * The site that this entry is currently managing. Only non-empty if this - * is for editing an existing entry. - * @type {?string} - */ - currentSite: { - type: String, - value: null, - }, - - /** - * Whether the dialog should update the host access to be "on specific - * sites" before adding a new host permission. - */ - updateHostAccess: { - type: Boolean, - value: false, - }, - - /** - * The site to add an exception for. - * @private - */ - site_: String, - - /** - * Whether the currently-entered input is valid. - * @private - */ - inputInvalid_: { - type: Boolean, - value: false, - }, - }, - - /** @override */ - attached: function() { - if (this.currentSite !== null && this.currentSite !== undefined) { - this.site_ = this.currentSite; - this.validate_(); - } - this.$.dialog.showModal(); - }, - - /** @return {boolean} */ - isOpen: function() { - return this.$.dialog.open; + /** + * The site that this entry is currently managing. Only non-empty if this + * is for editing an existing entry. + * @type {?string} + */ + currentSite: { + type: String, + value: null, }, /** - * Validates that the pattern entered is valid. - * @private + * Whether the dialog should update the host access to be "on specific + * sites" before adding a new host permission. */ - validate_: function() { - // If input is empty, disable the action button, but don't show the red - // invalid message. - if (this.site_.trim().length == 0) { - this.inputInvalid_ = false; - return; - } - - const valid = patternRegExp.test(this.site_); - this.inputInvalid_ = !valid; + updateHostAccess: { + type: Boolean, + value: false, }, /** - * @return {string} + * The site to add an exception for. * @private */ - computeDialogTitle_: function() { - const stringId = this.currentSite === null ? 'runtimeHostsDialogTitle' : - 'hostPermissionsEdit'; - return loadTimeData.getString(stringId); - }, + site_: String, /** - * @return {boolean} + * Whether the currently-entered input is valid. * @private */ - computeSubmitButtonDisabled_: function() { - return this.inputInvalid_ || this.site_ === undefined || - this.site_.trim().length == 0; + inputInvalid_: { + type: Boolean, + value: false, }, + }, - /** - * @return {string} - * @private - */ - computeSubmitButtonLabel_: function() { - const stringId = this.currentSite === null ? 'add' : 'save'; - return loadTimeData.getString(stringId); - }, + /** @override */ + attached: function() { + if (this.currentSite !== null && this.currentSite !== undefined) { + this.site_ = this.currentSite; + this.validate_(); + } + this.$.dialog.showModal(); + }, - /** @private */ - onCancelTap_: function() { - this.$.dialog.cancel(); - }, + /** @return {boolean} */ + isOpen: function() { + return this.$.dialog.open; + }, - /** - * The tap handler for the submit button (adds the pattern and closes - * the dialog). - * @private - */ - onSubmitTap_: function() { - if (this.currentSite !== null) { - this.handleEdit_(); - } else { - this.handleAdd_(); - } - }, + /** + * Validates that the pattern entered is valid. + * @private + */ + validate_: function() { + // If input is empty, disable the action button, but don't show the red + // invalid message. + if (this.site_.trim().length == 0) { + this.inputInvalid_ = false; + return; + } - /** - * Handles adding a new site entry. - * @private - */ - handleAdd_: function() { - assert(!this.currentSite); + const valid = patternRegExp.test(this.site_); + this.inputInvalid_ = !valid; + }, - if (this.updateHostAccess) { - this.delegate.setItemHostAccess( - this.itemId, chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES); - } + /** + * @return {string} + * @private + */ + computeDialogTitle_: function() { + const stringId = this.currentSite === null ? 'runtimeHostsDialogTitle' : + 'hostPermissionsEdit'; + return loadTimeData.getString(stringId); + }, - this.addPermission_(); - }, + /** + * @return {boolean} + * @private + */ + computeSubmitButtonDisabled_: function() { + return this.inputInvalid_ || this.site_ === undefined || + this.site_.trim().length == 0; + }, - /** - * Handles editing an existing site entry. - * @private - */ - handleEdit_: function() { - assert(this.currentSite); - assert( - !this.updateHostAccess, - 'Editing host permissions should only be possible if the host ' + - 'access is already set to specific sites.'); + /** + * @return {string} + * @private + */ + computeSubmitButtonLabel_: function() { + const stringId = this.currentSite === null ? 'add' : 'save'; + return loadTimeData.getString(stringId); + }, - if (this.currentSite == this.site_) { - // No change in values, so no need to update anything. - this.$.dialog.close(); - return; - } + /** @private */ + onCancelTap_: function() { + this.$.dialog.cancel(); + }, - // Editing an existing entry is done by removing the current site entry, - // and then adding the new one. - this.delegate.removeRuntimeHostPermission(this.itemId, this.currentSite) - .then(() => { - this.addPermission_(); - }); - }, + /** + * The tap handler for the submit button (adds the pattern and closes + * the dialog). + * @private + */ + onSubmitTap_: function() { + if (this.currentSite !== null) { + this.handleEdit_(); + } else { + this.handleAdd_(); + } + }, - /** - * Adds the runtime host permission through the delegate. If successful, - * closes the dialog; otherwise displays the invalid input message. - * @private - */ - addPermission_: function() { - const pattern = getPatternFromSite(this.site_); - this.delegate.addRuntimeHostPermission(this.itemId, pattern) - .then( - () => { - this.$.dialog.close(); - }, - () => { - this.inputInvalid_ = true; - }); - }, - }); + /** + * Handles adding a new site entry. + * @private + */ + handleAdd_: function() { + assert(!this.currentSite); + + if (this.updateHostAccess) { + this.delegate.setItemHostAccess( + this.itemId, chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES); + } + + this.addPermission_(); + }, + + /** + * Handles editing an existing site entry. + * @private + */ + handleEdit_: function() { + assert(this.currentSite); + assert( + !this.updateHostAccess, + 'Editing host permissions should only be possible if the host ' + + 'access is already set to specific sites.'); + + if (this.currentSite == this.site_) { + // No change in values, so no need to update anything. + this.$.dialog.close(); + return; + } + + // Editing an existing entry is done by removing the current site entry, + // and then adding the new one. + this.delegate.removeRuntimeHostPermission(this.itemId, this.currentSite) + .then(() => { + this.addPermission_(); + }); + }, + + /** + * Adds the runtime host permission through the delegate. If successful, + * closes the dialog; otherwise displays the invalid input message. + * @private + */ + addPermission_: function() { + const pattern = getPatternFromSite(this.site_); + this.delegate.addRuntimeHostPermission(this.itemId, pattern) + .then( + () => { + this.$.dialog.close(); + }, + () => { + this.inputInvalid_ = true; + }); + }, +});
diff --git a/chrome/browser/resources/extensions/service.js b/chrome/browser/resources/extensions/service.js index 1c9967b..0e1e52c 100644 --- a/chrome/browser/resources/extensions/service.js +++ b/chrome/browser/resources/extensions/service.js
@@ -11,455 +11,453 @@ import {ItemDelegate} from './item.js'; import {KeyboardShortcutDelegate} from './keyboard_shortcut_delegate.js'; import {LoadErrorDelegate} from './load_error.js'; -import {Dialog,navigation,Page} from './navigation_helper.js'; +import {Dialog, navigation, Page} from './navigation_helper.js'; import {PackDialogDelegate} from './pack_dialog.js'; import {ToolbarDelegate} from './toolbar.js'; +/** + * @implements {ActivityLogDelegate} + * @implements {ActivityLogEventDelegate} + * @implements {ErrorPageDelegate} + * @implements {ItemDelegate} + * @implements {KeyboardShortcutDelegate} + * @implements {LoadErrorDelegate} + * @implements {PackDialogDelegate} + * @implements {ToolbarDelegate} + */ +export class Service { + constructor() { + /** @private {boolean} */ + this.isDeleting_ = false; + + /** @private {!Set<string>} */ + this.eventsToIgnoreOnce_ = new Set(); + } + + getProfileConfiguration() { + return new Promise(function(resolve, reject) { + chrome.developerPrivate.getProfileConfiguration(resolve); + }); + } + + getItemStateChangedTarget() { + return chrome.developerPrivate.onItemStateChanged; + } + /** - * @implements {ActivityLogDelegate} - * @implements {ActivityLogEventDelegate} - * @implements {ErrorPageDelegate} - * @implements {ItemDelegate} - * @implements {KeyboardShortcutDelegate} - * @implements {LoadErrorDelegate} - * @implements {PackDialogDelegate} - * @implements {ToolbarDelegate} + * @param {string} extensionId + * @param {!chrome.developerPrivate.EventType} eventType + * @return {boolean} */ - export class Service { - constructor() { - /** @private {boolean} */ + shouldIgnoreUpdate(extensionId, eventType) { + return this.eventsToIgnoreOnce_.delete(`${extensionId}_${eventType}`); + } + + /** + * @param {string} extensionId + * @param {!chrome.developerPrivate.EventType} eventType + */ + ignoreNextEvent(extensionId, eventType) { + this.eventsToIgnoreOnce_.add(`${extensionId}_${eventType}`); + } + + getProfileStateChangedTarget() { + return chrome.developerPrivate.onProfileStateChanged; + } + + getExtensionsInfo() { + return new Promise(function(resolve, reject) { + chrome.developerPrivate.getExtensionsInfo( + {includeDisabled: true, includeTerminated: true}, resolve); + }); + } + + /** @override */ + getExtensionSize(id) { + return new Promise(function(resolve, reject) { + chrome.developerPrivate.getExtensionSize(id, resolve); + }); + } + + /** @override */ + addRuntimeHostPermission(id, host) { + return new Promise((resolve, reject) => { + chrome.developerPrivate.addHostPermission(id, host, () => { + if (chrome.runtime.lastError) { + reject(chrome.runtime.lastError.message); + return; + } + resolve(); + }); + }); + } + + /** @override */ + removeRuntimeHostPermission(id, host) { + return new Promise((resolve, reject) => { + chrome.developerPrivate.removeHostPermission(id, host, () => { + if (chrome.runtime.lastError) { + reject(chrome.runtime.lastError.message); + return; + } + resolve(); + }); + }); + } + + /** + * Opens a file browser dialog for the user to select a file (or directory). + * @param {chrome.developerPrivate.SelectType} selectType + * @param {chrome.developerPrivate.FileType} fileType + * @return {Promise<string>} The promise to be resolved with the selected + * path. + */ + chooseFilePath_(selectType, fileType) { + return new Promise(function(resolve, reject) { + chrome.developerPrivate.choosePath(selectType, fileType, function(path) { + if (chrome.runtime.lastError && + chrome.runtime.lastError != 'File selection was canceled.') { + reject(chrome.runtime.lastError); + } else { + resolve(path || ''); + } + }); + }); + } + + /** @override */ + updateExtensionCommandKeybinding(extensionId, commandName, keybinding) { + chrome.developerPrivate.updateExtensionCommand({ + extensionId: extensionId, + commandName: commandName, + keybinding: keybinding, + }); + } + + /** @override */ + updateExtensionCommandScope(extensionId, commandName, scope) { + // The COMMAND_REMOVED event needs to be ignored since it is sent before + // the command is added back with the updated scope but can be handled + // after the COMMAND_ADDED event. + this.ignoreNextEvent( + extensionId, chrome.developerPrivate.EventType.COMMAND_REMOVED); + chrome.developerPrivate.updateExtensionCommand({ + extensionId: extensionId, + commandName: commandName, + scope: scope, + }); + } + + + /** @override */ + setShortcutHandlingSuspended(isCapturing) { + chrome.developerPrivate.setShortcutHandlingSuspended(isCapturing); + } + + /** + * @param {chrome.developerPrivate.LoadUnpackedOptions=} opt_options + * @return {!Promise} A signal that loading finished, rejected if any error + * occurred. + * @private + */ + loadUnpackedHelper_(opt_options) { + return new Promise(function(resolve, reject) { + const options = Object.assign( + { + failQuietly: true, + populateError: true, + }, + opt_options); + + chrome.developerPrivate.loadUnpacked(options, (loadError) => { + if (chrome.runtime.lastError && + chrome.runtime.lastError.message != + 'File selection was canceled.') { + throw new Error(chrome.runtime.lastError.message); + } + if (loadError) { + return reject(loadError); + } + + resolve(); + }); + }); + } + + /** @override */ + deleteItem(id) { + if (this.isDeleting_) { + return; + } + this.isDeleting_ = true; + chrome.management.uninstall(id, {showConfirmDialog: true}, () => { + // The "last error" was almost certainly the user canceling the dialog. + // Do nothing. We only check it so we don't get noisy logs. + /** @suppress {suspiciousCode} */ + chrome.runtime.lastError; this.isDeleting_ = false; + }); + } - /** @private {!Set<string>} */ - this.eventsToIgnoreOnce_ = new Set(); - } + /** @override */ + setItemEnabled(id, isEnabled) { + chrome.management.setEnabled(id, isEnabled); + } - getProfileConfiguration() { - return new Promise(function(resolve, reject) { - chrome.developerPrivate.getProfileConfiguration(resolve); + /** @override */ + setItemAllowedIncognito(id, isAllowedIncognito) { + chrome.developerPrivate.updateExtensionConfiguration({ + extensionId: id, + incognitoAccess: isAllowedIncognito, + }); + } + + /** @override */ + setItemAllowedOnFileUrls(id, isAllowedOnFileUrls) { + chrome.developerPrivate.updateExtensionConfiguration({ + extensionId: id, + fileAccess: isAllowedOnFileUrls, + }); + } + + /** @override */ + setItemHostAccess(id, hostAccess) { + chrome.developerPrivate.updateExtensionConfiguration({ + extensionId: id, + hostAccess: hostAccess, + }); + } + + /** @override */ + setItemCollectsErrors(id, collectsErrors) { + chrome.developerPrivate.updateExtensionConfiguration({ + extensionId: id, + errorCollection: collectsErrors, + }); + } + + /** @override */ + inspectItemView(id, view) { + chrome.developerPrivate.openDevTools({ + extensionId: id, + renderProcessId: view.renderProcessId, + renderViewId: view.renderViewId, + incognito: view.incognito, + }); + } + + /** + * @param {string} url + * @override + */ + openUrl(url) { + window.open(url); + } + + /** @override */ + reloadItem(id) { + return new Promise(function(resolve, reject) { + chrome.developerPrivate.reload( + id, {failQuietly: true, populateErrorForUnpacked: true}, + (loadError) => { + if (loadError) { + reject(loadError); + return; + } + + resolve(); + }); + }); + } + + /** @override */ + repairItem(id) { + chrome.developerPrivate.repairExtension(id); + } + + /** @override */ + showItemOptionsPage(extension) { + assert(extension && extension.optionsPage); + if (extension.optionsPage.openInTab) { + chrome.developerPrivate.showOptions(extension.id); + } else { + navigation.navigateTo({ + page: Page.DETAILS, + subpage: Dialog.OPTIONS, + extensionId: extension.id, }); } - - getItemStateChangedTarget() { - return chrome.developerPrivate.onItemStateChanged; - } - - /** - * @param {string} extensionId - * @param {!chrome.developerPrivate.EventType} eventType - * @return {boolean} - */ - shouldIgnoreUpdate(extensionId, eventType) { - return this.eventsToIgnoreOnce_.delete(`${extensionId}_${eventType}`); - } - - /** - * @param {string} extensionId - * @param {!chrome.developerPrivate.EventType} eventType - */ - ignoreNextEvent(extensionId, eventType) { - this.eventsToIgnoreOnce_.add(`${extensionId}_${eventType}`); - } - - getProfileStateChangedTarget() { - return chrome.developerPrivate.onProfileStateChanged; - } - - getExtensionsInfo() { - return new Promise(function(resolve, reject) { - chrome.developerPrivate.getExtensionsInfo( - {includeDisabled: true, includeTerminated: true}, resolve); - }); - } - - /** @override */ - getExtensionSize(id) { - return new Promise(function(resolve, reject) { - chrome.developerPrivate.getExtensionSize(id, resolve); - }); - } - - /** @override */ - addRuntimeHostPermission(id, host) { - return new Promise((resolve, reject) => { - chrome.developerPrivate.addHostPermission(id, host, () => { - if (chrome.runtime.lastError) { - reject(chrome.runtime.lastError.message); - return; - } - resolve(); - }); - }); - } - - /** @override */ - removeRuntimeHostPermission(id, host) { - return new Promise((resolve, reject) => { - chrome.developerPrivate.removeHostPermission(id, host, () => { - if (chrome.runtime.lastError) { - reject(chrome.runtime.lastError.message); - return; - } - resolve(); - }); - }); - } - - /** - * Opens a file browser dialog for the user to select a file (or directory). - * @param {chrome.developerPrivate.SelectType} selectType - * @param {chrome.developerPrivate.FileType} fileType - * @return {Promise<string>} The promise to be resolved with the selected - * path. - */ - chooseFilePath_(selectType, fileType) { - return new Promise(function(resolve, reject) { - chrome.developerPrivate.choosePath( - selectType, fileType, function(path) { - if (chrome.runtime.lastError && - chrome.runtime.lastError != 'File selection was canceled.') { - reject(chrome.runtime.lastError); - } else { - resolve(path || ''); - } - }); - }); - } - - /** @override */ - updateExtensionCommandKeybinding(extensionId, commandName, keybinding) { - chrome.developerPrivate.updateExtensionCommand({ - extensionId: extensionId, - commandName: commandName, - keybinding: keybinding, - }); - } - - /** @override */ - updateExtensionCommandScope(extensionId, commandName, scope) { - // The COMMAND_REMOVED event needs to be ignored since it is sent before - // the command is added back with the updated scope but can be handled - // after the COMMAND_ADDED event. - this.ignoreNextEvent( - extensionId, chrome.developerPrivate.EventType.COMMAND_REMOVED); - chrome.developerPrivate.updateExtensionCommand({ - extensionId: extensionId, - commandName: commandName, - scope: scope, - }); - } - - - /** @override */ - setShortcutHandlingSuspended(isCapturing) { - chrome.developerPrivate.setShortcutHandlingSuspended(isCapturing); - } - - /** - * @param {chrome.developerPrivate.LoadUnpackedOptions=} opt_options - * @return {!Promise} A signal that loading finished, rejected if any error - * occurred. - * @private - */ - loadUnpackedHelper_(opt_options) { - return new Promise(function(resolve, reject) { - const options = Object.assign( - { - failQuietly: true, - populateError: true, - }, - opt_options); - - chrome.developerPrivate.loadUnpacked( - options, (loadError) => { - if (chrome.runtime.lastError && - chrome.runtime.lastError.message != - 'File selection was canceled.') { - throw new Error(chrome.runtime.lastError.message); - } - if (loadError) { - return reject(loadError); - } - - resolve(); - }); - }); - } - - /** @override */ - deleteItem(id) { - if (this.isDeleting_) { - return; - } - this.isDeleting_ = true; - chrome.management.uninstall(id, {showConfirmDialog: true}, () => { - // The "last error" was almost certainly the user canceling the dialog. - // Do nothing. We only check it so we don't get noisy logs. - /** @suppress {suspiciousCode} */ - chrome.runtime.lastError; - this.isDeleting_ = false; - }); - } - - /** @override */ - setItemEnabled(id, isEnabled) { - chrome.management.setEnabled(id, isEnabled); - } - - /** @override */ - setItemAllowedIncognito(id, isAllowedIncognito) { - chrome.developerPrivate.updateExtensionConfiguration({ - extensionId: id, - incognitoAccess: isAllowedIncognito, - }); - } - - /** @override */ - setItemAllowedOnFileUrls(id, isAllowedOnFileUrls) { - chrome.developerPrivate.updateExtensionConfiguration({ - extensionId: id, - fileAccess: isAllowedOnFileUrls, - }); - } - - /** @override */ - setItemHostAccess(id, hostAccess) { - chrome.developerPrivate.updateExtensionConfiguration({ - extensionId: id, - hostAccess: hostAccess, - }); - } - - /** @override */ - setItemCollectsErrors(id, collectsErrors) { - chrome.developerPrivate.updateExtensionConfiguration({ - extensionId: id, - errorCollection: collectsErrors, - }); - } - - /** @override */ - inspectItemView(id, view) { - chrome.developerPrivate.openDevTools({ - extensionId: id, - renderProcessId: view.renderProcessId, - renderViewId: view.renderViewId, - incognito: view.incognito, - }); - } - - /** - * @param {string} url - * @override - */ - openUrl(url) { - window.open(url); - } - - /** @override */ - reloadItem(id) { - return new Promise(function(resolve, reject) { - chrome.developerPrivate.reload( - id, {failQuietly: true, populateErrorForUnpacked: true}, - (loadError) => { - if (loadError) { - reject(loadError); - return; - } - - resolve(); - }); - }); - } - - /** @override */ - repairItem(id) { - chrome.developerPrivate.repairExtension(id); - } - - /** @override */ - showItemOptionsPage(extension) { - assert(extension && extension.optionsPage); - if (extension.optionsPage.openInTab) { - chrome.developerPrivate.showOptions(extension.id); - } else { - navigation.navigateTo({ - page: Page.DETAILS, - subpage: Dialog.OPTIONS, - extensionId: extension.id, - }); - } - } - - /** @override */ - setProfileInDevMode(inDevMode) { - chrome.developerPrivate.updateProfileConfiguration( - {inDeveloperMode: inDevMode}); - } - - /** @override */ - loadUnpacked() { - return this.loadUnpackedHelper_(); - } - - /** @override */ - retryLoadUnpacked(retryGuid) { - // Attempt to load an unpacked extension, optionally as another attempt at - // a previously-specified load. - return this.loadUnpackedHelper_({retryGuid: retryGuid}); - } - - /** @override */ - choosePackRootDirectory() { - return this.chooseFilePath_( - chrome.developerPrivate.SelectType.FOLDER, - chrome.developerPrivate.FileType.LOAD); - } - - /** @override */ - choosePrivateKeyPath() { - return this.chooseFilePath_( - chrome.developerPrivate.SelectType.FILE, - chrome.developerPrivate.FileType.PEM); - } - - /** @override */ - packExtension(rootPath, keyPath, flag, callback) { - chrome.developerPrivate.packDirectory(rootPath, keyPath, flag, callback); - } - - /** @override */ - updateAllExtensions() { - return new Promise((resolve) => { - chrome.developerPrivate.autoUpdate(resolve); - chrome.metricsPrivate.recordUserAction('Options_UpdateExtensions'); - }); - } - - /** @override */ - deleteErrors(extensionId, errorIds, type) { - chrome.developerPrivate.deleteExtensionErrors({ - extensionId: extensionId, - errorIds: errorIds, - type: type, - }); - } - - /** @override */ - requestFileSource(args) { - return new Promise(function(resolve, reject) { - chrome.developerPrivate.requestFileSource(args, resolve); - }); - } - - /** @override */ - showInFolder(id) { - chrome.developerPrivate.showPath(id); - } - - /** @override */ - getExtensionActivityLog(extensionId) { - return new Promise(function(resolve, reject) { - chrome.activityLogPrivate.getExtensionActivities( - { - activityType: chrome.activityLogPrivate.ExtensionActivityFilter.ANY, - extensionId: extensionId - }, - resolve); - }); - } - - /** @override */ - getFilteredExtensionActivityLog(extensionId, searchTerm) { - const anyType = chrome.activityLogPrivate.ExtensionActivityFilter.ANY; - - // Construct one filter for each API call we will make: one for substring - // search by api call, one for substring search by page URL, and one for - // substring search by argument URL. % acts as a wildcard. - const activityLogFilters = [ - { - activityType: anyType, - extensionId: extensionId, - apiCall: `%${searchTerm}%`, - }, - { - activityType: anyType, - extensionId: extensionId, - pageUrl: `%${searchTerm}%`, - }, - { - activityType: anyType, - extensionId: extensionId, - argUrl: `%${searchTerm}%` - } - ]; - - const promises = activityLogFilters.map( - filter => new Promise(function(resolve, reject) { - chrome.activityLogPrivate.getExtensionActivities(filter, resolve); - })); - - return Promise.all(promises).then(results => { - // We may have results that are present in one or more searches, so - // we merge them here. We also assume that every distinct activity - // id corresponds to exactly one activity. - const activitiesById = new Map(); - for (const result of results) { - for (const activity of result.activities) { - activitiesById.set(activity.activityId, activity); - } - } - - return {activities: Array.from(activitiesById.values())}; - }); - } - - /** @override */ - deleteActivitiesById(activityIds) { - return new Promise(function(resolve, reject) { - chrome.activityLogPrivate.deleteActivities(activityIds, resolve); - }); - } - - /** @override */ - deleteActivitiesFromExtension(extensionId) { - return new Promise(function(resolve, reject) { - chrome.activityLogPrivate.deleteActivitiesByExtension( - extensionId, resolve); - }); - } - - /** @override */ - getOnExtensionActivity() { - return chrome.activityLogPrivate.onExtensionActivity; - } - - /** @override */ - downloadActivities(rawActivityData, fileName) { - const blob = new Blob([rawActivityData], {type: 'application/json'}); - const url = URL.createObjectURL(blob); - const a = document.createElement('a'); - a.href = url; - a.download = fileName; - a.click(); - } - - /** - * Attempts to load an unpacked extension via a drag-n-drop gesture. - * @return {!Promise} - */ - loadUnpackedFromDrag() { - return this.loadUnpackedHelper_({useDraggedPath: true}); - } - - installDroppedFile() { - chrome.developerPrivate.installDroppedFile(); - } - - notifyDragInstallInProgress() { - chrome.developerPrivate.notifyDragInstallInProgress(); - } } - addSingletonGetter(Service); + /** @override */ + setProfileInDevMode(inDevMode) { + chrome.developerPrivate.updateProfileConfiguration( + {inDeveloperMode: inDevMode}); + } + + /** @override */ + loadUnpacked() { + return this.loadUnpackedHelper_(); + } + + /** @override */ + retryLoadUnpacked(retryGuid) { + // Attempt to load an unpacked extension, optionally as another attempt at + // a previously-specified load. + return this.loadUnpackedHelper_({retryGuid: retryGuid}); + } + + /** @override */ + choosePackRootDirectory() { + return this.chooseFilePath_( + chrome.developerPrivate.SelectType.FOLDER, + chrome.developerPrivate.FileType.LOAD); + } + + /** @override */ + choosePrivateKeyPath() { + return this.chooseFilePath_( + chrome.developerPrivate.SelectType.FILE, + chrome.developerPrivate.FileType.PEM); + } + + /** @override */ + packExtension(rootPath, keyPath, flag, callback) { + chrome.developerPrivate.packDirectory(rootPath, keyPath, flag, callback); + } + + /** @override */ + updateAllExtensions() { + return new Promise((resolve) => { + chrome.developerPrivate.autoUpdate(resolve); + chrome.metricsPrivate.recordUserAction('Options_UpdateExtensions'); + }); + } + + /** @override */ + deleteErrors(extensionId, errorIds, type) { + chrome.developerPrivate.deleteExtensionErrors({ + extensionId: extensionId, + errorIds: errorIds, + type: type, + }); + } + + /** @override */ + requestFileSource(args) { + return new Promise(function(resolve, reject) { + chrome.developerPrivate.requestFileSource(args, resolve); + }); + } + + /** @override */ + showInFolder(id) { + chrome.developerPrivate.showPath(id); + } + + /** @override */ + getExtensionActivityLog(extensionId) { + return new Promise(function(resolve, reject) { + chrome.activityLogPrivate.getExtensionActivities( + { + activityType: chrome.activityLogPrivate.ExtensionActivityFilter.ANY, + extensionId: extensionId + }, + resolve); + }); + } + + /** @override */ + getFilteredExtensionActivityLog(extensionId, searchTerm) { + const anyType = chrome.activityLogPrivate.ExtensionActivityFilter.ANY; + + // Construct one filter for each API call we will make: one for substring + // search by api call, one for substring search by page URL, and one for + // substring search by argument URL. % acts as a wildcard. + const activityLogFilters = [ + { + activityType: anyType, + extensionId: extensionId, + apiCall: `%${searchTerm}%`, + }, + { + activityType: anyType, + extensionId: extensionId, + pageUrl: `%${searchTerm}%`, + }, + { + activityType: anyType, + extensionId: extensionId, + argUrl: `%${searchTerm}%` + } + ]; + + const promises = activityLogFilters.map( + filter => new Promise(function(resolve, reject) { + chrome.activityLogPrivate.getExtensionActivities(filter, resolve); + })); + + return Promise.all(promises).then(results => { + // We may have results that are present in one or more searches, so + // we merge them here. We also assume that every distinct activity + // id corresponds to exactly one activity. + const activitiesById = new Map(); + for (const result of results) { + for (const activity of result.activities) { + activitiesById.set(activity.activityId, activity); + } + } + + return {activities: Array.from(activitiesById.values())}; + }); + } + + /** @override */ + deleteActivitiesById(activityIds) { + return new Promise(function(resolve, reject) { + chrome.activityLogPrivate.deleteActivities(activityIds, resolve); + }); + } + + /** @override */ + deleteActivitiesFromExtension(extensionId) { + return new Promise(function(resolve, reject) { + chrome.activityLogPrivate.deleteActivitiesByExtension( + extensionId, resolve); + }); + } + + /** @override */ + getOnExtensionActivity() { + return chrome.activityLogPrivate.onExtensionActivity; + } + + /** @override */ + downloadActivities(rawActivityData, fileName) { + const blob = new Blob([rawActivityData], {type: 'application/json'}); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = fileName; + a.click(); + } + + /** + * Attempts to load an unpacked extension via a drag-n-drop gesture. + * @return {!Promise} + */ + loadUnpackedFromDrag() { + return this.loadUnpackedHelper_({useDraggedPath: true}); + } + + installDroppedFile() { + chrome.developerPrivate.installDroppedFile(); + } + + notifyDragInstallInProgress() { + chrome.developerPrivate.notifyDragInstallInProgress(); + } +} + +addSingletonGetter(Service);
diff --git a/chrome/browser/resources/extensions/shortcut_input.js b/chrome/browser/resources/extensions/shortcut_input.js index 67a9261..eace4ad 100644 --- a/chrome/browser/resources/extensions/shortcut_input.js +++ b/chrome/browser/resources/extensions/shortcut_input.js
@@ -22,223 +22,223 @@ NEED_CHARACTER: 3, }; - // The UI to display and manage keyboard shortcuts set for extension commands. - Polymer({ - is: 'extensions-shortcut-input', +// The UI to display and manage keyboard shortcuts set for extension commands. +Polymer({ + is: 'extensions-shortcut-input', - _template: html`{__html_template__}`, + _template: html`{__html_template__}`, - properties: { - /** @type {!KeyboardShortcutDelegate} */ - delegate: Object, + properties: { + /** @type {!KeyboardShortcutDelegate} */ + delegate: Object, - item: { - type: String, - value: '', - }, - - commandName: { - type: String, - value: '', - }, - - shortcut: { - type: String, - value: '', - }, - - /** @private */ - capturing_: { - type: Boolean, - value: false, - }, - - /** @private {!ShortcutError} */ - error_: { - type: Number, - value: 0, - }, - - /** @private */ - pendingShortcut_: { - type: String, - value: '', - }, + item: { + type: String, + value: '', }, - /** @override */ - ready: function() { - const node = this.$.input; - node.addEventListener('mouseup', this.startCapture_.bind(this)); - node.addEventListener('blur', this.endCapture_.bind(this)); - node.addEventListener('focus', this.startCapture_.bind(this)); - node.addEventListener('keydown', this.onKeyDown_.bind(this)); - node.addEventListener('keyup', this.onKeyUp_.bind(this)); + commandName: { + type: String, + value: '', + }, + + shortcut: { + type: String, + value: '', }, /** @private */ - startCapture_: function() { - if (this.capturing_) { - return; - } - this.capturing_ = true; - this.delegate.setShortcutHandlingSuspended(true); + capturing_: { + type: Boolean, + value: false, + }, + + /** @private {!ShortcutError} */ + error_: { + type: Number, + value: 0, }, /** @private */ - endCapture_: function() { + pendingShortcut_: { + type: String, + value: '', + }, + }, + + /** @override */ + ready: function() { + const node = this.$.input; + node.addEventListener('mouseup', this.startCapture_.bind(this)); + node.addEventListener('blur', this.endCapture_.bind(this)); + node.addEventListener('focus', this.startCapture_.bind(this)); + node.addEventListener('keydown', this.onKeyDown_.bind(this)); + node.addEventListener('keyup', this.onKeyUp_.bind(this)); + }, + + /** @private */ + startCapture_: function() { + if (this.capturing_) { + return; + } + this.capturing_ = true; + this.delegate.setShortcutHandlingSuspended(true); + }, + + /** @private */ + endCapture_: function() { + if (!this.capturing_) { + return; + } + this.pendingShortcut_ = ''; + this.capturing_ = false; + const input = this.$.input; + input.blur(); + input.invalid = false; + this.delegate.setShortcutHandlingSuspended(false); + }, + + /** + * @param {!Event} e + * @private + */ + onKeyDown_: function(e) { + if (e.target == this.$.clear) { + return; + } + + if (e.keyCode == Key.Escape) { if (!this.capturing_) { + // If we're not currently capturing, allow escape to propagate. return; } - this.pendingShortcut_ = ''; - this.capturing_ = false; - const input = this.$.input; - input.blur(); - input.invalid = false; - this.delegate.setShortcutHandlingSuspended(false); - }, - - /** - * @param {!Event} e - * @private - */ - onKeyDown_: function(e) { - if (e.target == this.$.clear) { - return; - } - - if (e.keyCode == Key.Escape) { - if (!this.capturing_) { - // If we're not currently capturing, allow escape to propagate. - return; - } - // Otherwise, escape cancels capturing. - this.endCapture_(); - e.preventDefault(); - e.stopPropagation(); - return; - } - if (e.keyCode == Key.Tab) { - // Allow tab propagation for keyboard navigation. - return; - } - - if (!this.capturing_) { - this.startCapture_(); - } - - this.handleKey_(/** @type {!KeyboardEvent} */ (e)); - }, - - /** - * @param {!Event} e - * @private - */ - onKeyUp_: function(e) { - // Ignores pressing 'Space' or 'Enter' on the clear button. In 'Enter's - // case, the clear button disappears before key-up, so 'Enter's key-up - // target becomes the input field, not the clear button, and needs to - // be caught explicitly. - if (e.target == this.$.clear || e.key == 'Enter') { - return; - } - - if (e.keyCode == Key.Escape || e.keyCode == Key.Tab) { - return; - } - - this.handleKey_(/** @type {!KeyboardEvent} */ (e)); - }, - - /** - * @param {!ShortcutError} error - * @param {string} includeStartModifier - * @param {string} tooManyModifiers - * @param {string} needCharacter - * @return {string} UI string. - * @private - */ - getErrorString_: function( - error, includeStartModifier, tooManyModifiers, needCharacter) { - if (error == ShortcutError.TOO_MANY_MODIFIERS) { - return tooManyModifiers; - } - if (error == ShortcutError.NEED_CHARACTER) { - return needCharacter; - } - return includeStartModifier; - }, - - /** - * @param {!KeyboardEvent} e - * @private - */ - handleKey_: function(e) { - // While capturing, we prevent all events from bubbling, to prevent - // shortcuts lacking the right modifier (F3 for example) from activating - // and ending capture prematurely. + // Otherwise, escape cancels capturing. + this.endCapture_(); e.preventDefault(); e.stopPropagation(); + return; + } + if (e.keyCode == Key.Tab) { + // Allow tab propagation for keyboard navigation. + return; + } - // We don't allow both Ctrl and Alt in the same keybinding. - // TODO(devlin): This really should go in hasValidModifiers, - // but that requires updating the existing page as well. - if (e.ctrlKey && e.altKey) { - this.error_ = ShortcutError.TOO_MANY_MODIFIERS; - this.$.input.invalid = true; - return; - } - if (!hasValidModifiers(e)) { - this.pendingShortcut_ = ''; - this.error_ = ShortcutError.INCLUDE_START_MODIFIER; - this.$.input.invalid = true; - return; - } - this.pendingShortcut_ = keystrokeToString(e); - if (!isValidKeyCode(e.keyCode)) { - this.error_ = ShortcutError.NEED_CHARACTER; - this.$.input.invalid = true; - return; - } - this.$.input.invalid = false; + if (!this.capturing_) { + this.startCapture_(); + } - this.commitPending_(); - this.endCapture_(); - }, + this.handleKey_(/** @type {!KeyboardEvent} */ (e)); + }, - /** @private */ - commitPending_: function() { - this.shortcut = this.pendingShortcut_; - this.delegate.updateExtensionCommandKeybinding( - this.item, this.commandName, this.shortcut); - }, + /** + * @param {!Event} e + * @private + */ + onKeyUp_: function(e) { + // Ignores pressing 'Space' or 'Enter' on the clear button. In 'Enter's + // case, the clear button disappears before key-up, so 'Enter's key-up + // target becomes the input field, not the clear button, and needs to + // be caught explicitly. + if (e.target == this.$.clear || e.key == 'Enter') { + return; + } - /** - * @return {string} The text to be displayed in the shortcut field. - * @private - */ - computeText_: function() { - const shortcutString = - this.capturing_ ? this.pendingShortcut_ : this.shortcut; - return shortcutString.split('+').join(' + '); - }, + if (e.keyCode == Key.Escape || e.keyCode == Key.Tab) { + return; + } - /** - * @return {boolean} Whether the clear button is hidden. - * @private - */ - computeClearHidden_: function() { - // We don't want to show the clear button if the input is currently - // capturing a new shortcut or if there is no shortcut to clear. - return this.capturing_ || !this.shortcut; - }, + this.handleKey_(/** @type {!KeyboardEvent} */ (e)); + }, - /** @private */ - onClearTap_: function() { - assert(this.shortcut); + /** + * @param {!ShortcutError} error + * @param {string} includeStartModifier + * @param {string} tooManyModifiers + * @param {string} needCharacter + * @return {string} UI string. + * @private + */ + getErrorString_: function( + error, includeStartModifier, tooManyModifiers, needCharacter) { + if (error == ShortcutError.TOO_MANY_MODIFIERS) { + return tooManyModifiers; + } + if (error == ShortcutError.NEED_CHARACTER) { + return needCharacter; + } + return includeStartModifier; + }, + /** + * @param {!KeyboardEvent} e + * @private + */ + handleKey_: function(e) { + // While capturing, we prevent all events from bubbling, to prevent + // shortcuts lacking the right modifier (F3 for example) from activating + // and ending capture prematurely. + e.preventDefault(); + e.stopPropagation(); + + // We don't allow both Ctrl and Alt in the same keybinding. + // TODO(devlin): This really should go in hasValidModifiers, + // but that requires updating the existing page as well. + if (e.ctrlKey && e.altKey) { + this.error_ = ShortcutError.TOO_MANY_MODIFIERS; + this.$.input.invalid = true; + return; + } + if (!hasValidModifiers(e)) { this.pendingShortcut_ = ''; - this.commitPending_(); - this.endCapture_(); - }, - }); + this.error_ = ShortcutError.INCLUDE_START_MODIFIER; + this.$.input.invalid = true; + return; + } + this.pendingShortcut_ = keystrokeToString(e); + if (!isValidKeyCode(e.keyCode)) { + this.error_ = ShortcutError.NEED_CHARACTER; + this.$.input.invalid = true; + return; + } + this.$.input.invalid = false; + + this.commitPending_(); + this.endCapture_(); + }, + + /** @private */ + commitPending_: function() { + this.shortcut = this.pendingShortcut_; + this.delegate.updateExtensionCommandKeybinding( + this.item, this.commandName, this.shortcut); + }, + + /** + * @return {string} The text to be displayed in the shortcut field. + * @private + */ + computeText_: function() { + const shortcutString = + this.capturing_ ? this.pendingShortcut_ : this.shortcut; + return shortcutString.split('+').join(' + '); + }, + + /** + * @return {boolean} Whether the clear button is hidden. + * @private + */ + computeClearHidden_: function() { + // We don't want to show the clear button if the input is currently + // capturing a new shortcut or if there is no shortcut to clear. + return this.capturing_ || !this.shortcut; + }, + + /** @private */ + onClearTap_: function() { + assert(this.shortcut); + + this.pendingShortcut_ = ''; + this.commitPending_(); + this.endCapture_(); + }, +});
diff --git a/chrome/browser/resources/extensions/shortcut_util.js b/chrome/browser/resources/extensions/shortcut_util.js index ed09384f..0f61a402 100644 --- a/chrome/browser/resources/extensions/shortcut_util.js +++ b/chrome/browser/resources/extensions/shortcut_util.js
@@ -6,191 +6,194 @@ import {isChromeOS, isMac} from 'chrome://resources/js/cr.m.js'; - /** @enum {number} */ - export const Key = { - Comma: 188, - Del: 46, - Down: 40, - End: 35, - Escape: 27, - Home: 36, - Ins: 45, - Left: 37, - MediaNextTrack: 176, - MediaPlayPause: 179, - MediaPrevTrack: 177, - MediaStop: 178, - PageDown: 34, - PageUp: 33, - Period: 190, - Right: 39, - Space: 32, - Tab: 9, - Up: 38, - }; +/** @enum {number} */ +export const Key = { + Comma: 188, + Del: 46, + Down: 40, + End: 35, + Escape: 27, + Home: 36, + Ins: 45, + Left: 37, + MediaNextTrack: 176, + MediaPlayPause: 179, + MediaPrevTrack: 177, + MediaStop: 178, + PageDown: 34, + PageUp: 33, + Period: 190, + Right: 39, + Space: 32, + Tab: 9, + Up: 38, +}; - /** - * Enum for whether we require modifiers of a keycode. - * @enum {number} - */ - const ModifierPolicy = {NOT_ALLOWED: 0, REQUIRED: 1}; +/** + * Enum for whether we require modifiers of a keycode. + * @enum {number} + */ +const ModifierPolicy = { + NOT_ALLOWED: 0, + REQUIRED: 1 +}; - /** - * Gets the ModifierPolicy. Currently only "MediaNextTrack", "MediaPrevTrack", - * "MediaStop", "MediaPlayPause" are required to be used without any modifier. - * @param {number} keyCode - * @return {ModifierPolicy} - */ - function getModifierPolicy(keyCode) { - switch (keyCode) { - case Key.MediaNextTrack: - case Key.MediaPlayPause: - case Key.MediaPrevTrack: - case Key.MediaStop: - return ModifierPolicy.NOT_ALLOWED; - default: - return ModifierPolicy.REQUIRED; +/** + * Gets the ModifierPolicy. Currently only "MediaNextTrack", "MediaPrevTrack", + * "MediaStop", "MediaPlayPause" are required to be used without any modifier. + * @param {number} keyCode + * @return {ModifierPolicy} + */ +function getModifierPolicy(keyCode) { + switch (keyCode) { + case Key.MediaNextTrack: + case Key.MediaPlayPause: + case Key.MediaPrevTrack: + case Key.MediaStop: + return ModifierPolicy.NOT_ALLOWED; + default: + return ModifierPolicy.REQUIRED; + } +} + +/** + * Returns whether the keyboard event has a key modifier, which could affect + * how it's handled. + * @param {!KeyboardEvent} e + * @param {boolean} countShiftAsModifier Whether the 'Shift' key should be + * counted as modifier. + * @return {boolean} True if the event has any modifiers. + */ +function hasModifier(e, countShiftAsModifier) { + return e.ctrlKey || e.altKey || + // Meta key is only relevant on Mac and CrOS, where we treat Command + // and Search (respectively) as modifiers. + (isMac && e.metaKey) || (isChromeOS && e.metaKey) || + (countShiftAsModifier && e.shiftKey); +} + +/** + * Checks whether the passed in |keyCode| is a valid extension command key. + * @param {number} keyCode + * @return {boolean} Whether the key is valid. + */ +export function isValidKeyCode(keyCode) { + if (keyCode == Key.Escape) { + return false; + } + for (const k in Key) { + if (Key[k] == keyCode) { + return true; } } + return (keyCode >= 'A'.charCodeAt(0) && keyCode <= 'Z'.charCodeAt(0)) || + (keyCode >= '0'.charCodeAt(0) && keyCode <= '9'.charCodeAt(0)); +} - /** - * Returns whether the keyboard event has a key modifier, which could affect - * how it's handled. - * @param {!KeyboardEvent} e - * @param {boolean} countShiftAsModifier Whether the 'Shift' key should be - * counted as modifier. - * @return {boolean} True if the event has any modifiers. - */ - function hasModifier(e, countShiftAsModifier) { - return e.ctrlKey || e.altKey || - // Meta key is only relevant on Mac and CrOS, where we treat Command - // and Search (respectively) as modifiers. - (isMac && e.metaKey) || (isChromeOS && e.metaKey) || - (countShiftAsModifier && e.shiftKey); +/** + * Converts a keystroke event to string form, ignoring invalid extension + * commands. + * @param {!KeyboardEvent} e + * @return {string} The keystroke as a string. + */ +export function keystrokeToString(e) { + const output = []; + // TODO(devlin): Should this be i18n'd? + if (isMac && e.metaKey) { + output.push('Command'); + } + if (isChromeOS && e.metaKey) { + output.push('Search'); + } + if (e.ctrlKey) { + output.push('Ctrl'); + } + if (!e.ctrlKey && e.altKey) { + output.push('Alt'); + } + if (e.shiftKey) { + output.push('Shift'); } - /** - * Checks whether the passed in |keyCode| is a valid extension command key. - * @param {number} keyCode - * @return {boolean} Whether the key is valid. - */ - export function isValidKeyCode(keyCode) { - if (keyCode == Key.Escape) { - return false; - } - for (const k in Key) { - if (Key[k] == keyCode) { - return true; + const keyCode = e.keyCode; + if (isValidKeyCode(keyCode)) { + if ((keyCode >= 'A'.charCodeAt(0) && keyCode <= 'Z'.charCodeAt(0)) || + (keyCode >= '0'.charCodeAt(0) && keyCode <= '9'.charCodeAt(0))) { + output.push(String.fromCharCode(keyCode)); + } else { + switch (keyCode) { + case Key.Comma: + output.push('Comma'); + break; + case Key.Del: + output.push('Delete'); + break; + case Key.Down: + output.push('Down'); + break; + case Key.End: + output.push('End'); + break; + case Key.Home: + output.push('Home'); + break; + case Key.Ins: + output.push('Insert'); + break; + case Key.Left: + output.push('Left'); + break; + case Key.MediaNextTrack: + output.push('MediaNextTrack'); + break; + case Key.MediaPlayPause: + output.push('MediaPlayPause'); + break; + case Key.MediaPrevTrack: + output.push('MediaPrevTrack'); + break; + case Key.MediaStop: + output.push('MediaStop'); + break; + case Key.PageDown: + output.push('PageDown'); + break; + case Key.PageUp: + output.push('PageUp'); + break; + case Key.Period: + output.push('Period'); + break; + case Key.Right: + output.push('Right'); + break; + case Key.Space: + output.push('Space'); + break; + case Key.Tab: + output.push('Tab'); + break; + case Key.Up: + output.push('Up'); + break; } } - return (keyCode >= 'A'.charCodeAt(0) && keyCode <= 'Z'.charCodeAt(0)) || - (keyCode >= '0'.charCodeAt(0) && keyCode <= '9'.charCodeAt(0)); } - /** - * Converts a keystroke event to string form, ignoring invalid extension - * commands. - * @param {!KeyboardEvent} e - * @return {string} The keystroke as a string. - */ - export function keystrokeToString(e) { - const output = []; - // TODO(devlin): Should this be i18n'd? - if (isMac && e.metaKey) { - output.push('Command'); - } - if (isChromeOS && e.metaKey) { - output.push('Search'); - } - if (e.ctrlKey) { - output.push('Ctrl'); - } - if (!e.ctrlKey && e.altKey) { - output.push('Alt'); - } - if (e.shiftKey) { - output.push('Shift'); - } + return output.join('+'); +} - const keyCode = e.keyCode; - if (isValidKeyCode(keyCode)) { - if ((keyCode >= 'A'.charCodeAt(0) && keyCode <= 'Z'.charCodeAt(0)) || - (keyCode >= '0'.charCodeAt(0) && keyCode <= '9'.charCodeAt(0))) { - output.push(String.fromCharCode(keyCode)); - } else { - switch (keyCode) { - case Key.Comma: - output.push('Comma'); - break; - case Key.Del: - output.push('Delete'); - break; - case Key.Down: - output.push('Down'); - break; - case Key.End: - output.push('End'); - break; - case Key.Home: - output.push('Home'); - break; - case Key.Ins: - output.push('Insert'); - break; - case Key.Left: - output.push('Left'); - break; - case Key.MediaNextTrack: - output.push('MediaNextTrack'); - break; - case Key.MediaPlayPause: - output.push('MediaPlayPause'); - break; - case Key.MediaPrevTrack: - output.push('MediaPrevTrack'); - break; - case Key.MediaStop: - output.push('MediaStop'); - break; - case Key.PageDown: - output.push('PageDown'); - break; - case Key.PageUp: - output.push('PageUp'); - break; - case Key.Period: - output.push('Period'); - break; - case Key.Right: - output.push('Right'); - break; - case Key.Space: - output.push('Space'); - break; - case Key.Tab: - output.push('Tab'); - break; - case Key.Up: - output.push('Up'); - break; - } - } - } - - return output.join('+'); +/** + * Returns true if the event has valid modifiers. + * @param {!KeyboardEvent} e The keyboard event to consider. + * @return {boolean} True if the event is valid. + */ +export function hasValidModifiers(e) { + switch (getModifierPolicy(e.keyCode)) { + case ModifierPolicy.REQUIRED: + return hasModifier(e, false); + case ModifierPolicy.NOT_ALLOWED: + return !hasModifier(e, true); } - - /** - * Returns true if the event has valid modifiers. - * @param {!KeyboardEvent} e The keyboard event to consider. - * @return {boolean} True if the event is valid. - */ - export function hasValidModifiers(e) { - switch (getModifierPolicy(e.keyCode)) { - case ModifierPolicy.REQUIRED: - return hasModifier(e, false); - case ModifierPolicy.NOT_ALLOWED: - return !hasModifier(e, true); - } - assertNotReached(); - } + assertNotReached(); +}
diff --git a/chrome/browser/resources/extensions/sidebar.js b/chrome/browser/resources/extensions/sidebar.js index 4fc5a75e..5252323 100644 --- a/chrome/browser/resources/extensions/sidebar.js +++ b/chrome/browser/resources/extensions/sidebar.js
@@ -11,38 +11,38 @@ import {navigation, Page} from './navigation_helper.js'; - Polymer({ - is: 'extensions-sidebar', +Polymer({ + is: 'extensions-sidebar', - _template: html`{__html_template__}`, + _template: html`{__html_template__}`, - properties: { - isSupervised: Boolean, - }, + properties: { + isSupervised: Boolean, + }, - hostAttributes: { - role: 'navigation', - }, + hostAttributes: { + role: 'navigation', + }, - /** @override */ - attached: function() { - this.$.sectionMenu.select( - navigation.getCurrentPage().page == Page.SHORTCUTS ? 1 : 0); - }, + /** @override */ + attached: function() { + this.$.sectionMenu.select( + navigation.getCurrentPage().page == Page.SHORTCUTS ? 1 : 0); + }, - /** - * @param {!Event} e - * @private - */ - onLinkTap_: function(e) { - e.preventDefault(); - navigation.navigateTo({page: e.target.dataset.path}); - this.fire('close-drawer'); - }, + /** + * @param {!Event} e + * @private + */ + onLinkTap_: function(e) { + e.preventDefault(); + navigation.navigateTo({page: e.target.dataset.path}); + this.fire('close-drawer'); + }, - /** @private */ - onMoreExtensionsTap_: function() { - assert(!this.isSupervised); - chrome.metricsPrivate.recordUserAction('Options_GetMoreExtensions'); - }, - }); + /** @private */ + onMoreExtensionsTap_: function() { + assert(!this.isSupervised); + chrome.metricsPrivate.recordUserAction('Options_GetMoreExtensions'); + }, +});
diff --git a/chrome/browser/resources/extensions/toggle_row.js b/chrome/browser/resources/extensions/toggle_row.js index 9a49b1b..43be17b5 100644 --- a/chrome/browser/resources/extensions/toggle_row.js +++ b/chrome/browser/resources/extensions/toggle_row.js
@@ -8,69 +8,69 @@ import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +/** + * An extensions-toggle-row provides a way of having a clickable row that can + * modify a cr-toggle, by leveraging the native <label> functionality. It uses + * a hidden native <input type="checkbox"> to achieve this. + */ +Polymer({ + is: 'extensions-toggle-row', + + _template: html`{__html_template__}`, + + properties: { + checked: Boolean, + + disabled: Boolean, + }, + /** - * An extensions-toggle-row provides a way of having a clickable row that can - * modify a cr-toggle, by leveraging the native <label> functionality. It uses - * a hidden native <input type="checkbox"> to achieve this. + * Exposing the clickable part of extensions-toggle-row for testing + * purposes. + * @return {!HTMLElement} */ - Polymer({ - is: 'extensions-toggle-row', + getLabel() { + return /** @type {!HTMLElement} */ (this.$.label); + }, - _template: html`{__html_template__}`, + /** + * @param {!Event} e + * @private + */ + onNativeClick_: function(e) { + // Even though the native checkbox is hidden and can't be actually + // cilcked/tapped by the user, because it resides within the <label> the + // browser emits an extraneous event when the label is clicked. Stop + // propagation so that it does not interfere with |onLabelTap_| listener. + e.stopPropagation(); + }, - properties: { - checked: Boolean, + /** + * Fires when the native checkbox changes value. This happens when the user + * clicks directly on the <label>. + * @param {!Event} e + * @private + */ + onNativeChange_: function(e) { + e.stopPropagation(); - disabled: Boolean, - }, + // Sync value of native checkbox and cr-toggle and |checked|. + this.$.crToggle.checked = this.$.native.checked; + this.checked = this.$.native.checked; - /** - * Exposing the clickable part of extensions-toggle-row for testing - * purposes. - * @return {!HTMLElement} - */ - getLabel() { - return /** @type {!HTMLElement} */ (this.$.label); - }, + this.fire('change', this.checked); + }, - /** - * @param {!Event} e - * @private - */ - onNativeClick_: function(e) { - // Even though the native checkbox is hidden and can't be actually - // cilcked/tapped by the user, because it resides within the <label> the - // browser emits an extraneous event when the label is clicked. Stop - // propagation so that it does not interfere with |onLabelTap_| listener. - e.stopPropagation(); - }, + /** + * @param {!CustomEvent<boolean>} e + * @private + */ + onCrToggleChange_: function(e) { + e.stopPropagation(); - /** - * Fires when the native checkbox changes value. This happens when the user - * clicks directly on the <label>. - * @param {!Event} e - * @private - */ - onNativeChange_: function(e) { - e.stopPropagation(); + // Sync value of native checkbox and cr-toggle. + this.$.native.checked = e.detail; - // Sync value of native checkbox and cr-toggle and |checked|. - this.$.crToggle.checked = this.$.native.checked; - this.checked = this.$.native.checked; - - this.fire('change', this.checked); - }, - - /** - * @param {!CustomEvent<boolean>} e - * @private - */ - onCrToggleChange_: function(e) { - e.stopPropagation(); - - // Sync value of native checkbox and cr-toggle. - this.$.native.checked = e.detail; - - this.fire('change', this.checked); - }, - }); + this.fire('change', this.checked); + }, +});
diff --git a/chrome/browser/resources/extensions/toolbar.js b/chrome/browser/resources/extensions/toolbar.js index ea79ff8..8615d4b 100644 --- a/chrome/browser/resources/extensions/toolbar.js +++ b/chrome/browser/resources/extensions/toolbar.js
@@ -17,187 +17,187 @@ import {IronA11yAnnouncer} from 'chrome://resources/polymer/v3_0/iron-a11y-announcer/iron-a11y-announcer.js'; import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; - /** @interface */ - export class ToolbarDelegate { - /** - * Toggles whether or not the profile is in developer mode. - * @param {boolean} inDevMode - */ - setProfileInDevMode(inDevMode) {} +/** @interface */ +export class ToolbarDelegate { + /** + * Toggles whether or not the profile is in developer mode. + * @param {boolean} inDevMode + */ + setProfileInDevMode(inDevMode) {} - /** - * Opens the dialog to load unpacked extensions. - * @return {!Promise} - */ - loadUnpacked() {} + /** + * Opens the dialog to load unpacked extensions. + * @return {!Promise} + */ + loadUnpacked() {} - /** - * Updates all extensions. - * @return {!Promise} - */ - updateAllExtensions() {} - } + /** + * Updates all extensions. + * @return {!Promise} + */ + updateAllExtensions() {} +} - Polymer({ - is: 'extensions-toolbar', +Polymer({ + is: 'extensions-toolbar', - _template: html`{__html_template__}`, + _template: html`{__html_template__}`, - properties: { - /** @type {ToolbarDelegate} */ - delegate: Object, + properties: { + /** @type {ToolbarDelegate} */ + delegate: Object, - inDevMode: { - type: Boolean, - value: false, - observer: 'onInDevModeChanged_', - reflectToAttribute: true, - }, - - devModeControlledByPolicy: Boolean, - - isSupervised: Boolean, - - // <if expr="chromeos"> - kioskEnabled: Boolean, - // </if> - - canLoadUnpacked: Boolean, - - /** @private */ - expanded_: Boolean, - - /** @private */ - showPackDialog_: Boolean, - - /** - * Prevents initiating update while update is in progress. - * @private - */ - isUpdating_: {type: Boolean, value: false} + inDevMode: { + type: Boolean, + value: false, + observer: 'onInDevModeChanged_', + reflectToAttribute: true, }, - behaviors: [I18nBehavior], + devModeControlledByPolicy: Boolean, - hostAttributes: { - role: 'banner', - }, - - /** - * @return {boolean} - * @private - */ - shouldDisableDevMode_: function() { - return this.devModeControlledByPolicy || this.isSupervised; - }, - - /** - * @return {string} - * @private - */ - getTooltipText_: function() { - return this.i18n( - this.isSupervised ? 'controlledSettingChildRestriction' : - 'controlledSettingPolicy'); - }, - - /** - * @return {string} - * @private - */ - getIcon_: function() { - return this.isSupervised ? 'cr20:kite' : 'cr20:domain'; - }, - - /** - * @param {!CustomEvent<boolean>} e - * @private - */ - onDevModeToggleChange_: function(e) { - this.delegate.setProfileInDevMode(e.detail); - chrome.metricsPrivate.recordUserAction( - 'Options_ToggleDeveloperMode_' + (e.detail ? 'Enabled' : 'Disabled')); - }, - - /** - * @param {boolean} current - * @param {boolean} previous - * @private - */ - onInDevModeChanged_: function(current, previous) { - const drawer = this.$.devDrawer; - if (this.inDevMode) { - if (drawer.hidden) { - drawer.hidden = false; - // Requesting the offsetTop will cause a reflow (to account for - // hidden). - /** @suppress {suspiciousCode} */ drawer.offsetTop; - } - } else { - if (previous == undefined) { - drawer.hidden = true; - return; - } - - listenOnce(drawer, 'transitionend', e => { - if (!this.inDevMode) { - drawer.hidden = true; - } - }); - } - this.expanded_ = !this.expanded_; - }, - - /** @private */ - onLoadUnpackedTap_: function() { - this.delegate.loadUnpacked().catch(loadError => { - this.fire('load-error', loadError); - }); - chrome.metricsPrivate.recordUserAction('Options_LoadUnpackedExtension'); - }, - - /** @private */ - onPackTap_: function() { - chrome.metricsPrivate.recordUserAction('Options_PackExtension'); - this.showPackDialog_ = true; - }, - - /** @private */ - onPackDialogClose_: function() { - this.showPackDialog_ = false; - this.$.packExtensions.focus(); - }, + isSupervised: Boolean, // <if expr="chromeos"> - /** @private */ - onKioskTap_: function() { - this.fire('kiosk-tap'); - }, + kioskEnabled: Boolean, // </if> + canLoadUnpacked: Boolean, + /** @private */ - onUpdateNowTap_: function() { - // If already updating, do not initiate another update. - if (this.isUpdating_) { + expanded_: Boolean, + + /** @private */ + showPackDialog_: Boolean, + + /** + * Prevents initiating update while update is in progress. + * @private + */ + isUpdating_: {type: Boolean, value: false} + }, + + behaviors: [I18nBehavior], + + hostAttributes: { + role: 'banner', + }, + + /** + * @return {boolean} + * @private + */ + shouldDisableDevMode_: function() { + return this.devModeControlledByPolicy || this.isSupervised; + }, + + /** + * @return {string} + * @private + */ + getTooltipText_: function() { + return this.i18n( + this.isSupervised ? 'controlledSettingChildRestriction' : + 'controlledSettingPolicy'); + }, + + /** + * @return {string} + * @private + */ + getIcon_: function() { + return this.isSupervised ? 'cr20:kite' : 'cr20:domain'; + }, + + /** + * @param {!CustomEvent<boolean>} e + * @private + */ + onDevModeToggleChange_: function(e) { + this.delegate.setProfileInDevMode(e.detail); + chrome.metricsPrivate.recordUserAction( + 'Options_ToggleDeveloperMode_' + (e.detail ? 'Enabled' : 'Disabled')); + }, + + /** + * @param {boolean} current + * @param {boolean} previous + * @private + */ + onInDevModeChanged_: function(current, previous) { + const drawer = this.$.devDrawer; + if (this.inDevMode) { + if (drawer.hidden) { + drawer.hidden = false; + // Requesting the offsetTop will cause a reflow (to account for + // hidden). + /** @suppress {suspiciousCode} */ drawer.offsetTop; + } + } else { + if (previous == undefined) { + drawer.hidden = true; return; } - this.isUpdating_ = true; + listenOnce(drawer, 'transitionend', e => { + if (!this.inDevMode) { + drawer.hidden = true; + } + }); + } + this.expanded_ = !this.expanded_; + }, - const toastManager = getInstance(); - // Keep the toast open indefinitely. - toastManager.duration = 0; - toastManager.show(this.i18n('toolbarUpdatingToast'), false); - this.delegate.updateAllExtensions().then( - () => { - toastManager.hide(); - toastManager.duration = 3000; - toastManager.show(this.i18n('toolbarUpdateDone'), false); - this.isUpdating_ = false; - }, - () => { - toastManager.hide(); - this.isUpdating_ = false; - }); - }, - }); + /** @private */ + onLoadUnpackedTap_: function() { + this.delegate.loadUnpacked().catch(loadError => { + this.fire('load-error', loadError); + }); + chrome.metricsPrivate.recordUserAction('Options_LoadUnpackedExtension'); + }, + + /** @private */ + onPackTap_: function() { + chrome.metricsPrivate.recordUserAction('Options_PackExtension'); + this.showPackDialog_ = true; + }, + + /** @private */ + onPackDialogClose_: function() { + this.showPackDialog_ = false; + this.$.packExtensions.focus(); + }, + + // <if expr="chromeos"> + /** @private */ + onKioskTap_: function() { + this.fire('kiosk-tap'); + }, + // </if> + + /** @private */ + onUpdateNowTap_: function() { + // If already updating, do not initiate another update. + if (this.isUpdating_) { + return; + } + + this.isUpdating_ = true; + + const toastManager = getInstance(); + // Keep the toast open indefinitely. + toastManager.duration = 0; + toastManager.show(this.i18n('toolbarUpdatingToast'), false); + this.delegate.updateAllExtensions().then( + () => { + toastManager.hide(); + toastManager.duration = 3000; + toastManager.show(this.i18n('toolbarUpdateDone'), false); + this.isUpdating_ = false; + }, + () => { + toastManager.hide(); + this.isUpdating_ = false; + }); + }, +});
diff --git a/chrome/browser/signin/chrome_signin_proxying_url_loader_factory.cc b/chrome/browser/signin/chrome_signin_proxying_url_loader_factory.cc index 10e1b0d..3e5ca05 100644 --- a/chrome/browser/signin/chrome_signin_proxying_url_loader_factory.cc +++ b/chrome/browser/signin/chrome_signin_proxying_url_loader_factory.cc
@@ -166,8 +166,8 @@ base::OnceClosure destruction_callback_; - // Messages received by |client_binding_| are forwarded to |target_client_|. - mojo::Binding<network::mojom::URLLoaderClient> client_binding_; + // Messages received by |client_receiver_| are forwarded to |target_client_|. + mojo::Receiver<network::mojom::URLLoaderClient> client_receiver_{this}; network::mojom::URLLoaderClientPtr target_client_; // Messages received by |loader_receiver_| are forwarded to |target_loader_|. @@ -310,11 +310,10 @@ referrer_origin_(request.referrer.GetOrigin()), resource_type_(static_cast<content::ResourceType>(request.resource_type)), is_main_frame_(request.is_main_frame), - client_binding_(this), target_client_(std::move(client)), loader_receiver_(this, std::move(loader_receiver)) { network::mojom::URLLoaderClientPtr proxy_client; - client_binding_.Bind(mojo::MakeRequest(&proxy_client)); + client_receiver_.Bind(mojo::MakeRequest(&proxy_client)); net::HttpRequestHeaders modified_headers; std::vector<std::string> removed_headers; @@ -347,7 +346,7 @@ 2, base::BindOnce(&InProgressRequest::OnBindingsClosed, base::Unretained(this))); loader_receiver_.set_disconnect_handler(closure); - client_binding_.set_connection_error_handler(closure); + client_receiver_.set_disconnect_handler(closure); } void ProxyingURLLoaderFactory::InProgressRequest::FollowRedirect(
diff --git a/chrome/browser/task_manager/task_manager_browsertest.cc b/chrome/browser/task_manager/task_manager_browsertest.cc index 401d1ac..bae72c0 100644 --- a/chrome/browser/task_manager/task_manager_browsertest.cc +++ b/chrome/browser/task_manager/task_manager_browsertest.cc
@@ -516,15 +516,7 @@ ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnyApp())); } -// Flaky - crbug.com/102553 -#if defined(OS_LINUX) -#define MAYBE_NoticeHostedAppTabAfterReload \ - DISABLED_NoticeHostedAppTabAfterReload -#else -#define MAYBE_NoticeHostedAppTabAfterReload NoticeHostedAppTabAfterReload -#endif -IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, - MAYBE_NoticeHostedAppTabAfterReload) { +IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeHostedAppTabAfterReload) { // The app under test acts on URLs whose host is "localhost", // so the URLs we navigate to must have host "localhost". GURL base_url = embedded_test_server()->GetURL( @@ -554,15 +546,7 @@ ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnyExtension())); } -// Flaky - crbug.com/102553 -#if defined(OS_LINUX) -#define MAYBE_NoticeHostedAppTabBeforeReload \ - DISABLED_NoticeHostedAppTabBeforeReload -#else -#define MAYBE_NoticeHostedAppTabBeforeReload NoticeHostedAppTabBeforeReload -#endif -IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, - MAYBE_NoticeHostedAppTabBeforeReload) { +IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeHostedAppTabBeforeReload) { // The app under test acts on URLs whose host is "localhost", // so the URLs we navigate to must have host "localhost". GURL base_url = embedded_test_server()->GetURL(
diff --git a/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings.grd b/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings.grd index 9d3ff28..d2e9ba28 100644 --- a/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings.grd +++ b/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings.grd
@@ -126,10 +126,10 @@ List of credentials to be filled on touch is closed. </message> <message name="IDS_MANAGE_PASSWORDS" desc="Title of the button at the end of a touch to fill sheet that will open the password preferences when tapped."> - Manage Passwords + Manage passwords </message> <message name="IDS_TOUCH_TO_FILL_CONFIRM" desc="Title of the button that confirms filling the only available set of credentials."> - Use Password + Use password </message> </messages> </release>
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd index 6e8221d..e652c8c6 100644 --- a/chrome/browser/ui/android/strings/android_chrome_strings.grd +++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -3477,6 +3477,9 @@ <message name="IDS_TOP_VIEW_NAMES_FILTER_LABEL" desc="The label shown for the names filter toggle button (allowing the user to exclude names)."> Names </message> + <message name="IDS_TOP_VIEW_ADDRESS_FILTER_LABEL" desc="The label shown for the address filter toggle button (allowing the user to exclude names)."> + Addresses + </message> <message name="IDS_TOP_VIEW_EMAIL_FILTER_LABEL" desc="The label shown for the email filter toggle button (allowing the user to exclude emails)."> Email addresses </message>
diff --git a/chrome/browser/ui/input_method/input_method_engine_base.cc b/chrome/browser/ui/input_method/input_method_engine_base.cc index 2af08ea9..645d9fd 100644 --- a/chrome/browser/ui/input_method/input_method_engine_base.cc +++ b/chrome/browser/ui/input_method/input_method_engine_base.cc
@@ -208,7 +208,7 @@ void InputMethodEngineBase::Disable() { std::string last_component_id{active_component_id_}; active_component_id_.clear(); - ConfirmCompositionText(/* reset_engine */ true); + ConfirmCompositionText(/* reset_engine */ true, /* keep_selection */ false); observer_->OnDeactivated(last_component_id); } @@ -423,7 +423,7 @@ // When there is composition text, commit it to the text field first before // changing the composition range. - ConfirmCompositionText(/* reset_engine */ false); + ConfirmCompositionText(/* reset_engine */ false, /* keep_selection */ false); std::vector<ui::ImeTextSpan> text_spans; for (const auto& segment : segments) { @@ -509,11 +509,12 @@ input_context->DeleteSurroundingText(offset, number_of_chars); } -void InputMethodEngineBase::ConfirmCompositionText(bool reset_engine) { +void InputMethodEngineBase::ConfirmCompositionText(bool reset_engine, + bool keep_selection) { ui::IMEInputContextHandlerInterface* input_context = ui::IMEBridge::Get()->GetInputContextHandler(); if (input_context) - input_context->ConfirmCompositionText(reset_engine); + input_context->ConfirmCompositionText(reset_engine, keep_selection); } } // namespace input_method
diff --git a/chrome/browser/ui/input_method/input_method_engine_base.h b/chrome/browser/ui/input_method/input_method_engine_base.h index f4e8af7..265df3ce 100644 --- a/chrome/browser/ui/input_method/input_method_engine_base.h +++ b/chrome/browser/ui/input_method/input_method_engine_base.h
@@ -159,6 +159,10 @@ // is not focused. bool CommitText(int context_id, const char* text, std::string* error); + // Notifies InputContextHandler to commit any composition text. + // Set |reset_engine| to false if the event was from the extension. + void ConfirmCompositionText(bool reset_engine, bool keep_selection); + // Deletes |number_of_chars| unicode characters as the basis of |offset| from // the surrounding text. The |offset| is relative position based on current // caret. @@ -242,9 +246,6 @@ // Sends the key event to the window tree host. virtual bool SendKeyEvent(ui::KeyEvent* ui_event, const std::string& code) = 0; - // Notifies InputContextHandler to commit any composition text. - // Set |reset_engine| to false if the event was from the extension. - void ConfirmCompositionText(bool reset_engine); ui::TextInputType current_input_type_;
diff --git a/chrome/browser/ui/views/intent_picker_bubble_view.cc b/chrome/browser/ui/views/intent_picker_bubble_view.cc index efc3505..fb4553b 100644 --- a/chrome/browser/ui/views/intent_picker_bubble_view.cc +++ b/chrome/browser/ui/views/intent_picker_bubble_view.cc
@@ -6,6 +6,7 @@ #include <utility> +#include "base/feature_list.h" #include "base/i18n/rtl.h" #include "base/strings/string_piece.h" #include "base/strings/utf_string_conversions.h" @@ -16,6 +17,7 @@ #include "chrome/browser/ui/views/chrome_typography.h" #include "chrome/browser/ui/views/toolbar/toolbar_ink_drop_util.h" #include "chrome/browser/ui/views/toolbar/toolbar_view.h" +#include "chrome/common/chrome_features.h" #include "chrome/grit/generated_resources.h" #include "components/url_formatter/elide_url.h" #include "content/public/browser/navigation_handle.h" @@ -514,11 +516,14 @@ // TODO(crbug.com/826982): allow PWAs to have their decision persisted when // there is a central Chrome OS apps registry to store persistence. // TODO(crbug.com/1000037): allow to persist remote devices too. - auto selected_app_type = app_info_[selected_app_tag_].type; - const bool should_enable = - selected_app_type != apps::PickerEntryType::kWeb && - selected_app_type != apps::PickerEntryType::kDevice; - + bool should_enable = false; + if (base::FeatureList::IsEnabled(features::kAppServiceIntentHandling)) { + should_enable = true; + } else { + auto selected_app_type = app_info_[selected_app_tag_].type; + should_enable = selected_app_type != apps::PickerEntryType::kWeb && + selected_app_type != apps::PickerEntryType::kDevice; + } // Reset the checkbox state to the default unchecked if becomes disabled. if (!should_enable) remember_selection_checkbox_->SetChecked(false);
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc index 131cd34..783adeb 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -264,7 +264,7 @@ // session here. It may affect the selection status, so order is // also important. if (IsIMEComposing()) { - ConfirmCompositionText(); + ConfirmCompositionText(/* keep_selection */ false); GetInputMethod()->CancelComposition(this); }
diff --git a/chrome/browser/ui/webui/certificate_viewer_webui.cc b/chrome/browser/ui/webui/certificate_viewer_webui.cc index 7f7d4392..e686be8 100644 --- a/chrome/browser/ui/webui/certificate_viewer_webui.cc +++ b/chrome/browser/ui/webui/certificate_viewer_webui.cc
@@ -278,9 +278,7 @@ return data; } -void CertificateViewerDialog::OnDialogShown( - content::WebUI* webui, - content::RenderViewHost* render_view_host) { +void CertificateViewerDialog::OnDialogShown(content::WebUI* webui) { webui_ = webui; }
diff --git a/chrome/browser/ui/webui/certificate_viewer_webui.h b/chrome/browser/ui/webui/certificate_viewer_webui.h index 98958c4..b4e185e 100644 --- a/chrome/browser/ui/webui/certificate_viewer_webui.h +++ b/chrome/browser/ui/webui/certificate_viewer_webui.h
@@ -54,8 +54,7 @@ std::vector<content::WebUIMessageHandler*>* handlers) const override; void GetDialogSize(gfx::Size* size) const override; std::string GetDialogArgs() const override; - void OnDialogShown(content::WebUI* webui, - content::RenderViewHost* render_view_host) override; + void OnDialogShown(content::WebUI* webui) override; void OnDialogClosed(const std::string& json_retval) override; void OnCloseContents(content::WebContents* source, bool* out_close_dialog) override;
diff --git a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.cc b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.cc index 9cee749..1ce28bd 100644 --- a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.cc +++ b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.cc
@@ -207,9 +207,7 @@ return std::string(); } -void AssistantOptInDialog::OnDialogShown( - content::WebUI* webui, - content::RenderViewHost* render_view_host) { +void AssistantOptInDialog::OnDialogShown(content::WebUI* webui) { assistant_ui_ = static_cast<AssistantOptInUI*>(webui->GetController()); }
diff --git a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.h b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.h index a93c248..8e39515b 100644 --- a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.h +++ b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.h
@@ -63,8 +63,7 @@ // ui::WebDialogDelegate void GetDialogSize(gfx::Size* size) const override; std::string GetDialogArgs() const override; - void OnDialogShown(content::WebUI* webui, - content::RenderViewHost* render_view_host) override; + void OnDialogShown(content::WebUI* webui) override; void OnDialogClosed(const std::string& json_retval) override; private:
diff --git a/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_dialog.cc b/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_dialog.cc index 4b553d8a..a22310f 100644 --- a/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_dialog.cc +++ b/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_dialog.cc
@@ -70,11 +70,9 @@ return installer_ui_ == nullptr || installer_ui_->can_close(); } -void CrostiniInstallerDialog::OnDialogShown( - content::WebUI* webui, - content::RenderViewHost* render_view_host) { +void CrostiniInstallerDialog::OnDialogShown(content::WebUI* webui) { installer_ui_ = static_cast<CrostiniInstallerUI*>(webui->GetController()); - return SystemWebDialogDelegate::OnDialogShown(webui, render_view_host); + return SystemWebDialogDelegate::OnDialogShown(webui); } void CrostiniInstallerDialog::OnCloseContents(content::WebContents* source,
diff --git a/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_dialog.h b/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_dialog.h index e17a627..2c96d9f 100644 --- a/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_dialog.h +++ b/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_dialog.h
@@ -26,8 +26,7 @@ bool ShouldShowCloseButton() const override; void AdjustWidgetInitParams(views::Widget::InitParams* params) override; bool CanCloseDialog() const override; - void OnDialogShown(content::WebUI* webui, - content::RenderViewHost* render_view_host) override; + void OnDialogShown(content::WebUI* webui) override; void OnCloseContents(content::WebContents* source, bool* out_close_dialog) override;
diff --git a/chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.cc b/chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.cc index 23267bce..c90e0ee 100644 --- a/chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.cc +++ b/chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.cc
@@ -123,9 +123,7 @@ return std::string(); } -void SystemWebDialogDelegate::OnDialogShown( - content::WebUI* webui, - content::RenderViewHost* render_view_host) { +void SystemWebDialogDelegate::OnDialogShown(content::WebUI* webui) { webui_ = webui; if (features::IsSplitSettingsEnabled()) {
diff --git a/chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.h b/chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.h index e9b0e2f..1b58252 100644 --- a/chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.h +++ b/chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.h
@@ -61,8 +61,7 @@ void GetDialogSize(gfx::Size* size) const override; bool CanResizeDialog() const override; std::string GetDialogArgs() const override; - void OnDialogShown(content::WebUI* webui, - content::RenderViewHost* render_view_host) override; + void OnDialogShown(content::WebUI* webui) override; // Note: deletes |this|. void OnDialogClosed(const std::string& json_retval) override; void OnCloseContents(content::WebContents* source,
diff --git a/chrome/browser/ui/webui/chromeos/terminal/terminal_source.cc b/chrome/browser/ui/webui/chromeos/terminal/terminal_source.cc index 2f96140..c63f034 100644 --- a/chrome/browser/ui/webui/chromeos/terminal/terminal_source.cc +++ b/chrome/browser/ui/webui/chromeos/terminal/terminal_source.cc
@@ -13,6 +13,7 @@ #include "chrome/common/url_constants.h" #include "chrome/common/webui_url_constants.h" #include "net/base/mime_util.h" +#include "third_party/zlib/google/compression_utils.h" namespace { // TODO(crbug.com/846546): Initially set to load crosh, but change to @@ -26,7 +27,15 @@ void ReadFile(const base::FilePath& path, const content::URLDataSource::GotDataCallback& callback) { std::string content; + // First look for uncompressed resource, then try for gzipped file. bool result = base::ReadFileToString(path, &content); + if (!result) { + result = + base::ReadFileToString(base::FilePath(path.value() + ".gz"), &content); + std::string uncompressed; + result = compression::GzipUncompress(content, &uncompressed); + content = std::move(uncompressed); + } // Allow missing files in <root>/_locales only. DCHECK(result || base::FilePath(kTerminalRoot) .Append("_locales")
diff --git a/chrome/browser/ui/webui/constrained_web_dialog_ui.cc b/chrome/browser/ui/webui/constrained_web_dialog_ui.cc index 3a0975b..b59728f 100644 --- a/chrome/browser/ui/webui/constrained_web_dialog_ui.cc +++ b/chrome/browser/ui/webui/constrained_web_dialog_ui.cc
@@ -15,7 +15,6 @@ #include "base/values.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/render_frame_host.h" -#include "content/public/browser/render_view_host.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_ui.h" #include "content/public/browser/web_ui_message_handler.h" @@ -28,7 +27,6 @@ #endif using content::RenderFrameHost; -using content::RenderViewHost; using content::WebContents; using content::WebUIMessageHandler; @@ -85,8 +83,7 @@ web_ui()->AddMessageHandler(base::WrapUnique(handler)); } - dialog_delegate->OnDialogShown(web_ui(), - render_frame_host->GetRenderViewHost()); + dialog_delegate->OnDialogShown(web_ui()); } void ConstrainedWebDialogUI::OnDialogCloseMessage(const base::ListValue* args) {
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.cc b/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.cc index 9ab19f0..7e3af1e 100644 --- a/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.cc +++ b/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.cc
@@ -128,10 +128,8 @@ return false; } -void InlineLoginHandlerDialogChromeOS::OnDialogShown( - content::WebUI* webui, - content::RenderViewHost* render_view_host) { - SystemWebDialogDelegate::OnDialogShown(webui, render_view_host); +void InlineLoginHandlerDialogChromeOS::OnDialogShown(content::WebUI* webui) { + SystemWebDialogDelegate::OnDialogShown(webui); web_modal::WebContentsModalDialogManager::CreateForWebContents( webui->GetWebContents()); web_modal::WebContentsModalDialogManager::FromWebContents(
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.h b/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.h index 5a5e94f..bc650fd 100644 --- a/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.h +++ b/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.h
@@ -46,8 +46,7 @@ void GetDialogSize(gfx::Size* size) const override; std::string GetDialogArgs() const override; bool ShouldShowDialogTitle() const override; - void OnDialogShown(content::WebUI* webui, - content::RenderViewHost* render_view_host) override; + void OnDialogShown(content::WebUI* webui) override; private: InlineLoginHandlerModalDelegate delegate_;
diff --git a/chrome/browser/vr/service/browser_xr_runtime.cc b/chrome/browser/vr/service/browser_xr_runtime.cc index 0c6825d6..cd06168 100644 --- a/chrome/browser/vr/service/browser_xr_runtime.cc +++ b/chrome/browser/vr/service/browser_xr_runtime.cc
@@ -396,24 +396,6 @@ } } -void BrowserXRRuntime::OnDeviceActivated( - device::mojom::VRDisplayEventReason reason, - base::OnceCallback<void(bool)> on_handled) { - if (listening_for_activation_service_) { - listening_for_activation_service_->OnActivate(reason, - std::move(on_handled)); - } else { - std::move(on_handled).Run(true /* will_not_present */); - } -} - -void BrowserXRRuntime::OnDeviceIdle( - device::mojom::VRDisplayEventReason reason) { - for (VRServiceImpl* service : services_) { - service->OnDeactivate(reason); - } -} - void BrowserXRRuntime::OnVisibilityStateChanged( device::mojom::XRVisibilityState visibility_state) { for (VRServiceImpl* service : services_) { @@ -441,11 +423,6 @@ if (service == presenting_service_) { ExitPresent(service, base::DoNothing()); } - if (service == listening_for_activation_service_) { - // Not listening for activation. - listening_for_activation_service_ = nullptr; - runtime_->SetListeningForActivate(false); - } } void BrowserXRRuntime::ExitPresent( @@ -524,18 +501,6 @@ StopImmersiveSession(base::DoNothing()); } -void BrowserXRRuntime::UpdateListeningForActivate(VRServiceImpl* service) { - if (service->ListeningForActivate() && service->InFocusedFrame()) { - bool was_listening = !!listening_for_activation_service_; - listening_for_activation_service_ = service; - if (!was_listening) - OnListeningForActivate(true); - } else if (listening_for_activation_service_ == service) { - listening_for_activation_service_ = nullptr; - OnListeningForActivate(false); - } -} - void BrowserXRRuntime::InitializeAndGetDisplayInfo( content::RenderFrameHost* render_frame_host, device::mojom::VRService::GetImmersiveVRDisplayInfoCallback callback) { @@ -551,8 +516,4 @@ base::BindOnce(&BrowserXRRuntime::OnInitialized, base::Unretained(this))); } -void BrowserXRRuntime::OnListeningForActivate(bool is_listening) { - runtime_->SetListeningForActivate(is_listening); -} - } // namespace vr
diff --git a/chrome/browser/vr/service/browser_xr_runtime.h b/chrome/browser/vr/service/browser_xr_runtime.h index abe7dab..d4d566a1 100644 --- a/chrome/browser/vr/service/browser_xr_runtime.h +++ b/chrome/browser/vr/service/browser_xr_runtime.h
@@ -79,7 +79,6 @@ VRServiceImpl* GetServiceWithActiveImmersiveSession() { return presenting_service_; } - void UpdateListeningForActivate(VRServiceImpl* service); device::mojom::VRDisplayInfoPtr GetVRDisplayInfo() { return display_info_.Clone(); @@ -103,14 +102,10 @@ void OnDisplayInfoChanged( device::mojom::VRDisplayInfoPtr vr_device_info) override; void OnExitPresent() override; - void OnDeviceActivated(device::mojom::VRDisplayEventReason reason, - base::OnceCallback<void(bool)> on_handled) override; - void OnDeviceIdle(device::mojom::VRDisplayEventReason reason) override; void OnVisibilityStateChanged( device::mojom::XRVisibilityState visibility_state) override; void StopImmersiveSession(VRServiceImpl::ExitPresentCallback on_exited); - void OnListeningForActivate(bool is_listening); void OnRequestSessionResult( base::WeakPtr<VRServiceImpl> service, device::mojom::XRRuntimeSessionOptionsPtr options, @@ -129,7 +124,6 @@ std::set<VRServiceImpl*> services_; device::mojom::VRDisplayInfoPtr display_info_; - VRServiceImpl* listening_for_activation_service_ = nullptr; VRServiceImpl* presenting_service_ = nullptr; mojo::AssociatedReceiver<device::mojom::XRRuntimeEventListener> receiver_{
diff --git a/chrome/browser/vr/service/vr_service_impl.cc b/chrome/browser/vr/service/vr_service_impl.cc index 9b1cfbb..f903b13 100644 --- a/chrome/browser/vr/service/vr_service_impl.cc +++ b/chrome/browser/vr/service/vr_service_impl.cc
@@ -219,12 +219,6 @@ } in_focused_frame_ = focused; - if (ListeningForActivate()) { - BrowserXRRuntime* immersive_runtime = - runtime_manager_->GetImmersiveVrRuntime(); - if (immersive_runtime) - immersive_runtime->UpdateListeningForActivate(this); - } for (const auto& controller : magic_window_controllers_) controller->SetFrameDataRestricted(!focused); @@ -611,21 +605,6 @@ } } -void VRServiceImpl::SetListeningForActivate( - mojo::PendingRemote<device::mojom::VRDisplayClient> display_client) { - // TODO(crbug.com/999745): Remove the check if the condition to check if - // |display_client| is nullptr is not required. - if (display_client) - display_client_.Bind(std::move(display_client)); - else - display_client_.reset(); - BrowserXRRuntime* immersive_runtime = - runtime_manager_->GetImmersiveVrRuntime(); - if (immersive_runtime && display_client_) { - immersive_runtime->UpdateListeningForActivate(this); - } -} - void VRServiceImpl::GetImmersiveVRDisplayInfo( device::mojom::VRService::GetImmersiveVRDisplayInfoCallback callback) { if (!initialization_complete_) { @@ -669,21 +648,6 @@ client->OnVisibilityStateChanged(visiblity_state); } -void VRServiceImpl::OnActivate(device::mojom::VRDisplayEventReason reason, - base::OnceCallback<void(bool)> on_handled) { - DVLOG(2) << __func__; - if (display_client_) { - display_client_->OnActivate(reason, std::move(on_handled)); - } -} - -void VRServiceImpl::OnDeactivate(device::mojom::VRDisplayEventReason reason) { - DVLOG(2) << __func__; - if (display_client_) { - display_client_->OnDeactivate(reason); - } -} - content::WebContents* VRServiceImpl::GetWebContents() { return content::WebContents::FromRenderFrameHost(render_frame_host_); }
diff --git a/chrome/browser/vr/service/vr_service_impl.h b/chrome/browser/vr/service/vr_service_impl.h index b17188d..44b98156 100644 --- a/chrome/browser/vr/service/vr_service_impl.h +++ b/chrome/browser/vr/service/vr_service_impl.h
@@ -81,10 +81,6 @@ void OnExitPresent(); void OnVisibilityStateChanged( device::mojom::XRVisibilityState visibility_state); - void OnActivate(device::mojom::VRDisplayEventReason reason, - base::OnceCallback<void(bool)> on_handled); - void OnDeactivate(device::mojom::VRDisplayEventReason reason); - bool ListeningForActivate() { return !!display_client_; } bool InFocusedFrame() { return in_focused_frame_; } void OnDisplayInfoChanged(); void RuntimesChanged(); @@ -95,10 +91,6 @@ content::WebContents* GetWebContents(); - void SetListeningForActivate( - mojo::PendingRemote<device::mojom::VRDisplayClient> display_client) - override; - private: // content::WebContentsObserver implementation void OnWebContentsFocused(content::RenderWidgetHost* host) override; @@ -171,9 +163,6 @@ // List of callbacks to run when initialization is completed. std::vector<base::OnceCallback<void()>> pending_requests_; - // This is required for WebVR 1.1 backwards compatibility. - mojo::Remote<device::mojom::VRDisplayClient> display_client_; - bool initialization_complete_ = false; bool in_focused_frame_ = false; bool frames_throttled_ = false;
diff --git a/chrome/browser/web_applications/components/manifest_update_task.cc b/chrome/browser/web_applications/components/manifest_update_task.cc index 44dc2f1..f5e621d 100644 --- a/chrome/browser/web_applications/components/manifest_update_task.cc +++ b/chrome/browser/web_applications/components/manifest_update_task.cc
@@ -87,7 +87,11 @@ } DCHECK(data.manifest); - if (!IsUpdateNeededForManifest(*data.manifest)) { + std::unique_ptr<WebApplicationInfo> web_application_info = + std::make_unique<WebApplicationInfo>(); + UpdateWebAppInfoFromManifest(*data.manifest, web_application_info.get(), + ForInstallableSite::kYes); + if (!IsUpdateNeeded(*web_application_info)) { DestroySelf(ManifestUpdateResult::kAppUpToDate); return; } @@ -95,29 +99,26 @@ stage_ = Stage::kPendingWindowsClosed; Observe(nullptr); ui_manager_.NotifyOnAllAppWindowsClosed( - app_id_, base::Bind(&ManifestUpdateTask::OnAllAppWindowsClosed, - AsWeakPtr(), *data.manifest)); + app_id_, base::BindOnce(&ManifestUpdateTask::OnAllAppWindowsClosed, + AsWeakPtr(), std::move(web_application_info))); } -bool ManifestUpdateTask::IsUpdateNeededForManifest( - const blink::Manifest& manifest) const { - if (app_id_ != GenerateAppIdFromURL(manifest.start_url)) +bool ManifestUpdateTask::IsUpdateNeeded( + const WebApplicationInfo& web_application_info) const { + if (app_id_ != GenerateAppIdFromURL(web_application_info.app_url)) return false; - if (manifest.theme_color != registrar_.GetAppThemeColor(app_id_)) + if (web_application_info.theme_color != registrar_.GetAppThemeColor(app_id_)) return true; // TODO(crbug.com/926083): Check more manifest fields. return false; } -void ManifestUpdateTask::OnAllAppWindowsClosed(blink::Manifest manifest) { +void ManifestUpdateTask::OnAllAppWindowsClosed( + std::unique_ptr<WebApplicationInfo> web_application_info) { DCHECK_EQ(stage_, Stage::kPendingWindowsClosed); - auto web_application_info = std::make_unique<WebApplicationInfo>(); - UpdateWebAppInfoFromManifest(manifest, web_application_info.get(), - ForInstallableSite::kYes); - // The app's name must not change due to an automatic update. web_application_info->title = base::UTF8ToUTF16(registrar_.GetAppShortName(app_id_)); @@ -137,16 +138,23 @@ break; } + std::unique_ptr<WebApplicationInfo> web_application_info_for_dchecking; +#if DCHECK_IS_ON() + web_application_info_for_dchecking = + std::make_unique<WebApplicationInfo>(*web_application_info); +#endif + stage_ = Stage::kPendingInstallation; install_manager_.UpdateWebAppFromInfo( app_id_, std::move(web_application_info), - base::Bind(&ManifestUpdateTask::OnInstallationComplete, AsWeakPtr(), - std::move(manifest))); + base::BindOnce(&ManifestUpdateTask::OnInstallationComplete, AsWeakPtr(), + std::move(web_application_info_for_dchecking))); } -void ManifestUpdateTask::OnInstallationComplete(blink::Manifest manifest, - const AppId& app_id, - InstallResultCode code) { +void ManifestUpdateTask::OnInstallationComplete( + std::unique_ptr<WebApplicationInfo> opt_web_application_info, + const AppId& app_id, + InstallResultCode code) { DCHECK_EQ(stage_, Stage::kPendingInstallation); if (!IsSuccess(code)) { @@ -155,7 +163,7 @@ } DCHECK_EQ(app_id_, app_id); - DCHECK(!IsUpdateNeededForManifest(manifest)); + DCHECK(!IsUpdateNeeded(*opt_web_application_info)); DCHECK_EQ(code, InstallResultCode::kSuccessAlreadyInstalled); DestroySelf(ManifestUpdateResult::kAppUpdated);
diff --git a/chrome/browser/web_applications/components/manifest_update_task.h b/chrome/browser/web_applications/components/manifest_update_task.h index 874e1ecf..5a0c495 100644 --- a/chrome/browser/web_applications/components/manifest_update_task.h +++ b/chrome/browser/web_applications/components/manifest_update_task.h
@@ -12,6 +12,7 @@ #include "third_party/blink/public/common/manifest/manifest.h" struct InstallableData; +struct WebApplicationInfo; namespace web_app { @@ -71,11 +72,13 @@ }; void OnDidGetInstallableData(const InstallableData& data); - bool IsUpdateNeededForManifest(const blink::Manifest& manifest) const; - void OnAllAppWindowsClosed(blink::Manifest manifest); - void OnInstallationComplete(blink::Manifest manifest, - const AppId& app_id, - InstallResultCode code); + bool IsUpdateNeeded(const WebApplicationInfo& web_application_info) const; + void OnAllAppWindowsClosed( + std::unique_ptr<WebApplicationInfo> web_application_info); + void OnInstallationComplete( + std::unique_ptr<WebApplicationInfo> opt_web_application_info, + const AppId& app_id, + InstallResultCode code); void DestroySelf(ManifestUpdateResult result); const AppRegistrar& registrar_;
diff --git a/chrome/browser/web_applications/components/web_app_data_retriever_unittest.cc b/chrome/browser/web_applications/components/web_app_data_retriever_unittest.cc index 628fc8e..2497749 100644 --- a/chrome/browser/web_applications/components/web_app_data_retriever_unittest.cc +++ b/chrome/browser/web_applications/components/web_app_data_retriever_unittest.cc
@@ -24,7 +24,8 @@ #include "content/public/browser/site_instance.h" #include "content/public/test/browser_task_environment.h" #include "content/public/test/web_contents_tester.h" -#include "mojo/public/cpp/bindings/associated_binding.h" +#include "mojo/public/cpp/bindings/associated_receiver.h" +#include "mojo/public/cpp/bindings/pending_associated_receiver.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h" #include "third_party/blink/public/common/manifest/manifest.h" @@ -52,8 +53,8 @@ } void Bind(mojo::ScopedInterfaceEndpointHandle handle) { - binding_.Bind( - mojo::AssociatedInterfaceRequest<ChromeRenderFrame>(std::move(handle))); + receiver_.Bind( + mojo::PendingAssociatedReceiver<ChromeRenderFrame>(std::move(handle))); } // Set |web_app_info| to respond on |GetWebApplicationInfo|. @@ -68,7 +69,7 @@ private: WebApplicationInfo web_app_info_; - mojo::AssociatedBinding<chrome::mojom::ChromeRenderFrame> binding_{this}; + mojo::AssociatedReceiver<chrome::mojom::ChromeRenderFrame> receiver_{this}; }; class WebAppDataRetrieverTest : public ChromeRenderViewHostTestHarness {
diff --git a/chrome/browser/web_applications/test/test_web_app_registry_controller.cc b/chrome/browser/web_applications/test/test_web_app_registry_controller.cc index 1cdcbe6..a7cdc37b 100644 --- a/chrome/browser/web_applications/test/test_web_app_registry_controller.cc +++ b/chrome/browser/web_applications/test/test_web_app_registry_controller.cc
@@ -52,11 +52,20 @@ update->DeleteApp(app_id); } +void TestWebAppRegistryController::SetInstallWebAppsAfterSyncDelegate( + InstallWebAppsAfterSyncDelegate delegate) { + install_web_apps_after_sync_delegate_ = delegate; +} + void TestWebAppRegistryController::InstallWebAppsAfterSync( std::vector<WebApp*> web_apps, RepeatingInstallCallback callback) { - for (WebApp* web_app : web_apps) - callback.Run(web_app->app_id(), InstallResultCode::kSuccessNewInstall); + if (install_web_apps_after_sync_delegate_) { + install_web_apps_after_sync_delegate_.Run(std::move(web_apps), callback); + } else { + for (WebApp* web_app : web_apps) + callback.Run(web_app->app_id(), InstallResultCode::kSuccessNewInstall); + } } void TestWebAppRegistryController::UninstallWebAppsAfterSync(
diff --git a/chrome/browser/web_applications/test/test_web_app_registry_controller.h b/chrome/browser/web_applications/test/test_web_app_registry_controller.h index 3b891788..d8cc611 100644 --- a/chrome/browser/web_applications/test/test_web_app_registry_controller.h +++ b/chrome/browser/web_applications/test/test_web_app_registry_controller.h
@@ -7,6 +7,7 @@ #include <memory> +#include "base/callback.h" #include "chrome/browser/web_applications/components/web_app_helpers.h" #include "chrome/browser/web_applications/web_app_registrar.h" #include "chrome/browser/web_applications/web_app_sync_install_delegate.h" @@ -37,6 +38,12 @@ void UnregisterApp(const AppId& app_id); void UnregisterAll(); + using InstallWebAppsAfterSyncDelegate = + base::RepeatingCallback<void(std::vector<WebApp*> web_apps, + RepeatingInstallCallback callback)>; + void SetInstallWebAppsAfterSyncDelegate( + InstallWebAppsAfterSyncDelegate delegate); + // SyncInstallDelegate: void InstallWebAppsAfterSync(std::vector<WebApp*> web_apps, RepeatingInstallCallback callback) override; @@ -52,6 +59,8 @@ WebAppSyncBridge& sync_bridge() { return *sync_bridge_; } private: + InstallWebAppsAfterSyncDelegate install_web_apps_after_sync_delegate_; + std::unique_ptr<TestWebAppDatabaseFactory> database_factory_; std::unique_ptr<WebAppRegistrarMutable> mutable_registrar_; testing::NiceMock<syncer::MockModelTypeChangeProcessor> mock_processor_;
diff --git a/chrome/browser/web_applications/web_app_database.cc b/chrome/browser/web_applications/web_app_database.cc index d11eba0..837eb32 100644 --- a/chrome/browser/web_applications/web_app_database.cc +++ b/chrome/browser/web_applications/web_app_database.cc
@@ -47,11 +47,11 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(opened_); - DCHECK(!update_data.IsEmpty()); - std::unique_ptr<syncer::ModelTypeStore::WriteBatch> write_batch = store_->CreateWriteBatch(); + // |update_data| can be empty here but we should write |metadata_change_list| + // anyway. write_batch->TakeMetadataChangesFrom(std::move(metadata_change_list)); for (const std::unique_ptr<WebApp>& web_app : update_data.apps_to_create) {
diff --git a/chrome/browser/web_applications/web_app_sync_bridge.cc b/chrome/browser/web_applications/web_app_sync_bridge.cc index f18cc68..c4e47f4 100644 --- a/chrome/browser/web_applications/web_app_sync_bridge.cc +++ b/chrome/browser/web_applications/web_app_sync_bridge.cc
@@ -23,7 +23,6 @@ #include "chrome/common/channel_info.h" #include "components/sync/base/model_type.h" #include "components/sync/base/report_unrecoverable_error.h" -#include "components/sync/model/entity_data.h" #include "components/sync/model/metadata_batch.h" #include "components/sync/model/metadata_change_list.h" #include "components/sync/model/model_type_store.h" @@ -34,8 +33,6 @@ namespace web_app { -namespace { - bool AreAppsLocallyInstalledByDefault() { #if defined(OS_CHROMEOS) // On Chrome OS, sync always locally installs an app. @@ -45,8 +42,6 @@ #endif } -} // namespace - std::unique_ptr<syncer::EntityData> CreateSyncEntityData(const WebApp& app) { auto entity_data = std::make_unique<syncer::EntityData>(); entity_data->name = app.name(); @@ -388,6 +383,9 @@ void WebAppSyncBridge::ApplySyncChangesToRegistrar( std::unique_ptr<RegistryUpdateData> update_local_data) { + if (update_local_data->IsEmpty()) + return; + std::vector<WebApp*> apps_to_install; for (const auto& web_app : update_local_data->apps_to_create) apps_to_install.push_back(web_app.get());
diff --git a/chrome/browser/web_applications/web_app_sync_bridge.h b/chrome/browser/web_applications/web_app_sync_bridge.h index 95b8f704..5489edf 100644 --- a/chrome/browser/web_applications/web_app_sync_bridge.h +++ b/chrome/browser/web_applications/web_app_sync_bridge.h
@@ -16,6 +16,7 @@ #include "chrome/browser/web_applications/web_app.h" #include "chrome/browser/web_applications/web_app_registrar.h" #include "components/sync/model/entity_change.h" +#include "components/sync/model/entity_data.h" #include "components/sync/model/model_type_sync_bridge.h" class Profile; @@ -27,6 +28,10 @@ class ModelTypeChangeProcessor; } // namespace syncer +namespace sync_pb { +class WebAppSpecifics; +} // namespace sync_pb + namespace web_app { class AbstractWebAppDatabaseFactory; @@ -126,7 +131,10 @@ DISALLOW_COPY_AND_ASSIGN(WebAppSyncBridge); }; +bool AreAppsLocallyInstalledByDefault(); + std::unique_ptr<syncer::EntityData> CreateSyncEntityData(const WebApp& app); + void ApplySyncDataToApp(const sync_pb::WebAppSpecifics& sync_data, WebApp* app); } // namespace web_app
diff --git a/chrome/browser/web_applications/web_app_sync_bridge_unittest.cc b/chrome/browser/web_applications/web_app_sync_bridge_unittest.cc index 31ede9b..ce2d2fc 100644 --- a/chrome/browser/web_applications/web_app_sync_bridge_unittest.cc +++ b/chrome/browser/web_applications/web_app_sync_bridge_unittest.cc
@@ -5,8 +5,11 @@ #include "chrome/browser/web_applications/web_app_sync_bridge.h" #include <memory> +#include <vector> #include "base/run_loop.h" +#include "base/stl_util.h" +#include "base/strings/string_number_conversions.h" #include "base/test/bind_test_util.h" #include "chrome/browser/web_applications/components/web_app_constants.h" #include "chrome/browser/web_applications/components/web_app_helpers.h" @@ -24,6 +27,16 @@ namespace { +using testing::_; + +using AppsList = std::vector<std::unique_ptr<WebApp>>; + +void RemoveWebAppFromAppsList(AppsList* apps_list, const AppId& app_id) { + base::EraseIf(*apps_list, [app_id](const std::unique_ptr<WebApp>& app) { + return app->app_id() == app_id; + }); +} + bool IsSyncDataEqual(const WebApp& expected_app, const syncer::EntityData& entity_data) { if (!entity_data.specifics.has_web_app()) @@ -63,6 +76,78 @@ return !data_batch->HasNext(); } +std::unique_ptr<WebApp> CreateWebApp(const std::string& url) { + const GURL launch_url(url); + const AppId app_id = GenerateAppIdFromURL(launch_url); + + auto web_app = std::make_unique<WebApp>(app_id); + web_app->SetLaunchUrl(launch_url); + web_app->SetUserDisplayMode(DisplayMode::kStandalone); + web_app->SetName("Name"); + return web_app; +} + +std::unique_ptr<WebApp> CreateWebAppWithSyncOnlyFields(const std::string& url) { + const GURL launch_url(url); + const AppId app_id = GenerateAppIdFromURL(launch_url); + + auto web_app = std::make_unique<WebApp>(app_id); + web_app->AddSource(Source::kSync); + web_app->SetLaunchUrl(launch_url); + web_app->SetUserDisplayMode(DisplayMode::kStandalone); + return web_app; +} + +AppsList CreateAppsList(const std::string& base_url, int num_apps) { + AppsList apps_list; + + for (int i = 0; i < num_apps; ++i) { + apps_list.push_back( + CreateWebAppWithSyncOnlyFields(base_url + base::NumberToString(i))); + } + + return apps_list; +} + +void InsertAppIntoRegistry(Registry* registry, std::unique_ptr<WebApp> app) { + AppId app_id = app->app_id(); + ASSERT_FALSE(base::Contains(*registry, app_id)); + registry->emplace(std::move(app_id), std::move(app)); +} + +void InsertAppsListIntoRegistry(Registry* registry, const AppsList& apps_list) { + for (const std::unique_ptr<WebApp>& app : apps_list) + registry->emplace(app->app_id(), std::make_unique<WebApp>(*app)); +} + +void ConvertAppsListToEntityChangeList( + const AppsList& apps_list, + syncer::EntityChangeList* sync_data_list) { + for (auto& app : apps_list) { + std::unique_ptr<syncer::EntityChange> entity_change = + syncer::EntityChange::CreateAdd(app->app_id(), + CreateSyncEntityData(*app)); + sync_data_list->push_back(std::move(entity_change)); + } +} + +// Returns true if the app converted from entity_data exists in the apps_list. +bool RemoveEntityDataAppFromAppsList(const std::string& storage_key, + const syncer::EntityData& entity_data, + AppsList* apps_list) { + for (auto& app : *apps_list) { + if (app->app_id() == storage_key) { + if (!IsSyncDataEqual(*app, entity_data)) + return false; + + RemoveWebAppFromAppsList(apps_list, storage_key); + return true; + } + } + + return false; +} + } // namespace class WebAppSyncBridgeTest : public WebAppTest { @@ -83,37 +168,9 @@ void InitSyncBridge() { controller().Init(); } - std::unique_ptr<WebApp> CreateWebApp(const std::string& url) { - const GURL launch_url(url); - const AppId app_id = GenerateAppIdFromURL(launch_url); - - auto web_app = std::make_unique<WebApp>(app_id); - web_app->SetLaunchUrl(launch_url); - web_app->SetUserDisplayMode(DisplayMode::kStandalone); - web_app->SetName("Name"); - return web_app; - } - - std::unique_ptr<WebApp> CreateWebAppWithSyncOnlyFields( - const std::string& url) { - const GURL launch_url(url); - const AppId app_id = GenerateAppIdFromURL(launch_url); - - auto web_app = std::make_unique<WebApp>(app_id); - web_app->AddSource(Source::kSync); - web_app->SetLaunchUrl(launch_url); - web_app->SetUserDisplayMode(DisplayMode::kStandalone); - return web_app; - } - - void InsertAppIntoRegistry(Registry* registry, std::unique_ptr<WebApp> app) { - AppId app_id = app->app_id(); - ASSERT_FALSE(base::Contains(*registry, app_id)); - registry->emplace(std::move(app_id), std::move(app)); - } - - void InsertAppCopyIntoRegistry(Registry* registry, const WebApp& app) { - registry->emplace(app.app_id(), std::make_unique<WebApp>(app)); + bool IsDatabaseRegistryEqualToRegistrar() { + Registry registry = database_factory().ReadRegistry(); + return IsRegistryEqual(registrar_registry(), registry); } protected: @@ -127,6 +184,10 @@ return controller().database_factory(); } WebAppSyncBridge& sync_bridge() { return controller().sync_bridge(); } + WebAppRegistrar& registrar() { return controller().mutable_registrar(); } + Registry& registrar_registry() { + return controller().mutable_registrar().registry(); + } private: std::unique_ptr<TestWebAppRegistryController> test_registry_controller_; @@ -156,7 +217,7 @@ database_factory().WriteRegistry(registry); - EXPECT_CALL(processor(), ModelReadyToSync(testing::_)).Times(1); + EXPECT_CALL(processor(), ModelReadyToSync(_)).Times(1); InitSyncBridge(); { @@ -198,4 +259,141 @@ EXPECT_EQ(app->app_id(), sync_bridge().GetStorageKey(*entity_data)); } +TEST_F(WebAppSyncBridgeTest, MergeSyncData_LocalSetAndServerSetAreEmpty) { + InitSyncBridge(); + + syncer::EntityChangeList sync_data_list; + + EXPECT_CALL(processor(), Put(_, _, _)).Times(0); + + sync_bridge().MergeSyncData(sync_bridge().CreateMetadataChangeList(), + std::move(sync_data_list)); +} + +TEST_F(WebAppSyncBridgeTest, MergeSyncData_LocalSetEqualsServerSet) { + AppsList apps = CreateAppsList("https://example.com/", 10); + + Registry registry; + InsertAppsListIntoRegistry(®istry, apps); + database_factory().WriteRegistry(registry); + InitSyncBridge(); + + // The incoming list of apps from the sync server. + syncer::EntityChangeList sync_data_list; + ConvertAppsListToEntityChangeList(apps, &sync_data_list); + + EXPECT_CALL(processor(), Put(_, _, _)).Times(0); + + sync_bridge().MergeSyncData(sync_bridge().CreateMetadataChangeList(), + std::move(sync_data_list)); + + EXPECT_TRUE(IsRegistryEqual(registrar_registry(), registry)); + EXPECT_TRUE(IsDatabaseRegistryEqualToRegistrar()); +} + +TEST_F(WebAppSyncBridgeTest, MergeSyncData_LocalSetGreaterThanServerSet) { + AppsList local_and_server_apps = CreateAppsList("https://example.com/", 10); + AppsList expected_local_apps_to_upload = + CreateAppsList("https://example.org/", 10); + + Registry registry; + InsertAppsListIntoRegistry(®istry, local_and_server_apps); + InsertAppsListIntoRegistry(®istry, expected_local_apps_to_upload); + database_factory().WriteRegistry(registry); + InitSyncBridge(); + + auto metadata_change_list = sync_bridge().CreateMetadataChangeList(); + syncer::MetadataChangeList* metadata_ptr = metadata_change_list.get(); + + syncer::EntityChangeList sync_data_list; + ConvertAppsListToEntityChangeList(local_and_server_apps, &sync_data_list); + + base::RunLoop run_loop; + ON_CALL(processor(), Put(_, _, _)) + .WillByDefault([&](const std::string& storage_key, + std::unique_ptr<syncer::EntityData> entity_data, + syncer::MetadataChangeList* metadata) { + EXPECT_EQ(metadata_ptr, metadata); + EXPECT_TRUE(RemoveEntityDataAppFromAppsList( + storage_key, *entity_data, &expected_local_apps_to_upload)); + if (expected_local_apps_to_upload.empty()) + run_loop.Quit(); + }); + + sync_bridge().MergeSyncData(std::move(metadata_change_list), + std::move(sync_data_list)); + run_loop.Run(); + + EXPECT_TRUE(IsRegistryEqual(registrar_registry(), registry)); + EXPECT_TRUE(IsDatabaseRegistryEqualToRegistrar()); +} + +TEST_F(WebAppSyncBridgeTest, MergeSyncData_LocalSetLessThanServerSet) { + AppsList local_and_server_apps = CreateAppsList("https://example.com/", 10); + AppsList expected_apps_to_install = + CreateAppsList("https://example.org/", 10); + // These fields are not synced, these are just expected values. + for (std::unique_ptr<WebApp>& expected_app_to_install : + expected_apps_to_install) { + expected_app_to_install->SetIsLocallyInstalled( + AreAppsLocallyInstalledByDefault()); + expected_app_to_install->SetIsInSyncInstall(true); + } + + Registry registry; + InsertAppsListIntoRegistry(®istry, local_and_server_apps); + database_factory().WriteRegistry(registry); + InitSyncBridge(); + + syncer::EntityChangeList sync_data_list; + ConvertAppsListToEntityChangeList(expected_apps_to_install, &sync_data_list); + ConvertAppsListToEntityChangeList(local_and_server_apps, &sync_data_list); + + EXPECT_CALL(processor(), Put(_, _, _)).Times(0); + + base::RunLoop run_loop; + controller().SetInstallWebAppsAfterSyncDelegate(base::BindLambdaForTesting( + [&](std::vector<WebApp*> apps_to_install, + TestWebAppRegistryController::RepeatingInstallCallback callback) { + for (WebApp* app_to_install : apps_to_install) { + // The app must be registered. + EXPECT_TRUE(registrar().GetAppById(app_to_install->app_id())); + // Add the app copy to the expected registry. + registry.emplace(app_to_install->app_id(), + std::make_unique<WebApp>(*app_to_install)); + + // Find the app in expected_apps_to_install set and remove the entry. + bool found = false; + for (const std::unique_ptr<WebApp>& expected_app_to_install : + expected_apps_to_install) { + if (expected_app_to_install->app_id() == app_to_install->app_id()) { + EXPECT_EQ(*expected_app_to_install, *app_to_install); + RemoveWebAppFromAppsList(&expected_apps_to_install, + expected_app_to_install->app_id()); + found = true; + break; + } + } + EXPECT_TRUE(found); + } + + EXPECT_TRUE(expected_apps_to_install.empty()); + + // Run the callbacks to fulfill the contract. + for (WebApp* app_to_install : apps_to_install) { + callback.Run(app_to_install->app_id(), + InstallResultCode::kSuccessNewInstall); + } + + run_loop.Quit(); + })); + + sync_bridge().MergeSyncData(sync_bridge().CreateMetadataChangeList(), + std::move(sync_data_list)); + run_loop.Run(); + + EXPECT_TRUE(IsRegistryEqual(registrar_registry(), registry)); + EXPECT_TRUE(IsDatabaseRegistryEqualToRegistrar()); +} + } // namespace web_app
diff --git a/chrome/chrome_cleaner/BUILD.gn b/chrome/chrome_cleaner/BUILD.gn index fbd2d8d..1671a3f 100644 --- a/chrome/chrome_cleaner/BUILD.gn +++ b/chrome/chrome_cleaner/BUILD.gn
@@ -64,9 +64,6 @@ } test("chrome_cleaner_unittests") { - # Make this target findable from the "all" target used by the builders. - visibility += [ "//.:gn_all" ] - sources = [ "//chrome/chrome_cleaner/test/test_main.cc", ] @@ -126,3 +123,23 @@ ] } } + +group("chrome_cleaner") { + testonly = true + + # Make this target findable from the "all" target used by the builders. + visibility += [ "//.:gn_all" ] + + deps = [ + ":chrome_cleaner_unittests", + "//chrome/chrome_cleaner/executables:chrome_cleanup_tool", + "//chrome/chrome_cleaner/executables:software_reporter_tool", + ] + + if (is_internal_chrome_cleaner_build) { + deps += [ + "${chrome_cleaner_internal_root}:build_targets", + "${chrome_cleaner_internal_root}:test_targets", + ] + } +}
diff --git a/chrome/common/extensions/api/input_method_private.json b/chrome/common/extensions/api/input_method_private.json index 6e3e976..2c4fc78 100644 --- a/chrome/common/extensions/api/input_method_private.json +++ b/chrome/common/extensions/api/input_method_private.json
@@ -243,6 +243,19 @@ } ] }, { + "name": "finishComposingText", + "type": "function", + "description": "Commits the text currently being composed without moving the selected text range", + "parameters": [ + { + "type": "function", + "name": "callback", + "optional": true, + "description": "Called when the operation completes.", + "parameters": [] + } + ] + }, { "name": "notifyImeMenuItemActivated", "type": "function", "description": "Fires the input.ime.onMenuItemActivated event.",
diff --git a/chrome/renderer/extensions/cast_streaming_native_handler.cc b/chrome/renderer/extensions/cast_streaming_native_handler.cc index 46b4abd..455c66c 100644 --- a/chrome/renderer/extensions/cast_streaming_native_handler.cc +++ b/chrome/renderer/extensions/cast_streaming_native_handler.cc
@@ -79,10 +79,11 @@ constexpr int kBitsPerKilobit = 1000; bool HexDecode(const std::string& input, std::string* output) { - std::vector<uint8_t> bytes; - if (!base::HexStringToBytes(input, &bytes)) + DCHECK(output->empty()); + if (!base::HexStringToString(input, output)) { + output->clear(); return false; - output->assign(reinterpret_cast<const char*>(&bytes[0]), bytes.size()); + } return true; }
diff --git a/chrome/services/app_service/BUILD.gn b/chrome/services/app_service/BUILD.gn index 3fa14d2..77d9de0 100644 --- a/chrome/services/app_service/BUILD.gn +++ b/chrome/services/app_service/BUILD.gn
@@ -10,11 +10,13 @@ deps = [ "//base", + "//components/prefs", "//mojo/public/cpp/bindings", + "//services/service_manager/public/cpp", ] public_deps = [ - "//chrome/services//app_service/public/cpp:preferred_apps", + "//chrome/services/app_service/public/cpp:preferred_apps", "//chrome/services/app_service/public/mojom", ] } @@ -28,8 +30,8 @@ deps = [ ":lib", - "//chrome/services//app_service/public/cpp:intents", - "//chrome/services//app_service/public/cpp:preferred_apps", + "//chrome/services/app_service/public/cpp:intents", + "//chrome/services/app_service/public/cpp:preferred_apps", "//testing/gtest", ] }
diff --git a/chrome/services/app_service/app_service_impl.cc b/chrome/services/app_service/app_service_impl.cc index 1ad1e98a..3eee6dfd 100644 --- a/chrome/services/app_service/app_service_impl.cc +++ b/chrome/services/app_service/app_service_impl.cc
@@ -11,6 +11,7 @@ #include "chrome/services/app_service/public/mojom/types.mojom.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" +#include "components/prefs/scoped_user_pref_update.h" #include "services/preferences/public/cpp/pref_service_factory.h" #include "services/service_manager/public/cpp/connector.h" @@ -34,7 +35,6 @@ if (connector) { ConnectToPrefService(connector); } - InitializePreferredApps(); } AppServiceImpl::~AppServiceImpl() = default; @@ -81,7 +81,9 @@ // TODO: store the opts somewhere. // Initialise the Preferred Apps in the Subscribers on register. - subscriber->InitializePreferredApps(preferred_apps_.GetValue()); + if (preferred_apps_.IsInitialized()) { + subscriber->InitializePreferredApps(preferred_apps_.GetValue()); + } // Add the new subscriber to the set. subscribers_.Add(std::move(subscriber)); @@ -173,7 +175,20 @@ const std::string& app_id, apps::mojom::IntentFilterPtr intent_filter, apps::mojom::IntentPtr intent) { + // TODO(crbug.com/853604): Solve the issue where user set preferred app + // before pref connected. + if (!preferred_apps_.IsInitialized()) { + return; + } + preferred_apps_.AddPreferredApp(app_id, intent_filter); + + if (pref_service_) { + DictionaryPrefUpdate update(pref_service_.get(), kAppServicePreferredApps); + DCHECK(PreferredApps::VerifyPreferredApps(update.Get())); + PreferredApps::AddPreferredApp(app_id, intent_filter, update.Get()); + } + for (auto& subscriber : subscribers_) { subscriber->OnPreferredAppSet(app_id, intent_filter->Clone()); } @@ -186,17 +201,21 @@ std::move(intent)); } -void AppServiceImpl::OnPublisherDisconnected(apps::mojom::AppType app_type) { - publishers_.erase(app_type); -} - PreferredApps& AppServiceImpl::GetPreferredAppsForTesting() { return preferred_apps_; } +void AppServiceImpl::OnPublisherDisconnected(apps::mojom::AppType app_type) { + publishers_.erase(app_type); +} + void AppServiceImpl::InitializePreferredApps() { - // TODO(crbug.com/853604): Initialise from disk. - preferred_apps_.Init(nullptr); + DCHECK(pref_service_); + preferred_apps_.Init( + pref_service_->GetDictionary(kAppServicePreferredApps)->CreateDeepCopy()); + for (auto& subscriber : subscribers_) { + subscriber->InitializePreferredApps(preferred_apps_.GetValue()); + } } void AppServiceImpl::ConnectToPrefService( @@ -218,12 +237,13 @@ void AppServiceImpl::OnPrefServiceConnected( std::unique_ptr<PrefService> pref_service) { - if (!pref_service) + if (!pref_service) { + // TODO(crbug.com/853604): Handle if not successfully connected. return; + } DCHECK_EQ(nullptr, pref_service_); pref_service_ = std::move(pref_service); - - // TODO(crbug.com/853604): use the pref service to get and set preference. + InitializePreferredApps(); } } // namespace apps
diff --git a/chrome/services/app_service/app_service_impl_unittest.cc b/chrome/services/app_service/app_service_impl_unittest.cc index 2e97daa..e3a4a2e 100644 --- a/chrome/services/app_service/app_service_impl_unittest.cc +++ b/chrome/services/app_service/app_service_impl_unittest.cc
@@ -253,6 +253,7 @@ TEST_F(AppServiceImplTest, PreferredApps) { // Test Initialize. AppServiceImpl impl(nullptr); + impl.GetPreferredAppsForTesting().Init(nullptr); // TODO(crbug.com/853604): Update this test after reading from disk done. EXPECT_TRUE(impl.GetPreferredAppsForTesting().GetValue().DictEmpty());
diff --git a/chrome/services/app_service/public/cpp/preferred_apps.cc b/chrome/services/app_service/public/cpp/preferred_apps.cc index c7652eb..eafa69a 100644 --- a/chrome/services/app_service/public/cpp/preferred_apps.cc +++ b/chrome/services/app_service/public/cpp/preferred_apps.cc
@@ -89,11 +89,13 @@ auto* condition_type_dict = dict->FindKey(ConditionTypeToString(condition_type)); - if (!condition_type_dict) + if (!condition_type_dict) { return nullptr; + } - if (condition_type != apps::mojom::ConditionType::kPattern) + if (condition_type != apps::mojom::ConditionType::kPattern) { return condition_type_dict->FindKey(value); + } // For pattern matching, we need to go through all patterns and match types // to see if we have a match. @@ -152,11 +154,13 @@ base::Value* dict, base::Optional<std::string>* best_match_app_id) { auto* found_dict = FindDictionaryForTypeAndValue(dict, condition_type, value); - if (!found_dict) + if (!found_dict) { return found_dict; + } std::string* app_id = found_dict->FindStringKey(kAppId); - if (app_id) + if (app_id) { *best_match_app_id = *app_id; + } return found_dict; } @@ -249,20 +253,22 @@ // static // Recursively verifies that the structure of |value| matches what we expect. - +// // |value| should be a dictionary where each item is either: // * key == kAppId and a string value, or // * some other string value with a dictionary value. bool PreferredApps::VerifyPreferredApps(base::Value* value) { - if (!value->is_dict()) + if (!value->is_dict()) { return false; + } bool all_items_valid = true; for (const auto& key_value : value->DictItems()) { bool item_valid = false; - if (key_value.first == kAppId) + if (key_value.first == kAppId) { item_valid = key_value.second.is_string(); - else + } else { item_valid = VerifyPreferredApps(&key_value.second); + } if (!item_valid) { all_items_valid = false; break; @@ -271,6 +277,24 @@ return all_items_valid; } +// static +// Add a preferred app for a preferred app dictionary. +bool PreferredApps::AddPreferredApp( + const std::string& app_id, + const apps::mojom::IntentFilterPtr& intent_filter, + base::Value* preferred_apps) { + if (!preferred_apps) { + return false; + } + + // For an |intent_filter| there could be multiple |conditions|, and for each + // condition, there could be multiple |condition_values|. When we set + // preferred app for and |intent_filter|, we need to add the preferred app for + // all combinations of these |condition_values|. + SetPreferredApp(intent_filter->conditions, 0, preferred_apps, app_id); + return true; +} + void PreferredApps::Init(std::unique_ptr<base::Value> preferred_apps) { if (preferred_apps && VerifyPreferredApps(preferred_apps.get())) { preferred_apps_ = std::move(preferred_apps); @@ -286,21 +310,16 @@ if (!preferred_apps_) { return false; } - - // For an |intent_filter| there could be multiple |conditions|, and for each - // condition, there could be multiple |condition_values|. When we set - // preferred app for and |intent_filter|, we need to add the preferred app for - // all combinations of these |condition_values|. - SetPreferredApp(intent_filter->conditions, 0, preferred_apps_.get(), app_id); - return true; + return AddPreferredApp(app_id, intent_filter, preferred_apps_.get()); } base::Optional<std::string> PreferredApps::FindPreferredAppForIntent( const apps::mojom::IntentPtr& intent) { base::Optional<std::string> best_match_app_id = base::nullopt; - if (!preferred_apps_) + if (!preferred_apps_) { return best_match_app_id; + } // Currently only support intent that has the full URL. if (!intent->scheme.has_value() || !intent->host.has_value() || @@ -314,14 +333,16 @@ auto* scheme_dict = FindDictAndUpdateBestMatchAppId( apps::mojom::ConditionType::kScheme, intent->scheme.value(), preferred_apps_.get(), &best_match_app_id); - if (!scheme_dict) + if (!scheme_dict) { return best_match_app_id; + } auto* host_dict = FindDictAndUpdateBestMatchAppId( apps::mojom::ConditionType::kHost, intent->host.value(), scheme_dict, &best_match_app_id); - if (!host_dict) + if (!host_dict) { return best_match_app_id; + } FindDictAndUpdateBestMatchAppId(apps::mojom::ConditionType::kPattern, intent->path.value(), host_dict, @@ -339,4 +360,8 @@ return preferred_apps_->Clone(); } +bool PreferredApps::IsInitialized() { + return preferred_apps_ != nullptr; +} + } // namespace apps
diff --git a/chrome/services/app_service/public/cpp/preferred_apps.h b/chrome/services/app_service/public/cpp/preferred_apps.h index 7eb9efb9..d084e9d 100644 --- a/chrome/services/app_service/public/cpp/preferred_apps.h +++ b/chrome/services/app_service/public/cpp/preferred_apps.h
@@ -45,6 +45,11 @@ static bool VerifyPreferredApps(base::Value* dict); + // Add a preferred app for an |intent_filter| for |preferred_apps|. + static bool AddPreferredApp(const std::string& app_id, + const apps::mojom::IntentFilterPtr& intent_filter, + base::Value* preferred_apps); + void Init(std::unique_ptr<base::Value> preferred_apps); // Add a preferred app for an |intent_filter|. @@ -61,6 +66,8 @@ // Get a copy of the preferred apps. base::Value GetValue(); + bool IsInitialized(); + private: std::unique_ptr<base::Value> preferred_apps_;
diff --git a/chrome/test/data/webui/extensions/code_section_test.js b/chrome/test/data/webui/extensions/code_section_test.js index b1e1e400..27c3e7e 100644 --- a/chrome/test/data/webui/extensions/code_section_test.js +++ b/chrome/test/data/webui/extensions/code_section_test.js
@@ -8,113 +8,113 @@ import {assert} from 'chrome://resources/js/assert.m.js'; import {isVisible} from '../test_util.m.js'; - window.extension_code_section_tests = {}; - extension_code_section_tests.suiteName = 'ExtensionCodeSectionTest'; - /** @enum {string} */ - extension_code_section_tests.TestNames = { - Layout: 'layout', - LongSource: 'long source', - }; +window.extension_code_section_tests = {}; +extension_code_section_tests.suiteName = 'ExtensionCodeSectionTest'; +/** @enum {string} */ +extension_code_section_tests.TestNames = { + Layout: 'layout', + LongSource: 'long source', +}; - suite(extension_code_section_tests.suiteName, function() { - /** @type {ExtensionsCodeSectionElement} */ - let codeSection; +suite(extension_code_section_tests.suiteName, function() { + /** @type {ExtensionsCodeSectionElement} */ + let codeSection; - const couldNotDisplayCode = 'No code here'; + const couldNotDisplayCode = 'No code here'; - // Initialize an extension item before each test. - setup(function() { - PolymerTest.clearBody(); - codeSection = document.createElement('extensions-code-section'); - codeSection.couldNotDisplayCode = couldNotDisplayCode; - document.body.appendChild(codeSection); - }); + // Initialize an extension item before each test. + setup(function() { + PolymerTest.clearBody(); + codeSection = document.createElement('extensions-code-section'); + codeSection.couldNotDisplayCode = couldNotDisplayCode; + document.body.appendChild(codeSection); + }); - test(assert(extension_code_section_tests.TestNames.Layout), function() { - /** @type {chrome.developerPrivate.RequestFileSourceResponse} */ - const code = { - beforeHighlight: 'this part before the highlight\nAnd this too\n', - highlight: 'highlight this part\n', - afterHighlight: 'this part after the highlight', + test(assert(extension_code_section_tests.TestNames.Layout), function() { + /** @type {chrome.developerPrivate.RequestFileSourceResponse} */ + const code = { + beforeHighlight: 'this part before the highlight\nAnd this too\n', + highlight: 'highlight this part\n', + afterHighlight: 'this part after the highlight', + message: 'Highlight message', + }; + + const testIsVisible = isVisible.bind(null, codeSection); + expectFalse(!!codeSection.code); + expectTrue(codeSection.$$('#scroll-container').hidden); + expectFalse(testIsVisible('#main')); + expectTrue(testIsVisible('#no-code')); + + codeSection.code = code; + codeSection.isActive = true; + expectTrue(testIsVisible('#main')); + expectFalse(testIsVisible('#no-code')); + + let codeSections = + codeSection.shadowRoot.querySelectorAll('#source span span'); + + expectEquals(code.beforeHighlight, codeSections[0].textContent); + expectEquals(code.highlight, codeSections[1].textContent); + expectEquals(code.afterHighlight, codeSections[2].textContent); + + expectEquals( + '1\n2\n3\n4', codeSection.$$('#line-numbers span').textContent.trim()); + }); + + test(assert(extension_code_section_tests.TestNames.LongSource), function() { + /** @type {chrome.developerPrivate.RequestFileSourceResponse} */ + let code; + let lineNums; + + function setCodeContent(beforeLineCount, afterLineCount) { + code = { + beforeHighlight: '', + highlight: 'highlight', + afterHighlight: '', message: 'Highlight message', }; - - const testIsVisible = isVisible.bind(null, codeSection); - expectFalse(!!codeSection.code); - expectTrue(codeSection.$$('#scroll-container').hidden); - expectFalse(testIsVisible('#main')); - expectTrue(testIsVisible('#no-code')); - - codeSection.code = code; - codeSection.isActive = true; - expectTrue(testIsVisible('#main')); - expectFalse(testIsVisible('#no-code')); - - let codeSections = - codeSection.shadowRoot.querySelectorAll('#source span span'); - - expectEquals(code.beforeHighlight, codeSections[0].textContent); - expectEquals(code.highlight, codeSections[1].textContent); - expectEquals(code.afterHighlight, codeSections[2].textContent); - - expectEquals( - '1\n2\n3\n4', codeSection.$$('#line-numbers span').textContent.trim()); - }); - - test(assert(extension_code_section_tests.TestNames.LongSource), function() { - /** @type {chrome.developerPrivate.RequestFileSourceResponse} */ - let code; - let lineNums; - - function setCodeContent(beforeLineCount, afterLineCount) { - code = { - beforeHighlight: '', - highlight: 'highlight', - afterHighlight: '', - message: 'Highlight message', - }; - for (let i = 0; i < beforeLineCount; i++) { - code.beforeHighlight += 'a\n'; - } - for (let i = 0; i < afterLineCount; i++) { - code.afterHighlight += 'a\n'; - } + for (let i = 0; i < beforeLineCount; i++) { + code.beforeHighlight += 'a\n'; } + for (let i = 0; i < afterLineCount; i++) { + code.afterHighlight += 'a\n'; + } + } - setCodeContent(0, 2000); - codeSection.code = code; - lineNums = codeSection.$$('#line-numbers span').textContent; - // Length should be 1000 +- 1. - expectTrue(lineNums.split('\n').length >= 999); - expectTrue(lineNums.split('\n').length <= 1001); - expectTrue(!!lineNums.match(/^1\n/)); - expectTrue(!!lineNums.match(/1000/)); - expectFalse(!!lineNums.match(/1001/)); - expectTrue(codeSection.$$('#line-numbers .more-code.before').hidden); - expectFalse(codeSection.$$('#line-numbers .more-code.after').hidden); + setCodeContent(0, 2000); + codeSection.code = code; + lineNums = codeSection.$$('#line-numbers span').textContent; + // Length should be 1000 +- 1. + expectTrue(lineNums.split('\n').length >= 999); + expectTrue(lineNums.split('\n').length <= 1001); + expectTrue(!!lineNums.match(/^1\n/)); + expectTrue(!!lineNums.match(/1000/)); + expectFalse(!!lineNums.match(/1001/)); + expectTrue(codeSection.$$('#line-numbers .more-code.before').hidden); + expectFalse(codeSection.$$('#line-numbers .more-code.after').hidden); - setCodeContent(1000, 1000); - codeSection.code = code; - lineNums = codeSection.$$('#line-numbers span').textContent; - // Length should be 1000 +- 1. - expectTrue(lineNums.split('\n').length >= 999); - expectTrue(lineNums.split('\n').length <= 1001); - expectFalse(!!lineNums.match(/^1\n/)); - expectTrue(!!lineNums.match(/1000/)); - expectFalse(!!lineNums.match(/1999/)); - expectFalse(codeSection.$$('#line-numbers .more-code.before').hidden); - expectFalse(codeSection.$$('#line-numbers .more-code.after').hidden); + setCodeContent(1000, 1000); + codeSection.code = code; + lineNums = codeSection.$$('#line-numbers span').textContent; + // Length should be 1000 +- 1. + expectTrue(lineNums.split('\n').length >= 999); + expectTrue(lineNums.split('\n').length <= 1001); + expectFalse(!!lineNums.match(/^1\n/)); + expectTrue(!!lineNums.match(/1000/)); + expectFalse(!!lineNums.match(/1999/)); + expectFalse(codeSection.$$('#line-numbers .more-code.before').hidden); + expectFalse(codeSection.$$('#line-numbers .more-code.after').hidden); - setCodeContent(2000, 0); - codeSection.code = code; - lineNums = codeSection.$$('#line-numbers span').textContent; - // Length should be 1000 +- 1. - expectTrue(lineNums.split('\n').length >= 999); - expectTrue(lineNums.split('\n').length <= 1001); - expectFalse(!!lineNums.match(/^1\n/)); - expectTrue(!!lineNums.match(/1002/)); - expectTrue(!!lineNums.match(/2000/)); - expectFalse(codeSection.$$('#line-numbers .more-code.before').hidden); - expectTrue(codeSection.$$('#line-numbers .more-code.after').hidden); - }); + setCodeContent(2000, 0); + codeSection.code = code; + lineNums = codeSection.$$('#line-numbers span').textContent; + // Length should be 1000 +- 1. + expectTrue(lineNums.split('\n').length >= 999); + expectTrue(lineNums.split('\n').length <= 1001); + expectFalse(!!lineNums.match(/^1\n/)); + expectTrue(!!lineNums.match(/1002/)); + expectTrue(!!lineNums.match(/2000/)); + expectFalse(codeSection.$$('#line-numbers .more-code.before').hidden); + expectTrue(codeSection.$$('#line-numbers .more-code.after').hidden); }); +});
diff --git a/chrome/test/data/webui/extensions/detail_view_test.js b/chrome/test/data/webui/extensions/detail_view_test.js index cd53ce5..9d43c48 100644 --- a/chrome/test/data/webui/extensions/detail_view_test.js +++ b/chrome/test/data/webui/extensions/detail_view_test.js
@@ -12,387 +12,384 @@ import {createExtensionInfo, MockItemDelegate} from './test_util.js'; - window.extension_detail_view_tests = {}; - extension_detail_view_tests.suiteName = 'ExtensionDetailViewTest'; - /** @enum {string} */ - extension_detail_view_tests.TestNames = { - Layout: 'layout', - LayoutSource: 'layout of source section', - ClickableElements: 'clickable elements', - Indicator: 'indicator', - Warnings: 'warnings', - }; +window.extension_detail_view_tests = {}; +extension_detail_view_tests.suiteName = 'ExtensionDetailViewTest'; +/** @enum {string} */ +extension_detail_view_tests.TestNames = { + Layout: 'layout', + LayoutSource: 'layout of source section', + ClickableElements: 'clickable elements', + Indicator: 'indicator', + Warnings: 'warnings', +}; - suite(extension_detail_view_tests.suiteName, function() { - /** - * Extension item created before each test. - * @type {Item} - */ - let item; +suite(extension_detail_view_tests.suiteName, function() { + /** + * Extension item created before each test. + * @type {Item} + */ + let item; - /** - * Backing extension data for the item. - * @type {chrome.developerPrivate.ExtensionInfo} - */ - let extensionData; + /** + * Backing extension data for the item. + * @type {chrome.developerPrivate.ExtensionInfo} + */ + let extensionData; - /** @type {MockItemDelegate} */ - let mockDelegate; + /** @type {MockItemDelegate} */ + let mockDelegate; - // Initialize an extension item before each test. - setup(function() { - PolymerTest.clearBody(); - extensionData = createExtensionInfo({ - incognitoAccess: {isEnabled: true, isActive: false}, - fileAccess: {isEnabled: true, isActive: false}, - errorCollection: {isEnabled: true, isActive: false}, - }); - mockDelegate = new MockItemDelegate(); - item = document.createElement('extensions-detail-view'); - item.set('data', extensionData); - item.set('delegate', mockDelegate); - item.set('inDevMode', false); - item.set('incognitoAvailable', true); - item.set('showActivityLog', false); - document.body.appendChild(item); + // Initialize an extension item before each test. + setup(function() { + PolymerTest.clearBody(); + extensionData = createExtensionInfo({ + incognitoAccess: {isEnabled: true, isActive: false}, + fileAccess: {isEnabled: true, isActive: false}, + errorCollection: {isEnabled: true, isActive: false}, }); + mockDelegate = new MockItemDelegate(); + item = document.createElement('extensions-detail-view'); + item.set('data', extensionData); + item.set('delegate', mockDelegate); + item.set('inDevMode', false); + item.set('incognitoAvailable', true); + item.set('showActivityLog', false); + document.body.appendChild(item); + }); - test(assert(extension_detail_view_tests.TestNames.Layout), function() { + test(assert(extension_detail_view_tests.TestNames.Layout), function() { + flush(); + + const testIsVisible = isVisible.bind(null, item); + expectTrue(testIsVisible('#closeButton')); + expectTrue(testIsVisible('#icon')); + expectTrue(testIsVisible('#enable-toggle')); + expectFalse(testIsVisible('#extensions-options')); + expectTrue( + item.$.description.textContent.indexOf('This is an extension') !== -1); + + // Check the checkboxes visibility and state. They should be visible + // only if the associated option is enabled, and checked if the + // associated option is active. + const accessOptions = [ + {key: 'incognitoAccess', id: '#allow-incognito'}, + {key: 'fileAccess', id: '#allow-on-file-urls'}, + {key: 'errorCollection', id: '#collect-errors'}, + ]; + const isChecked = id => item.$$(id).checked; + for (let option of accessOptions) { + expectTrue(isVisible(item, option.id)); + expectFalse(isChecked(option.id), option.id); + item.set('data.' + option.key + '.isEnabled', false); flush(); + expectFalse(isVisible(item, option.id)); + item.set('data.' + option.key + '.isEnabled', true); + item.set('data.' + option.key + '.isActive', true); + flush(); + expectTrue(isVisible(item, option.id)); + expectTrue(isChecked(option.id)); + } - const testIsVisible = isVisible.bind(null, item); - expectTrue(testIsVisible('#closeButton')); - expectTrue(testIsVisible('#icon')); - expectTrue(testIsVisible('#enable-toggle')); - expectFalse(testIsVisible('#extensions-options')); - expectTrue( - item.$.description.textContent.indexOf('This is an extension') !== - -1); + expectFalse(testIsVisible('#dependent-extensions-list')); + item.set( + 'data.dependentExtensions', + [{id: 'aaa', name: 'Dependent1'}, {id: 'bbb', name: 'Dependent2'}]); + flush(); + expectTrue(testIsVisible('#dependent-extensions-list')); + expectEquals( + 2, item.$$('#dependent-extensions-list').querySelectorAll('li').length); - // Check the checkboxes visibility and state. They should be visible - // only if the associated option is enabled, and checked if the - // associated option is active. - const accessOptions = [ - {key: 'incognitoAccess', id: '#allow-incognito'}, - {key: 'fileAccess', id: '#allow-on-file-urls'}, - {key: 'errorCollection', id: '#collect-errors'}, - ]; - const isChecked = id => item.$$(id).checked; - for (let option of accessOptions) { - expectTrue(isVisible(item, option.id)); - expectFalse(isChecked(option.id), option.id); - item.set('data.' + option.key + '.isEnabled', false); + expectFalse(testIsVisible('#permissions-list')); + expectFalse(testIsVisible('#host-access')); + expectFalse(testIsVisible('extensions-runtime-host-permissions')); + + expectTrue(testIsVisible('#no-permissions')); + item.set( + 'data.permissions', + {simplePermissions: ['Permission 1', 'Permission 2']}); + flush(); + expectTrue(testIsVisible('#permissions-list')); + expectEquals(2, item.$$('#permissions-list').querySelectorAll('li').length); + expectFalse(testIsVisible('#no-permissions')); + expectFalse(testIsVisible('#host-access')); + expectFalse(testIsVisible('extensions-runtime-host-permissions')); + + const optionsUrl = + 'chrome-extension://' + extensionData.id + '/options.html'; + item.set('data.optionsPage', {openInTab: true, url: optionsUrl}); + expectTrue(testIsVisible('#extensions-options')); + + expectFalse(testIsVisible('#extensionsActivityLogLink')); + item.set('showActivityLog', true); + flush(); + expectTrue(testIsVisible('#extensionsActivityLogLink')); + + item.set('data.manifestHomePageUrl', 'http://example.com'); + flush(); + expectTrue(testIsVisible('#extensionWebsite')); + item.set('data.manifestHomePageUrl', ''); + flush(); + expectFalse(testIsVisible('#extensionWebsite')); + + item.set('data.webStoreUrl', 'http://example.com'); + flush(); + expectTrue(testIsVisible('#viewInStore')); + item.set('data.webStoreUrl', ''); + flush(); + expectFalse(testIsVisible('#viewInStore')); + + expectFalse(testIsVisible('#id-section')); + expectFalse(testIsVisible('#inspectable-views')); + + item.set('inDevMode', true); + flush(); + expectTrue(testIsVisible('#id-section')); + expectTrue(testIsVisible('#inspectable-views')); + + assertTrue(item.data.incognitoAccess.isEnabled); + item.set('incognitoAvailable', false); + flush(); + expectFalse(testIsVisible('#allow-incognito')); + + item.set('incognitoAvailable', true); + flush(); + expectTrue(testIsVisible('#allow-incognito')); + + // Ensure that the "Extension options" button is disabled when the item + // itself is disabled. + const extensionOptions = item.$$('#extensions-options'); + assertFalse(extensionOptions.disabled); + item.set('data.state', chrome.developerPrivate.ExtensionState.DISABLED); + flush(); + assertTrue(extensionOptions.disabled); + + expectFalse(testIsVisible('.warning-icon')); + item.set('data.runtimeWarnings', ['Dummy warning']); + flush(); + expectTrue(testIsVisible('.warning-icon')); + + expectTrue(testIsVisible('#enable-toggle')); + expectFalse(testIsVisible('#terminated-reload-button')); + item.set('data.state', chrome.developerPrivate.ExtensionState.TERMINATED); + flush(); + expectFalse(testIsVisible('#enable-toggle')); + expectTrue(testIsVisible('#terminated-reload-button')); + + // Ensure that the runtime warning reload button is not visible if there + // are runtime warnings and the extension is terminated. + item.set('data.runtimeWarnings', ['Dummy warning']); + flush(); + expectFalse(testIsVisible('#warnings-reload-button')); + item.set('data.runtimeWarnings', []); + + // Reset item state back to DISABLED. + item.set('data.state', chrome.developerPrivate.ExtensionState.DISABLED); + flush(); + + // Ensure that without runtimeHostPermissions data, the sections are + // hidden. + expectTrue(testIsVisible('#no-site-access')); + expectFalse(testIsVisible('extensions-runtime-host-permissions')); + expectFalse(testIsVisible('extensions-host-permissions-toggle-list')); + + // Adding any runtime host permissions should result in the runtime host + // controls becoming visible. + const allSitesPermissions = { + simplePermissions: [], + runtimeHostPermissions: { + hosts: [{granted: false, host: '<all_urls>'}], + hasAllHosts: true, + hostAccess: chrome.developerPrivate.HostAccess.ON_CLICK, + }, + }; + item.set('data.permissions', allSitesPermissions); + flush(); + expectFalse(testIsVisible('#no-site-access')); + expectTrue(testIsVisible('extensions-runtime-host-permissions')); + expectFalse(testIsVisible('extensions-host-permissions-toggle-list')); + + const someSitesPermissions = { + simplePermissions: [], + runtimeHostPermissions: { + hosts: [ + {granted: true, host: 'https://chromium.org/*'}, + {granted: false, host: 'https://example.com/*'} + ], + hasAllHosts: false, + hostAccess: chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES, + }, + }; + item.set('data.permissions', someSitesPermissions); + flush(); + expectFalse(testIsVisible('#no-site-access')); + expectFalse(testIsVisible('extensions-runtime-host-permissions')); + expectTrue(testIsVisible('extensions-host-permissions-toggle-list')); + }); + + test(assert(extension_detail_view_tests.TestNames.LayoutSource), function() { + item.set('data.location', 'FROM_STORE'); + flush(); + assertEquals('Chrome Web Store', item.$.source.textContent.trim()); + assertFalse(isVisible(item, '#load-path')); + + item.set('data.location', 'THIRD_PARTY'); + flush(); + assertEquals('Added by a third-party', item.$.source.textContent.trim()); + assertFalse(isVisible(item, '#load-path')); + + item.set('data.location', 'UNPACKED'); + item.set('data.prettifiedPath', 'foo/bar/baz/'); + flush(); + assertEquals('Unpacked extension', item.$.source.textContent.trim()); + // Test whether the load path is displayed for unpacked extensions. + assertTrue(isVisible(item, '#load-path')); + + item.set('data.location', 'UNKNOWN'); + item.set('data.prettifiedPath', ''); + // |locationText| is expected to always be set if location is UNKNOWN. + item.set('data.locationText', 'Foo'); + flush(); + assertEquals('Foo', item.$.source.textContent.trim()); + assertFalse(isVisible(item, '#load-path')); + }); + + test( + assert(extension_detail_view_tests.TestNames.ClickableElements), + function() { + const optionsUrl = + 'chrome-extension://' + extensionData.id + '/options.html'; + item.set('data.optionsPage', {openInTab: true, url: optionsUrl}); + item.set('data.prettifiedPath', 'foo/bar/baz/'); + item.set('showActivityLog', true); flush(); - expectFalse(isVisible(item, option.id)); - item.set('data.' + option.key + '.isEnabled', true); - item.set('data.' + option.key + '.isActive', true); - flush(); - expectTrue(isVisible(item, option.id)); - expectTrue(isChecked(option.id)); - } - expectFalse(testIsVisible('#dependent-extensions-list')); - item.set( - 'data.dependentExtensions', - [{id: 'aaa', name: 'Dependent1'}, {id: 'bbb', name: 'Dependent2'}]); - flush(); - expectTrue(testIsVisible('#dependent-extensions-list')); - expectEquals( - 2, - item.$$('#dependent-extensions-list').querySelectorAll('li').length); - - expectFalse(testIsVisible('#permissions-list')); - expectFalse(testIsVisible('#host-access')); - expectFalse(testIsVisible('extensions-runtime-host-permissions')); - - expectTrue(testIsVisible('#no-permissions')); - item.set( - 'data.permissions', - {simplePermissions: ['Permission 1', 'Permission 2']}); - flush(); - expectTrue(testIsVisible('#permissions-list')); - expectEquals( - 2, item.$$('#permissions-list').querySelectorAll('li').length); - expectFalse(testIsVisible('#no-permissions')); - expectFalse(testIsVisible('#host-access')); - expectFalse(testIsVisible('extensions-runtime-host-permissions')); - - const optionsUrl = - 'chrome-extension://' + extensionData.id + '/options.html'; - item.set('data.optionsPage', {openInTab: true, url: optionsUrl}); - expectTrue(testIsVisible('#extensions-options')); - - expectFalse(testIsVisible('#extensionsActivityLogLink')); - item.set('showActivityLog', true); - flush(); - expectTrue(testIsVisible('#extensionsActivityLogLink')); - - item.set('data.manifestHomePageUrl', 'http://example.com'); - flush(); - expectTrue(testIsVisible('#extensionWebsite')); - item.set('data.manifestHomePageUrl', ''); - flush(); - expectFalse(testIsVisible('#extensionWebsite')); - - item.set('data.webStoreUrl', 'http://example.com'); - flush(); - expectTrue(testIsVisible('#viewInStore')); - item.set('data.webStoreUrl', ''); - flush(); - expectFalse(testIsVisible('#viewInStore')); - - expectFalse(testIsVisible('#id-section')); - expectFalse(testIsVisible('#inspectable-views')); - - item.set('inDevMode', true); - flush(); - expectTrue(testIsVisible('#id-section')); - expectTrue(testIsVisible('#inspectable-views')); - - assertTrue(item.data.incognitoAccess.isEnabled); - item.set('incognitoAvailable', false); - flush(); - expectFalse(testIsVisible('#allow-incognito')); - - item.set('incognitoAvailable', true); - flush(); - expectTrue(testIsVisible('#allow-incognito')); - - // Ensure that the "Extension options" button is disabled when the item - // itself is disabled. - const extensionOptions = item.$$('#extensions-options'); - assertFalse(extensionOptions.disabled); - item.set('data.state', chrome.developerPrivate.ExtensionState.DISABLED); - flush(); - assertTrue(extensionOptions.disabled); - - expectFalse(testIsVisible('.warning-icon')); - item.set('data.runtimeWarnings', ['Dummy warning']); - flush(); - expectTrue(testIsVisible('.warning-icon')); - - expectTrue(testIsVisible('#enable-toggle')); - expectFalse(testIsVisible('#terminated-reload-button')); - item.set('data.state', chrome.developerPrivate.ExtensionState.TERMINATED); - flush(); - expectFalse(testIsVisible('#enable-toggle')); - expectTrue(testIsVisible('#terminated-reload-button')); - - // Ensure that the runtime warning reload button is not visible if there - // are runtime warnings and the extension is terminated. - item.set('data.runtimeWarnings', ['Dummy warning']); - flush(); - expectFalse(testIsVisible('#warnings-reload-button')); - item.set('data.runtimeWarnings', []); - - // Reset item state back to DISABLED. - item.set('data.state', chrome.developerPrivate.ExtensionState.DISABLED); - flush(); - - // Ensure that without runtimeHostPermissions data, the sections are - // hidden. - expectTrue(testIsVisible('#no-site-access')); - expectFalse(testIsVisible('extensions-runtime-host-permissions')); - expectFalse(testIsVisible('extensions-host-permissions-toggle-list')); - - // Adding any runtime host permissions should result in the runtime host - // controls becoming visible. - const allSitesPermissions = { - simplePermissions: [], - runtimeHostPermissions: { - hosts: [{granted: false, host: '<all_urls>'}], - hasAllHosts: true, - hostAccess: chrome.developerPrivate.HostAccess.ON_CLICK, - }, - }; - item.set('data.permissions', allSitesPermissions); - flush(); - expectFalse(testIsVisible('#no-site-access')); - expectTrue(testIsVisible('extensions-runtime-host-permissions')); - expectFalse(testIsVisible('extensions-host-permissions-toggle-list')); - - const someSitesPermissions = { - simplePermissions: [], - runtimeHostPermissions: { - hosts: [ - {granted: true, host: 'https://chromium.org/*'}, - {granted: false, host: 'https://example.com/*'} - ], - hasAllHosts: false, - hostAccess: chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES, - }, - }; - item.set('data.permissions', someSitesPermissions); - flush(); - expectFalse(testIsVisible('#no-site-access')); - expectFalse(testIsVisible('extensions-runtime-host-permissions')); - expectTrue(testIsVisible('extensions-host-permissions-toggle-list')); - }); - - test(assert(extension_detail_view_tests.TestNames.LayoutSource), function() { - item.set('data.location', 'FROM_STORE'); - flush(); - assertEquals('Chrome Web Store', item.$.source.textContent.trim()); - assertFalse(isVisible(item, '#load-path')); - - item.set('data.location', 'THIRD_PARTY'); - flush(); - assertEquals('Added by a third-party', item.$.source.textContent.trim()); - assertFalse(isVisible(item, '#load-path')); - - item.set('data.location', 'UNPACKED'); - item.set('data.prettifiedPath', 'foo/bar/baz/'); - flush(); - assertEquals('Unpacked extension', item.$.source.textContent.trim()); - // Test whether the load path is displayed for unpacked extensions. - assertTrue(isVisible(item, '#load-path')); - - item.set('data.location', 'UNKNOWN'); - item.set('data.prettifiedPath', ''); - // |locationText| is expected to always be set if location is UNKNOWN. - item.set('data.locationText', 'Foo'); - flush(); - assertEquals('Foo', item.$.source.textContent.trim()); - assertFalse(isVisible(item, '#load-path')); - }); - - test( - assert(extension_detail_view_tests.TestNames.ClickableElements), - function() { - const optionsUrl = - 'chrome-extension://' + extensionData.id + '/options.html'; - item.set('data.optionsPage', {openInTab: true, url: optionsUrl}); - item.set('data.prettifiedPath', 'foo/bar/baz/'); - item.set('showActivityLog', true); - flush(); - - let currentPage = null; - navigation.addListener(newPage => { - currentPage = newPage; - }); - - // Even though the command line flag is not set for activity log, we - // still expect to navigate to it after clicking the link as the logic - // to redirect the page back to the details view is in manager.js. Since - // this behavior does not happen in the testing environment, we test the - // behavior in manager_test.js. - item.$$('#extensionsActivityLogLink').click(); - expectDeepEquals( - currentPage, - {page: Page.ACTIVITY_LOG, extensionId: extensionData.id}); - - // Reset current page and test delegate calls. - navigation.navigateTo( - {page: Page.DETAILS, extensionId: extensionData.id}); - currentPage = null; - - mockDelegate.testClickingCalls( - item.$$('#allow-incognito').getLabel(), 'setItemAllowedIncognito', - [extensionData.id, true]); - mockDelegate.testClickingCalls( - item.$$('#allow-on-file-urls').getLabel(), - 'setItemAllowedOnFileUrls', [extensionData.id, true]); - mockDelegate.testClickingCalls( - item.$$('#collect-errors').getLabel(), 'setItemCollectsErrors', - [extensionData.id, true]); - mockDelegate.testClickingCalls( - item.$$('#extensions-options'), 'showItemOptionsPage', - [extensionData]); - mockDelegate.testClickingCalls( - item.$$('#remove-extension'), 'deleteItem', [extensionData.id]); - mockDelegate.testClickingCalls( - item.$$('#load-path > a[is=\'action-link\']'), 'showInFolder', - [extensionData.id]); - mockDelegate.testClickingCalls( - item.$$('#warnings-reload-button'), 'reloadItem', - [extensionData.id], Promise.resolve()); - - // Terminate the extension so the reload button appears. - item.set( - 'data.state', chrome.developerPrivate.ExtensionState.TERMINATED); - flush(); - mockDelegate.testClickingCalls( - item.$$('#terminated-reload-button'), 'reloadItem', - [extensionData.id], Promise.resolve()); + let currentPage = null; + navigation.addListener(newPage => { + currentPage = newPage; }); - test(assert(extension_detail_view_tests.TestNames.Indicator), function() { - const indicator = item.$$('cr-tooltip-icon'); - expectTrue(indicator.hidden); - item.set('data.controlledInfo', {type: 'POLICY', text: 'policy'}); - flush(); - expectFalse(indicator.hidden); - }); + // Even though the command line flag is not set for activity log, we + // still expect to navigate to it after clicking the link as the logic + // to redirect the page back to the details view is in manager.js. Since + // this behavior does not happen in the testing environment, we test the + // behavior in manager_test.js. + item.$$('#extensionsActivityLogLink').click(); + expectDeepEquals( + currentPage, + {page: Page.ACTIVITY_LOG, extensionId: extensionData.id}); - test(assert(extension_detail_view_tests.TestNames.Warnings), function() { - const testWarningVisible = function(id, expectVisible) { - const f = expectVisible ? expectTrue : expectFalse; - f(isVisible(item, id)); - }; + // Reset current page and test delegate calls. + navigation.navigateTo( + {page: Page.DETAILS, extensionId: extensionData.id}); + currentPage = null; - testWarningVisible('#runtime-warnings', false); - testWarningVisible('#corrupted-warning', false); - testWarningVisible('#suspicious-warning', false); - testWarningVisible('#blacklisted-warning', false); - testWarningVisible('#update-required-warning', false); + mockDelegate.testClickingCalls( + item.$$('#allow-incognito').getLabel(), 'setItemAllowedIncognito', + [extensionData.id, true]); + mockDelegate.testClickingCalls( + item.$$('#allow-on-file-urls').getLabel(), + 'setItemAllowedOnFileUrls', [extensionData.id, true]); + mockDelegate.testClickingCalls( + item.$$('#collect-errors').getLabel(), 'setItemCollectsErrors', + [extensionData.id, true]); + mockDelegate.testClickingCalls( + item.$$('#extensions-options'), 'showItemOptionsPage', + [extensionData]); + mockDelegate.testClickingCalls( + item.$$('#remove-extension'), 'deleteItem', [extensionData.id]); + mockDelegate.testClickingCalls( + item.$$('#load-path > a[is=\'action-link\']'), 'showInFolder', + [extensionData.id]); + mockDelegate.testClickingCalls( + item.$$('#warnings-reload-button'), 'reloadItem', + [extensionData.id], Promise.resolve()); - item.set('data.runtimeWarnings', ['Dummy warning']); - flush(); - testWarningVisible('#runtime-warnings', true); - testWarningVisible('#corrupted-warning', false); - testWarningVisible('#suspicious-warning', false); - testWarningVisible('#blacklisted-warning', false); - testWarningVisible('#update-required-warning', false); + // Terminate the extension so the reload button appears. + item.set( + 'data.state', chrome.developerPrivate.ExtensionState.TERMINATED); + flush(); + mockDelegate.testClickingCalls( + item.$$('#terminated-reload-button'), 'reloadItem', + [extensionData.id], Promise.resolve()); + }); - item.set('data.disableReasons.corruptInstall', true); - flush(); - testWarningVisible('#runtime-warnings', true); - testWarningVisible('#corrupted-warning', true); - testWarningVisible('#suspicious-warning', false); - testWarningVisible('#blacklisted-warning', false); - testWarningVisible('#update-required-warning', false); - - item.set('data.disableReasons.suspiciousInstall', true); - flush(); - testWarningVisible('#runtime-warnings', true); - testWarningVisible('#corrupted-warning', true); - testWarningVisible('#suspicious-warning', true); - testWarningVisible('#blacklisted-warning', false); - testWarningVisible('#update-required-warning', false); - - item.set('data.blacklistText', 'This item is blacklisted'); - flush(); - testWarningVisible('#runtime-warnings', true); - testWarningVisible('#corrupted-warning', true); - testWarningVisible('#suspicious-warning', true); - testWarningVisible('#blacklisted-warning', true); - testWarningVisible('#update-required-warning', false); - - item.set('data.blacklistText', null); - flush(); - testWarningVisible('#runtime-warnings', true); - testWarningVisible('#corrupted-warning', true); - testWarningVisible('#suspicious-warning', true); - testWarningVisible('#blacklisted-warning', false); - testWarningVisible('#update-required-warning', false); - - item.set('data.disableReasons.updateRequired', true); - flush(); - testWarningVisible('#runtime-warnings', true); - testWarningVisible('#corrupted-warning', true); - testWarningVisible('#suspicious-warning', true); - testWarningVisible('#blacklisted-warning', false); - testWarningVisible('#update-required-warning', true); - - item.set('data.runtimeWarnings', []); - item.set('data.disableReasons.corruptInstall', false); - item.set('data.disableReasons.suspiciousInstall', false); - item.set('data.disableReasons.updateRequired', false); - flush(); - testWarningVisible('#runtime-warnings', false); - testWarningVisible('#corrupted-warning', false); - testWarningVisible('#suspicious-warning', false); - testWarningVisible('#blacklisted-warning', false); - testWarningVisible('#update-required-warning', false); - }); + test(assert(extension_detail_view_tests.TestNames.Indicator), function() { + const indicator = item.$$('cr-tooltip-icon'); + expectTrue(indicator.hidden); + item.set('data.controlledInfo', {type: 'POLICY', text: 'policy'}); + flush(); + expectFalse(indicator.hidden); }); + + test(assert(extension_detail_view_tests.TestNames.Warnings), function() { + const testWarningVisible = function(id, expectVisible) { + const f = expectVisible ? expectTrue : expectFalse; + f(isVisible(item, id)); + }; + + testWarningVisible('#runtime-warnings', false); + testWarningVisible('#corrupted-warning', false); + testWarningVisible('#suspicious-warning', false); + testWarningVisible('#blacklisted-warning', false); + testWarningVisible('#update-required-warning', false); + + item.set('data.runtimeWarnings', ['Dummy warning']); + flush(); + testWarningVisible('#runtime-warnings', true); + testWarningVisible('#corrupted-warning', false); + testWarningVisible('#suspicious-warning', false); + testWarningVisible('#blacklisted-warning', false); + testWarningVisible('#update-required-warning', false); + + item.set('data.disableReasons.corruptInstall', true); + flush(); + testWarningVisible('#runtime-warnings', true); + testWarningVisible('#corrupted-warning', true); + testWarningVisible('#suspicious-warning', false); + testWarningVisible('#blacklisted-warning', false); + testWarningVisible('#update-required-warning', false); + + item.set('data.disableReasons.suspiciousInstall', true); + flush(); + testWarningVisible('#runtime-warnings', true); + testWarningVisible('#corrupted-warning', true); + testWarningVisible('#suspicious-warning', true); + testWarningVisible('#blacklisted-warning', false); + testWarningVisible('#update-required-warning', false); + + item.set('data.blacklistText', 'This item is blacklisted'); + flush(); + testWarningVisible('#runtime-warnings', true); + testWarningVisible('#corrupted-warning', true); + testWarningVisible('#suspicious-warning', true); + testWarningVisible('#blacklisted-warning', true); + testWarningVisible('#update-required-warning', false); + + item.set('data.blacklistText', null); + flush(); + testWarningVisible('#runtime-warnings', true); + testWarningVisible('#corrupted-warning', true); + testWarningVisible('#suspicious-warning', true); + testWarningVisible('#blacklisted-warning', false); + testWarningVisible('#update-required-warning', false); + + item.set('data.disableReasons.updateRequired', true); + flush(); + testWarningVisible('#runtime-warnings', true); + testWarningVisible('#corrupted-warning', true); + testWarningVisible('#suspicious-warning', true); + testWarningVisible('#blacklisted-warning', false); + testWarningVisible('#update-required-warning', true); + + item.set('data.runtimeWarnings', []); + item.set('data.disableReasons.corruptInstall', false); + item.set('data.disableReasons.suspiciousInstall', false); + item.set('data.disableReasons.updateRequired', false); + flush(); + testWarningVisible('#runtime-warnings', false); + testWarningVisible('#corrupted-warning', false); + testWarningVisible('#suspicious-warning', false); + testWarningVisible('#blacklisted-warning', false); + testWarningVisible('#update-required-warning', false); + }); +});
diff --git a/chrome/test/data/webui/extensions/error_page_test.js b/chrome/test/data/webui/extensions/error_page_test.js index 48df47b..b979eed 100644 --- a/chrome/test/data/webui/extensions/error_page_test.js +++ b/chrome/test/data/webui/extensions/error_page_test.js
@@ -13,195 +13,192 @@ import {ClickMock, createExtensionInfo} from './test_util.js'; - window.extension_error_page_tests = {}; - extension_error_page_tests.suiteName = 'ExtensionErrorPageTest'; - /** @enum {string} */ - extension_error_page_tests.TestNames = { - Layout: 'layout', - CodeSection: 'code section', - ErrorSelection: 'error selection', +window.extension_error_page_tests = {}; +extension_error_page_tests.suiteName = 'ExtensionErrorPageTest'; +/** @enum {string} */ +extension_error_page_tests.TestNames = { + Layout: 'layout', + CodeSection: 'code section', + ErrorSelection: 'error selection', +}; + +/** @implements {ErrorPageDelegate} */ +class MockErrorPageDelegate extends ClickMock { + /** @override */ + deleteErrors(extensionId, errorIds, type) {} + + /** @override */ + requestFileSource(args) { + this.requestFileSourceArgs = args; + this.requestFileSourceResolver = new PromiseResolver(); + return this.requestFileSourceResolver.promise; + } +} + +suite(extension_error_page_tests.suiteName, function() { + /** @type {chrome.developerPrivate.ExtensionInfo} */ + let extensionData; + + /** @type {ExtensionsErrorPageElement} */ + let errorPage; + + /** @type {MockErrorPageDelegate} */ + let mockDelegate; + + const extensionId = 'a'.repeat(32); + + // Common data for runtime errors. + const runtimeErrorBase = { + type: chrome.developerPrivate.ErrorType.RUNTIME, + extensionId: extensionId, + fromIncognito: false, }; - /** @implements {ErrorPageDelegate} */ - class MockErrorPageDelegate extends ClickMock { - /** @override */ - deleteErrors(extensionId, errorIds, type) {} + // Common data for manifest errors. + const manifestErrorBase = { + type: chrome.developerPrivate.ErrorType.MANIFEST, + extensionId: extensionId, + fromIncognito: false, + }; - /** @override */ - requestFileSource(args) { - this.requestFileSourceArgs = args; - this.requestFileSourceResolver = new PromiseResolver(); - return this.requestFileSourceResolver.promise; - } - } - - suite(extension_error_page_tests.suiteName, function() { - /** @type {chrome.developerPrivate.ExtensionInfo} */ - let extensionData; - - /** @type {ExtensionsErrorPageElement} */ - let errorPage; - - /** @type {MockErrorPageDelegate} */ - let mockDelegate; - - const extensionId = 'a'.repeat(32); - - // Common data for runtime errors. - const runtimeErrorBase = { - type: chrome.developerPrivate.ErrorType.RUNTIME, - extensionId: extensionId, - fromIncognito: false, - }; - - // Common data for manifest errors. - const manifestErrorBase = { - type: chrome.developerPrivate.ErrorType.MANIFEST, - extensionId: extensionId, - fromIncognito: false, - }; - - // Initialize an extension item before each test. - setup(function() { - PolymerTest.clearBody(); - const runtimeError = Object.assign( - { - source: 'chrome-extension://' + extensionId + '/source.html', - message: 'message', - id: 1, - severity: chrome.developerPrivate.ErrorLevel.ERROR, - }, - runtimeErrorBase); - extensionData = createExtensionInfo({ - runtimeErrors: [runtimeError], - manifestErrors: [], - }); - errorPage = document.createElement('extensions-error-page'); - mockDelegate = new MockErrorPageDelegate(); - errorPage.delegate = mockDelegate; - errorPage.data = extensionData; - document.body.appendChild(errorPage); + // Initialize an extension item before each test. + setup(function() { + PolymerTest.clearBody(); + const runtimeError = Object.assign( + { + source: 'chrome-extension://' + extensionId + '/source.html', + message: 'message', + id: 1, + severity: chrome.developerPrivate.ErrorLevel.ERROR, + }, + runtimeErrorBase); + extensionData = createExtensionInfo({ + runtimeErrors: [runtimeError], + manifestErrors: [], }); - - test(assert(extension_error_page_tests.TestNames.Layout), function() { - flush(); - - const testIsVisible = isVisible.bind(null, errorPage); - expectTrue(testIsVisible('#closeButton')); - expectTrue(testIsVisible('#heading')); - expectTrue(testIsVisible('#errorsList')); - - let errorElements = errorPage.shadowRoot.querySelectorAll('.error-item'); - expectEquals(1, errorElements.length); - let error = errorElements[0]; - expectEquals( - 'message', error.querySelector('.error-message').textContent.trim()); - expectTrue(error.querySelector('iron-icon').icon == 'cr:error'); - - const manifestError = Object.assign( - { - source: 'manifest.json', - message: 'invalid key', - id: 2, - manifestKey: 'permissions', - }, - manifestErrorBase); - errorPage.set('data.manifestErrors', [manifestError]); - flush(); - errorElements = errorPage.shadowRoot.querySelectorAll('.error-item'); - expectEquals(2, errorElements.length); - error = errorElements[0]; - expectEquals( - 'invalid key', - error.querySelector('.error-message').textContent.trim()); - expectTrue(error.querySelector('iron-icon').icon == 'cr:warning'); - - mockDelegate.testClickingCalls( - error.querySelector('.icon-delete-gray'), 'deleteErrors', - [extensionId, [manifestError.id]]); - }); - - test( - assert(extension_error_page_tests.TestNames.CodeSection), - function(done) { - flush(); - - assertTrue(!!mockDelegate.requestFileSourceArgs); - const args = mockDelegate.requestFileSourceArgs; - expectEquals(extensionId, args.extensionId); - expectEquals('source.html', args.pathSuffix); - expectEquals('message', args.message); - - expectTrue(!!mockDelegate.requestFileSourceResolver); - const code = { - beforeHighlight: 'foo', - highlight: 'bar', - afterHighlight: 'baz', - message: 'quu', - }; - mockDelegate.requestFileSourceResolver.resolve(code); - mockDelegate.requestFileSourceResolver.promise.then(function() { - flush(); - expectEquals(code, errorPage.$$('extensions-code-section').code); - done(); - }); - }); - - test(assert(extension_error_page_tests.TestNames.ErrorSelection), - function() { - const nextRuntimeError = Object.assign( - { - source: 'chrome-extension://' + extensionId + '/other_source.html', - message: 'Other error', - id: 2, - severity: chrome.developerPrivate.ErrorLevel.ERROR, - renderProcessId: 111, - renderViewId: 222, - canInspect: true, - contextUrl: 'http://test.com', - stackTrace: [{url: 'url', lineNumber: 123, columnNumber: 321}], - }, - runtimeErrorBase); - // Add a new runtime error to the end. - errorPage.push('data.runtimeErrors', nextRuntimeError); - flush(); - - const errorElements = - errorPage.shadowRoot.querySelectorAll('.error-item .start'); - const ironCollapses = - errorPage.shadowRoot.querySelectorAll('iron-collapse'); - expectEquals(2, errorElements.length); - expectEquals(2, ironCollapses.length); - - // The first error should be focused by default, and we should have - // requested the source for it. - expectEquals( - extensionData.runtimeErrors[0], errorPage.getSelectedError()); - expectTrue(!!mockDelegate.requestFileSourceArgs); - let args = mockDelegate.requestFileSourceArgs; - expectEquals('source.html', args.pathSuffix); - expectTrue(ironCollapses[0].opened); - expectFalse(ironCollapses[1].opened); - mockDelegate.requestFileSourceResolver.resolve(null); - - mockDelegate.requestFileSourceResolver = new PromiseResolver(); - mockDelegate.requestFileSourceArgs = undefined; - - // Tap the second error. It should now be selected and we should request - // the source for it. - errorElements[1].click(); - expectEquals(nextRuntimeError, errorPage.getSelectedError()); - expectTrue(!!mockDelegate.requestFileSourceArgs); - args = mockDelegate.requestFileSourceArgs; - expectEquals('other_source.html', args.pathSuffix); - expectTrue(ironCollapses[1].opened); - expectFalse(ironCollapses[0].opened); - - expectEquals( - 'Unknown', - ironCollapses[0].querySelector('.context-url').textContent.trim()); - expectEquals( - nextRuntimeError.contextUrl, - ironCollapses[1].querySelector('.context-url').textContent.trim()); - }); + errorPage = document.createElement('extensions-error-page'); + mockDelegate = new MockErrorPageDelegate(); + errorPage.delegate = mockDelegate; + errorPage.data = extensionData; + document.body.appendChild(errorPage); }); + + test(assert(extension_error_page_tests.TestNames.Layout), function() { + flush(); + + const testIsVisible = isVisible.bind(null, errorPage); + expectTrue(testIsVisible('#closeButton')); + expectTrue(testIsVisible('#heading')); + expectTrue(testIsVisible('#errorsList')); + + let errorElements = errorPage.shadowRoot.querySelectorAll('.error-item'); + expectEquals(1, errorElements.length); + let error = errorElements[0]; + expectEquals( + 'message', error.querySelector('.error-message').textContent.trim()); + expectTrue(error.querySelector('iron-icon').icon == 'cr:error'); + + const manifestError = Object.assign( + { + source: 'manifest.json', + message: 'invalid key', + id: 2, + manifestKey: 'permissions', + }, + manifestErrorBase); + errorPage.set('data.manifestErrors', [manifestError]); + flush(); + errorElements = errorPage.shadowRoot.querySelectorAll('.error-item'); + expectEquals(2, errorElements.length); + error = errorElements[0]; + expectEquals( + 'invalid key', + error.querySelector('.error-message').textContent.trim()); + expectTrue(error.querySelector('iron-icon').icon == 'cr:warning'); + + mockDelegate.testClickingCalls( + error.querySelector('.icon-delete-gray'), 'deleteErrors', + [extensionId, [manifestError.id]]); + }); + + test( + assert(extension_error_page_tests.TestNames.CodeSection), function(done) { + flush(); + + assertTrue(!!mockDelegate.requestFileSourceArgs); + const args = mockDelegate.requestFileSourceArgs; + expectEquals(extensionId, args.extensionId); + expectEquals('source.html', args.pathSuffix); + expectEquals('message', args.message); + + expectTrue(!!mockDelegate.requestFileSourceResolver); + const code = { + beforeHighlight: 'foo', + highlight: 'bar', + afterHighlight: 'baz', + message: 'quu', + }; + mockDelegate.requestFileSourceResolver.resolve(code); + mockDelegate.requestFileSourceResolver.promise.then(function() { + flush(); + expectEquals(code, errorPage.$$('extensions-code-section').code); + done(); + }); + }); + + test(assert(extension_error_page_tests.TestNames.ErrorSelection), function() { + const nextRuntimeError = Object.assign( + { + source: 'chrome-extension://' + extensionId + '/other_source.html', + message: 'Other error', + id: 2, + severity: chrome.developerPrivate.ErrorLevel.ERROR, + renderProcessId: 111, + renderViewId: 222, + canInspect: true, + contextUrl: 'http://test.com', + stackTrace: [{url: 'url', lineNumber: 123, columnNumber: 321}], + }, + runtimeErrorBase); + // Add a new runtime error to the end. + errorPage.push('data.runtimeErrors', nextRuntimeError); + flush(); + + const errorElements = + errorPage.shadowRoot.querySelectorAll('.error-item .start'); + const ironCollapses = + errorPage.shadowRoot.querySelectorAll('iron-collapse'); + expectEquals(2, errorElements.length); + expectEquals(2, ironCollapses.length); + + // The first error should be focused by default, and we should have + // requested the source for it. + expectEquals(extensionData.runtimeErrors[0], errorPage.getSelectedError()); + expectTrue(!!mockDelegate.requestFileSourceArgs); + let args = mockDelegate.requestFileSourceArgs; + expectEquals('source.html', args.pathSuffix); + expectTrue(ironCollapses[0].opened); + expectFalse(ironCollapses[1].opened); + mockDelegate.requestFileSourceResolver.resolve(null); + + mockDelegate.requestFileSourceResolver = new PromiseResolver(); + mockDelegate.requestFileSourceArgs = undefined; + + // Tap the second error. It should now be selected and we should request + // the source for it. + errorElements[1].click(); + expectEquals(nextRuntimeError, errorPage.getSelectedError()); + expectTrue(!!mockDelegate.requestFileSourceArgs); + args = mockDelegate.requestFileSourceArgs; + expectEquals('other_source.html', args.pathSuffix); + expectTrue(ironCollapses[1].opened); + expectFalse(ironCollapses[0].opened); + + expectEquals( + 'Unknown', + ironCollapses[0].querySelector('.context-url').textContent.trim()); + expectEquals( + nextRuntimeError.contextUrl, + ironCollapses[1].querySelector('.context-url').textContent.trim()); + }); +});
diff --git a/chrome/test/data/webui/extensions/item_list_test.js b/chrome/test/data/webui/extensions/item_list_test.js index 3b95cbd..8d867cab 100644 --- a/chrome/test/data/webui/extensions/item_list_test.js +++ b/chrome/test/data/webui/extensions/item_list_test.js
@@ -10,110 +10,109 @@ import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {createExtensionInfo, testVisible} from './test_util.js'; - window.extension_item_list_tests = {}; - extension_item_list_tests.suiteName = 'ExtensionItemListTest'; - /** @enum {string} */ - extension_item_list_tests.TestNames = { - Filtering: 'item list filtering', - NoItemsMsg: 'empty item list', - NoSearchResultsMsg: 'empty item list filtering results', - LoadTimeData: 'loadTimeData contains isManaged and managedByOrg', - }; +window.extension_item_list_tests = {}; +extension_item_list_tests.suiteName = 'ExtensionItemListTest'; +/** @enum {string} */ +extension_item_list_tests.TestNames = { + Filtering: 'item list filtering', + NoItemsMsg: 'empty item list', + NoSearchResultsMsg: 'empty item list filtering results', + LoadTimeData: 'loadTimeData contains isManaged and managedByOrg', +}; - suite(extension_item_list_tests.suiteName, function() { - /** @type {extensions.ItemList} */ - let itemList; - let boundTestVisible; +suite(extension_item_list_tests.suiteName, function() { + /** @type {extensions.ItemList} */ + let itemList; + let boundTestVisible; - // Initialize an extension item before each test. - setup(function() { - PolymerTest.clearBody(); - itemList = document.createElement('extensions-item-list'); - boundTestVisible = testVisible.bind(null, itemList); + // Initialize an extension item before each test. + setup(function() { + PolymerTest.clearBody(); + itemList = document.createElement('extensions-item-list'); + boundTestVisible = testVisible.bind(null, itemList); - const createExt = createExtensionInfo; - const extensionItems = [ - createExt({name: 'Alpha', id: 'a'.repeat(32)}), - createExt({name: 'Bravo', id: 'b'.repeat(32)}), - createExt({name: 'Charlie', id: 'c'.repeat(32)}) - ]; - const appItems = [ - createExt({name: 'QQ', id: 'q'.repeat(32)}), - ]; - itemList.extensions = extensionItems; - itemList.apps = appItems; - itemList.filter = ''; - document.body.appendChild(itemList); - }); - - test(assert(extension_item_list_tests.TestNames.Filtering), function() { - function itemLengthEquals(num) { - flush(); - expectEquals( - itemList.shadowRoot.querySelectorAll('extensions-item').length, - num); - } - - // We should initially show all the items. - itemLengthEquals(4); - - // All extension items have an 'a'. - itemList.filter = 'a'; - itemLengthEquals(3); - // Filtering is case-insensitive, so all extension items should be shown. - itemList.filter = 'A'; - itemLengthEquals(3); - // Only 'Bravo' has a 'b'. - itemList.filter = 'b'; - itemLengthEquals(1); - expectEquals('Bravo', itemList.$$('extensions-item').data.name); - // Test inner substring (rather than prefix). - itemList.filter = 'lph'; - itemLengthEquals(1); - expectEquals('Alpha', itemList.$$('extensions-item').data.name); - // Test trailing/leading spaces. - itemList.filter = ' Alpha '; - itemLengthEquals(1); - expectEquals('Alpha', itemList.$$('extensions-item').data.name); - // Test string with no matching items. - itemList.filter = 'z'; - itemLengthEquals(0); - // A filter of '' should reset to show all items. - itemList.filter = ''; - itemLengthEquals(4); - // A filter of 'q' should should show just the apps item. - itemList.filter = 'q'; - itemLengthEquals(1); - }); - - test(assert(extension_item_list_tests.TestNames.NoItemsMsg), function() { - flush(); - boundTestVisible('#no-items', false); - boundTestVisible('#no-search-results', false); - - itemList.extensions = []; - itemList.apps = []; - flush(); - boundTestVisible('#no-items', true); - boundTestVisible('#no-search-results', false); - }); - - test( - assert(extension_item_list_tests.TestNames.NoSearchResultsMsg), - function() { - flush(); - boundTestVisible('#no-items', false); - boundTestVisible('#no-search-results', false); - - itemList.filter = 'non-existent name'; - flush(); - boundTestVisible('#no-items', false); - boundTestVisible('#no-search-results', true); - }); - - test(assert(extension_item_list_tests.TestNames.LoadTimeData), function() { - // Check that loadTimeData contains these values. - loadTimeData.getBoolean('isManaged'); - loadTimeData.getString('browserManagedByOrg'); - }); + const createExt = createExtensionInfo; + const extensionItems = [ + createExt({name: 'Alpha', id: 'a'.repeat(32)}), + createExt({name: 'Bravo', id: 'b'.repeat(32)}), + createExt({name: 'Charlie', id: 'c'.repeat(32)}) + ]; + const appItems = [ + createExt({name: 'QQ', id: 'q'.repeat(32)}), + ]; + itemList.extensions = extensionItems; + itemList.apps = appItems; + itemList.filter = ''; + document.body.appendChild(itemList); }); + + test(assert(extension_item_list_tests.TestNames.Filtering), function() { + function itemLengthEquals(num) { + flush(); + expectEquals( + itemList.shadowRoot.querySelectorAll('extensions-item').length, num); + } + + // We should initially show all the items. + itemLengthEquals(4); + + // All extension items have an 'a'. + itemList.filter = 'a'; + itemLengthEquals(3); + // Filtering is case-insensitive, so all extension items should be shown. + itemList.filter = 'A'; + itemLengthEquals(3); + // Only 'Bravo' has a 'b'. + itemList.filter = 'b'; + itemLengthEquals(1); + expectEquals('Bravo', itemList.$$('extensions-item').data.name); + // Test inner substring (rather than prefix). + itemList.filter = 'lph'; + itemLengthEquals(1); + expectEquals('Alpha', itemList.$$('extensions-item').data.name); + // Test trailing/leading spaces. + itemList.filter = ' Alpha '; + itemLengthEquals(1); + expectEquals('Alpha', itemList.$$('extensions-item').data.name); + // Test string with no matching items. + itemList.filter = 'z'; + itemLengthEquals(0); + // A filter of '' should reset to show all items. + itemList.filter = ''; + itemLengthEquals(4); + // A filter of 'q' should should show just the apps item. + itemList.filter = 'q'; + itemLengthEquals(1); + }); + + test(assert(extension_item_list_tests.TestNames.NoItemsMsg), function() { + flush(); + boundTestVisible('#no-items', false); + boundTestVisible('#no-search-results', false); + + itemList.extensions = []; + itemList.apps = []; + flush(); + boundTestVisible('#no-items', true); + boundTestVisible('#no-search-results', false); + }); + + test( + assert(extension_item_list_tests.TestNames.NoSearchResultsMsg), + function() { + flush(); + boundTestVisible('#no-items', false); + boundTestVisible('#no-search-results', false); + + itemList.filter = 'non-existent name'; + flush(); + boundTestVisible('#no-items', false); + boundTestVisible('#no-search-results', true); + }); + + test(assert(extension_item_list_tests.TestNames.LoadTimeData), function() { + // Check that loadTimeData contains these values. + loadTimeData.getBoolean('isManaged'); + loadTimeData.getString('browserManagedByOrg'); + }); +});
diff --git a/chrome/test/data/webui/extensions/item_test.js b/chrome/test/data/webui/extensions/item_test.js index c5fdce4..6ccf944 100644 --- a/chrome/test/data/webui/extensions/item_test.js +++ b/chrome/test/data/webui/extensions/item_test.js
@@ -14,342 +14,341 @@ import {TestService} from './test_service.js'; import {createExtensionInfo, MockItemDelegate, testVisible} from './test_util.js'; +/** + * The data used to populate the extension item. + * @type {chrome.developerPrivate.ExtensionInfo} + */ +const extensionData = createExtensionInfo(); + +// The normal elements, which should always be shown. +const normalElements = [ + {selector: '#name', text: extensionData.name}, + {selector: '#icon'}, + {selector: '#description', text: extensionData.description}, + {selector: '#enable-toggle'}, + {selector: '#detailsButton'}, + {selector: '#remove-button'}, +]; +// The developer elements, which should only be shown if in developer +// mode *and* showing details. +const devElements = [ + {selector: '#version', text: extensionData.version}, + {selector: '#extension-id', text: `ID: ${extensionData.id}`}, + {selector: '#inspect-views'}, + {selector: '#inspect-views a[is="action-link"]', text: 'foo.html,'}, + { + selector: '#inspect-views a[is="action-link"]:nth-of-type(2)', + text: '1 more…' + }, +]; + +/** + * Tests that the elements' visibility matches the expected visibility. + * @param {Item} item + * @param {Array<Object<string>>} elements + * @param {boolean} visibility + */ +function testElementsVisibility(item, elements, visibility) { + elements.forEach(function(element) { + testVisible(item, element.selector, visibility, element.text); + }); +} + +/** Tests that normal elements are visible. */ +function testNormalElementsAreVisible(item) { + testElementsVisibility(item, normalElements, true); +} + +/** Tests that normal elements are hidden. */ +function testNormalElementsAreHidden(item) { + testElementsVisibility(item, normalElements, false); +} + +/** Tests that dev elements are visible. */ +function testDeveloperElementsAreVisible(item) { + testElementsVisibility(item, devElements, true); +} + +/** Tests that dev elements are hidden. */ +function testDeveloperElementsAreHidden(item) { + testElementsVisibility(item, devElements, false); +} + +window.extension_item_tests = {}; +extension_item_tests.suiteName = 'ExtensionItemTest'; +/** @enum {string} */ +extension_item_tests.TestNames = { + ElementVisibilityNormalState: 'element visibility: normal state', + ElementVisibilityDeveloperState: + 'element visibility: after enabling developer mode', + ClickableItems: 'clickable items', + FailedReloadFiresLoadError: 'failed reload fires load error', + Warnings: 'warnings', + SourceIndicator: 'source indicator', + EnableToggle: 'toggle is disabled when necessary', + RemoveButton: 'remove button hidden when necessary', + HtmlInName: 'html in extension name', +}; + +suite(extension_item_tests.suiteName, function() { /** - * The data used to populate the extension item. - * @type {chrome.developerPrivate.ExtensionInfo} + * Extension item created before each test. + * @type {Item} */ - const extensionData = createExtensionInfo(); + let item; - // The normal elements, which should always be shown. - const normalElements = [ - {selector: '#name', text: extensionData.name}, - {selector: '#icon'}, - {selector: '#description', text: extensionData.description}, - {selector: '#enable-toggle'}, - {selector: '#detailsButton'}, - {selector: '#remove-button'}, - ]; - // The developer elements, which should only be shown if in developer - // mode *and* showing details. - const devElements = [ - {selector: '#version', text: extensionData.version}, - {selector: '#extension-id', text: `ID: ${extensionData.id}`}, - {selector: '#inspect-views'}, - {selector: '#inspect-views a[is="action-link"]', text: 'foo.html,'}, - { - selector: '#inspect-views a[is="action-link"]:nth-of-type(2)', - text: '1 more…' - }, - ]; + /** @type {MockItemDelegate} */ + let mockDelegate; - /** - * Tests that the elements' visibility matches the expected visibility. - * @param {Item} item - * @param {Array<Object<string>>} elements - * @param {boolean} visibility - */ - function testElementsVisibility(item, elements, visibility) { - elements.forEach(function(element) { - testVisible(item, element.selector, visibility, element.text); - }); - } + // Initialize an extension item before each test. + setup(function() { + PolymerTest.clearBody(); + mockDelegate = new MockItemDelegate(); + item = document.createElement('extensions-item'); + item.data = createExtensionInfo(); + item.delegate = mockDelegate; + document.body.appendChild(item); + const toastManager = document.createElement('cr-toast-manager'); + document.body.appendChild(toastManager); + }); - /** Tests that normal elements are visible. */ - function testNormalElementsAreVisible(item) { - testElementsVisibility(item, normalElements, true); - } + test( + assert(extension_item_tests.TestNames.ElementVisibilityNormalState), + function() { + testNormalElementsAreVisible(item); + testDeveloperElementsAreHidden(item); - /** Tests that normal elements are hidden. */ - function testNormalElementsAreHidden(item) { - testElementsVisibility(item, normalElements, false); - } - - /** Tests that dev elements are visible. */ - function testDeveloperElementsAreVisible(item) { - testElementsVisibility(item, devElements, true); - } - - /** Tests that dev elements are hidden. */ - function testDeveloperElementsAreHidden(item) { - testElementsVisibility(item, devElements, false); - } - - window.extension_item_tests = {}; - extension_item_tests.suiteName = 'ExtensionItemTest'; - /** @enum {string} */ - extension_item_tests.TestNames = { - ElementVisibilityNormalState: 'element visibility: normal state', - ElementVisibilityDeveloperState: - 'element visibility: after enabling developer mode', - ClickableItems: 'clickable items', - FailedReloadFiresLoadError: 'failed reload fires load error', - Warnings: 'warnings', - SourceIndicator: 'source indicator', - EnableToggle: 'toggle is disabled when necessary', - RemoveButton: 'remove button hidden when necessary', - HtmlInName: 'html in extension name', - }; - - suite(extension_item_tests.suiteName, function() { - /** - * Extension item created before each test. - * @type {Item} - */ - let item; - - /** @type {MockItemDelegate} */ - let mockDelegate; - - // Initialize an extension item before each test. - setup(function() { - PolymerTest.clearBody(); - mockDelegate = new MockItemDelegate(); - item = document.createElement('extensions-item'); - item.data = createExtensionInfo(); - item.delegate = mockDelegate; - document.body.appendChild(item); - const toastManager = document.createElement('cr-toast-manager'); - document.body.appendChild(toastManager); - }); - - test( - assert(extension_item_tests.TestNames.ElementVisibilityNormalState), - function() { - testNormalElementsAreVisible(item); - testDeveloperElementsAreHidden(item); - - expectTrue(item.$['enable-toggle'].checked); - item.set('data.state', 'DISABLED'); - expectFalse(item.$['enable-toggle'].checked); - item.set('data.state', 'BLACKLISTED'); - expectFalse(item.$['enable-toggle'].checked); - }); - - test( - assert(extension_item_tests.TestNames.ElementVisibilityDeveloperState), - function() { - item.set('inDevMode', true); - - testNormalElementsAreVisible(item); - testDeveloperElementsAreVisible(item); - - // Developer reload button should be visible only for enabled unpacked - // extensions. - testVisible(item, '#dev-reload-button', false); - - item.set('data.location', chrome.developerPrivate.Location.UNPACKED); - flush(); - testVisible(item, '#dev-reload-button', true); - - item.set('data.state', chrome.developerPrivate.ExtensionState.DISABLED); - flush(); - testVisible(item, '#dev-reload-button', false); - - item.set( - 'data.state', chrome.developerPrivate.ExtensionState.TERMINATED); - flush(); - testVisible(item, '#dev-reload-button', false); - }); - - /** Tests that the delegate methods are correctly called. */ - test(assert(extension_item_tests.TestNames.ClickableItems), function() { - item.set('inDevMode', true); - - mockDelegate.testClickingCalls( - item.$['remove-button'], 'deleteItem', [item.data.id]); - mockDelegate.testClickingCalls( - item.$['enable-toggle'], 'setItemEnabled', [item.data.id, false]); - mockDelegate.testClickingCalls( - item.$$('#inspect-views a[is="action-link"]'), 'inspectItemView', - [item.data.id, item.data.views[0]]); - - // Setup for testing navigation buttons. - let currentPage = null; - navigation.addListener(newPage => { - currentPage = newPage; + expectTrue(item.$['enable-toggle'].checked); + item.set('data.state', 'DISABLED'); + expectFalse(item.$['enable-toggle'].checked); + item.set('data.state', 'BLACKLISTED'); + expectFalse(item.$['enable-toggle'].checked); }); - tap(item.$$('#detailsButton')); - expectDeepEquals( - currentPage, {page: Page.DETAILS, extensionId: item.data.id}); + test( + assert(extension_item_tests.TestNames.ElementVisibilityDeveloperState), + function() { + item.set('inDevMode', true); - // Reset current page and test inspect-view navigation. - navigation.navigateTo({page: Page.LIST}); - currentPage = null; - tap(item.$$('#inspect-views a[is="action-link"]:nth-of-type(2)')); - expectDeepEquals( - currentPage, {page: Page.DETAILS, extensionId: item.data.id}); + testNormalElementsAreVisible(item); + testDeveloperElementsAreVisible(item); - item.set('data.disableReasons.corruptInstall', true); - flush(); - mockDelegate.testClickingCalls( - item.$$('#repair-button'), 'repairItem', [item.data.id]); + // Developer reload button should be visible only for enabled unpacked + // extensions. + testVisible(item, '#dev-reload-button', false); - item.set('data.state', chrome.developerPrivate.ExtensionState.TERMINATED); - flush(); - mockDelegate.testClickingCalls( - item.$$('#terminated-reload-button'), 'reloadItem', [item.data.id], - Promise.resolve()); + item.set('data.location', chrome.developerPrivate.Location.UNPACKED); + flush(); + testVisible(item, '#dev-reload-button', true); - item.set('data.location', chrome.developerPrivate.Location.UNPACKED); - item.set('data.state', chrome.developerPrivate.ExtensionState.ENABLED); - flush(); + item.set('data.state', chrome.developerPrivate.ExtensionState.DISABLED); + flush(); + testVisible(item, '#dev-reload-button', false); + + item.set( + 'data.state', chrome.developerPrivate.ExtensionState.TERMINATED); + flush(); + testVisible(item, '#dev-reload-button', false); + }); + + /** Tests that the delegate methods are correctly called. */ + test(assert(extension_item_tests.TestNames.ClickableItems), function() { + item.set('inDevMode', true); + + mockDelegate.testClickingCalls( + item.$['remove-button'], 'deleteItem', [item.data.id]); + mockDelegate.testClickingCalls( + item.$['enable-toggle'], 'setItemEnabled', [item.data.id, false]); + mockDelegate.testClickingCalls( + item.$$('#inspect-views a[is="action-link"]'), 'inspectItemView', + [item.data.id, item.data.views[0]]); + + // Setup for testing navigation buttons. + let currentPage = null; + navigation.addListener(newPage => { + currentPage = newPage; }); - /** Tests that the reload button properly fires the load-error event. */ - test( - assert(extension_item_tests.TestNames.FailedReloadFiresLoadError), - function() { - item.set('inDevMode', true); - item.set('data.location', chrome.developerPrivate.Location.UNPACKED); - flush(); - testVisible(item, '#dev-reload-button', true); + tap(item.$$('#detailsButton')); + expectDeepEquals( + currentPage, {page: Page.DETAILS, extensionId: item.data.id}); - // Check clicking the reload button. The reload button should fire a - // load-error event if and only if the reload fails (indicated by a - // rejected promise). - // This is a bit of a pain to verify because the promises finish - // asynchronously, so we have to use setTimeout()s. - let firedLoadError = false; - item.addEventListener('load-error', () => { - firedLoadError = true; - }); + // Reset current page and test inspect-view navigation. + navigation.navigateTo({page: Page.LIST}); + currentPage = null; + tap(item.$$('#inspect-views a[is="action-link"]:nth-of-type(2)')); + expectDeepEquals( + currentPage, {page: Page.DETAILS, extensionId: item.data.id}); - // This is easier to test with a TestBrowserProxy-style delegate. - const proxyDelegate = new TestService(); - item.delegate = proxyDelegate; + item.set('data.disableReasons.corruptInstall', true); + flush(); + mockDelegate.testClickingCalls( + item.$$('#repair-button'), 'repairItem', [item.data.id]); - const verifyEventPromise = function(expectCalled) { - return new Promise((resolve, reject) => { - setTimeout(() => { - expectEquals(expectCalled, firedLoadError); - resolve(); - }); - }); - }; + item.set('data.state', chrome.developerPrivate.ExtensionState.TERMINATED); + flush(); + mockDelegate.testClickingCalls( + item.$$('#terminated-reload-button'), 'reloadItem', [item.data.id], + Promise.resolve()); - tap(item.$$('#dev-reload-button')); - return proxyDelegate.whenCalled('reloadItem') - .then(function(id) { - expectEquals(item.data.id, id); - return verifyEventPromise(false); - }) - .then(function() { - proxyDelegate.resetResolver('reloadItem'); - proxyDelegate.setForceReloadItemError(true); - tap(item.$$('#dev-reload-button')); - return proxyDelegate.whenCalled('reloadItem'); - }) - .then(function(id) { - expectEquals(item.data.id, id); - return verifyEventPromise(true); - }); + item.set('data.location', chrome.developerPrivate.Location.UNPACKED); + item.set('data.state', chrome.developerPrivate.ExtensionState.ENABLED); + flush(); + }); + + /** Tests that the reload button properly fires the load-error event. */ + test( + assert(extension_item_tests.TestNames.FailedReloadFiresLoadError), + function() { + item.set('inDevMode', true); + item.set('data.location', chrome.developerPrivate.Location.UNPACKED); + flush(); + testVisible(item, '#dev-reload-button', true); + + // Check clicking the reload button. The reload button should fire a + // load-error event if and only if the reload fails (indicated by a + // rejected promise). + // This is a bit of a pain to verify because the promises finish + // asynchronously, so we have to use setTimeout()s. + let firedLoadError = false; + item.addEventListener('load-error', () => { + firedLoadError = true; }); - test(assert(extension_item_tests.TestNames.Warnings), function() { - const kCorrupt = 1 << 0; - const kSuspicious = 1 << 1; - const kBlacklisted = 1 << 2; - const kRuntime = 1 << 3; + // This is easier to test with a TestBrowserProxy-style delegate. + const proxyDelegate = new TestService(); + item.delegate = proxyDelegate; - function assertWarnings(mask) { - assertEquals( - !!(mask & kCorrupt), isVisible(item, '#corrupted-warning')); - assertEquals( - !!(mask & kSuspicious), isVisible(item, '#suspicious-warning')); - assertEquals( - !!(mask & kBlacklisted), isVisible(item, '#blacklisted-warning')); - assertEquals(!!(mask & kRuntime), isVisible(item, '#runtime-warnings')); - } + const verifyEventPromise = function(expectCalled) { + return new Promise((resolve, reject) => { + setTimeout(() => { + expectEquals(expectCalled, firedLoadError); + resolve(); + }); + }); + }; - assertWarnings(0); + tap(item.$$('#dev-reload-button')); + return proxyDelegate.whenCalled('reloadItem') + .then(function(id) { + expectEquals(item.data.id, id); + return verifyEventPromise(false); + }) + .then(function() { + proxyDelegate.resetResolver('reloadItem'); + proxyDelegate.setForceReloadItemError(true); + tap(item.$$('#dev-reload-button')); + return proxyDelegate.whenCalled('reloadItem'); + }) + .then(function(id) { + expectEquals(item.data.id, id); + return verifyEventPromise(true); + }); + }); - item.set('data.disableReasons.corruptInstall', true); - flush(); - assertWarnings(kCorrupt); + test(assert(extension_item_tests.TestNames.Warnings), function() { + const kCorrupt = 1 << 0; + const kSuspicious = 1 << 1; + const kBlacklisted = 1 << 2; + const kRuntime = 1 << 3; - item.set('data.disableReasons.suspiciousInstall', true); - flush(); - assertWarnings(kCorrupt | kSuspicious); - - item.set('data.blacklistText', 'This item is blacklisted'); - flush(); - assertWarnings(kCorrupt | kSuspicious | kBlacklisted); - - item.set('data.blacklistText', null); - flush(); - assertWarnings(kCorrupt | kSuspicious); - - item.set('data.runtimeWarnings', ['Dummy warning']); - flush(); - assertWarnings(kCorrupt | kSuspicious | kRuntime); - - item.set('data.disableReasons.corruptInstall', false); - item.set('data.disableReasons.suspiciousInstall', false); - item.set('data.runtimeWarnings', []); - flush(); - assertWarnings(0); - }); - - test(assert(extension_item_tests.TestNames.SourceIndicator), function() { - expectFalse(isVisible(item, '#source-indicator')); - item.set('data.location', 'UNPACKED'); - flush(); - expectTrue(isVisible(item, '#source-indicator')); - const icon = item.$$('#source-indicator iron-icon'); - assertTrue(!!icon); - expectEquals('extensions-icons:unpacked', icon.icon); - - item.set('data.location', 'THIRD_PARTY'); - flush(); - expectTrue(isVisible(item, '#source-indicator')); - expectEquals('extensions-icons:input', icon.icon); - - item.set('data.location', 'UNKNOWN'); - flush(); - expectTrue(isVisible(item, '#source-indicator')); - expectEquals('extensions-icons:input', icon.icon); - - item.set('data.location', 'FROM_STORE'); - item.set('data.controlledInfo', {type: 'POLICY', text: 'policy'}); - flush(); - expectTrue(isVisible(item, '#source-indicator')); - expectEquals('extensions-icons:business', icon.icon); - - item.set('data.controlledInfo', null); - flush(); - expectFalse(isVisible(item, '#source-indicator')); - }); - - test(assert(extension_item_tests.TestNames.EnableToggle), function() { - expectFalse(item.$['enable-toggle'].disabled); - - // Test case where user does not have permission. - item.set('data.userMayModify', false); - flush(); - expectTrue(item.$['enable-toggle'].disabled); - - // Test case of a blacklisted extension. - item.set('data.userMayModify', true); - item.set('data.state', 'BLACKLISTED'); - flush(); - expectTrue(item.$['enable-toggle'].disabled); - }); - - test(assert(extension_item_tests.TestNames.RemoveButton), function() { - expectFalse(item.$['remove-button'].hidden); - item.set('data.controlledInfo', {type: 'POLICY', text: 'policy'}); - flush(); - expectTrue(item.$['remove-button'].hidden); - }); - - test(assert(extension_item_tests.TestNames.HtmlInName), function() { - let name = '<HTML> in the name!'; - item.set('data.name', name); - flush(); - assertEquals(name, item.$.name.textContent.trim()); - // "Related to $1" is IDS_MD_EXTENSIONS_EXTENSION_A11Y_ASSOCIATION. + function assertWarnings(mask) { + assertEquals(!!(mask & kCorrupt), isVisible(item, '#corrupted-warning')); assertEquals( - `Related to ${name}`, item.$.a11yAssociation.textContent.trim()); - }); + !!(mask & kSuspicious), isVisible(item, '#suspicious-warning')); + assertEquals( + !!(mask & kBlacklisted), isVisible(item, '#blacklisted-warning')); + assertEquals(!!(mask & kRuntime), isVisible(item, '#runtime-warnings')); + } + + assertWarnings(0); + + item.set('data.disableReasons.corruptInstall', true); + flush(); + assertWarnings(kCorrupt); + + item.set('data.disableReasons.suspiciousInstall', true); + flush(); + assertWarnings(kCorrupt | kSuspicious); + + item.set('data.blacklistText', 'This item is blacklisted'); + flush(); + assertWarnings(kCorrupt | kSuspicious | kBlacklisted); + + item.set('data.blacklistText', null); + flush(); + assertWarnings(kCorrupt | kSuspicious); + + item.set('data.runtimeWarnings', ['Dummy warning']); + flush(); + assertWarnings(kCorrupt | kSuspicious | kRuntime); + + item.set('data.disableReasons.corruptInstall', false); + item.set('data.disableReasons.suspiciousInstall', false); + item.set('data.runtimeWarnings', []); + flush(); + assertWarnings(0); }); + + test(assert(extension_item_tests.TestNames.SourceIndicator), function() { + expectFalse(isVisible(item, '#source-indicator')); + item.set('data.location', 'UNPACKED'); + flush(); + expectTrue(isVisible(item, '#source-indicator')); + const icon = item.$$('#source-indicator iron-icon'); + assertTrue(!!icon); + expectEquals('extensions-icons:unpacked', icon.icon); + + item.set('data.location', 'THIRD_PARTY'); + flush(); + expectTrue(isVisible(item, '#source-indicator')); + expectEquals('extensions-icons:input', icon.icon); + + item.set('data.location', 'UNKNOWN'); + flush(); + expectTrue(isVisible(item, '#source-indicator')); + expectEquals('extensions-icons:input', icon.icon); + + item.set('data.location', 'FROM_STORE'); + item.set('data.controlledInfo', {type: 'POLICY', text: 'policy'}); + flush(); + expectTrue(isVisible(item, '#source-indicator')); + expectEquals('extensions-icons:business', icon.icon); + + item.set('data.controlledInfo', null); + flush(); + expectFalse(isVisible(item, '#source-indicator')); + }); + + test(assert(extension_item_tests.TestNames.EnableToggle), function() { + expectFalse(item.$['enable-toggle'].disabled); + + // Test case where user does not have permission. + item.set('data.userMayModify', false); + flush(); + expectTrue(item.$['enable-toggle'].disabled); + + // Test case of a blacklisted extension. + item.set('data.userMayModify', true); + item.set('data.state', 'BLACKLISTED'); + flush(); + expectTrue(item.$['enable-toggle'].disabled); + }); + + test(assert(extension_item_tests.TestNames.RemoveButton), function() { + expectFalse(item.$['remove-button'].hidden); + item.set('data.controlledInfo', {type: 'POLICY', text: 'policy'}); + flush(); + expectTrue(item.$['remove-button'].hidden); + }); + + test(assert(extension_item_tests.TestNames.HtmlInName), function() { + let name = '<HTML> in the name!'; + item.set('data.name', name); + flush(); + assertEquals(name, item.$.name.textContent.trim()); + // "Related to $1" is IDS_MD_EXTENSIONS_EXTENSION_A11Y_ASSOCIATION. + assertEquals( + `Related to ${name}`, item.$.a11yAssociation.textContent.trim()); + }); +});
diff --git a/chrome/test/data/webui/extensions/keyboard_shortcuts_test.js b/chrome/test/data/webui/extensions/keyboard_shortcuts_test.js index dfb4a72..b36081ff 100644 --- a/chrome/test/data/webui/extensions/keyboard_shortcuts_test.js +++ b/chrome/test/data/webui/extensions/keyboard_shortcuts_test.js
@@ -13,133 +13,131 @@ import {TestService} from './test_service.js'; import {createExtensionInfo} from './test_util.js'; - window.extension_shortcut_tests = {}; - extension_shortcut_tests.suiteName = 'ExtensionShortcutTest'; - /** @enum {string} */ - extension_shortcut_tests.TestNames = { - IsValidKeyCode: 'isValidKeyCode', - KeyStrokeToString: 'keystrokeToString', - Layout: 'Layout', - ScopeChange: 'ScopeChange', - }; +window.extension_shortcut_tests = {}; +extension_shortcut_tests.suiteName = 'ExtensionShortcutTest'; +/** @enum {string} */ +extension_shortcut_tests.TestNames = { + IsValidKeyCode: 'isValidKeyCode', + KeyStrokeToString: 'keystrokeToString', + Layout: 'Layout', + ScopeChange: 'ScopeChange', +}; - suite(extension_shortcut_tests.suiteName, function() { - /** @type {KeyboardShortcuts} */ - let keyboardShortcuts; - /** @type {chrome.developerPrivate.ExtensionInfo} */ - let noCommands; - /** @type {chrome.developerPrivate.ExtensionInfo} */ - let oneCommand; - /** @type {chrome.developerPrivate.ExtensionInfo} */ - let twoCommands; +suite(extension_shortcut_tests.suiteName, function() { + /** @type {KeyboardShortcuts} */ + let keyboardShortcuts; + /** @type {chrome.developerPrivate.ExtensionInfo} */ + let noCommands; + /** @type {chrome.developerPrivate.ExtensionInfo} */ + let oneCommand; + /** @type {chrome.developerPrivate.ExtensionInfo} */ + let twoCommands; - setup(function() { - PolymerTest.clearBody(); - keyboardShortcuts = - document.createElement('extensions-keyboard-shortcuts'); - keyboardShortcuts.delegate = new TestService(); + setup(function() { + PolymerTest.clearBody(); + keyboardShortcuts = document.createElement('extensions-keyboard-shortcuts'); + keyboardShortcuts.delegate = new TestService(); - noCommands = createExtensionInfo({id: 'a'.repeat(32)}); - oneCommand = createExtensionInfo({ - id: 'b'.repeat(32), - commands: [{ - description: 'Description', - keybinding: 'Ctrl+W', - name: 'bCommand', + noCommands = createExtensionInfo({id: 'a'.repeat(32)}); + oneCommand = createExtensionInfo({ + id: 'b'.repeat(32), + commands: [{ + description: 'Description', + keybinding: 'Ctrl+W', + name: 'bCommand', + isActive: true, + scope: 'CHROME', + isExtensionAction: true, + }] + }); + twoCommands = createExtensionInfo({ + id: 'c'.repeat(32), + commands: [ + { + description: 'Another Description', + keybinding: 'Alt+F4', + name: 'cCommand', isActive: true, + scope: 'GLOBAL', + isExtensionAction: false, + }, + { + description: 'Yet Another Description', + keybinding: '', + name: 'cCommand2', + isActive: false, scope: 'CHROME', - isExtensionAction: true, - }] - }); - twoCommands = createExtensionInfo({ - id: 'c'.repeat(32), - commands: [ - { - description: 'Another Description', - keybinding: 'Alt+F4', - name: 'cCommand', - isActive: true, - scope: 'GLOBAL', - isExtensionAction: false, - }, - { - description: 'Yet Another Description', - keybinding: '', - name: 'cCommand2', - isActive: false, - scope: 'CHROME', - isExtensionAction: false, - } - ] - }); - - keyboardShortcuts.set('items', [noCommands, oneCommand, twoCommands]); - - document.body.appendChild(keyboardShortcuts); - - flush(); + isExtensionAction: false, + } + ] }); - test(assert(extension_shortcut_tests.TestNames.Layout), function() { - const isVisibleOnCard = function(e, s) { - // We check the light DOM in the card because it's a regular old div, - // rather than a fancy-schmancy custom element. - return isVisible(e, s, true); - }; - const cards = - keyboardShortcuts.$$('#container').querySelectorAll('.shortcut-card'); - assertEquals(2, cards.length); + keyboardShortcuts.set('items', [noCommands, oneCommand, twoCommands]); - const card1 = cards[0]; - expectEquals( - oneCommand.name, card1.querySelector('.card-title span').textContent); - let commands = card1.querySelectorAll('.command-entry'); - assertEquals(1, commands.length); - expectTrue(isVisibleOnCard(commands[0], '.command-name')); - expectTrue(isVisibleOnCard(commands[0], 'select.md-select')); + document.body.appendChild(keyboardShortcuts); - const card2 = cards[1]; - commands = card2.querySelectorAll('.command-entry'); - assertEquals(2, commands.length); - }); - - test(extension_shortcut_tests.TestNames.IsValidKeyCode, function() { - expectTrue(isValidKeyCode('A'.charCodeAt(0))); - expectTrue(isValidKeyCode('F'.charCodeAt(0))); - expectTrue(isValidKeyCode('Z'.charCodeAt(0))); - expectTrue(isValidKeyCode('4'.charCodeAt(0))); - expectTrue(isValidKeyCode(Key.PageUp)); - expectTrue(isValidKeyCode(Key.MediaPlayPause)); - expectTrue(isValidKeyCode(Key.Down)); - expectFalse(isValidKeyCode(16)); // Shift - expectFalse(isValidKeyCode(17)); // Ctrl - expectFalse(isValidKeyCode(18)); // Alt - expectFalse(isValidKeyCode(113)); // F2 - expectFalse(isValidKeyCode(144)); // Num Lock - expectFalse(isValidKeyCode(43)); // + - expectFalse(isValidKeyCode(27)); // Escape - }); - - test(extension_shortcut_tests.TestNames.KeyStrokeToString, function() { - // Creating an event with the KeyboardEvent ctor doesn't work. Fake it. - const e = {keyCode: 'A'.charCodeAt(0)}; - expectEquals('A', keystrokeToString(e)); - e.ctrlKey = true; - expectEquals('Ctrl+A', keystrokeToString(e)); - e.shiftKey = true; - expectEquals('Ctrl+Shift+A', keystrokeToString(e)); - }); - - test(extension_shortcut_tests.TestNames.ScopeChange, function() { - const selectElement = keyboardShortcuts.$$('select'); - selectElement.value = 'GLOBAL'; - selectElement.dispatchEvent(new CustomEvent('change')); - return keyboardShortcuts.delegate - .whenCalled('updateExtensionCommandScope') - .then(params => { - assertEquals(oneCommand.id, params[0]); - assertEquals(oneCommand.commands[0].name, params[1]); - assertEquals(selectElement.value, params[2]); - }); - }); + flush(); }); + + test(assert(extension_shortcut_tests.TestNames.Layout), function() { + const isVisibleOnCard = function(e, s) { + // We check the light DOM in the card because it's a regular old div, + // rather than a fancy-schmancy custom element. + return isVisible(e, s, true); + }; + const cards = + keyboardShortcuts.$$('#container').querySelectorAll('.shortcut-card'); + assertEquals(2, cards.length); + + const card1 = cards[0]; + expectEquals( + oneCommand.name, card1.querySelector('.card-title span').textContent); + let commands = card1.querySelectorAll('.command-entry'); + assertEquals(1, commands.length); + expectTrue(isVisibleOnCard(commands[0], '.command-name')); + expectTrue(isVisibleOnCard(commands[0], 'select.md-select')); + + const card2 = cards[1]; + commands = card2.querySelectorAll('.command-entry'); + assertEquals(2, commands.length); + }); + + test(extension_shortcut_tests.TestNames.IsValidKeyCode, function() { + expectTrue(isValidKeyCode('A'.charCodeAt(0))); + expectTrue(isValidKeyCode('F'.charCodeAt(0))); + expectTrue(isValidKeyCode('Z'.charCodeAt(0))); + expectTrue(isValidKeyCode('4'.charCodeAt(0))); + expectTrue(isValidKeyCode(Key.PageUp)); + expectTrue(isValidKeyCode(Key.MediaPlayPause)); + expectTrue(isValidKeyCode(Key.Down)); + expectFalse(isValidKeyCode(16)); // Shift + expectFalse(isValidKeyCode(17)); // Ctrl + expectFalse(isValidKeyCode(18)); // Alt + expectFalse(isValidKeyCode(113)); // F2 + expectFalse(isValidKeyCode(144)); // Num Lock + expectFalse(isValidKeyCode(43)); // + + expectFalse(isValidKeyCode(27)); // Escape + }); + + test(extension_shortcut_tests.TestNames.KeyStrokeToString, function() { + // Creating an event with the KeyboardEvent ctor doesn't work. Fake it. + const e = {keyCode: 'A'.charCodeAt(0)}; + expectEquals('A', keystrokeToString(e)); + e.ctrlKey = true; + expectEquals('Ctrl+A', keystrokeToString(e)); + e.shiftKey = true; + expectEquals('Ctrl+Shift+A', keystrokeToString(e)); + }); + + test(extension_shortcut_tests.TestNames.ScopeChange, function() { + const selectElement = keyboardShortcuts.$$('select'); + selectElement.value = 'GLOBAL'; + selectElement.dispatchEvent(new CustomEvent('change')); + return keyboardShortcuts.delegate.whenCalled('updateExtensionCommandScope') + .then(params => { + assertEquals(oneCommand.id, params[0]); + assertEquals(oneCommand.commands[0].name, params[1]); + assertEquals(selectElement.value, params[2]); + }); + }); +});
diff --git a/chrome/test/data/webui/extensions/kiosk_mode_test.js b/chrome/test/data/webui/extensions/kiosk_mode_test.js index 70e5cfa9..f56477375 100644 --- a/chrome/test/data/webui/extensions/kiosk_mode_test.js +++ b/chrome/test/data/webui/extensions/kiosk_mode_test.js
@@ -12,238 +12,238 @@ import {flushTasks} from '../test_util.m.js'; import {TestKioskBrowserProxy} from './test_kiosk_browser_proxy.js'; - window.extension_kiosk_mode_tests = {}; - extension_kiosk_mode_tests.suiteName = 'kioskModeTests'; - /** @enum {string} */ - extension_kiosk_mode_tests.TestNames = { - AddButton: 'AddButton', - AddError: 'AddError', - AutoLaunch: 'AutoLaunch', - Bailout: 'Bailout', - Layout: 'Layout', - Updated: 'Updated', - }; +window.extension_kiosk_mode_tests = {}; +extension_kiosk_mode_tests.suiteName = 'kioskModeTests'; +/** @enum {string} */ +extension_kiosk_mode_tests.TestNames = { + AddButton: 'AddButton', + AddError: 'AddError', + AutoLaunch: 'AutoLaunch', + Bailout: 'Bailout', + Layout: 'Layout', + Updated: 'Updated', +}; - suite(extension_kiosk_mode_tests.suiteName, function() { - /** @type {KioskBrowserProxy} */ - let browserProxy; +suite(extension_kiosk_mode_tests.suiteName, function() { + /** @type {KioskBrowserProxy} */ + let browserProxy; - /** @type {ExtensionsKioskDialogElement} */ - let dialog; + /** @type {ExtensionsKioskDialogElement} */ + let dialog; - /** @type {!Array<!KioskApp>} */ - const basicApps = [ - { - id: 'app_1', - name: 'App1 Name', - iconURL: '', - autoLaunch: false, - isLoading: false, - }, - { - id: 'app_2', - name: 'App2 Name', - iconURL: '', - autoLaunch: false, - isLoading: false, - }, - ]; + /** @type {!Array<!KioskApp>} */ + const basicApps = [ + { + id: 'app_1', + name: 'App1 Name', + iconURL: '', + autoLaunch: false, + isLoading: false, + }, + { + id: 'app_2', + name: 'App2 Name', + iconURL: '', + autoLaunch: false, + isLoading: false, + }, + ]; - /** @param {!KioskAppSettings} */ - function setAppSettings(settings) { - const appSettings = { - apps: [], - disableBailout: false, - hasAutoLaunchApp: false, - }; + /** @param {!KioskAppSettings} */ + function setAppSettings(settings) { + const appSettings = { + apps: [], + disableBailout: false, + hasAutoLaunchApp: false, + }; - browserProxy.setAppSettings(Object.assign({}, appSettings, settings)); - } + browserProxy.setAppSettings(Object.assign({}, appSettings, settings)); + } - /** @param {!KioskSettings} */ - function setInitialSettings(settings) { - const initialSettings = { - kioskEnabled: true, - autoLaunchEnabled: false, - }; + /** @param {!KioskSettings} */ + function setInitialSettings(settings) { + const initialSettings = { + kioskEnabled: true, + autoLaunchEnabled: false, + }; - browserProxy.setInitialSettings( - Object.assign({}, initialSettings, settings)); - } + browserProxy.setInitialSettings( + Object.assign({}, initialSettings, settings)); + } - /** @return {!Promise} */ - function initPage() { - PolymerTest.clearBody(); - browserProxy.reset(); - dialog = document.createElement('extensions-kiosk-dialog'); - document.body.appendChild(dialog); + /** @return {!Promise} */ + function initPage() { + PolymerTest.clearBody(); + browserProxy.reset(); + dialog = document.createElement('extensions-kiosk-dialog'); + document.body.appendChild(dialog); - return browserProxy.whenCalled('getKioskAppSettings') - .then(() => flushTasks()); - } + return browserProxy.whenCalled('getKioskAppSettings') + .then(() => flushTasks()); + } - setup(function() { - browserProxy = new TestKioskBrowserProxy(); - setAppSettings({apps: basicApps.slice(0)}); - KioskBrowserProxyImpl.instance_ = browserProxy; + setup(function() { + browserProxy = new TestKioskBrowserProxy(); + setAppSettings({apps: basicApps.slice(0)}); + KioskBrowserProxyImpl.instance_ = browserProxy; - return initPage(); - }); + return initPage(); + }); - test(assert(extension_kiosk_mode_tests.TestNames.Layout), function() { - const apps = basicApps.slice(0); - apps[1].autoLaunch = true; - apps[1].isLoading = true; - setAppSettings({apps: apps, hasAutoLaunchApp: true}); + test(assert(extension_kiosk_mode_tests.TestNames.Layout), function() { + const apps = basicApps.slice(0); + apps[1].autoLaunch = true; + apps[1].isLoading = true; + setAppSettings({apps: apps, hasAutoLaunchApp: true}); - return initPage() - .then(() => { - const items = dialog.shadowRoot.querySelectorAll('.list-item'); - expectEquals(items.length, 2); - expectTrue(items[0].textContent.includes(basicApps[0].name)); - expectTrue(items[1].textContent.includes(basicApps[1].name)); - // Second item should show the auto-lauch label. - expectTrue(items[0].querySelector('span').hidden); - expectFalse(items[1].querySelector('span').hidden); - // No permission to edit auto-launch so buttons should be hidden. - expectTrue(items[0].querySelector('cr-button').hidden); - expectTrue(items[1].querySelector('cr-button').hidden); - // Bailout checkbox should be hidden when auto-launch editing - // disabled. - expectTrue(dialog.$$('cr-checkbox').hidden); + return initPage() + .then(() => { + const items = dialog.shadowRoot.querySelectorAll('.list-item'); + expectEquals(items.length, 2); + expectTrue(items[0].textContent.includes(basicApps[0].name)); + expectTrue(items[1].textContent.includes(basicApps[1].name)); + // Second item should show the auto-lauch label. + expectTrue(items[0].querySelector('span').hidden); + expectFalse(items[1].querySelector('span').hidden); + // No permission to edit auto-launch so buttons should be hidden. + expectTrue(items[0].querySelector('cr-button').hidden); + expectTrue(items[1].querySelector('cr-button').hidden); + // Bailout checkbox should be hidden when auto-launch editing + // disabled. + expectTrue(dialog.$$('cr-checkbox').hidden); - items[0].querySelector('.icon-delete-gray').click(); - flush(); - return browserProxy.whenCalled('removeKioskApp'); - }) - .then(appId => { - expectEquals(appId, basicApps[0].id); - }); - }); + items[0].querySelector('.icon-delete-gray').click(); + flush(); + return browserProxy.whenCalled('removeKioskApp'); + }) + .then(appId => { + expectEquals(appId, basicApps[0].id); + }); + }); - test(assert(extension_kiosk_mode_tests.TestNames.AutoLaunch), function() { - const apps = basicApps.slice(0); - apps[1].autoLaunch = true; - setAppSettings({apps: apps, hasAutoLaunchApp: true}); - setInitialSettings({autoLaunchEnabled: true}); + test(assert(extension_kiosk_mode_tests.TestNames.AutoLaunch), function() { + const apps = basicApps.slice(0); + apps[1].autoLaunch = true; + setAppSettings({apps: apps, hasAutoLaunchApp: true}); + setInitialSettings({autoLaunchEnabled: true}); - let buttons; - return initPage() - .then(() => { - buttons = dialog.shadowRoot.querySelectorAll('.list-item cr-button'); - // Has permission to edit auto-launch so buttons should be seen. - expectFalse(buttons[0].hidden); - expectFalse(buttons[1].hidden); + let buttons; + return initPage() + .then(() => { + buttons = dialog.shadowRoot.querySelectorAll('.list-item cr-button'); + // Has permission to edit auto-launch so buttons should be seen. + expectFalse(buttons[0].hidden); + expectFalse(buttons[1].hidden); - buttons[0].click(); - return browserProxy.whenCalled('enableKioskAutoLaunch'); - }) - .then(appId => { - expectEquals(appId, basicApps[0].id); + buttons[0].click(); + return browserProxy.whenCalled('enableKioskAutoLaunch'); + }) + .then(appId => { + expectEquals(appId, basicApps[0].id); - buttons[1].click(); - return browserProxy.whenCalled('disableKioskAutoLaunch'); - }) - .then(appId => { - expectEquals(appId, basicApps[1].id); - }); - }); + buttons[1].click(); + return browserProxy.whenCalled('disableKioskAutoLaunch'); + }) + .then(appId => { + expectEquals(appId, basicApps[1].id); + }); + }); - test(assert(extension_kiosk_mode_tests.TestNames.Bailout), function() { - const apps = basicApps.slice(0); - apps[1].autoLaunch = true; - setAppSettings({apps: apps, hasAutoLaunchApp: true}); - setInitialSettings({autoLaunchEnabled: true}); + test(assert(extension_kiosk_mode_tests.TestNames.Bailout), function() { + const apps = basicApps.slice(0); + apps[1].autoLaunch = true; + setAppSettings({apps: apps, hasAutoLaunchApp: true}); + setInitialSettings({autoLaunchEnabled: true}); - expectFalse(dialog.$['confirm-dialog'].open); + expectFalse(dialog.$['confirm-dialog'].open); - let bailoutCheckbox; - return initPage() - .then(() => { - bailoutCheckbox = dialog.$$('cr-checkbox'); - // Bailout checkbox should be usable when auto-launching. - expectFalse(bailoutCheckbox.hidden); - expectFalse(bailoutCheckbox.disabled); - expectFalse(bailoutCheckbox.checked); + let bailoutCheckbox; + return initPage() + .then(() => { + bailoutCheckbox = dialog.$$('cr-checkbox'); + // Bailout checkbox should be usable when auto-launching. + expectFalse(bailoutCheckbox.hidden); + expectFalse(bailoutCheckbox.disabled); + expectFalse(bailoutCheckbox.checked); - // Making sure canceling doesn't change anything. - bailoutCheckbox.click(); - flush(); - expectTrue(dialog.$['confirm-dialog'].open); + // Making sure canceling doesn't change anything. + bailoutCheckbox.click(); + flush(); + expectTrue(dialog.$['confirm-dialog'].open); - dialog.$['confirm-dialog'].querySelector('.cancel-button').click(); - flush(); - expectFalse(bailoutCheckbox.checked); - expectFalse(dialog.$['confirm-dialog'].open); - expectTrue(dialog.$.dialog.open); + dialog.$['confirm-dialog'].querySelector('.cancel-button').click(); + flush(); + expectFalse(bailoutCheckbox.checked); + expectFalse(dialog.$['confirm-dialog'].open); + expectTrue(dialog.$.dialog.open); - // Accepting confirmation dialog should trigger browserProxy call. - bailoutCheckbox.click(); - flush(); - expectTrue(dialog.$['confirm-dialog'].open); + // Accepting confirmation dialog should trigger browserProxy call. + bailoutCheckbox.click(); + flush(); + expectTrue(dialog.$['confirm-dialog'].open); - dialog.$['confirm-dialog'].querySelector('.action-button').click(); - flush(); - expectTrue(bailoutCheckbox.checked); - expectFalse(dialog.$['confirm-dialog'].open); - expectTrue(dialog.$.dialog.open); - return browserProxy.whenCalled('setDisableBailoutShortcut'); - }) - .then(disabled => { - expectTrue(disabled); + dialog.$['confirm-dialog'].querySelector('.action-button').click(); + flush(); + expectTrue(bailoutCheckbox.checked); + expectFalse(dialog.$['confirm-dialog'].open); + expectTrue(dialog.$.dialog.open); + return browserProxy.whenCalled('setDisableBailoutShortcut'); + }) + .then(disabled => { + expectTrue(disabled); - // Test clicking on checkbox again should simply re-enable bailout. - browserProxy.reset(); - bailoutCheckbox.click(); - expectFalse(bailoutCheckbox.checked); - expectFalse(dialog.$['confirm-dialog'].open); - return browserProxy.whenCalled('setDisableBailoutShortcut'); - }) - .then(disabled => { - expectFalse(disabled); - }); - }); + // Test clicking on checkbox again should simply re-enable bailout. + browserProxy.reset(); + bailoutCheckbox.click(); + expectFalse(bailoutCheckbox.checked); + expectFalse(dialog.$['confirm-dialog'].open); + return browserProxy.whenCalled('setDisableBailoutShortcut'); + }) + .then(disabled => { + expectFalse(disabled); + }); + }); - test(assert(extension_kiosk_mode_tests.TestNames.AddButton), function() { - const addButton = dialog.$['add-button']; - expectTrue(!!addButton); - expectTrue(addButton.disabled); + test(assert(extension_kiosk_mode_tests.TestNames.AddButton), function() { + const addButton = dialog.$['add-button']; + expectTrue(!!addButton); + expectTrue(addButton.disabled); - const addInput = dialog.$['add-input']; - addInput.value = 'blah'; - expectFalse(addButton.disabled); + const addInput = dialog.$['add-input']; + addInput.value = 'blah'; + expectFalse(addButton.disabled); - addButton.click(); - return browserProxy.whenCalled('addKioskApp').then(appId => { - expectEquals(appId, 'blah'); - }); - }); - - test(assert(extension_kiosk_mode_tests.TestNames.Updated), function() { - const items = dialog.shadowRoot.querySelectorAll('.list-item'); - expectTrue(items[0].textContent.includes(basicApps[0].name)); - - const newName = 'completely different name'; - - window.cr.webUIListenerCallback('kiosk-app-updated', { - id: basicApps[0].id, - name: newName, - iconURL: '', - autoLaunch: false, - isLoading: false, - }); - - expectFalse(items[0].textContent.includes(basicApps[0].name)); - expectTrue(items[0].textContent.includes(newName)); - }); - - test(assert(extension_kiosk_mode_tests.TestNames.AddError), function() { - const addInput = dialog.$['add-input']; - - expectFalse(!!addInput.invalid); - window.cr.webUIListenerCallback('kiosk-app-error', basicApps[0].id); - - expectTrue(!!addInput.invalid); - expectTrue(addInput.errorMessage.includes(basicApps[0].id)); + addButton.click(); + return browserProxy.whenCalled('addKioskApp').then(appId => { + expectEquals(appId, 'blah'); }); }); + + test(assert(extension_kiosk_mode_tests.TestNames.Updated), function() { + const items = dialog.shadowRoot.querySelectorAll('.list-item'); + expectTrue(items[0].textContent.includes(basicApps[0].name)); + + const newName = 'completely different name'; + + window.cr.webUIListenerCallback('kiosk-app-updated', { + id: basicApps[0].id, + name: newName, + iconURL: '', + autoLaunch: false, + isLoading: false, + }); + + expectFalse(items[0].textContent.includes(basicApps[0].name)); + expectTrue(items[0].textContent.includes(newName)); + }); + + test(assert(extension_kiosk_mode_tests.TestNames.AddError), function() { + const addInput = dialog.$['add-input']; + + expectFalse(!!addInput.invalid); + window.cr.webUIListenerCallback('kiosk-app-error', basicApps[0].id); + + expectTrue(!!addInput.invalid); + expectTrue(addInput.errorMessage.includes(basicApps[0].id)); + }); +});
diff --git a/chrome/test/data/webui/extensions/load_error_test.js b/chrome/test/data/webui/extensions/load_error_test.js index 4d6d4a73..e3789e89 100644 --- a/chrome/test/data/webui/extensions/load_error_test.js +++ b/chrome/test/data/webui/extensions/load_error_test.js
@@ -10,81 +10,81 @@ import {TestService} from './test_service.js'; import {isElementVisible} from './test_util.js'; - window.extension_load_error_tests = {}; - extension_load_error_tests.suiteName = 'ExtensionLoadErrorTests'; - /** @enum {string} */ - extension_load_error_tests.TestNames = { - RetryError: 'RetryError', - RetrySuccess: 'RetrySuccess', - CodeSection: 'Code Section', +window.extension_load_error_tests = {}; +extension_load_error_tests.suiteName = 'ExtensionLoadErrorTests'; +/** @enum {string} */ +extension_load_error_tests.TestNames = { + RetryError: 'RetryError', + RetrySuccess: 'RetrySuccess', + CodeSection: 'Code Section', +}; + +suite(extension_load_error_tests.suiteName, function() { + /** @type {ExtensionsLoadErrorElement} */ + let loadError; + + /** @type {MockDelegate} */ + let mockDelegate; + + const fakeGuid = 'uniqueId'; + + const stubLoadError = { + error: 'error', + path: 'some/path/', + retryGuid: fakeGuid, }; - suite(extension_load_error_tests.suiteName, function() { - /** @type {ExtensionsLoadErrorElement} */ - let loadError; + setup(function() { + PolymerTest.clearBody(); + mockDelegate = new TestService(); + loadError = document.createElement('extensions-load-error'); + loadError.delegate = mockDelegate; + loadError.loadError = stubLoadError; + document.body.appendChild(loadError); + }); - /** @type {MockDelegate} */ - let mockDelegate; + test(assert(extension_load_error_tests.TestNames.RetryError), function() { + const dialogElement = loadError.$$('cr-dialog').getNative(); + expectFalse(isElementVisible(dialogElement)); + loadError.show(); + expectTrue(isElementVisible(dialogElement)); - const fakeGuid = 'uniqueId'; - - const stubLoadError = { - error: 'error', - path: 'some/path/', - retryGuid: fakeGuid, - }; - - setup(function() { - PolymerTest.clearBody(); - mockDelegate = new TestService(); - loadError = document.createElement('extensions-load-error'); - loadError.delegate = mockDelegate; - loadError.loadError = stubLoadError; - document.body.appendChild(loadError); - }); - - test(assert(extension_load_error_tests.TestNames.RetryError), function() { - const dialogElement = loadError.$$('cr-dialog').getNative(); - expectFalse(isElementVisible(dialogElement)); - loadError.show(); + mockDelegate.setRetryLoadUnpackedError(stubLoadError); + loadError.$$('.action-button').click(); + return mockDelegate.whenCalled('retryLoadUnpacked').then(arg => { + expectEquals(fakeGuid, arg); expectTrue(isElementVisible(dialogElement)); - - mockDelegate.setRetryLoadUnpackedError(stubLoadError); - loadError.$$('.action-button').click(); - return mockDelegate.whenCalled('retryLoadUnpacked').then(arg => { - expectEquals(fakeGuid, arg); - expectTrue(isElementVisible(dialogElement)); - loadError.$$('.cancel-button').click(); - expectFalse(isElementVisible(dialogElement)); - }); - }); - - test(assert(extension_load_error_tests.TestNames.RetrySuccess), function() { - const dialogElement = loadError.$$('cr-dialog').getNative(); + loadError.$$('.cancel-button').click(); expectFalse(isElementVisible(dialogElement)); - loadError.show(); - expectTrue(isElementVisible(dialogElement)); - - loadError.$$('.action-button').click(); - return mockDelegate.whenCalled('retryLoadUnpacked').then(arg => { - expectEquals(fakeGuid, arg); - expectFalse(isElementVisible(dialogElement)); - }); - }); - - test(assert(extension_load_error_tests.TestNames.CodeSection), function() { - expectTrue(loadError.$.code.$$('#scroll-container').hidden); - const loadErrorWithSource = { - error: 'Some error', - path: '/some/path', - source: { - beforeHighlight: 'before', - highlight: 'highlight', - afterHighlight: 'after', - }, - }; - - loadError.loadError = loadErrorWithSource; - expectFalse(loadError.$.code.$$('#scroll-container').hidden); }); }); + + test(assert(extension_load_error_tests.TestNames.RetrySuccess), function() { + const dialogElement = loadError.$$('cr-dialog').getNative(); + expectFalse(isElementVisible(dialogElement)); + loadError.show(); + expectTrue(isElementVisible(dialogElement)); + + loadError.$$('.action-button').click(); + return mockDelegate.whenCalled('retryLoadUnpacked').then(arg => { + expectEquals(fakeGuid, arg); + expectFalse(isElementVisible(dialogElement)); + }); + }); + + test(assert(extension_load_error_tests.TestNames.CodeSection), function() { + expectTrue(loadError.$.code.$$('#scroll-container').hidden); + const loadErrorWithSource = { + error: 'Some error', + path: '/some/path', + source: { + beforeHighlight: 'before', + highlight: 'highlight', + afterHighlight: 'after', + }, + }; + + loadError.loadError = loadErrorWithSource; + expectFalse(loadError.$.code.$$('#scroll-container').hidden); + }); +});
diff --git a/chrome/test/data/webui/extensions/manager_test.js b/chrome/test/data/webui/extensions/manager_test.js index 313e360..8bedcc2 100644 --- a/chrome/test/data/webui/extensions/manager_test.js +++ b/chrome/test/data/webui/extensions/manager_test.js
@@ -8,127 +8,123 @@ import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {eventToPromise} from '../test_util.m.js'; - window.extension_manager_tests = {}; - extension_manager_tests.suiteName = 'ExtensionManagerTest'; - /** @enum {string} */ - extension_manager_tests.TestNames = { - ChangePages: 'change pages', - ItemListVisibility: 'item list visibility', - SplitItems: 'split items', - PageTitleUpdate: 'updates the title based on current route', - }; +window.extension_manager_tests = {}; +extension_manager_tests.suiteName = 'ExtensionManagerTest'; +/** @enum {string} */ +extension_manager_tests.TestNames = { + ChangePages: 'change pages', + ItemListVisibility: 'item list visibility', + SplitItems: 'split items', + PageTitleUpdate: 'updates the title based on current route', +}; - function getDataByName(list, name) { - return assert(list.find(function(el) { - return el.name == name; - })); +function getDataByName(list, name) { + return assert(list.find(function(el) { + return el.name == name; + })); +} + +suite(extension_manager_tests.suiteName, function() { + /** @type {Manager} */ + let manager; + + /** @param {string} viewElement */ + function assertViewActive(tagName) { + assertTrue(!!manager.$.viewManager.querySelector(`${tagName}.active`)); } - suite(extension_manager_tests.suiteName, function() { - /** @type {Manager} */ - let manager; + setup(function() { + PolymerTest.clearBody(); + manager = document.createElement('extensions-manager'); + document.body.appendChild(manager); - /** @param {string} viewElement */ - function assertViewActive(tagName) { - assertTrue(!!manager.$.viewManager.querySelector(`${tagName}.active`)); - } - - setup(function() { - PolymerTest.clearBody(); - manager = document.createElement('extensions-manager'); - document.body.appendChild(manager); - - // Wait for the first view to be active before starting tests, if one is - // not active already. Sometimes, on Mac with native HTML imports - // disabled, no views are active at this point. - return manager.$.viewManager.querySelector('.active') ? - Promise.resolve() : - eventToPromise('view-enter-start', manager); - }); - - test( - assert(extension_manager_tests.TestNames.ItemListVisibility), - function() { - const extension = getDataByName(manager.extensions_, 'My extension 1'); - - const list = manager.$['items-list']; - const listHasItemWithName = (name) => - !!list.extensions.find(el => el.name == name); - - expectEquals(manager.extensions_, manager.$['items-list'].extensions); - expectTrue(listHasItemWithName('My extension 1')); - - manager.removeItem_(extension.id); - flush(); - expectFalse(listHasItemWithName('My extension 1')); - - manager.addItem_('extensions_', extension); - flush(); - expectTrue(listHasItemWithName('My extension 1')); - }); - - test(assert(extension_manager_tests.TestNames.SplitItems), function() { - const sectionHasItemWithName = function(section, name) { - return !!manager[section].find(function(el) { - return el.name == name; - }); - }; - - // Test that we properly split up the items into two sections. - expectTrue(sectionHasItemWithName('extensions_', 'My extension 1')); - expectTrue(sectionHasItemWithName( - 'apps_', 'Platform App Test: minimal platform app')); - expectTrue(sectionHasItemWithName('apps_', 'hosted_app')); - expectTrue(sectionHasItemWithName('apps_', 'Packaged App Test')); - }); - - test(assert(extension_manager_tests.TestNames.ChangePages), function() { - manager.$$('extensions-toolbar').$$('cr-toolbar').$$('#menuButton') - .click(); - flush(); - - // We start on the item list. - manager.$$('#sidebar').$['sections-extensions'].click(); - flush(); - assertViewActive('extensions-item-list'); - - // Switch: item list -> keyboard shortcuts. - manager.$$('#sidebar').$['sections-shortcuts'].click(); - flush(); - assertViewActive('extensions-keyboard-shortcuts'); - - // Switch: item list -> detail view. - const item = manager.$['items-list'].$$('extensions-item'); - assert(item); - item.onDetailsTap_(); - flush(); - assertViewActive('extensions-detail-view'); - - // Switch: detail view -> keyboard shortcuts. - manager.$$('#sidebar').$['sections-shortcuts'].click(); - flush(); - assertViewActive('extensions-keyboard-shortcuts'); - - // We get back on the item list. - manager.$$('#sidebar').$['sections-extensions'].click(); - flush(); - assertViewActive('extensions-item-list'); - }); - - test(assert(extension_manager_tests.TestNames.PageTitleUpdate), function() { - expectEquals('Extensions', document.title); - - // Open details view with a valid ID. - navigation.navigateTo({ - page: Page.DETAILS, - extensionId: 'ldnnhddmnhbkjipkidpdiheffobcpfmf' - }); - flush(); - expectEquals('Extensions - My extension 1', document.title); - - // Navigate back to the list view and check the page title. - navigation.navigateTo({page: Page.LIST}); - flush(); - expectEquals('Extensions', document.title); - }); + // Wait for the first view to be active before starting tests, if one is + // not active already. Sometimes, on Mac with native HTML imports + // disabled, no views are active at this point. + return manager.$.viewManager.querySelector('.active') ? + Promise.resolve() : + eventToPromise('view-enter-start', manager); }); + + test( + assert(extension_manager_tests.TestNames.ItemListVisibility), function() { + const extension = getDataByName(manager.extensions_, 'My extension 1'); + + const list = manager.$['items-list']; + const listHasItemWithName = (name) => + !!list.extensions.find(el => el.name == name); + + expectEquals(manager.extensions_, manager.$['items-list'].extensions); + expectTrue(listHasItemWithName('My extension 1')); + + manager.removeItem_(extension.id); + flush(); + expectFalse(listHasItemWithName('My extension 1')); + + manager.addItem_('extensions_', extension); + flush(); + expectTrue(listHasItemWithName('My extension 1')); + }); + + test(assert(extension_manager_tests.TestNames.SplitItems), function() { + const sectionHasItemWithName = function(section, name) { + return !!manager[section].find(function(el) { + return el.name == name; + }); + }; + + // Test that we properly split up the items into two sections. + expectTrue(sectionHasItemWithName('extensions_', 'My extension 1')); + expectTrue(sectionHasItemWithName( + 'apps_', 'Platform App Test: minimal platform app')); + expectTrue(sectionHasItemWithName('apps_', 'hosted_app')); + expectTrue(sectionHasItemWithName('apps_', 'Packaged App Test')); + }); + + test(assert(extension_manager_tests.TestNames.ChangePages), function() { + manager.$$('extensions-toolbar').$$('cr-toolbar').$$('#menuButton').click(); + flush(); + + // We start on the item list. + manager.$$('#sidebar').$['sections-extensions'].click(); + flush(); + assertViewActive('extensions-item-list'); + + // Switch: item list -> keyboard shortcuts. + manager.$$('#sidebar').$['sections-shortcuts'].click(); + flush(); + assertViewActive('extensions-keyboard-shortcuts'); + + // Switch: item list -> detail view. + const item = manager.$['items-list'].$$('extensions-item'); + assert(item); + item.onDetailsTap_(); + flush(); + assertViewActive('extensions-detail-view'); + + // Switch: detail view -> keyboard shortcuts. + manager.$$('#sidebar').$['sections-shortcuts'].click(); + flush(); + assertViewActive('extensions-keyboard-shortcuts'); + + // We get back on the item list. + manager.$$('#sidebar').$['sections-extensions'].click(); + flush(); + assertViewActive('extensions-item-list'); + }); + + test(assert(extension_manager_tests.TestNames.PageTitleUpdate), function() { + expectEquals('Extensions', document.title); + + // Open details view with a valid ID. + navigation.navigateTo( + {page: Page.DETAILS, extensionId: 'ldnnhddmnhbkjipkidpdiheffobcpfmf'}); + flush(); + expectEquals('Extensions - My extension 1', document.title); + + // Navigate back to the list view and check the page title. + navigation.navigateTo({page: Page.LIST}); + flush(); + expectEquals('Extensions', document.title); + }); +});
diff --git a/chrome/test/data/webui/extensions/manager_unit_test.js b/chrome/test/data/webui/extensions/manager_unit_test.js index 1c91f19..33c9b444 100644 --- a/chrome/test/data/webui/extensions/manager_unit_test.js +++ b/chrome/test/data/webui/extensions/manager_unit_test.js
@@ -2,9 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -/** @fileoverview Suite of tests for extension-manager unit tests. Unlike +/** + * @fileoverview Suite of tests for extension-manager unit tests. Unlike * extension_manager_test.js, these tests are not interacting with the real - * chrome.developerPrivate API. */ + * chrome.developerPrivate API. + */ import {navigation, Page, Service} from 'chrome://extensions/extensions.js'; @@ -13,301 +15,300 @@ import {TestService} from './test_service.js'; import {createExtensionInfo} from './test_util.js'; - window.extension_manager_unit_tests = {}; - extension_manager_unit_tests.suiteName = 'ExtensionManagerUnitTest'; - /** @enum {string} */ - extension_manager_unit_tests.TestNames = { - EnableAndDisable: 'enable and disable', - ItemOrder: 'item order', - ProfileSettings: 'profile settings', - ToggleIncognitoMode: 'toggle incognito mode', - Uninstall: 'uninstall', - UninstallFromDetails: 'uninstall while in details view', - SetItemData: 'set item data', - UpdateItemData: 'update item data', - }; +window.extension_manager_unit_tests = {}; +extension_manager_unit_tests.suiteName = 'ExtensionManagerUnitTest'; +/** @enum {string} */ +extension_manager_unit_tests.TestNames = { + EnableAndDisable: 'enable and disable', + ItemOrder: 'item order', + ProfileSettings: 'profile settings', + ToggleIncognitoMode: 'toggle incognito mode', + Uninstall: 'uninstall', + UninstallFromDetails: 'uninstall while in details view', + SetItemData: 'set item data', + UpdateItemData: 'update item data', +}; - suite(extension_manager_unit_tests.suiteName, function() { - /** @type {Manager} */ - let manager; +suite(extension_manager_unit_tests.suiteName, function() { + /** @type {Manager} */ + let manager; - /** @type {TestService} */ - let service; + /** @type {TestService} */ + let service; - /** @type {?KioskBrowserProxy} */ - let browserProxy; + /** @type {?KioskBrowserProxy} */ + let browserProxy; - const testActivities = {activities: []}; + const testActivities = {activities: []}; - setup(function() { - PolymerTest.clearBody(); + setup(function() { + PolymerTest.clearBody(); - service = new TestService(); - Service.instance_ = service; + service = new TestService(); + Service.instance_ = service; - manager = document.createElement('extensions-manager'); - document.body.appendChild(manager); + manager = document.createElement('extensions-manager'); + document.body.appendChild(manager); - // Wait until Manager calls fetches data and initializes itself before - // making any assertions. - return Promise.all([ - service.whenCalled('getExtensionsInfo'), - service.whenCalled('getProfileConfiguration'), - ]); - }); - - /** - * Trigger an event that indicates that an extension was installed. - * @param {!chrome.developerPrivate.ExtensionInfo} info - */ - function simulateExtensionInstall(info) { - service.itemStateChangedTarget.callListeners({ - event_type: chrome.developerPrivate.EventType.INSTALLED, - extensionInfo: info, - }); - } - - // Test that newly added items are inserted in the correct order. - test(assert(extension_manager_unit_tests.TestNames.ItemOrder), function() { - expectEquals(0, manager.extensions_.length); - - const alphaFromStore = createExtensionInfo( - {location: 'FROM_STORE', name: 'Alpha', id: 'a'.repeat(32)}); - simulateExtensionInstall(alphaFromStore); - expectEquals(1, manager.extensions_.length); - expectEquals(alphaFromStore.id, manager.extensions_[0].id); - - // Unpacked extensions come first. - const betaUnpacked = createExtensionInfo( - {location: 'UNPACKED', name: 'Beta', id: 'b'.repeat(32)}); - simulateExtensionInstall(betaUnpacked); - expectEquals(2, manager.extensions_.length); - expectEquals(betaUnpacked.id, manager.extensions_[0].id); - expectEquals(alphaFromStore.id, manager.extensions_[1].id); - - // Extensions from the same location are sorted by name. - let gammaUnpacked = createExtensionInfo( - {location: 'UNPACKED', name: 'Gamma', id: 'c'.repeat(32)}); - simulateExtensionInstall(gammaUnpacked); - expectEquals(3, manager.extensions_.length); - expectEquals(betaUnpacked.id, manager.extensions_[0].id); - expectEquals(gammaUnpacked.id, manager.extensions_[1].id); - expectEquals(alphaFromStore.id, manager.extensions_[2].id); - - // The name-sort should be case-insensitive, and should fall back on - // id. - const aaFromStore = createExtensionInfo( - {location: 'FROM_STORE', name: 'AA', id: 'd'.repeat(32)}); - simulateExtensionInstall(aaFromStore); - const AaFromStore = createExtensionInfo( - {location: 'FROM_STORE', name: 'Aa', id: 'e'.repeat(32)}); - simulateExtensionInstall(AaFromStore); - const aAFromStore = createExtensionInfo( - {location: 'FROM_STORE', name: 'aA', id: 'f'.repeat(32)}); - simulateExtensionInstall(aAFromStore); - - expectEquals(6, manager.extensions_.length); - expectEquals(betaUnpacked.id, manager.extensions_[0].id); - expectEquals(gammaUnpacked.id, manager.extensions_[1].id); - expectEquals(aaFromStore.id, manager.extensions_[2].id); - expectEquals(AaFromStore.id, manager.extensions_[3].id); - expectEquals(aAFromStore.id, manager.extensions_[4].id); - expectEquals(alphaFromStore.id, manager.extensions_[5].id); - }); - - test(assert(extension_manager_unit_tests.TestNames.SetItemData), function() { - const description = 'description'; - - const extension = createExtensionInfo({description: description}); - simulateExtensionInstall(extension); - - // The detail view is not present until navigation. - expectFalse(!!manager.$$('extensions-detail-view')); - navigation.navigateTo({page: Page.DETAILS, extensionId: extension.id}); - const detailsView = manager.$$('extensions-detail-view'); - expectTrue(!!detailsView); // View should now be present. - expectEquals(extension.id, detailsView.data.id); - expectEquals(description, detailsView.data.description); - expectEquals( - description, - detailsView.$$('.section .section-content').textContent.trim()); - }); - - test( - assert(extension_manager_unit_tests.TestNames.UpdateItemData), - function() { - const oldDescription = 'old description'; - const newDescription = 'new description'; - - const extension = createExtensionInfo({description: oldDescription}); - simulateExtensionInstall(extension); - const secondExtension = createExtensionInfo({ - description: 'irrelevant', - id: 'b'.repeat(32), - }); - simulateExtensionInstall(secondExtension); - - navigation.navigateTo( - {page: Page.DETAILS, extensionId: extension.id}); - const detailsView = manager.$$('extensions-detail-view'); - - let extensionCopy = Object.assign({}, extension); - extensionCopy.description = newDescription; - service.itemStateChangedTarget.callListeners({ - event_type: chrome.developerPrivate.EventType.PREFS_CHANGED, - extensionInfo: extensionCopy, - }); - - // Updating a different extension shouldn't have any impact. - let secondExtensionCopy = Object.assign({}, secondExtension); - secondExtensionCopy.description = 'something else'; - service.itemStateChangedTarget.callListeners({ - event_type: chrome.developerPrivate.EventType.PREFS_CHANGED, - extensionInfo: secondExtensionCopy, - }); - expectEquals(extension.id, detailsView.data.id); - expectEquals(newDescription, detailsView.data.description); - expectEquals( - newDescription, - detailsView.$$('.section .section-content').textContent.trim()); - }); - - test( - assert(extension_manager_unit_tests.TestNames.ProfileSettings), - function() { - expectFalse(manager.inDevMode); - - service.profileStateChangedTarget.callListeners( - {inDeveloperMode: true}); - expectTrue(manager.inDevMode); - - service.profileStateChangedTarget.callListeners( - {inDeveloperMode: false}); - expectFalse(manager.inDevMode); - - service.profileStateChangedTarget.callListeners( - {canLoadUnpacked: true}); - expectTrue(manager.canLoadUnpacked); - - service.profileStateChangedTarget.callListeners( - {canLoadUnpacked: false}); - expectFalse(manager.canLoadUnpacked); - }); - - test(assert(extension_manager_unit_tests.TestNames.Uninstall), function() { - expectEquals(0, manager.extensions_.length); - - const extension = createExtensionInfo( - {location: 'FROM_STORE', name: 'Alpha', id: 'a'.repeat(32)}); - simulateExtensionInstall(extension); - expectEquals(1, manager.extensions_.length); - - service.itemStateChangedTarget.callListeners({ - event_type: chrome.developerPrivate.EventType.UNINSTALLED, - // When an extension is uninstalled, only the ID is passed back from - // C++. - item_id: extension.id, - }); - - expectEquals(0, manager.extensions_.length); - }); - - /** @param {string} tagName */ - function assertViewActive(tagName) { - expectTrue(!!manager.$.viewManager.querySelector(`${tagName}.active`)); - } - - test( - assert(extension_manager_unit_tests.TestNames.UninstallFromDetails), - function(done) { - const extension = createExtensionInfo( - {location: 'FROM_STORE', name: 'Alpha', id: 'a'.repeat(32)}); - simulateExtensionInstall(extension); - - navigation.navigateTo({page: Page.DETAILS, extensionId: extension.id}); - flush(); - assertViewActive('extensions-detail-view'); - - window.addEventListener('popstate', () => { - assertViewActive('extensions-item-list'); - done(); - }); - - service.itemStateChangedTarget.callListeners({ - event_type: chrome.developerPrivate.EventType.UNINSTALLED, - // When an extension is uninstalled, only the ID is passed back from - // C++. - item_id: extension.id, - }); - }); - - test( - assert(extension_manager_unit_tests.TestNames.ToggleIncognitoMode), - function() { - expectEquals(0, manager.extensions_.length); - const extension = createExtensionInfo( - {location: 'FROM_STORE', name: 'Alpha', id: 'a'.repeat(32)}); - simulateExtensionInstall(extension); - expectEquals(1, manager.extensions_.length); - - expectEquals(extension, manager.extensions_[0]); - expectTrue(extension.incognitoAccess.isEnabled); - expectFalse(extension.incognitoAccess.isActive); - - // Simulate granting incognito permission. - const extensionCopy1 = Object.assign({}, extension); - extensionCopy1.incognitoAccess.isActive = true; - service.itemStateChangedTarget.callListeners({ - event_type: chrome.developerPrivate.EventType.LOADED, - extensionInfo: extensionCopy1, - }); - - expectTrue(manager.extensions_[0].incognitoAccess.isActive); - - // Simulate revoking incognito permission. - const extensionCopy2 = Object.assign({}, extension); - extensionCopy2.incognitoAccess.isActive = false; - service.itemStateChangedTarget.callListeners({ - event_type: chrome.developerPrivate.EventType.LOADED, - extensionInfo: extensionCopy2, - }); - expectFalse(manager.extensions_[0].incognitoAccess.isActive); - }); - - test( - assert(extension_manager_unit_tests.TestNames.EnableAndDisable), - function() { - const ExtensionState = chrome.developerPrivate.ExtensionState; - expectEquals(0, manager.extensions_.length); - const extension = createExtensionInfo({ - location: 'FROM_STORE', - name: 'My extension 1', - id: 'a'.repeat(32) - }); - simulateExtensionInstall(extension); - expectEquals(1, manager.extensions_.length); - - expectEquals(extension, manager.extensions_[0]); - expectEquals('My extension 1', extension.name); - expectEquals(ExtensionState.ENABLED, extension.state); - - // Simulate disabling an extension. - const extensionCopy1 = Object.assign({}, extension); - extensionCopy1.state = ExtensionState.DISABLED; - service.itemStateChangedTarget.callListeners({ - event_type: chrome.developerPrivate.EventType.LOADED, - extensionInfo: extensionCopy1, - }); - expectEquals(ExtensionState.DISABLED, manager.extensions_[0].state); - - // Simulate re-enabling an extension. - // Simulate disabling an extension. - const extensionCopy2 = Object.assign({}, extension); - extensionCopy2.state = ExtensionState.ENABLED; - service.itemStateChangedTarget.callListeners({ - event_type: chrome.developerPrivate.EventType.LOADED, - extensionInfo: extensionCopy2, - }); - expectEquals(ExtensionState.ENABLED, manager.extensions_[0].state); - }); + // Wait until Manager calls fetches data and initializes itself before + // making any assertions. + return Promise.all([ + service.whenCalled('getExtensionsInfo'), + service.whenCalled('getProfileConfiguration'), + ]); }); + + /** + * Trigger an event that indicates that an extension was installed. + * @param {!chrome.developerPrivate.ExtensionInfo} info + */ + function simulateExtensionInstall(info) { + service.itemStateChangedTarget.callListeners({ + event_type: chrome.developerPrivate.EventType.INSTALLED, + extensionInfo: info, + }); + } + + // Test that newly added items are inserted in the correct order. + test(assert(extension_manager_unit_tests.TestNames.ItemOrder), function() { + expectEquals(0, manager.extensions_.length); + + const alphaFromStore = createExtensionInfo( + {location: 'FROM_STORE', name: 'Alpha', id: 'a'.repeat(32)}); + simulateExtensionInstall(alphaFromStore); + expectEquals(1, manager.extensions_.length); + expectEquals(alphaFromStore.id, manager.extensions_[0].id); + + // Unpacked extensions come first. + const betaUnpacked = createExtensionInfo( + {location: 'UNPACKED', name: 'Beta', id: 'b'.repeat(32)}); + simulateExtensionInstall(betaUnpacked); + expectEquals(2, manager.extensions_.length); + expectEquals(betaUnpacked.id, manager.extensions_[0].id); + expectEquals(alphaFromStore.id, manager.extensions_[1].id); + + // Extensions from the same location are sorted by name. + let gammaUnpacked = createExtensionInfo( + {location: 'UNPACKED', name: 'Gamma', id: 'c'.repeat(32)}); + simulateExtensionInstall(gammaUnpacked); + expectEquals(3, manager.extensions_.length); + expectEquals(betaUnpacked.id, manager.extensions_[0].id); + expectEquals(gammaUnpacked.id, manager.extensions_[1].id); + expectEquals(alphaFromStore.id, manager.extensions_[2].id); + + // The name-sort should be case-insensitive, and should fall back on + // id. + const aaFromStore = createExtensionInfo( + {location: 'FROM_STORE', name: 'AA', id: 'd'.repeat(32)}); + simulateExtensionInstall(aaFromStore); + const AaFromStore = createExtensionInfo( + {location: 'FROM_STORE', name: 'Aa', id: 'e'.repeat(32)}); + simulateExtensionInstall(AaFromStore); + const aAFromStore = createExtensionInfo( + {location: 'FROM_STORE', name: 'aA', id: 'f'.repeat(32)}); + simulateExtensionInstall(aAFromStore); + + expectEquals(6, manager.extensions_.length); + expectEquals(betaUnpacked.id, manager.extensions_[0].id); + expectEquals(gammaUnpacked.id, manager.extensions_[1].id); + expectEquals(aaFromStore.id, manager.extensions_[2].id); + expectEquals(AaFromStore.id, manager.extensions_[3].id); + expectEquals(aAFromStore.id, manager.extensions_[4].id); + expectEquals(alphaFromStore.id, manager.extensions_[5].id); + }); + + test(assert(extension_manager_unit_tests.TestNames.SetItemData), function() { + const description = 'description'; + + const extension = createExtensionInfo({description: description}); + simulateExtensionInstall(extension); + + // The detail view is not present until navigation. + expectFalse(!!manager.$$('extensions-detail-view')); + navigation.navigateTo({page: Page.DETAILS, extensionId: extension.id}); + const detailsView = manager.$$('extensions-detail-view'); + expectTrue(!!detailsView); // View should now be present. + expectEquals(extension.id, detailsView.data.id); + expectEquals(description, detailsView.data.description); + expectEquals( + description, + detailsView.$$('.section .section-content').textContent.trim()); + }); + + test( + assert(extension_manager_unit_tests.TestNames.UpdateItemData), + function() { + const oldDescription = 'old description'; + const newDescription = 'new description'; + + const extension = createExtensionInfo({description: oldDescription}); + simulateExtensionInstall(extension); + const secondExtension = createExtensionInfo({ + description: 'irrelevant', + id: 'b'.repeat(32), + }); + simulateExtensionInstall(secondExtension); + + navigation.navigateTo({page: Page.DETAILS, extensionId: extension.id}); + const detailsView = manager.$$('extensions-detail-view'); + + let extensionCopy = Object.assign({}, extension); + extensionCopy.description = newDescription; + service.itemStateChangedTarget.callListeners({ + event_type: chrome.developerPrivate.EventType.PREFS_CHANGED, + extensionInfo: extensionCopy, + }); + + // Updating a different extension shouldn't have any impact. + let secondExtensionCopy = Object.assign({}, secondExtension); + secondExtensionCopy.description = 'something else'; + service.itemStateChangedTarget.callListeners({ + event_type: chrome.developerPrivate.EventType.PREFS_CHANGED, + extensionInfo: secondExtensionCopy, + }); + expectEquals(extension.id, detailsView.data.id); + expectEquals(newDescription, detailsView.data.description); + expectEquals( + newDescription, + detailsView.$$('.section .section-content').textContent.trim()); + }); + + test( + assert(extension_manager_unit_tests.TestNames.ProfileSettings), + function() { + expectFalse(manager.inDevMode); + + service.profileStateChangedTarget.callListeners( + {inDeveloperMode: true}); + expectTrue(manager.inDevMode); + + service.profileStateChangedTarget.callListeners( + {inDeveloperMode: false}); + expectFalse(manager.inDevMode); + + service.profileStateChangedTarget.callListeners( + {canLoadUnpacked: true}); + expectTrue(manager.canLoadUnpacked); + + service.profileStateChangedTarget.callListeners( + {canLoadUnpacked: false}); + expectFalse(manager.canLoadUnpacked); + }); + + test(assert(extension_manager_unit_tests.TestNames.Uninstall), function() { + expectEquals(0, manager.extensions_.length); + + const extension = createExtensionInfo( + {location: 'FROM_STORE', name: 'Alpha', id: 'a'.repeat(32)}); + simulateExtensionInstall(extension); + expectEquals(1, manager.extensions_.length); + + service.itemStateChangedTarget.callListeners({ + event_type: chrome.developerPrivate.EventType.UNINSTALLED, + // When an extension is uninstalled, only the ID is passed back from + // C++. + item_id: extension.id, + }); + + expectEquals(0, manager.extensions_.length); + }); + + /** @param {string} tagName */ + function assertViewActive(tagName) { + expectTrue(!!manager.$.viewManager.querySelector(`${tagName}.active`)); + } + + test( + assert(extension_manager_unit_tests.TestNames.UninstallFromDetails), + function(done) { + const extension = createExtensionInfo( + {location: 'FROM_STORE', name: 'Alpha', id: 'a'.repeat(32)}); + simulateExtensionInstall(extension); + + navigation.navigateTo({page: Page.DETAILS, extensionId: extension.id}); + flush(); + assertViewActive('extensions-detail-view'); + + window.addEventListener('popstate', () => { + assertViewActive('extensions-item-list'); + done(); + }); + + service.itemStateChangedTarget.callListeners({ + event_type: chrome.developerPrivate.EventType.UNINSTALLED, + // When an extension is uninstalled, only the ID is passed back from + // C++. + item_id: extension.id, + }); + }); + + test( + assert(extension_manager_unit_tests.TestNames.ToggleIncognitoMode), + function() { + expectEquals(0, manager.extensions_.length); + const extension = createExtensionInfo( + {location: 'FROM_STORE', name: 'Alpha', id: 'a'.repeat(32)}); + simulateExtensionInstall(extension); + expectEquals(1, manager.extensions_.length); + + expectEquals(extension, manager.extensions_[0]); + expectTrue(extension.incognitoAccess.isEnabled); + expectFalse(extension.incognitoAccess.isActive); + + // Simulate granting incognito permission. + const extensionCopy1 = Object.assign({}, extension); + extensionCopy1.incognitoAccess.isActive = true; + service.itemStateChangedTarget.callListeners({ + event_type: chrome.developerPrivate.EventType.LOADED, + extensionInfo: extensionCopy1, + }); + + expectTrue(manager.extensions_[0].incognitoAccess.isActive); + + // Simulate revoking incognito permission. + const extensionCopy2 = Object.assign({}, extension); + extensionCopy2.incognitoAccess.isActive = false; + service.itemStateChangedTarget.callListeners({ + event_type: chrome.developerPrivate.EventType.LOADED, + extensionInfo: extensionCopy2, + }); + expectFalse(manager.extensions_[0].incognitoAccess.isActive); + }); + + test( + assert(extension_manager_unit_tests.TestNames.EnableAndDisable), + function() { + const ExtensionState = chrome.developerPrivate.ExtensionState; + expectEquals(0, manager.extensions_.length); + const extension = createExtensionInfo({ + location: 'FROM_STORE', + name: 'My extension 1', + id: 'a'.repeat(32) + }); + simulateExtensionInstall(extension); + expectEquals(1, manager.extensions_.length); + + expectEquals(extension, manager.extensions_[0]); + expectEquals('My extension 1', extension.name); + expectEquals(ExtensionState.ENABLED, extension.state); + + // Simulate disabling an extension. + const extensionCopy1 = Object.assign({}, extension); + extensionCopy1.state = ExtensionState.DISABLED; + service.itemStateChangedTarget.callListeners({ + event_type: chrome.developerPrivate.EventType.LOADED, + extensionInfo: extensionCopy1, + }); + expectEquals(ExtensionState.DISABLED, manager.extensions_[0].state); + + // Simulate re-enabling an extension. + // Simulate disabling an extension. + const extensionCopy2 = Object.assign({}, extension); + extensionCopy2.state = ExtensionState.ENABLED; + service.itemStateChangedTarget.callListeners({ + event_type: chrome.developerPrivate.EventType.LOADED, + extensionInfo: extensionCopy2, + }); + expectEquals(ExtensionState.ENABLED, manager.extensions_[0].state); + }); +});
diff --git a/chrome/test/data/webui/extensions/navigation_helper_test.js b/chrome/test/data/webui/extensions/navigation_helper_test.js index d85abcf..915bf91 100644 --- a/chrome/test/data/webui/extensions/navigation_helper_test.js +++ b/chrome/test/data/webui/extensions/navigation_helper_test.js
@@ -7,199 +7,194 @@ import {assert} from 'chrome://resources/js/assert.m.js'; import {MockMethod} from '../mock_controller.m.js'; - window.extension_navigation_helper_tests = {}; - extension_navigation_helper_tests.suiteName = 'ExtensionNavigationHelperTest'; - /** @enum {string} */ - extension_navigation_helper_tests.TestNames = { - Basic: 'basic', - Conversions: 'conversions', - PushAndReplaceState: 'push and replace state', - SupportedRoutes: 'supported routes' - }; +window.extension_navigation_helper_tests = {}; +extension_navigation_helper_tests.suiteName = 'ExtensionNavigationHelperTest'; +/** @enum {string} */ +extension_navigation_helper_tests.TestNames = { + Basic: 'basic', + Conversions: 'conversions', + PushAndReplaceState: 'push and replace state', + SupportedRoutes: 'supported routes' +}; - /** - * @return {!Promise<void>} A promise that resolves after the next popstate - * event. - */ - function getOnPopState() { - return new Promise(function(resolve, reject) { - window.addEventListener('popstate', function listener() { - window.removeEventListener('popstate', listener); - // Resolve asynchronously to allow all other listeners to run. - window.setTimeout(resolve, 0); - }); +/** + * @return {!Promise<void>} A promise that resolves after the next popstate + * event. + */ +function getOnPopState() { + return new Promise(function(resolve, reject) { + window.addEventListener('popstate', function listener() { + window.removeEventListener('popstate', listener); + // Resolve asynchronously to allow all other listeners to run. + window.setTimeout(resolve, 0); }); - } + }); +} - suite(extension_navigation_helper_tests.suiteName, function() { - let navigationHelper; +suite(extension_navigation_helper_tests.suiteName, function() { + let navigationHelper; - setup(function() { - PolymerTest.clearBody(); - navigationHelper = new NavigationHelper(); - }); + setup(function() { + PolymerTest.clearBody(); + navigationHelper = new NavigationHelper(); + }); - test(assert(extension_navigation_helper_tests.TestNames.Basic), function() { - const id = 'a'.repeat(32); - const mock = new MockMethod(); - const changePage = function(state) { - mock.recordCall([state]); - }; + test(assert(extension_navigation_helper_tests.TestNames.Basic), function() { + const id = 'a'.repeat(32); + const mock = new MockMethod(); + const changePage = function(state) { + mock.recordCall([state]); + }; - navigationHelper.addListener(changePage); + navigationHelper.addListener(changePage); - expectDeepEquals({page: Page.LIST}, navigationHelper.getCurrentPage()); + expectDeepEquals({page: Page.LIST}, navigationHelper.getCurrentPage()); - let currentLength = history.length; - navigationHelper.updateHistory({page: Page.DETAILS, extensionId: id}); - expectEquals(++currentLength, history.length); + let currentLength = history.length; + navigationHelper.updateHistory({page: Page.DETAILS, extensionId: id}); + expectEquals(++currentLength, history.length); - navigationHelper.updateHistory({page: Page.ERRORS, extensionId: id}); - expectEquals(++currentLength, history.length); + navigationHelper.updateHistory({page: Page.ERRORS, extensionId: id}); + expectEquals(++currentLength, history.length); - mock.addExpectation({page: Page.DETAILS, extensionId: id}); - const waitForPop = getOnPopState(); - history.back(); - return waitForPop - .then(() => { - mock.verifyMock(); + mock.addExpectation({page: Page.DETAILS, extensionId: id}); + const waitForPop = getOnPopState(); + history.back(); + return waitForPop + .then(() => { + mock.verifyMock(); - mock.addExpectation({page: Page.LIST}); - const waitForNextPop = getOnPopState(); - history.back(); - return waitForNextPop; - }) - .then(() => { - mock.verifyMock(); - }); - }); - - test( - assert(extension_navigation_helper_tests.TestNames.Conversions), - function() { - const id = 'a'.repeat(32); - const stateUrlPairs = { - extensions: { - url: 'chrome://extensions/', - state: {page: Page.LIST}, - }, - details: { - url: 'chrome://extensions/?id=' + id, - state: {page: Page.DETAILS, extensionId: id}, - }, - options: { - url: 'chrome://extensions/?options=' + id, - state: { - page: Page.DETAILS, - extensionId: id, - subpage: Dialog.OPTIONS, - }, - }, - errors: { - url: 'chrome://extensions/?errors=' + id, - state: {page: Page.ERRORS, extensionId: id}, - }, - shortcuts: { - url: 'chrome://extensions/shortcuts', - state: {page: Page.SHORTCUTS}, - }, - }; - - // Test url -> state. - for (let key in stateUrlPairs) { - let entry = stateUrlPairs[key]; - history.pushState({}, '', entry.url); - expectDeepEquals( - entry.state, navigationHelper.getCurrentPage(), key); - } - - // Test state -> url. - for (let key in stateUrlPairs) { - let entry = stateUrlPairs[key]; - navigationHelper.updateHistory(entry.state); - expectEquals(entry.url, location.href, key); - } - }); - - test( - assert(extension_navigation_helper_tests.TestNames.PushAndReplaceState), - function() { - const id1 = 'a'.repeat(32); - const id2 = 'b'.repeat(32); - - history.pushState({}, '', 'chrome://extensions/'); - expectDeepEquals( - {page: Page.LIST}, navigationHelper.getCurrentPage()); - - let expectedLength = history.length; - - // Navigating to a new page pushes new state. - navigationHelper.updateHistory( - {page: Page.DETAILS, extensionId: id1}); - expectEquals(++expectedLength, history.length); - - // Navigating to a subpage (like the options page) just opens a - // dialog, and shouldn't push new state. - navigationHelper.updateHistory( - {page: Page.DETAILS, extensionId: id1, subpage: Dialog.OPTIONS}); - expectEquals(expectedLength, history.length); - - // Navigating away from a subpage also shouldn't push state (it just - // closes the dialog). - navigationHelper.updateHistory( - {page: Page.DETAILS, extensionId: id1}); - expectEquals(expectedLength, history.length); - - // Navigating away should push new state. - navigationHelper.updateHistory({page: Page.LIST}); - expectEquals(++expectedLength, history.length); - - // Navigating to a subpage of a different page should push state. - navigationHelper.updateHistory( - {page: Page.DETAILS, extensionId: id1, subpage: Dialog.OPTIONS}); - expectEquals(++expectedLength, history.length); - - // Navigating away from a subpage to a page for a different item - // should push state. - navigationHelper.updateHistory( - {page: Page.DETAILS, extensionId: id2}); - expectEquals(++expectedLength, history.length); - - // Using replaceWith, which passes true for replaceState should not - // push state. - navigationHelper.updateHistory( - {page: Page.DETAILS, extensionId: id1}, true /* replaceState */); - expectEquals(expectedLength, history.length); - }); - - test( - assert(extension_navigation_helper_tests.TestNames.SupportedRoutes), - function() { - function removeEndSlash(url) { - const CANONICAL_PATH_REGEX = /([\/-\w]+)\/$/; - return url.replace(CANONICAL_PATH_REGEX, '$1'); - } - - // If it should not redirect, leave newUrl as undefined. - function testIfRedirected(url, newUrl) { - history.pushState({}, '', url); - const testNavigationHelper = new NavigationHelper(); - expectEquals( - removeEndSlash(window.location.href), - removeEndSlash(newUrl || url)); - } - - testIfRedirected('chrome://extensions'); - testIfRedirected('chrome://extensions/'); - testIfRedirected('chrome://extensions/shortcuts'); - testIfRedirected('chrome://extensions/shortcuts/'); - testIfRedirected( - 'chrome://extensions/fake-route', 'chrome://extensions'); - // Test trailing slash works. - - // Test legacy paths - testIfRedirected( - 'chrome://extensions/configureCommands', - 'chrome://extensions/shortcuts'); + mock.addExpectation({page: Page.LIST}); + const waitForNextPop = getOnPopState(); + history.back(); + return waitForNextPop; + }) + .then(() => { + mock.verifyMock(); }); }); + + test( + assert(extension_navigation_helper_tests.TestNames.Conversions), + function() { + const id = 'a'.repeat(32); + const stateUrlPairs = { + extensions: { + url: 'chrome://extensions/', + state: {page: Page.LIST}, + }, + details: { + url: 'chrome://extensions/?id=' + id, + state: {page: Page.DETAILS, extensionId: id}, + }, + options: { + url: 'chrome://extensions/?options=' + id, + state: { + page: Page.DETAILS, + extensionId: id, + subpage: Dialog.OPTIONS, + }, + }, + errors: { + url: 'chrome://extensions/?errors=' + id, + state: {page: Page.ERRORS, extensionId: id}, + }, + shortcuts: { + url: 'chrome://extensions/shortcuts', + state: {page: Page.SHORTCUTS}, + }, + }; + + // Test url -> state. + for (let key in stateUrlPairs) { + let entry = stateUrlPairs[key]; + history.pushState({}, '', entry.url); + expectDeepEquals(entry.state, navigationHelper.getCurrentPage(), key); + } + + // Test state -> url. + for (let key in stateUrlPairs) { + let entry = stateUrlPairs[key]; + navigationHelper.updateHistory(entry.state); + expectEquals(entry.url, location.href, key); + } + }); + + test( + assert(extension_navigation_helper_tests.TestNames.PushAndReplaceState), + function() { + const id1 = 'a'.repeat(32); + const id2 = 'b'.repeat(32); + + history.pushState({}, '', 'chrome://extensions/'); + expectDeepEquals({page: Page.LIST}, navigationHelper.getCurrentPage()); + + let expectedLength = history.length; + + // Navigating to a new page pushes new state. + navigationHelper.updateHistory({page: Page.DETAILS, extensionId: id1}); + expectEquals(++expectedLength, history.length); + + // Navigating to a subpage (like the options page) just opens a + // dialog, and shouldn't push new state. + navigationHelper.updateHistory( + {page: Page.DETAILS, extensionId: id1, subpage: Dialog.OPTIONS}); + expectEquals(expectedLength, history.length); + + // Navigating away from a subpage also shouldn't push state (it just + // closes the dialog). + navigationHelper.updateHistory({page: Page.DETAILS, extensionId: id1}); + expectEquals(expectedLength, history.length); + + // Navigating away should push new state. + navigationHelper.updateHistory({page: Page.LIST}); + expectEquals(++expectedLength, history.length); + + // Navigating to a subpage of a different page should push state. + navigationHelper.updateHistory( + {page: Page.DETAILS, extensionId: id1, subpage: Dialog.OPTIONS}); + expectEquals(++expectedLength, history.length); + + // Navigating away from a subpage to a page for a different item + // should push state. + navigationHelper.updateHistory({page: Page.DETAILS, extensionId: id2}); + expectEquals(++expectedLength, history.length); + + // Using replaceWith, which passes true for replaceState should not + // push state. + navigationHelper.updateHistory( + {page: Page.DETAILS, extensionId: id1}, true /* replaceState */); + expectEquals(expectedLength, history.length); + }); + + test( + assert(extension_navigation_helper_tests.TestNames.SupportedRoutes), + function() { + function removeEndSlash(url) { + const CANONICAL_PATH_REGEX = /([\/-\w]+)\/$/; + return url.replace(CANONICAL_PATH_REGEX, '$1'); + } + + // If it should not redirect, leave newUrl as undefined. + function testIfRedirected(url, newUrl) { + history.pushState({}, '', url); + const testNavigationHelper = new NavigationHelper(); + expectEquals( + removeEndSlash(window.location.href), + removeEndSlash(newUrl || url)); + } + + testIfRedirected('chrome://extensions'); + testIfRedirected('chrome://extensions/'); + testIfRedirected('chrome://extensions/shortcuts'); + testIfRedirected('chrome://extensions/shortcuts/'); + testIfRedirected( + 'chrome://extensions/fake-route', 'chrome://extensions'); + // Test trailing slash works. + + // Test legacy paths + testIfRedirected( + 'chrome://extensions/configureCommands', + 'chrome://extensions/shortcuts'); + }); +});
diff --git a/chrome/test/data/webui/extensions/options_dialog_test.js b/chrome/test/data/webui/extensions/options_dialog_test.js index abc120e..95f52e6 100644 --- a/chrome/test/data/webui/extensions/options_dialog_test.js +++ b/chrome/test/data/webui/extensions/options_dialog_test.js
@@ -8,61 +8,61 @@ import {assert} from 'chrome://resources/js/assert.m.js'; import {eventToPromise} from '../test_util.m.js'; - window.extension_options_dialog_tests = {}; - extension_options_dialog_tests.suiteName = 'ExtensionOptionsDialogTests'; - /** @enum {string} */ - extension_options_dialog_tests.TestNames = { - Layout: 'Layout', - }; +window.extension_options_dialog_tests = {}; +extension_options_dialog_tests.suiteName = 'ExtensionOptionsDialogTests'; +/** @enum {string} */ +extension_options_dialog_tests.TestNames = { + Layout: 'Layout', +}; - suite(extension_options_dialog_tests.suiteName, function() { - /** @type {ExtensionsOptionsDialogElement} */ - let optionsDialog; +suite(extension_options_dialog_tests.suiteName, function() { + /** @type {ExtensionsOptionsDialogElement} */ + let optionsDialog; - /** @type {chrome.developerPrivate.ExtensionInfo} */ - let data; + /** @type {chrome.developerPrivate.ExtensionInfo} */ + let data; - setup(function() { - PolymerTest.clearBody(); - optionsDialog = document.createElement('extensions-options-dialog'); - document.body.appendChild(optionsDialog); + setup(function() { + PolymerTest.clearBody(); + optionsDialog = document.createElement('extensions-options-dialog'); + document.body.appendChild(optionsDialog); - const service = Service.getInstance(); - return service.getExtensionsInfo().then(function(info) { - assertEquals(1, info.length); - data = info[0]; - }); - }); - - function isDialogVisible() { - const dialogElement = optionsDialog.$.dialog.getNative(); - const rect = dialogElement.getBoundingClientRect(); - return rect.width * rect.height > 0; - } - - test(assert(extension_options_dialog_tests.TestNames.Layout), function() { - // Try showing the dialog. - assertFalse(isDialogVisible()); - optionsDialog.show(data); - return eventToPromise('cr-dialog-open', optionsDialog) - .then(() => { - // Wait more than 50ms for the debounced size update. - return new Promise(r => setTimeout(r, 100)); - }) - .then(() => { - assertTrue(isDialogVisible()); - - const dialogElement = optionsDialog.$.dialog.getNative(); - const rect = dialogElement.getBoundingClientRect(); - assertGE(rect.width, OptionsDialogMinWidth); - assertLE(rect.height, OptionsDialogMaxHeight); - // This is the header height with default font size. - assertGE(rect.height, 68); - - assertEquals( - data.name, - assert(optionsDialog.$$('#icon-and-name-wrapper span')) - .textContent.trim()); - }); + const service = Service.getInstance(); + return service.getExtensionsInfo().then(function(info) { + assertEquals(1, info.length); + data = info[0]; }); }); + + function isDialogVisible() { + const dialogElement = optionsDialog.$.dialog.getNative(); + const rect = dialogElement.getBoundingClientRect(); + return rect.width * rect.height > 0; + } + + test(assert(extension_options_dialog_tests.TestNames.Layout), function() { + // Try showing the dialog. + assertFalse(isDialogVisible()); + optionsDialog.show(data); + return eventToPromise('cr-dialog-open', optionsDialog) + .then(() => { + // Wait more than 50ms for the debounced size update. + return new Promise(r => setTimeout(r, 100)); + }) + .then(() => { + assertTrue(isDialogVisible()); + + const dialogElement = optionsDialog.$.dialog.getNative(); + const rect = dialogElement.getBoundingClientRect(); + assertGE(rect.width, OptionsDialogMinWidth); + assertLE(rect.height, OptionsDialogMaxHeight); + // This is the header height with default font size. + assertGE(rect.height, 68); + + assertEquals( + data.name, + assert(optionsDialog.$$('#icon-and-name-wrapper span')) + .textContent.trim()); + }); + }); +});
diff --git a/chrome/test/data/webui/extensions/pack_dialog_test.js b/chrome/test/data/webui/extensions/pack_dialog_test.js index ab1497ae..7848df9f 100644 --- a/chrome/test/data/webui/extensions/pack_dialog_test.js +++ b/chrome/test/data/webui/extensions/pack_dialog_test.js
@@ -14,221 +14,221 @@ import {isElementVisible} from './test_util.js'; - window.extension_pack_dialog_tests = {}; - extension_pack_dialog_tests.suiteName = 'ExtensionPackDialogTests'; - /** @enum {string} */ - extension_pack_dialog_tests.TestNames = { - Interaction: 'Interaction', - PackSuccess: 'PackSuccess', - PackWarning: 'PackWarning', - PackError: 'PackError', - }; +window.extension_pack_dialog_tests = {}; +extension_pack_dialog_tests.suiteName = 'ExtensionPackDialogTests'; +/** @enum {string} */ +extension_pack_dialog_tests.TestNames = { + Interaction: 'Interaction', + PackSuccess: 'PackSuccess', + PackWarning: 'PackWarning', + PackError: 'PackError', +}; - /** @implements {PackDialogDelegate} */ - class MockDelegate { - constructor() { - this.mockResponse = null; - this.rootPromise; - this.keyPromise; - this.flag = 0; - } - - /** @override */ - choosePackRootDirectory() { - this.rootPromise = new PromiseResolver(); - return this.rootPromise.promise; - } - - /** @override */ - choosePrivateKeyPath() { - this.keyPromise = new PromiseResolver(); - return this.keyPromise.promise; - } - - /** @override */ - packExtension(rootPath, keyPath, flag, callback) { - this.rootPath = rootPath; - this.keyPath = keyPath; - this.flag = flag; - - if (callback && this.mockResponse) { - callback(this.mockResponse); - } - } +/** @implements {PackDialogDelegate} */ +class MockDelegate { + constructor() { + this.mockResponse = null; + this.rootPromise; + this.keyPromise; + this.flag = 0; } - suite(extension_pack_dialog_tests.suiteName, function() { - /** @type {ExtensionsPackDialogElement} */ - let packDialog; + /** @override */ + choosePackRootDirectory() { + this.rootPromise = new PromiseResolver(); + return this.rootPromise.promise; + } - /** @type {MockDelegate} */ - let mockDelegate; + /** @override */ + choosePrivateKeyPath() { + this.keyPromise = new PromiseResolver(); + return this.keyPromise.promise; + } - setup(function() { - PolymerTest.clearBody(); - mockDelegate = new MockDelegate(); - packDialog = document.createElement('extensions-pack-dialog'); - packDialog.delegate = mockDelegate; - document.body.appendChild(packDialog); - }); + /** @override */ + packExtension(rootPath, keyPath, flag, callback) { + this.rootPath = rootPath; + this.keyPath = keyPath; + this.flag = flag; - test(assert(extension_pack_dialog_tests.TestNames.Interaction), function() { - const dialogElement = packDialog.$$('cr-dialog').getNative(); + if (callback && this.mockResponse) { + callback(this.mockResponse); + } + } +} - expectTrue(isElementVisible(dialogElement)); - expectEquals('', packDialog.$$('#root-dir').value); - packDialog.$$('#root-dir-browse').click(); - expectTrue(!!mockDelegate.rootPromise); - expectEquals('', packDialog.$$('#root-dir').value); - const kRootPath = 'this/is/a/path'; +suite(extension_pack_dialog_tests.suiteName, function() { + /** @type {ExtensionsPackDialogElement} */ + let packDialog; - const promises = []; - promises.push(mockDelegate.rootPromise.promise.then(function() { - expectEquals(kRootPath, packDialog.$$('#root-dir').value); - expectEquals(kRootPath, packDialog.packDirectory_); - })); + /** @type {MockDelegate} */ + let mockDelegate; - flush(); - expectEquals('', packDialog.$$('#key-file').value); - packDialog.$$('#key-file-browse').click(); - expectTrue(!!mockDelegate.keyPromise); - expectEquals('', packDialog.$$('#key-file').value); - const kKeyPath = 'here/is/another/path'; + setup(function() { + PolymerTest.clearBody(); + mockDelegate = new MockDelegate(); + packDialog = document.createElement('extensions-pack-dialog'); + packDialog.delegate = mockDelegate; + document.body.appendChild(packDialog); + }); - promises.push(mockDelegate.keyPromise.promise.then(function() { - expectEquals(kKeyPath, packDialog.$$('#key-file').value); - expectEquals(kKeyPath, packDialog.keyFile_); - })); + test(assert(extension_pack_dialog_tests.TestNames.Interaction), function() { + const dialogElement = packDialog.$$('cr-dialog').getNative(); - mockDelegate.rootPromise.resolve(kRootPath); - mockDelegate.keyPromise.resolve(kKeyPath); + expectTrue(isElementVisible(dialogElement)); + expectEquals('', packDialog.$$('#root-dir').value); + packDialog.$$('#root-dir-browse').click(); + expectTrue(!!mockDelegate.rootPromise); + expectEquals('', packDialog.$$('#root-dir').value); + const kRootPath = 'this/is/a/path'; - return Promise.all(promises).then(function() { - packDialog.$$('.action-button').click(); - expectEquals(kRootPath, mockDelegate.rootPath); - expectEquals(kKeyPath, mockDelegate.keyPath); - }); - }); + const promises = []; + promises.push(mockDelegate.rootPromise.promise.then(function() { + expectEquals(kRootPath, packDialog.$$('#root-dir').value); + expectEquals(kRootPath, packDialog.packDirectory_); + })); - test(assert(extension_pack_dialog_tests.TestNames.PackSuccess), function() { - const dialogElement = packDialog.$$('cr-dialog').getNative(); - let packDialogAlert; - let alertElement; + flush(); + expectEquals('', packDialog.$$('#key-file').value); + packDialog.$$('#key-file-browse').click(); + expectTrue(!!mockDelegate.keyPromise); + expectEquals('', packDialog.$$('#key-file').value); + const kKeyPath = 'here/is/another/path'; - expectTrue(isElementVisible(dialogElement)); + promises.push(mockDelegate.keyPromise.promise.then(function() { + expectEquals(kKeyPath, packDialog.$$('#key-file').value); + expectEquals(kKeyPath, packDialog.keyFile_); + })); - const kRootPath = 'this/is/a/path'; - mockDelegate.mockResponse = { - status: chrome.developerPrivate.PackStatus.SUCCESS - }; + mockDelegate.rootPromise.resolve(kRootPath); + mockDelegate.keyPromise.resolve(kKeyPath); - packDialog.$$('#root-dir-browse').click(); - mockDelegate.rootPromise.resolve(kRootPath); - - return mockDelegate.rootPromise.promise - .then(() => { - expectEquals(kRootPath, packDialog.$$('#root-dir').value); - packDialog.$$('.action-button').click(); - - return flushTasks(); - }) - .then(() => { - packDialogAlert = packDialog.$$('extensions-pack-dialog-alert'); - alertElement = packDialogAlert.$.dialog.getNative(); - expectTrue(isElementVisible(alertElement)); - expectTrue(isElementVisible(dialogElement)); - expectTrue(!!packDialogAlert.$$('.action-button')); - - const wait = eventToPromise('close', dialogElement); - // After 'ok', both dialogs should be closed. - packDialogAlert.$$('.action-button').click(); - - return wait; - }) - .then(() => { - expectFalse(isElementVisible(alertElement)); - expectFalse(isElementVisible(dialogElement)); - }); - }); - - test(assert(extension_pack_dialog_tests.TestNames.PackError), function() { - const dialogElement = packDialog.$$('cr-dialog').getNative(); - let packDialogAlert; - let alertElement; - - expectTrue(isElementVisible(dialogElement)); - - const kRootPath = 'this/is/a/path'; - mockDelegate.mockResponse = { - status: chrome.developerPrivate.PackStatus.ERROR - }; - - packDialog.$$('#root-dir-browse').click(); - mockDelegate.rootPromise.resolve(kRootPath); - - return mockDelegate.rootPromise.promise.then(() => { - expectEquals(kRootPath, packDialog.$$('#root-dir').value); - packDialog.$$('.action-button').click(); - flush(); - - // Make sure new alert and the appropriate buttons are visible. - packDialogAlert = packDialog.$$('extensions-pack-dialog-alert'); - alertElement = packDialogAlert.$.dialog.getNative(); - expectTrue(isElementVisible(alertElement)); - expectTrue(isElementVisible(dialogElement)); - expectTrue(!!packDialogAlert.$$('.action-button')); - - // After cancel, original dialog is still open and values unchanged. - packDialogAlert.$$('.action-button').click(); - flush(); - expectFalse(isElementVisible(alertElement)); - expectTrue(isElementVisible(dialogElement)); - expectEquals(kRootPath, packDialog.$$('#root-dir').value); - }); - }); - - test(assert(extension_pack_dialog_tests.TestNames.PackWarning), function() { - const dialogElement = packDialog.$$('cr-dialog').getNative(); - let packDialogAlert; - let alertElement; - - expectTrue(isElementVisible(dialogElement)); - - const kRootPath = 'this/is/a/path'; - mockDelegate.mockResponse = { - status: chrome.developerPrivate.PackStatus.WARNING, - item_path: 'item_path', - pem_path: 'pem_path', - override_flags: 1, - }; - - packDialog.$$('#root-dir-browse').click(); - mockDelegate.rootPromise.resolve(kRootPath); - - return mockDelegate.rootPromise.promise - .then(() => { - expectEquals(kRootPath, packDialog.$$('#root-dir').value); - packDialog.$$('.action-button').click(); - flush(); - - // Make sure new alert and the appropriate buttons are visible. - packDialogAlert = packDialog.$$('extensions-pack-dialog-alert'); - alertElement = packDialogAlert.$.dialog.getNative(); - expectTrue(isElementVisible(alertElement)); - expectTrue(isElementVisible(dialogElement)); - expectFalse(packDialogAlert.$$('.cancel-button').hidden); - expectFalse(packDialogAlert.$$('.action-button').hidden); - - // Make sure "proceed anyway" try to pack extension again. - const whenClosed = eventToPromise('close', packDialogAlert); - packDialogAlert.$$('.action-button').click(); - return whenClosed; - }) - .then(() => { - // Make sure packExtension is called again with the right params. - expectFalse(isElementVisible(alertElement)); - expectEquals( - mockDelegate.flag, mockDelegate.mockResponse.override_flags); - }); + return Promise.all(promises).then(function() { + packDialog.$$('.action-button').click(); + expectEquals(kRootPath, mockDelegate.rootPath); + expectEquals(kKeyPath, mockDelegate.keyPath); }); }); + + test(assert(extension_pack_dialog_tests.TestNames.PackSuccess), function() { + const dialogElement = packDialog.$$('cr-dialog').getNative(); + let packDialogAlert; + let alertElement; + + expectTrue(isElementVisible(dialogElement)); + + const kRootPath = 'this/is/a/path'; + mockDelegate.mockResponse = { + status: chrome.developerPrivate.PackStatus.SUCCESS + }; + + packDialog.$$('#root-dir-browse').click(); + mockDelegate.rootPromise.resolve(kRootPath); + + return mockDelegate.rootPromise.promise + .then(() => { + expectEquals(kRootPath, packDialog.$$('#root-dir').value); + packDialog.$$('.action-button').click(); + + return flushTasks(); + }) + .then(() => { + packDialogAlert = packDialog.$$('extensions-pack-dialog-alert'); + alertElement = packDialogAlert.$.dialog.getNative(); + expectTrue(isElementVisible(alertElement)); + expectTrue(isElementVisible(dialogElement)); + expectTrue(!!packDialogAlert.$$('.action-button')); + + const wait = eventToPromise('close', dialogElement); + // After 'ok', both dialogs should be closed. + packDialogAlert.$$('.action-button').click(); + + return wait; + }) + .then(() => { + expectFalse(isElementVisible(alertElement)); + expectFalse(isElementVisible(dialogElement)); + }); + }); + + test(assert(extension_pack_dialog_tests.TestNames.PackError), function() { + const dialogElement = packDialog.$$('cr-dialog').getNative(); + let packDialogAlert; + let alertElement; + + expectTrue(isElementVisible(dialogElement)); + + const kRootPath = 'this/is/a/path'; + mockDelegate.mockResponse = { + status: chrome.developerPrivate.PackStatus.ERROR + }; + + packDialog.$$('#root-dir-browse').click(); + mockDelegate.rootPromise.resolve(kRootPath); + + return mockDelegate.rootPromise.promise.then(() => { + expectEquals(kRootPath, packDialog.$$('#root-dir').value); + packDialog.$$('.action-button').click(); + flush(); + + // Make sure new alert and the appropriate buttons are visible. + packDialogAlert = packDialog.$$('extensions-pack-dialog-alert'); + alertElement = packDialogAlert.$.dialog.getNative(); + expectTrue(isElementVisible(alertElement)); + expectTrue(isElementVisible(dialogElement)); + expectTrue(!!packDialogAlert.$$('.action-button')); + + // After cancel, original dialog is still open and values unchanged. + packDialogAlert.$$('.action-button').click(); + flush(); + expectFalse(isElementVisible(alertElement)); + expectTrue(isElementVisible(dialogElement)); + expectEquals(kRootPath, packDialog.$$('#root-dir').value); + }); + }); + + test(assert(extension_pack_dialog_tests.TestNames.PackWarning), function() { + const dialogElement = packDialog.$$('cr-dialog').getNative(); + let packDialogAlert; + let alertElement; + + expectTrue(isElementVisible(dialogElement)); + + const kRootPath = 'this/is/a/path'; + mockDelegate.mockResponse = { + status: chrome.developerPrivate.PackStatus.WARNING, + item_path: 'item_path', + pem_path: 'pem_path', + override_flags: 1, + }; + + packDialog.$$('#root-dir-browse').click(); + mockDelegate.rootPromise.resolve(kRootPath); + + return mockDelegate.rootPromise.promise + .then(() => { + expectEquals(kRootPath, packDialog.$$('#root-dir').value); + packDialog.$$('.action-button').click(); + flush(); + + // Make sure new alert and the appropriate buttons are visible. + packDialogAlert = packDialog.$$('extensions-pack-dialog-alert'); + alertElement = packDialogAlert.$.dialog.getNative(); + expectTrue(isElementVisible(alertElement)); + expectTrue(isElementVisible(dialogElement)); + expectFalse(packDialogAlert.$$('.cancel-button').hidden); + expectFalse(packDialogAlert.$$('.action-button').hidden); + + // Make sure "proceed anyway" try to pack extension again. + const whenClosed = eventToPromise('close', packDialogAlert); + packDialogAlert.$$('.action-button').click(); + return whenClosed; + }) + .then(() => { + // Make sure packExtension is called again with the right params. + expectFalse(isElementVisible(alertElement)); + expectEquals( + mockDelegate.flag, mockDelegate.mockResponse.override_flags); + }); + }); +});
diff --git a/chrome/test/data/webui/extensions/shortcut_input_test.js b/chrome/test/data/webui/extensions/shortcut_input_test.js index cf8f2bb..4921036 100644 --- a/chrome/test/data/webui/extensions/shortcut_input_test.js +++ b/chrome/test/data/webui/extensions/shortcut_input_test.js
@@ -18,106 +18,104 @@ import {TestService} from './test_service.js'; - window.extension_shortcut_input_tests = {}; - extension_shortcut_input_tests.suiteName = 'ExtensionShortcutInputTest'; - /** @enum {string} */ - extension_shortcut_input_tests.TestNames = { - Basic: 'basic', - }; +window.extension_shortcut_input_tests = {}; +extension_shortcut_input_tests.suiteName = 'ExtensionShortcutInputTest'; +/** @enum {string} */ +extension_shortcut_input_tests.TestNames = { + Basic: 'basic', +}; - suite(extension_shortcut_input_tests.suiteName, function() { - /** @type {ExtensionsShortcutInputElement} */ - let input; +suite(extension_shortcut_input_tests.suiteName, function() { + /** @type {ExtensionsShortcutInputElement} */ + let input; - setup(function() { - PolymerTest.clearBody(); - input = document.createElement('extensions-shortcut-input'); - input.delegate = new TestService(); - input.commandName = 'Command'; - input.item = 'itemid'; - document.body.appendChild(input); - flush(); - }); - - test(assert(extension_shortcut_input_tests.TestNames.Basic), function() { - const field = input.$['input']; - assertEquals('', field.value); - const isClearVisible = isVisible.bind(null, input, '#clear', false); - expectFalse(isClearVisible()); - - // Click the input. Capture should start. - tap(field); - return input.delegate.whenCalled('setShortcutHandlingSuspended') - .then((arg) => { - assertTrue(arg); - input.delegate.reset(); - - assertEquals('', field.value); - expectFalse(isClearVisible()); - - // Press character. - keyDownOn(field, 'A', []); - assertEquals('', field.value); - expectTrue(field.errorMessage.startsWith('Include')); - // Add shift to character. - keyDownOn(field, 'A', ['shift']); - assertEquals('', field.value); - expectTrue(field.errorMessage.startsWith('Include')); - // Press ctrl. - keyDownOn(field, 17, ['ctrl']); - assertEquals('Ctrl', field.value); - assertEquals('Type a letter', field.errorMessage); - // Add shift. - keyDownOn(field, 16, ['ctrl', 'shift']); - assertEquals('Ctrl + Shift', field.value); - assertEquals('Type a letter', field.errorMessage); - // Remove shift. - keyUpOn(field, 16, ['ctrl']); - assertEquals('Ctrl', field.value); - assertEquals('Type a letter', field.errorMessage); - // Add alt (ctrl + alt is invalid). - keyDownOn(field, 18, ['ctrl', 'alt']); - assertEquals('Ctrl', field.value); - // Remove alt. - keyUpOn(field, 18, ['ctrl']); - assertEquals('Ctrl', field.value); - assertEquals('Type a letter', field.errorMessage); - - // Add 'A'. Once a valid shortcut is typed (like Ctrl + A), it is - // committed. - keyDownOn(field, 65, ['ctrl']); - return input.delegate.whenCalled( - 'updateExtensionCommandKeybinding'); - }) - .then((arg) => { - input.delegate.reset(); - expectDeepEquals(['itemid', 'Command', 'Ctrl+A'], arg); - assertEquals('Ctrl + A', field.value); - assertEquals('Ctrl+A', input.shortcut); - expectTrue(isClearVisible()); - - // Test clearing the shortcut. - tap(input.$['clear']); - return input.delegate.whenCalled( - 'updateExtensionCommandKeybinding'); - }) - .then((arg) => { - input.delegate.reset(); - expectDeepEquals(['itemid', 'Command', ''], arg); - assertEquals('', input.shortcut); - expectFalse(isClearVisible()); - - tap(field); - return input.delegate.whenCalled('setShortcutHandlingSuspended'); - }) - .then((arg) => { - input.delegate.reset(); - expectTrue(arg); - - // Test ending capture using the escape key. - keyDownOn(field, 27); // Escape key. - return input.delegate.whenCalled('setShortcutHandlingSuspended'); - }) - .then(expectFalse); - }); + setup(function() { + PolymerTest.clearBody(); + input = document.createElement('extensions-shortcut-input'); + input.delegate = new TestService(); + input.commandName = 'Command'; + input.item = 'itemid'; + document.body.appendChild(input); + flush(); }); + + test(assert(extension_shortcut_input_tests.TestNames.Basic), function() { + const field = input.$['input']; + assertEquals('', field.value); + const isClearVisible = isVisible.bind(null, input, '#clear', false); + expectFalse(isClearVisible()); + + // Click the input. Capture should start. + tap(field); + return input.delegate.whenCalled('setShortcutHandlingSuspended') + .then((arg) => { + assertTrue(arg); + input.delegate.reset(); + + assertEquals('', field.value); + expectFalse(isClearVisible()); + + // Press character. + keyDownOn(field, 'A', []); + assertEquals('', field.value); + expectTrue(field.errorMessage.startsWith('Include')); + // Add shift to character. + keyDownOn(field, 'A', ['shift']); + assertEquals('', field.value); + expectTrue(field.errorMessage.startsWith('Include')); + // Press ctrl. + keyDownOn(field, 17, ['ctrl']); + assertEquals('Ctrl', field.value); + assertEquals('Type a letter', field.errorMessage); + // Add shift. + keyDownOn(field, 16, ['ctrl', 'shift']); + assertEquals('Ctrl + Shift', field.value); + assertEquals('Type a letter', field.errorMessage); + // Remove shift. + keyUpOn(field, 16, ['ctrl']); + assertEquals('Ctrl', field.value); + assertEquals('Type a letter', field.errorMessage); + // Add alt (ctrl + alt is invalid). + keyDownOn(field, 18, ['ctrl', 'alt']); + assertEquals('Ctrl', field.value); + // Remove alt. + keyUpOn(field, 18, ['ctrl']); + assertEquals('Ctrl', field.value); + assertEquals('Type a letter', field.errorMessage); + + // Add 'A'. Once a valid shortcut is typed (like Ctrl + A), it is + // committed. + keyDownOn(field, 65, ['ctrl']); + return input.delegate.whenCalled('updateExtensionCommandKeybinding'); + }) + .then((arg) => { + input.delegate.reset(); + expectDeepEquals(['itemid', 'Command', 'Ctrl+A'], arg); + assertEquals('Ctrl + A', field.value); + assertEquals('Ctrl+A', input.shortcut); + expectTrue(isClearVisible()); + + // Test clearing the shortcut. + tap(input.$['clear']); + return input.delegate.whenCalled('updateExtensionCommandKeybinding'); + }) + .then((arg) => { + input.delegate.reset(); + expectDeepEquals(['itemid', 'Command', ''], arg); + assertEquals('', input.shortcut); + expectFalse(isClearVisible()); + + tap(field); + return input.delegate.whenCalled('setShortcutHandlingSuspended'); + }) + .then((arg) => { + input.delegate.reset(); + expectTrue(arg); + + // Test ending capture using the escape key. + keyDownOn(field, 27); // Escape key. + return input.delegate.whenCalled('setShortcutHandlingSuspended'); + }) + .then(expectFalse); + }); +});
diff --git a/chrome/test/data/webui/extensions/sidebar_test.js b/chrome/test/data/webui/extensions/sidebar_test.js index 075a35d..5a596ac 100644 --- a/chrome/test/data/webui/extensions/sidebar_test.js +++ b/chrome/test/data/webui/extensions/sidebar_test.js
@@ -12,78 +12,78 @@ import {testVisible} from './test_util.js'; - window.extension_sidebar_tests = {}; - extension_sidebar_tests.suiteName = 'ExtensionSidebarTest'; +window.extension_sidebar_tests = {}; +extension_sidebar_tests.suiteName = 'ExtensionSidebarTest'; - /** @enum {string} */ - extension_sidebar_tests.TestNames = { - LayoutAndClickHandlers: 'layout and click handlers', - SetSelected: 'set selected', - }; +/** @enum {string} */ +extension_sidebar_tests.TestNames = { + LayoutAndClickHandlers: 'layout and click handlers', + SetSelected: 'set selected', +}; - suite(extension_sidebar_tests.suiteName, function() { - /** @type {extensions.Sidebar} */ - let sidebar; +suite(extension_sidebar_tests.suiteName, function() { + /** @type {extensions.Sidebar} */ + let sidebar; - setup(function() { - PolymerTest.clearBody(); - sidebar = document.createElement('extensions-sidebar'); - document.body.appendChild(sidebar); - }); + setup(function() { + PolymerTest.clearBody(); + sidebar = document.createElement('extensions-sidebar'); + document.body.appendChild(sidebar); + }); - test(assert(extension_sidebar_tests.TestNames.SetSelected), function() { - const selector = '.section-item.iron-selected'; - expectFalse(!!sidebar.$$(selector)); + test(assert(extension_sidebar_tests.TestNames.SetSelected), function() { + const selector = '.section-item.iron-selected'; + expectFalse(!!sidebar.$$(selector)); - window.history.replaceState(undefined, '', '/shortcuts'); - PolymerTest.clearBody(); - sidebar = document.createElement('extensions-sidebar'); - document.body.appendChild(sidebar); - const whenSelected = eventToPromise('iron-select', sidebar.$.sectionMenu); - flush(); - return whenSelected - .then(function() { - expectEquals(sidebar.$$(selector).id, 'sections-shortcuts'); + window.history.replaceState(undefined, '', '/shortcuts'); + PolymerTest.clearBody(); + sidebar = document.createElement('extensions-sidebar'); + document.body.appendChild(sidebar); + const whenSelected = eventToPromise('iron-select', sidebar.$.sectionMenu); + flush(); + return whenSelected + .then(function() { + expectEquals(sidebar.$$(selector).id, 'sections-shortcuts'); - window.history.replaceState(undefined, '', '/'); - PolymerTest.clearBody(); - sidebar = document.createElement('extensions-sidebar'); - document.body.appendChild(sidebar); - const whenSelected = - eventToPromise('iron-select', sidebar.$.sectionMenu); - flush(); - return whenSelected; - }) - .then(function() { - expectEquals(sidebar.$$(selector).id, 'sections-extensions'); - }); - }); - - test( - assert(extension_sidebar_tests.TestNames.LayoutAndClickHandlers), - function(done) { - const boundTestVisible = testVisible.bind(null, sidebar); - boundTestVisible('#sections-extensions', true); - boundTestVisible('#sections-shortcuts', true); - boundTestVisible('#more-extensions', true); - - sidebar.isSupervised = true; + window.history.replaceState(undefined, '', '/'); + PolymerTest.clearBody(); + sidebar = document.createElement('extensions-sidebar'); + document.body.appendChild(sidebar); + const whenSelected = + eventToPromise('iron-select', sidebar.$.sectionMenu); flush(); - boundTestVisible('#more-extensions', false); - - let currentPage; - navigation.addListener(newPage => { - currentPage = newPage; - }); - - tap(sidebar.$$('#sections-shortcuts')); - expectDeepEquals(currentPage, {page: Page.SHORTCUTS}); - - tap(sidebar.$$('#sections-extensions')); - expectDeepEquals(currentPage, {page: Page.LIST}); - - // Clicking on the link for the current page should close the dialog. - sidebar.addEventListener('close-drawer', () => done()); - tap(sidebar.$$('#sections-extensions')); + return whenSelected; + }) + .then(function() { + expectEquals(sidebar.$$(selector).id, 'sections-extensions'); }); }); + + test( + assert(extension_sidebar_tests.TestNames.LayoutAndClickHandlers), + function(done) { + const boundTestVisible = testVisible.bind(null, sidebar); + boundTestVisible('#sections-extensions', true); + boundTestVisible('#sections-shortcuts', true); + boundTestVisible('#more-extensions', true); + + sidebar.isSupervised = true; + flush(); + boundTestVisible('#more-extensions', false); + + let currentPage; + navigation.addListener(newPage => { + currentPage = newPage; + }); + + tap(sidebar.$$('#sections-shortcuts')); + expectDeepEquals(currentPage, {page: Page.SHORTCUTS}); + + tap(sidebar.$$('#sections-extensions')); + expectDeepEquals(currentPage, {page: Page.LIST}); + + // Clicking on the link for the current page should close the dialog. + sidebar.addEventListener('close-drawer', () => done()); + tap(sidebar.$$('#sections-extensions')); + }); +});
diff --git a/chrome/test/data/webui/extensions/test_service.js b/chrome/test/data/webui/extensions/test_service.js index bd3dc818..c6741f7c 100644 --- a/chrome/test/data/webui/extensions/test_service.js +++ b/chrome/test/data/webui/extensions/test_service.js
@@ -5,218 +5,217 @@ import {FakeChromeEvent} from '../fake_chrome_event.m.js'; import {TestBrowserProxy} from '../test_browser_proxy.m.js'; - /** An extensions.Service implementation to be used in tests. */ - export class TestService extends TestBrowserProxy { - constructor() { - super([ - 'addRuntimeHostPermission', - 'deleteActivitiesById', - 'deleteActivitiesFromExtension', - 'downloadActivities', - 'getExtensionActivityLog', - 'getExtensionsInfo', - 'getExtensionSize', - 'getFilteredExtensionActivityLog', - 'getProfileConfiguration', - 'loadUnpacked', - 'retryLoadUnpacked', - 'reloadItem', - 'removeRuntimeHostPermission', - 'setItemHostAccess', - 'setProfileInDevMode', - 'setShortcutHandlingSuspended', - 'shouldIgnoreUpdate', - 'updateAllExtensions', - 'updateExtensionCommandKeybinding', - 'updateExtensionCommandScope', - ]); +/** An extensions.Service implementation to be used in tests. */ +export class TestService extends TestBrowserProxy { + constructor() { + super([ + 'addRuntimeHostPermission', + 'deleteActivitiesById', + 'deleteActivitiesFromExtension', + 'downloadActivities', + 'getExtensionActivityLog', + 'getExtensionsInfo', + 'getExtensionSize', + 'getFilteredExtensionActivityLog', + 'getProfileConfiguration', + 'loadUnpacked', + 'retryLoadUnpacked', + 'reloadItem', + 'removeRuntimeHostPermission', + 'setItemHostAccess', + 'setProfileInDevMode', + 'setShortcutHandlingSuspended', + 'shouldIgnoreUpdate', + 'updateAllExtensions', + 'updateExtensionCommandKeybinding', + 'updateExtensionCommandScope', + ]); - this.itemStateChangedTarget = new FakeChromeEvent(); - this.profileStateChangedTarget = new FakeChromeEvent(); - this.extensionActivityTarget = new FakeChromeEvent(); + this.itemStateChangedTarget = new FakeChromeEvent(); + this.profileStateChangedTarget = new FakeChromeEvent(); + this.extensionActivityTarget = new FakeChromeEvent(); - /** @type {boolean} */ - this.acceptRuntimeHostPermission = true; + /** @type {boolean} */ + this.acceptRuntimeHostPermission = true; - /** @private {!chrome.developerPrivate.LoadError} */ - this.retryLoadUnpackedError_; + /** @private {!chrome.developerPrivate.LoadError} */ + this.retryLoadUnpackedError_; - /** @type {boolean} */ - this.forceReloadItemError_ = false; + /** @type {boolean} */ + this.forceReloadItemError_ = false; - /** @type {!chrome.activityLogPrivate.ActivityResultSet|undefined} */ - this.testActivities; - } - - /** - * @param {!chrome.developerPrivate.LoadError} error - */ - setRetryLoadUnpackedError(error) { - this.retryLoadUnpackedError_ = error; - } - - /** - * @param {boolean} force - */ - setForceReloadItemError(force) { - this.forceReloadItemError_ = force; - } - - /** @override */ - addRuntimeHostPermission(id, site) { - this.methodCalled('addRuntimeHostPermission', [id, site]); - return this.acceptRuntimeHostPermission ? Promise.resolve() : - Promise.reject(); - } - - /** @override */ - getProfileConfiguration() { - this.methodCalled('getProfileConfiguration'); - return Promise.resolve({inDeveloperMode: false}); - } - - /** @override */ - getItemStateChangedTarget() { - return this.itemStateChangedTarget; - } - - /** @override */ - getProfileStateChangedTarget() { - return this.profileStateChangedTarget; - } - - /** @override */ - getExtensionsInfo() { - this.methodCalled('getExtensionsInfo'); - return Promise.resolve([]); - } - - /** @override */ - getExtensionSize() { - this.methodCalled('getExtensionSize'); - return Promise.resolve('20 MB'); - } - - /** @override */ - removeRuntimeHostPermission(id, site) { - this.methodCalled('removeRuntimeHostPermission', [id, site]); - return Promise.resolve(); - } - - /** @override */ - setItemHostAccess(id, access) { - this.methodCalled('setItemHostAccess', [id, access]); - } - - /** @override */ - setShortcutHandlingSuspended(enable) { - this.methodCalled('setShortcutHandlingSuspended', enable); - } - - /** @override */ - shouldIgnoreUpdate(extensionId, eventType) { - this.methodCalled('shouldIgnoreUpdate', [extensionId, eventType]); - } - - /** @override */ - updateExtensionCommandKeybinding(item, commandName, keybinding) { - this.methodCalled( - 'updateExtensionCommandKeybinding', [item, commandName, keybinding]); - } - - /** @override */ - updateExtensionCommandScope(item, commandName, scope) { - this.methodCalled( - 'updateExtensionCommandScope', [item, commandName, scope]); - } - - /** @override */ - loadUnpacked() { - this.methodCalled('loadUnpacked'); - return Promise.resolve(); - } - - /** @override */ - reloadItem(id) { - this.methodCalled('reloadItem', id); - return this.forceReloadItemError_ ? Promise.reject() : Promise.resolve(); - } - - /** @override */ - retryLoadUnpacked(guid) { - this.methodCalled('retryLoadUnpacked', guid); - return (this.retryLoadUnpackedError_ !== undefined) ? - Promise.reject(this.retryLoadUnpackedError_) : - Promise.resolve(); - } - - /** @override */ - setProfileInDevMode(inDevMode) { - this.methodCalled('setProfileInDevMode', inDevMode); - } - - /** @override */ - updateAllExtensions() { - this.methodCalled('updateAllExtensions'); - return Promise.resolve(); - } - - /** @override */ - getExtensionActivityLog(id) { - this.methodCalled('getExtensionActivityLog', id); - return Promise.resolve(this.testActivities); - } - - /** @override */ - getFilteredExtensionActivityLog(id, searchTerm) { - // This is functionally identical to getFilteredExtensionActivityLog in - // service.js but we do the filtering here instead of making API calls - // with filter objects. - this.methodCalled('getFilteredExtensionActivityLog', id, searchTerm); - - // Convert everything to lowercase as searching is not case sensitive. - const lowerCaseSearchTerm = searchTerm.toLowerCase(); - - const activities = this.testActivities.activities; - const apiCallMatches = activities.filter( - activity => - activity.apiCall.toLowerCase().includes(lowerCaseSearchTerm)); - const pageUrlMatches = activities.filter( - activity => activity.pageUrl && - activity.pageUrl.toLowerCase().includes(lowerCaseSearchTerm)); - const argUrlMatches = activities.filter( - activity => activity.argUrl && - activity.argUrl.toLowerCase().includes(lowerCaseSearchTerm)); - - return Promise.resolve({ - activities: [...apiCallMatches, ...pageUrlMatches, ...argUrlMatches] - }); - } - - /** @override */ - deleteActivitiesById(activityIds) { - // Pretend to delete all activities specified by activityIds. - const newActivities = this.testActivities.activities.filter( - activity => !activityIds.includes(activity.activityId)); - this.testActivities = {activities: newActivities}; - - this.methodCalled('deleteActivitiesById', activityIds); - return Promise.resolve(); - } - - /** @override */ - deleteActivitiesFromExtension(extensionId) { - this.methodCalled('deleteActivitiesFromExtension', extensionId); - return Promise.resolve(); - } - - /** @override */ - getOnExtensionActivity() { - return this.extensionActivityTarget; - } - - /** @override */ - downloadActivities(rawActivityData, fileName) { - this.methodCalled('downloadActivities', [rawActivityData, fileName]); - } + /** @type {!chrome.activityLogPrivate.ActivityResultSet|undefined} */ + this.testActivities; } + + /** + * @param {!chrome.developerPrivate.LoadError} error + */ + setRetryLoadUnpackedError(error) { + this.retryLoadUnpackedError_ = error; + } + + /** + * @param {boolean} force + */ + setForceReloadItemError(force) { + this.forceReloadItemError_ = force; + } + + /** @override */ + addRuntimeHostPermission(id, site) { + this.methodCalled('addRuntimeHostPermission', [id, site]); + return this.acceptRuntimeHostPermission ? Promise.resolve() : + Promise.reject(); + } + + /** @override */ + getProfileConfiguration() { + this.methodCalled('getProfileConfiguration'); + return Promise.resolve({inDeveloperMode: false}); + } + + /** @override */ + getItemStateChangedTarget() { + return this.itemStateChangedTarget; + } + + /** @override */ + getProfileStateChangedTarget() { + return this.profileStateChangedTarget; + } + + /** @override */ + getExtensionsInfo() { + this.methodCalled('getExtensionsInfo'); + return Promise.resolve([]); + } + + /** @override */ + getExtensionSize() { + this.methodCalled('getExtensionSize'); + return Promise.resolve('20 MB'); + } + + /** @override */ + removeRuntimeHostPermission(id, site) { + this.methodCalled('removeRuntimeHostPermission', [id, site]); + return Promise.resolve(); + } + + /** @override */ + setItemHostAccess(id, access) { + this.methodCalled('setItemHostAccess', [id, access]); + } + + /** @override */ + setShortcutHandlingSuspended(enable) { + this.methodCalled('setShortcutHandlingSuspended', enable); + } + + /** @override */ + shouldIgnoreUpdate(extensionId, eventType) { + this.methodCalled('shouldIgnoreUpdate', [extensionId, eventType]); + } + + /** @override */ + updateExtensionCommandKeybinding(item, commandName, keybinding) { + this.methodCalled( + 'updateExtensionCommandKeybinding', [item, commandName, keybinding]); + } + + /** @override */ + updateExtensionCommandScope(item, commandName, scope) { + this.methodCalled( + 'updateExtensionCommandScope', [item, commandName, scope]); + } + + /** @override */ + loadUnpacked() { + this.methodCalled('loadUnpacked'); + return Promise.resolve(); + } + + /** @override */ + reloadItem(id) { + this.methodCalled('reloadItem', id); + return this.forceReloadItemError_ ? Promise.reject() : Promise.resolve(); + } + + /** @override */ + retryLoadUnpacked(guid) { + this.methodCalled('retryLoadUnpacked', guid); + return (this.retryLoadUnpackedError_ !== undefined) ? + Promise.reject(this.retryLoadUnpackedError_) : + Promise.resolve(); + } + + /** @override */ + setProfileInDevMode(inDevMode) { + this.methodCalled('setProfileInDevMode', inDevMode); + } + + /** @override */ + updateAllExtensions() { + this.methodCalled('updateAllExtensions'); + return Promise.resolve(); + } + + /** @override */ + getExtensionActivityLog(id) { + this.methodCalled('getExtensionActivityLog', id); + return Promise.resolve(this.testActivities); + } + + /** @override */ + getFilteredExtensionActivityLog(id, searchTerm) { + // This is functionally identical to getFilteredExtensionActivityLog in + // service.js but we do the filtering here instead of making API calls + // with filter objects. + this.methodCalled('getFilteredExtensionActivityLog', id, searchTerm); + + // Convert everything to lowercase as searching is not case sensitive. + const lowerCaseSearchTerm = searchTerm.toLowerCase(); + + const activities = this.testActivities.activities; + const apiCallMatches = activities.filter( + activity => + activity.apiCall.toLowerCase().includes(lowerCaseSearchTerm)); + const pageUrlMatches = activities.filter( + activity => activity.pageUrl && + activity.pageUrl.toLowerCase().includes(lowerCaseSearchTerm)); + const argUrlMatches = activities.filter( + activity => activity.argUrl && + activity.argUrl.toLowerCase().includes(lowerCaseSearchTerm)); + + return Promise.resolve( + {activities: [...apiCallMatches, ...pageUrlMatches, ...argUrlMatches]}); + } + + /** @override */ + deleteActivitiesById(activityIds) { + // Pretend to delete all activities specified by activityIds. + const newActivities = this.testActivities.activities.filter( + activity => !activityIds.includes(activity.activityId)); + this.testActivities = {activities: newActivities}; + + this.methodCalled('deleteActivitiesById', activityIds); + return Promise.resolve(); + } + + /** @override */ + deleteActivitiesFromExtension(extensionId) { + this.methodCalled('deleteActivitiesFromExtension', extensionId); + return Promise.resolve(); + } + + /** @override */ + getOnExtensionActivity() { + return this.extensionActivityTarget; + } + + /** @override */ + downloadActivities(rawActivityData, fileName) { + this.methodCalled('downloadActivities', [rawActivityData, fileName]); + } +}
diff --git a/chrome/test/data/webui/extensions/test_util.js b/chrome/test/data/webui/extensions/test_util.js index 496a2cb2..6b28675 100644 --- a/chrome/test/data/webui/extensions/test_util.js +++ b/chrome/test/data/webui/extensions/test_util.js
@@ -8,224 +8,223 @@ import {TestKioskBrowserProxy} from './test_kiosk_browser_proxy.js'; - /** A mock to test that clicking on an element calls a specific method. */ - export class ClickMock { - /** - * Tests clicking on an element and expecting a call. - * @param {HTMLElement} element The element to click on. - * @param {string} callName The function expected to be called. - * @param {Array<*>=} opt_expectedArgs The arguments the function is - * expected to be called with. - * @param {*=} opt_returnValue The value to return from the function call. - */ - testClickingCalls(element, callName, opt_expectedArgs, opt_returnValue) { - const mock = new MockController(); - const mockMethod = mock.createFunctionMock(this, callName); - mockMethod.returnValue = opt_returnValue; - MockMethod.prototype.addExpectation.apply(mockMethod, opt_expectedArgs); - element.click(); - mock.verifyMocks(); - } +/** A mock to test that clicking on an element calls a specific method. */ +export class ClickMock { + /** + * Tests clicking on an element and expecting a call. + * @param {HTMLElement} element The element to click on. + * @param {string} callName The function expected to be called. + * @param {Array<*>=} opt_expectedArgs The arguments the function is + * expected to be called with. + * @param {*=} opt_returnValue The value to return from the function call. + */ + testClickingCalls(element, callName, opt_expectedArgs, opt_returnValue) { + const mock = new MockController(); + const mockMethod = mock.createFunctionMock(this, callName); + mockMethod.returnValue = opt_returnValue; + MockMethod.prototype.addExpectation.apply(mockMethod, opt_expectedArgs); + element.click(); + mock.verifyMocks(); + } +} + +/** + * A mock to test receiving expected events and verify that they were called + * with the proper detail values. + */ +export class ListenerMock { + constructor() { + /** @private {Object<{satisfied: boolean, args: !Object}>} */ + this.listeners_ = {}; } /** - * A mock to test receiving expected events and verify that they were called - * with the proper detail values. + * @param {string} eventName + * @param {Event} e */ - export class ListenerMock { - constructor() { - /** @private {Object<{satisfied: boolean, args: !Object}>} */ - this.listeners_ = {}; + onEvent_(eventName, e) { + assert(this.listeners_.hasOwnProperty(eventName)); + if (this.listeners_[eventName].satisfied) { + // Event was already called and checked. We could always make this + // more intelligent by allowing for subsequent calls, removing the + // listener, etc, but there's no need right now. + return; } + const expected = this.listeners_[eventName].args || {}; + expectDeepEquals(e.detail, expected); + this.listeners_[eventName].satisfied = true; + } - /** - * @param {string} eventName - * @param {Event} e - */ - onEvent_(eventName, e) { - assert(this.listeners_.hasOwnProperty(eventName)); - if (this.listeners_[eventName].satisfied) { - // Event was already called and checked. We could always make this - // more intelligent by allowing for subsequent calls, removing the - // listener, etc, but there's no need right now. - return; + /** + * Adds an expected event. + * @param {!EventTarget} target + * @param {string} eventName + * @param {Object=} opt_eventArgs If omitted, will check that the details + * are empty (i.e., {}). + */ + addListener(target, eventName, opt_eventArgs) { + assert(!this.listeners_.hasOwnProperty(eventName)); + this.listeners_[eventName] = {args: opt_eventArgs || {}, satisfied: false}; + target.addEventListener(eventName, this.onEvent_.bind(this, eventName)); + } + + /** Verifies the expectations set. */ + verify() { + const missingEvents = []; + for (const key in this.listeners_) { + if (!this.listeners_[key].satisfied) { + missingEvents.push(key); } - const expected = this.listeners_[eventName].args || {}; - expectDeepEquals(e.detail, expected); - this.listeners_[eventName].satisfied = true; } + expectEquals(0, missingEvents.length, JSON.stringify(missingEvents)); + } +} - /** - * Adds an expected event. - * @param {!EventTarget} target - * @param {string} eventName - * @param {Object=} opt_eventArgs If omitted, will check that the details - * are empty (i.e., {}). - */ - addListener(target, eventName, opt_eventArgs) { - assert(!this.listeners_.hasOwnProperty(eventName)); - this.listeners_[eventName] = - {args: opt_eventArgs || {}, satisfied: false}; - target.addEventListener(eventName, this.onEvent_.bind(this, eventName)); - } - - /** Verifies the expectations set. */ - verify() { - const missingEvents = []; - for (const key in this.listeners_) { - if (!this.listeners_[key].satisfied) { - missingEvents.push(key); - } - } - expectEquals(0, missingEvents.length, JSON.stringify(missingEvents)); - } +/** + * A mock delegate for the item, capable of testing functionality. + * @implements {extensions.ItemDelegate} + */ +export class MockItemDelegate extends ClickMock { + constructor() { + super(); } - /** - * A mock delegate for the item, capable of testing functionality. - * @implements {extensions.ItemDelegate} - */ - export class MockItemDelegate extends ClickMock { - constructor() { - super(); - } + /** @override */ + deleteItem(id) {} - /** @override */ - deleteItem(id) {} + /** @override */ + setItemEnabled(id, enabled) {} - /** @override */ - setItemEnabled(id, enabled) {} + /** @override */ + showItemDetails(id) {} - /** @override */ - showItemDetails(id) {} + /** @override */ + setItemAllowedIncognito(id, enabled) {} - /** @override */ - setItemAllowedIncognito(id, enabled) {} + /** @override */ + setItemAllowedOnFileUrls(id, enabled) {} - /** @override */ - setItemAllowedOnFileUrls(id, enabled) {} + /** @override */ + setItemHostAccess(id, hostAccess) {} - /** @override */ - setItemHostAccess(id, hostAccess) {} + /** @override */ + setItemCollectsErrors(id, enabled) {} - /** @override */ - setItemCollectsErrors(id, enabled) {} + /** @override */ + inspectItemView(id, view) {} - /** @override */ - inspectItemView(id, view) {} + /** @override */ + reloadItem(id) {} - /** @override */ - reloadItem(id) {} + /** @override */ + repairItem(id) {} - /** @override */ - repairItem(id) {} + /** @override */ + showItemOptionsPage(id) {} - /** @override */ - showItemOptionsPage(id) {} + /** @override */ + showInFolder(id) {} - /** @override */ - showInFolder(id) {} - - /** @override */ - getExtensionSize(id) { - return Promise.resolve('10 MB'); - } + /** @override */ + getExtensionSize(id) { + return Promise.resolve('10 MB'); } +} - /** - * @param {!HTMLElement} element - * @return {boolean} whether or not the element passed in is visible - */ - export function isElementVisible(element) { - const rect = element.getBoundingClientRect(); - return rect.width * rect.height > 0; // Width and height is never negative. +/** + * @param {!HTMLElement} element + * @return {boolean} whether or not the element passed in is visible + */ +export function isElementVisible(element) { + const rect = element.getBoundingClientRect(); + return rect.width * rect.height > 0; // Width and height is never negative. +} + +/** + * Tests that the element's visibility matches |expectedVisible| and, + * optionally, has specific content if it is visible. + * @param {!HTMLElement} parentEl The parent element to query for the element. + * @param {string} selector The selector to find the element. + * @param {boolean} expectedVisible Whether the element should be + * visible. + * @param {string=} opt_expectedText The expected textContent value. + */ +export function testVisible( + parentEl, selector, expectedVisible, opt_expectedText) { + const visible = isVisible(parentEl, selector); + expectEquals(expectedVisible, visible, selector); + if (expectedVisible && visible && opt_expectedText) { + const element = parentEl.$$(selector); + expectEquals(opt_expectedText, element.textContent.trim(), selector); } +} - /** - * Tests that the element's visibility matches |expectedVisible| and, - * optionally, has specific content if it is visible. - * @param {!HTMLElement} parentEl The parent element to query for the element. - * @param {string} selector The selector to find the element. - * @param {boolean} expectedVisible Whether the element should be - * visible. - * @param {string=} opt_expectedText The expected textContent value. - */ - export function testVisible( - parentEl, selector, expectedVisible, opt_expectedText) { - const visible = isVisible(parentEl, selector); - expectEquals(expectedVisible, visible, selector); - if (expectedVisible && visible && opt_expectedText) { - const element = parentEl.$$(selector); - expectEquals(opt_expectedText, element.textContent.trim(), selector); - } - } - - /** - * Creates an ExtensionInfo object. - * @param {Object=} opt_properties A set of properties that will be used on - * the resulting ExtensionInfo (otherwise defaults will be used). - * @return {chrome.developerPrivate.ExtensionInfo} - */ - export function createExtensionInfo(opt_properties) { - const id = opt_properties && opt_properties.hasOwnProperty('id') ? - opt_properties['id'] : - 'a'.repeat(32); - const baseUrl = 'chrome-extension://' + id + '/'; - return Object.assign( - { - commands: [], - dependentExtensions: [], - description: 'This is an extension', - disableReasons: { - suspiciousInstall: false, - corruptInstall: false, - updateRequired: false, - }, - homePage: {specified: false, url: ''}, - iconUrl: 'chrome://extension-icon/' + id + '/24/0', - id: id, - incognitoAccess: {isEnabled: true, isActive: false}, - location: 'FROM_STORE', - manifestErrors: [], - name: 'Wonderful Extension', - runtimeErrors: [], - runtimeWarnings: [], - permissions: {simplePermissions: []}, - state: 'ENABLED', - type: 'EXTENSION', - userMayModify: true, - version: '2.0', - views: [{url: baseUrl + 'foo.html'}, {url: baseUrl + 'bar.html'}], +/** + * Creates an ExtensionInfo object. + * @param {Object=} opt_properties A set of properties that will be used on + * the resulting ExtensionInfo (otherwise defaults will be used). + * @return {chrome.developerPrivate.ExtensionInfo} + */ +export function createExtensionInfo(opt_properties) { + const id = opt_properties && opt_properties.hasOwnProperty('id') ? + opt_properties['id'] : + 'a'.repeat(32); + const baseUrl = 'chrome-extension://' + id + '/'; + return Object.assign( + { + commands: [], + dependentExtensions: [], + description: 'This is an extension', + disableReasons: { + suspiciousInstall: false, + corruptInstall: false, + updateRequired: false, }, - opt_properties); - } + homePage: {specified: false, url: ''}, + iconUrl: 'chrome://extension-icon/' + id + '/24/0', + id: id, + incognitoAccess: {isEnabled: true, isActive: false}, + location: 'FROM_STORE', + manifestErrors: [], + name: 'Wonderful Extension', + runtimeErrors: [], + runtimeWarnings: [], + permissions: {simplePermissions: []}, + state: 'ENABLED', + type: 'EXTENSION', + userMayModify: true, + version: '2.0', + views: [{url: baseUrl + 'foo.html'}, {url: baseUrl + 'bar.html'}], + }, + opt_properties); +} - /** - * Finds all nodes matching |query| under |root|, within self and children's - * Shadow DOM. - * @param {!Node} root - * @param {string} query The CSS query - * @return {!Array<!HTMLElement>} - */ - export function findMatches(root, query) { - let elements = new Set(); - function doSearch(node) { - if (node.nodeType == Node.ELEMENT_NODE) { - const matches = node.querySelectorAll(query); - for (let match of matches) { - elements.add(match); - } - } - let child = node.firstChild; - while (child !== null) { - doSearch(child); - child = child.nextSibling; - } - const shadowRoot = node.shadowRoot; - if (shadowRoot) { - doSearch(shadowRoot); +/** + * Finds all nodes matching |query| under |root|, within self and children's + * Shadow DOM. + * @param {!Node} root + * @param {string} query The CSS query + * @return {!Array<!HTMLElement>} + */ +export function findMatches(root, query) { + let elements = new Set(); + function doSearch(node) { + if (node.nodeType == Node.ELEMENT_NODE) { + const matches = node.querySelectorAll(query); + for (let match of matches) { + elements.add(match); } } - doSearch(root); - return Array.from(elements); + let child = node.firstChild; + while (child !== null) { + doSearch(child); + child = child.nextSibling; + } + const shadowRoot = node.shadowRoot; + if (shadowRoot) { + doSearch(shadowRoot); + } } + doSearch(root); + return Array.from(elements); +}
diff --git a/chrome/test/data/webui/extensions/toolbar_test.js b/chrome/test/data/webui/extensions/toolbar_test.js index 731fbc33..ecb8d77 100644 --- a/chrome/test/data/webui/extensions/toolbar_test.js +++ b/chrome/test/data/webui/extensions/toolbar_test.js
@@ -12,140 +12,140 @@ import {TestService} from './test_service.js'; import {testVisible} from './test_util.js'; - /** @fileoverview Suite of tests for extension-toolbar. */ - window.extension_toolbar_tests = {}; - extension_toolbar_tests.suiteName = 'ExtensionToolbarTest'; - /** @enum {string} */ - extension_toolbar_tests.TestNames = { - Layout: 'layout', - ClickHandlers: 'click handlers', - DevModeToggle: 'dev mode toggle', - KioskMode: 'kiosk mode button' - }; +/** @fileoverview Suite of tests for extension-toolbar. */ +window.extension_toolbar_tests = {}; +extension_toolbar_tests.suiteName = 'ExtensionToolbarTest'; +/** @enum {string} */ +extension_toolbar_tests.TestNames = { + Layout: 'layout', + ClickHandlers: 'click handlers', + DevModeToggle: 'dev mode toggle', + KioskMode: 'kiosk mode button' +}; - suite(extension_toolbar_tests.suiteName, function() { - /** @type {MockDelegate} */ - let mockDelegate; +suite(extension_toolbar_tests.suiteName, function() { + /** @type {MockDelegate} */ + let mockDelegate; - /** @type {ExtensionsToolbarElement} */ - let toolbar; + /** @type {ExtensionsToolbarElement} */ + let toolbar; - setup(function() { - PolymerTest.clearBody(); - toolbar = document.createElement('extensions-toolbar'); - document.body.appendChild(toolbar); - toolbar.inDevMode = false; - toolbar.devModeControlledByPolicy = false; - toolbar.isSupervised = false; - if (isChromeOS) { - toolbar.kioskEnabled = false; - } - mockDelegate = new TestService(); - toolbar.set('delegate', mockDelegate); - - // The toast manager is normally a child of the <extensions-manager> - // element, so add it separately for this test. - const toastManager = document.createElement('cr-toast-manager'); - document.body.appendChild(toastManager); - }); - - test(assert(extension_toolbar_tests.TestNames.Layout), function() { - const boundTestVisible = testVisible.bind(null, toolbar); - boundTestVisible('#devMode', true); - assertEquals(toolbar.$.devMode.disabled, false); - boundTestVisible('#loadUnpacked', false); - boundTestVisible('#packExtensions', false); - boundTestVisible('#updateNow', false); - toolbar.set('inDevMode', true); - flush(); - - boundTestVisible('#devMode', true); - assertEquals(toolbar.$.devMode.disabled, false); - boundTestVisible('#loadUnpacked', true); - boundTestVisible('#packExtensions', true); - boundTestVisible('#updateNow', true); - - toolbar.set('canLoadUnpacked', false); - flush(); - - boundTestVisible('#devMode', true); - boundTestVisible('#loadUnpacked', false); - boundTestVisible('#packExtensions', true); - boundTestVisible('#updateNow', true); - }); - - test(assert(extension_toolbar_tests.TestNames.DevModeToggle), function() { - const toggle = toolbar.$.devMode; - assertFalse(toggle.disabled); - - // Test that the dev-mode toggle is disabled when a policy exists. - toolbar.set('devModeControlledByPolicy', true); - flush(); - assertTrue(toggle.disabled); - - toolbar.set('devModeControlledByPolicy', false); - flush(); - assertFalse(toggle.disabled); - - // Test that the dev-mode toggle is disabled when the user is supervised. - toolbar.set('isSupervised', true); - flush(); - assertTrue(toggle.disabled); - }); - - test(assert(extension_toolbar_tests.TestNames.ClickHandlers), function() { - toolbar.set('inDevMode', true); - flush(); - - toolbar.$.devMode.click(); - return mockDelegate.whenCalled('setProfileInDevMode') - .then(function(arg) { - assertFalse(arg); - mockDelegate.reset(); - toolbar.$.devMode.click(); - return mockDelegate.whenCalled('setProfileInDevMode'); - }) - .then(function(arg) { - assertTrue(arg); - toolbar.$.loadUnpacked.click(); - return mockDelegate.whenCalled('loadUnpacked'); - }) - .then(function() { - const toastManager = getInstance(); - assertFalse(toastManager.isToastOpen); - toolbar.$.updateNow.click(); - // Simulate user rapidly clicking update button multiple times. - toolbar.$.updateNow.click(); - assertTrue(toastManager.isToastOpen); - return mockDelegate.whenCalled('updateAllExtensions'); - }) - .then(function() { - assertEquals(1, mockDelegate.getCallCount('updateAllExtensions')); - assertFalse(!!toolbar.$$('extensions-pack-dialog')); - toolbar.$.packExtensions.click(); - flush(); - const dialog = toolbar.$$('extensions-pack-dialog'); - assertTrue(!!dialog); - - if (!isMac) { - const whenFocused = - eventToPromise('focus', toolbar.$.packExtensions); - dialog.$.dialog.cancel(); - return whenFocused; - } - }); - }); - + setup(function() { + PolymerTest.clearBody(); + toolbar = document.createElement('extensions-toolbar'); + document.body.appendChild(toolbar); + toolbar.inDevMode = false; + toolbar.devModeControlledByPolicy = false; + toolbar.isSupervised = false; if (isChromeOS) { - test(assert(extension_toolbar_tests.TestNames.KioskMode), function() { - const button = toolbar.$.kioskExtensions; - expectTrue(button.hidden); - toolbar.kioskEnabled = true; - expectFalse(button.hidden); - - const whenTapped = eventToPromise('kiosk-tap', toolbar); - button.click(); - return whenTapped; - }); + toolbar.kioskEnabled = false; } + mockDelegate = new TestService(); + toolbar.set('delegate', mockDelegate); + + // The toast manager is normally a child of the <extensions-manager> + // element, so add it separately for this test. + const toastManager = document.createElement('cr-toast-manager'); + document.body.appendChild(toastManager); }); + + test(assert(extension_toolbar_tests.TestNames.Layout), function() { + const boundTestVisible = testVisible.bind(null, toolbar); + boundTestVisible('#devMode', true); + assertEquals(toolbar.$.devMode.disabled, false); + boundTestVisible('#loadUnpacked', false); + boundTestVisible('#packExtensions', false); + boundTestVisible('#updateNow', false); + toolbar.set('inDevMode', true); + flush(); + + boundTestVisible('#devMode', true); + assertEquals(toolbar.$.devMode.disabled, false); + boundTestVisible('#loadUnpacked', true); + boundTestVisible('#packExtensions', true); + boundTestVisible('#updateNow', true); + + toolbar.set('canLoadUnpacked', false); + flush(); + + boundTestVisible('#devMode', true); + boundTestVisible('#loadUnpacked', false); + boundTestVisible('#packExtensions', true); + boundTestVisible('#updateNow', true); + }); + + test(assert(extension_toolbar_tests.TestNames.DevModeToggle), function() { + const toggle = toolbar.$.devMode; + assertFalse(toggle.disabled); + + // Test that the dev-mode toggle is disabled when a policy exists. + toolbar.set('devModeControlledByPolicy', true); + flush(); + assertTrue(toggle.disabled); + + toolbar.set('devModeControlledByPolicy', false); + flush(); + assertFalse(toggle.disabled); + + // Test that the dev-mode toggle is disabled when the user is supervised. + toolbar.set('isSupervised', true); + flush(); + assertTrue(toggle.disabled); + }); + + test(assert(extension_toolbar_tests.TestNames.ClickHandlers), function() { + toolbar.set('inDevMode', true); + flush(); + + toolbar.$.devMode.click(); + return mockDelegate.whenCalled('setProfileInDevMode') + .then(function(arg) { + assertFalse(arg); + mockDelegate.reset(); + toolbar.$.devMode.click(); + return mockDelegate.whenCalled('setProfileInDevMode'); + }) + .then(function(arg) { + assertTrue(arg); + toolbar.$.loadUnpacked.click(); + return mockDelegate.whenCalled('loadUnpacked'); + }) + .then(function() { + const toastManager = getInstance(); + assertFalse(toastManager.isToastOpen); + toolbar.$.updateNow.click(); + // Simulate user rapidly clicking update button multiple times. + toolbar.$.updateNow.click(); + assertTrue(toastManager.isToastOpen); + return mockDelegate.whenCalled('updateAllExtensions'); + }) + .then(function() { + assertEquals(1, mockDelegate.getCallCount('updateAllExtensions')); + assertFalse(!!toolbar.$$('extensions-pack-dialog')); + toolbar.$.packExtensions.click(); + flush(); + const dialog = toolbar.$$('extensions-pack-dialog'); + assertTrue(!!dialog); + + if (!isMac) { + const whenFocused = + eventToPromise('focus', toolbar.$.packExtensions); + dialog.$.dialog.cancel(); + return whenFocused; + } + }); + }); + + if (isChromeOS) { + test(assert(extension_toolbar_tests.TestNames.KioskMode), function() { + const button = toolbar.$.kioskExtensions; + expectTrue(button.hidden); + toolbar.kioskEnabled = true; + expectFalse(button.hidden); + + const whenTapped = eventToPromise('kiosk-tap', toolbar); + button.click(); + return whenTapped; + }); + } +});
diff --git a/chromecast/bindings/BUILD.gn b/chromecast/bindings/BUILD.gn index 0405012..a0cebfc 100644 --- a/chromecast/bindings/BUILD.gn +++ b/chromecast/bindings/BUILD.gn
@@ -56,7 +56,7 @@ } } -if (is_linux) { +if (is_linux || is_android) { source_set("bindings_manager_cast") { sources = [ "bindings_manager_cast.cc", @@ -111,7 +111,7 @@ source_set("browsertests") { testonly = true deps = [] - if (is_linux) { + if (is_linux || is_android) { deps += [ "//chromecast/bindings:browsertests_cast" ] } }
diff --git a/chromecast/browser/cast_extension_url_loader_factory.cc b/chromecast/browser/cast_extension_url_loader_factory.cc index c54976c..e4e8f5ad6 100644 --- a/chromecast/browser/cast_extension_url_loader_factory.cc +++ b/chromecast/browser/cast_extension_url_loader_factory.cc
@@ -51,8 +51,7 @@ mojo::PendingReceiver<network::mojom::URLLoader> loader_receiver, network::mojom::URLLoaderClientPtr client) : original_loader_receiver_(this, std::move(loader_receiver)), - original_client_(std::move(client)), - network_client_binding_(this) { + original_client_(std::move(client)) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); // If there is a client error, clean up the request. original_client_.set_connection_error_handler(base::BindOnce( @@ -70,13 +69,13 @@ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); network::mojom::URLLoaderClientPtr network_client; - network_client_binding_.Bind(mojo::MakeRequest(&network_client)); + network_client_receiver_.Bind(mojo::MakeRequest(&network_client)); network_factory->CreateLoaderAndStart( mojo::MakeRequest(&network_loader_), routing_id, request_id, options, request, std::move(network_client), traffic_annotation); - network_client_binding_.set_connection_error_handler(base::BindOnce( + network_client_receiver_.set_disconnect_handler(base::BindOnce( &CastExtensionURLLoader::OnNetworkError, base::Unretained(this))); } @@ -159,7 +158,8 @@ network::mojom::URLLoaderClientPtr original_client_; // This is the URLLoaderClient passed to the network URLLoaderFactory. - mojo::Binding<network::mojom::URLLoaderClient> network_client_binding_; + mojo::Receiver<network::mojom::URLLoaderClient> network_client_receiver_{ + this}; // This is the URLLoader from the network URLLoaderFactory. network::mojom::URLLoaderPtr network_loader_;
diff --git a/chromeos/tools/concat_dbus_conf_files.py b/chromeos/tools/concat_dbus_conf_files.py new file mode 100755 index 0000000..7bdbeac3 --- /dev/null +++ b/chromeos/tools/concat_dbus_conf_files.py
@@ -0,0 +1,43 @@ +#!/usr/bin/env python +# 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. + +"""Concatenates D-Bus busconfig files.""" + +import sys +import xml.etree.ElementTree + + +_BUSCONFIG_FILE_HEADER="""<!DOCTYPE busconfig + PUBLIC "-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN" + "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> +""" + + +def main(): + if len(sys.argv) < 3: + sys.stderr.write('Usage: %s OUTFILE INFILES\n' % (sys.argv[0])) + sys.exit(1) + + out_path = sys.argv[1] + in_paths = sys.argv[2:] + + # Parse the first input file. + tree = xml.etree.ElementTree.parse(in_paths[0]) + assert(tree.getroot().tag == 'busconfig') + + # Append the remaining input files to the first file. + for path in in_paths[1:]: + current_tree = xml.etree.ElementTree.parse(path) + assert(current_tree.getroot().tag == 'busconfig') + for child in current_tree.getroot(): + tree.getroot().append(child) + + # Output the result. + with open(out_path, "w") as f: + f.write(_BUSCONFIG_FILE_HEADER) + tree.write(f) + +if __name__ == '__main__': + main()
diff --git a/components/arc/ime/arc_ime_service.cc b/components/arc/ime/arc_ime_service.cc index 3dd4c9c..17c0d39 100644 --- a/components/arc/ime/arc_ime_service.cc +++ b/components/arc/ime/arc_ime_service.cc
@@ -396,9 +396,16 @@ ime_bridge_->SendSetCompositionText(composition); } -void ArcImeService::ConfirmCompositionText() { +void ArcImeService::ConfirmCompositionText(bool keep_selection) { + // TODO(b/134473433) Modify this function so that when keep_selection is + // true, the selection is not changed when text committed + if (keep_selection) { + NOTIMPLEMENTED_LOG_ONCE(); + } InvalidateSurroundingTextAndSelectionRange(); has_composition_text_ = false; + // Note: SendConfirmCompositonText() will commit the text and + // keep the selection unchanged ime_bridge_->SendConfirmCompositionText(); }
diff --git a/components/arc/ime/arc_ime_service.h b/components/arc/ime/arc_ime_service.h index 8b59b60..9a19a3d 100644 --- a/components/arc/ime/arc_ime_service.h +++ b/components/arc/ime/arc_ime_service.h
@@ -112,7 +112,7 @@ // Overridden from ui::TextInputClient: void SetCompositionText(const ui::CompositionText& composition) override; - void ConfirmCompositionText() override; + void ConfirmCompositionText(bool keep_selection) override; void ClearCompositionText() override; void InsertText(const base::string16& text) override; void InsertChar(const ui::KeyEvent& event) override;
diff --git a/components/arc/ime/arc_ime_service_unittest.cc b/components/arc/ime/arc_ime_service_unittest.cc index ee62ec6..d5d16a9 100644 --- a/components/arc/ime/arc_ime_service_unittest.cc +++ b/components/arc/ime/arc_ime_service_unittest.cc
@@ -227,7 +227,7 @@ instance_->SetCompositionText(composition); EXPECT_TRUE(instance_->HasCompositionText()); - instance_->ConfirmCompositionText(); + instance_->ConfirmCompositionText(/* keep_selection */ false); EXPECT_FALSE(instance_->HasCompositionText()); instance_->SetCompositionText(composition);
diff --git a/components/download/internal/common/resource_downloader.cc b/components/download/internal/common/resource_downloader.cc index 47545234..7d7840923 100644 --- a/components/download/internal/common/resource_downloader.cc +++ b/components/download/internal/common/resource_downloader.cc
@@ -164,8 +164,8 @@ std::vector<GURL>(1, resource_request_->url), is_background_mode); network::mojom::URLLoaderClientPtr url_loader_client_ptr; - url_loader_client_binding_ = - std::make_unique<mojo::Binding<network::mojom::URLLoaderClient>>( + url_loader_client_receiver_ = + std::make_unique<mojo::Receiver<network::mojom::URLLoaderClient>>( url_loader_client_.get(), mojo::MakeRequest(&url_loader_client_ptr)); // Set up the URLLoader @@ -211,8 +211,8 @@ url_loader_client_->OnStartLoadingResponseBody(std::move(response_body)); // Bind the new client. - url_loader_client_binding_ = - std::make_unique<mojo::Binding<network::mojom::URLLoaderClient>>( + url_loader_client_receiver_ = + std::make_unique<mojo::Receiver<network::mojom::URLLoaderClient>>( url_loader_client_.get(), std::move(endpoints->url_loader_client)); }
diff --git a/components/download/internal/common/resource_downloader.h b/components/download/internal/common/resource_downloader.h index fe7cb243a..0fa309e8 100644 --- a/components/download/internal/common/resource_downloader.h +++ b/components/download/internal/common/resource_downloader.h
@@ -10,7 +10,7 @@ #include "components/download/public/common/download_response_handler.h" #include "components/download/public/common/download_utils.h" #include "components/download/public/common/url_download_handler.h" -#include "mojo/public/cpp/bindings/binding.h" +#include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/bindings/remote.h" #include "net/cert/cert_status_flags.h" #include "services/device/public/mojom/wake_lock.mojom.h" @@ -120,9 +120,10 @@ // Object that will handle the response. std::unique_ptr<network::mojom::URLLoaderClient> url_loader_client_; - // URLLoaderClient binding. It sends any requests to the |url_loader_client_|. - std::unique_ptr<mojo::Binding<network::mojom::URLLoaderClient>> - url_loader_client_binding_; + // URLLoaderClient receiver. It sends any requests to the + // |url_loader_client_|. + std::unique_ptr<mojo::Receiver<network::mojom::URLLoaderClient>> + url_loader_client_receiver_; // URLLoader for sending out the request. network::mojom::URLLoaderPtr url_loader_;
diff --git a/components/drive/BUILD.gn b/components/drive/BUILD.gn index dc1b3fb..9b8cb960 100644 --- a/components/drive/BUILD.gn +++ b/components/drive/BUILD.gn
@@ -97,81 +97,24 @@ if (is_chromeos) { source_set("drive_chromeos") { sources = [ - "chromeos/about_resource_loader.cc", - "chromeos/about_resource_loader.h", - "chromeos/about_resource_root_folder_id_loader.cc", - "chromeos/about_resource_root_folder_id_loader.h", - "chromeos/change_list_loader.cc", - "chromeos/change_list_loader.h", - "chromeos/change_list_loader_observer.h", "chromeos/change_list_processor.cc", "chromeos/change_list_processor.h", - "chromeos/default_corpus_change_list_loader.cc", - "chromeos/default_corpus_change_list_loader.h", - "chromeos/directory_loader.cc", - "chromeos/directory_loader.h", - "chromeos/drive_change_list_loader.h", "chromeos/drive_file_util.cc", "chromeos/drive_file_util.h", "chromeos/drive_operation_queue.h", "chromeos/file_cache.cc", "chromeos/file_cache.h", - "chromeos/file_system.cc", - "chromeos/file_system.h", - "chromeos/file_system/copy_operation.cc", - "chromeos/file_system/copy_operation.h", - "chromeos/file_system/create_directory_operation.cc", - "chromeos/file_system/create_directory_operation.h", - "chromeos/file_system/create_file_operation.cc", - "chromeos/file_system/create_file_operation.h", - "chromeos/file_system/download_operation.cc", - "chromeos/file_system/download_operation.h", - "chromeos/file_system/get_file_for_saving_operation.cc", - "chromeos/file_system/get_file_for_saving_operation.h", - "chromeos/file_system/move_operation.cc", - "chromeos/file_system/move_operation.h", - "chromeos/file_system/open_file_operation.cc", - "chromeos/file_system/open_file_operation.h", - "chromeos/file_system/operation_delegate.cc", - "chromeos/file_system/operation_delegate.h", - "chromeos/file_system/remove_operation.cc", - "chromeos/file_system/remove_operation.h", - "chromeos/file_system/search_operation.cc", - "chromeos/file_system/search_operation.h", - "chromeos/file_system/set_property_operation.cc", - "chromeos/file_system/set_property_operation.h", - "chromeos/file_system/touch_operation.cc", - "chromeos/file_system/touch_operation.h", - "chromeos/file_system/truncate_operation.cc", - "chromeos/file_system/truncate_operation.h", "chromeos/file_system_interface.cc", "chromeos/file_system_interface.h", "chromeos/file_system_observer.h", - "chromeos/loader_controller.cc", - "chromeos/loader_controller.h", "chromeos/remove_stale_cache_files.cc", "chromeos/remove_stale_cache_files.h", "chromeos/resource_metadata.cc", "chromeos/resource_metadata.h", - "chromeos/root_folder_id_loader.h", "chromeos/search_metadata.cc", "chromeos/search_metadata.h", - "chromeos/start_page_token_loader.cc", - "chromeos/start_page_token_loader.h", - "chromeos/sync/entry_revert_performer.cc", - "chromeos/sync/entry_revert_performer.h", - "chromeos/sync/entry_update_performer.cc", - "chromeos/sync/entry_update_performer.h", - "chromeos/sync/remove_performer.cc", - "chromeos/sync/remove_performer.h", - "chromeos/sync_client.cc", - "chromeos/sync_client.h", "chromeos/team_drive.cc", "chromeos/team_drive.h", - "chromeos/team_drive_change_list_loader.cc", - "chromeos/team_drive_change_list_loader.h", - "chromeos/team_drive_list_loader.cc", - "chromeos/team_drive_list_loader.h", "chromeos/team_drive_list_observer.h", ] deps = [ @@ -192,10 +135,6 @@ sources = [ "chromeos/drive_test_util.cc", "chromeos/drive_test_util.h", - "chromeos/dummy_file_system.cc", - "chromeos/dummy_file_system.h", - "chromeos/fake_file_system.cc", - "chromeos/fake_file_system.h", "chromeos/fake_free_disk_space_getter.cc", "chromeos/fake_free_disk_space_getter.h", ]
diff --git a/components/drive/DEPS b/components/drive/DEPS index 850ce58..851b225 100644 --- a/components/drive/DEPS +++ b/components/drive/DEPS
@@ -16,48 +16,22 @@ specific_include_rules = { # The following test dependencies should be removed to fully componentize this # directory. crbug.com/498951 - r"(copy_operation_unittest\.cc" - r"|create_directory_operation_unittest\.cc" - r"|create_file_operation_unittest\.cc" - r"|download_operation_unittest\.cc" - r"|drive_test_util\.h" - r"|entry_revert_performer_unittest\.cc" - r"|entry_update_performer_unittest\.cc" - r"|get_file_for_saving_operation_unittest\.cc" - r"|move_operation_unittest\.cc" - r"|open_file_operation_unittest\.cc" - r"|operation_test_base\.cc" - r"|remove_operation_unittest\.cc" - r"|remove_performer_unittest\.cc" - r"|search_operation_unittest\.cc" - r"|set_property_operation_unittest\.cc" - r"|truncate_operation_unittest\.cc" - r")": [ + "drive_test_util\.h": [ "+content/public/test/test_utils.h", ], # The following test dependencies should be removed to fully componentize this # directory. crbug.com/498951 - r"(about_resource_loader_unittest\.cc" - r"|change_list_loader_unittest\.cc" - r"|change_list_processor_unittest\.cc" - r"|directory_loader_unittest\.cc" + r"(change_list_processor_unittest\.cc" r"|drive_file_util_unittest\.cc" - r"|fake_file_system_unittest\.cc" r"|file_cache_unittest\.cc" r"|file_system_core_util_unittest\.cc" - r"|file_system_unittest\.cc" r"|file_write_watcher_unittest\.cc" r"|job_scheduler_unittest\.cc" - r"|operation_test_base\.h" r"|remove_stale_cache_files_unittest\.cc" r"|resource_metadata_storage_unittest\.cc" r"|resource_metadata_unittest\.cc" r"|search_metadata_unittest\.cc" - r"|start_page_token_loader_unittest\.cc" - r"|sync_client_unittest\.cc" - r"|team_drive_change_list_loader_unittest\.cc" - r"|team_drive_list_loader_unittest\.cc" r")": [ "+content/public/test/browser_task_environment.h", ], @@ -65,11 +39,7 @@ # The following test dependencies should be removed to fully componentize this # directory. crbug.com/498951 r"(drive_uploader\.cc" - r"|fake_file_system\.cc" - r"|file_system_unittest\.cc" r"|file_write_watcher_unittest\.cc" - r"|get_file_for_saving_operation_unittest\.cc" - r"|operation_test_base\.cc" r")": [ "+content/public/browser/browser_thread.h", ],
diff --git a/components/drive/about_resource_loader_unittest.cc b/components/drive/about_resource_loader_unittest.cc deleted file mode 100644 index d9a1340f..0000000 --- a/components/drive/about_resource_loader_unittest.cc +++ /dev/null
@@ -1,208 +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 "components/drive/chromeos/about_resource_loader.h" - -#include <memory> - -#include "base/command_line.h" -#include "base/files/scoped_temp_dir.h" -#include "base/test/test_mock_time_task_runner.h" -#include "base/threading/thread_task_runner_handle.h" -#include "components/drive/chromeos/drive_test_util.h" -#include "components/drive/chromeos/file_cache.h" -#include "components/drive/chromeos/resource_metadata.h" -#include "components/drive/event_logger.h" -#include "components/drive/job_scheduler.h" -#include "components/drive/resource_metadata_storage.h" -#include "components/drive/service/fake_drive_service.h" -#include "components/drive/service/test_util.h" -#include "components/prefs/testing_pref_service.h" -#include "mojo/public/cpp/bindings/pending_remote.h" -#include "services/network/test/test_network_connection_tracker.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace drive { -namespace internal { - -namespace { - -struct DestroyHelper { - template <typename T> - void operator()(T* object) const { - if (object) { - object->Destroy(); - } - } -}; - -} // namespace - -class AboutResourceLoaderTest : public testing::Test { - protected: - void SetUp() override { - task_runner_ = base::MakeRefCounted<base::TestMockTimeTaskRunner>( - base::TestMockTimeTaskRunner::Type::kBoundToThread); - - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - - pref_service_ = std::make_unique<TestingPrefServiceSimple>(); - test_util::RegisterDrivePrefs(pref_service_->registry()); - - logger_ = std::make_unique<EventLogger>(); - - drive_service_ = std::make_unique<FakeDriveService>(); - ASSERT_TRUE(test_util::SetUpTestEntries(drive_service_.get())); - - network::TestNetworkConnectionTracker::GetInstance()->SetConnectionType( - network::mojom::ConnectionType::CONNECTION_WIFI); - scheduler_ = std::make_unique<JobScheduler>( - pref_service_.get(), logger_.get(), drive_service_.get(), - network::TestNetworkConnectionTracker::GetInstance(), - task_runner_.get(), mojo::NullRemote()); - metadata_storage_.reset( - new ResourceMetadataStorage(temp_dir_.GetPath(), task_runner_.get())); - ASSERT_TRUE(metadata_storage_->Initialize()); - - cache_.reset(new FileCache(metadata_storage_.get(), temp_dir_.GetPath(), - task_runner_.get(), - nullptr /* free_disk_space_getter */)); - ASSERT_TRUE(cache_->Initialize()); - - metadata_.reset(new ResourceMetadata(metadata_storage_.get(), cache_.get(), - task_runner_.get())); - ASSERT_EQ(FILE_ERROR_OK, metadata_->Initialize()); - - about_resource_loader_ = std::make_unique<AboutResourceLoader>( - scheduler_.get(), task_runner_->GetMockTickClock()); - } - - void TearDown() override { - // We need to manually reset the objects that implement the Destroy idiom, - // that deletes the object on the |task_runner_|. This is simpler than - // introducing custom deleters that capture the |task_runner_| and - // invoke RunUntilIdle(). - metadata_.reset(); - cache_.reset(); - metadata_storage_.reset(); - task_runner_->RunUntilIdle(); - } - - // Adds a new file to the root directory of the service. - std::unique_ptr<google_apis::FileResource> AddNewFile( - const std::string& title) { - google_apis::DriveApiErrorCode error = google_apis::DRIVE_FILE_ERROR; - std::unique_ptr<google_apis::FileResource> entry; - drive_service_->AddNewFile( - "text/plain", "content text", drive_service_->GetRootResourceId(), - title, - false, // shared_with_me - google_apis::test_util::CreateCopyResultCallback(&error, &entry)); - task_runner_->RunUntilIdle(); - EXPECT_EQ(google_apis::HTTP_CREATED, error); - return entry; - } - - scoped_refptr<base::TestMockTimeTaskRunner> task_runner_; - base::ScopedTempDir temp_dir_; - std::unique_ptr<TestingPrefServiceSimple> pref_service_; - std::unique_ptr<EventLogger> logger_; - std::unique_ptr<FakeDriveService> drive_service_; - std::unique_ptr<JobScheduler> scheduler_; - std::unique_ptr<ResourceMetadataStorage, DestroyHelper> metadata_storage_; - std::unique_ptr<FileCache, DestroyHelper> cache_; - std::unique_ptr<ResourceMetadata, DestroyHelper> metadata_; - std::unique_ptr<AboutResourceLoader> about_resource_loader_; -}; - -TEST_F(AboutResourceLoaderTest, AboutResourceLoader) { - google_apis::DriveApiErrorCode error[6] = {}; - std::unique_ptr<google_apis::AboutResource> about[6]; - - // No resource is cached at the beginning. - ASSERT_FALSE(about_resource_loader_->cached_about_resource()); - - // Since no resource is cached, this "Get" should trigger the update. - about_resource_loader_->GetAboutResource( - google_apis::test_util::CreateCopyResultCallback(error + 0, about + 0)); - // Since there is one in-flight update, the next "Get" just wait for it. - about_resource_loader_->GetAboutResource( - google_apis::test_util::CreateCopyResultCallback(error + 1, about + 1)); - - task_runner_->RunUntilIdle(); - EXPECT_EQ(google_apis::HTTP_SUCCESS, error[0]); - EXPECT_EQ(google_apis::HTTP_SUCCESS, error[1]); - const int64_t first_changestamp = about[0]->largest_change_id(); - EXPECT_EQ(first_changestamp, about[1]->largest_change_id()); - ASSERT_TRUE(about_resource_loader_->cached_about_resource()); - EXPECT_EQ( - first_changestamp, - about_resource_loader_->cached_about_resource()->largest_change_id()); - - // Increment changestamp by 1. - AddNewFile("temp"); - // Explicitly calling UpdateAboutResource will start another API call. - about_resource_loader_->UpdateAboutResource( - google_apis::test_util::CreateCopyResultCallback(error + 2, about + 2)); - // It again waits for the in-flight UpdateAboutResoure call, even though this - // time there is a cached result. - about_resource_loader_->GetAboutResource( - google_apis::test_util::CreateCopyResultCallback(error + 3, about + 3)); - - task_runner_->RunUntilIdle(); - EXPECT_EQ(google_apis::HTTP_SUCCESS, error[2]); - EXPECT_EQ(google_apis::HTTP_SUCCESS, error[3]); - EXPECT_EQ(first_changestamp + 1, about[2]->largest_change_id()); - EXPECT_EQ(first_changestamp + 1, about[3]->largest_change_id()); - EXPECT_EQ( - first_changestamp + 1, - about_resource_loader_->cached_about_resource()->largest_change_id()); - - // Increment changestamp by 1. - AddNewFile("temp2"); - // Now no UpdateAboutResource task is running. Returns the cached result. - about_resource_loader_->GetAboutResource( - google_apis::test_util::CreateCopyResultCallback(error + 4, about + 4)); - // Explicitly calling UpdateAboutResource will start another API call. - about_resource_loader_->UpdateAboutResource( - google_apis::test_util::CreateCopyResultCallback(error + 5, about + 5)); - - task_runner_->RunUntilIdle(); - EXPECT_EQ(google_apis::HTTP_NO_CONTENT, error[4]); - EXPECT_EQ(google_apis::HTTP_SUCCESS, error[5]); - EXPECT_EQ(first_changestamp + 1, about[4]->largest_change_id()); - EXPECT_EQ(first_changestamp + 2, about[5]->largest_change_id()); - EXPECT_EQ( - first_changestamp + 2, - about_resource_loader_->cached_about_resource()->largest_change_id()); - - EXPECT_EQ(3, drive_service_->about_resource_load_count()); -} - -TEST_F(AboutResourceLoaderTest, EvictCache) { - google_apis::DriveApiErrorCode error; - std::unique_ptr<google_apis::AboutResource> about; - - // No resource is cached at the beginning. - ASSERT_FALSE(about_resource_loader_->cached_about_resource()); - - // Since no resource is cached, this "Get" should trigger the update. - about_resource_loader_->GetAboutResource( - google_apis::test_util::CreateCopyResultCallback(&error, &about)); - - task_runner_->RunUntilIdle(); - EXPECT_EQ(google_apis::HTTP_SUCCESS, error); - - // Should have a cached resource. - ASSERT_TRUE(about_resource_loader_->cached_about_resource()); - - // Advance the timer should evict the cache. - task_runner_->FastForwardUntilNoTasksRemain(); - - // Cache should be evicted. - ASSERT_FALSE(about_resource_loader_->cached_about_resource()); -} - -} // namespace internal -} // namespace drive
diff --git a/components/drive/change_list_loader_unittest.cc b/components/drive/change_list_loader_unittest.cc deleted file mode 100644 index 6d556ce..0000000 --- a/components/drive/change_list_loader_unittest.cc +++ /dev/null
@@ -1,407 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/drive/chromeos/change_list_loader.h" - -#include <stdint.h> - -#include <memory> - -#include "base/callback_helpers.h" -#include "base/command_line.h" -#include "base/files/scoped_temp_dir.h" -#include "base/macros.h" -#include "base/run_loop.h" -#include "base/single_thread_task_runner.h" -#include "base/threading/thread_task_runner_handle.h" -#include "components/drive/chromeos/about_resource_loader.h" -#include "components/drive/chromeos/about_resource_root_folder_id_loader.h" -#include "components/drive/chromeos/change_list_loader_observer.h" -#include "components/drive/chromeos/drive_test_util.h" -#include "components/drive/chromeos/file_cache.h" -#include "components/drive/chromeos/loader_controller.h" -#include "components/drive/chromeos/resource_metadata.h" -#include "components/drive/chromeos/start_page_token_loader.h" -#include "components/drive/event_logger.h" -#include "components/drive/file_change.h" -#include "components/drive/file_system_core_util.h" -#include "components/drive/job_scheduler.h" -#include "components/drive/service/fake_drive_service.h" -#include "components/drive/service/test_util.h" -#include "components/prefs/testing_pref_service.h" -#include "content/public/test/browser_task_environment.h" -#include "google_apis/drive/drive_api_parser.h" -#include "google_apis/drive/test_util.h" -#include "mojo/public/cpp/bindings/pending_remote.h" -#include "services/network/test/test_network_connection_tracker.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace drive { -namespace internal { - -class TestChangeListLoaderObserver : public ChangeListLoaderObserver { - public: - explicit TestChangeListLoaderObserver(ChangeListLoader* loader) - : loader_(loader), - load_from_server_complete_count_(0), - initial_load_complete_count_(0) { - loader_->AddObserver(this); - } - - ~TestChangeListLoaderObserver() override { loader_->RemoveObserver(this); } - - const FileChange& changed_files() const { return changed_files_; } - void clear_changed_files() { changed_files_.ClearForTest(); } - - const FileChange& changed_team_drives() const { return changed_team_drives_; } - - int load_from_server_complete_count() const { - return load_from_server_complete_count_; - } - int initial_load_complete_count() const { - return initial_load_complete_count_; - } - - // ChageListObserver overrides: - void OnFileChanged(const FileChange& changed_files) override { - changed_files_.Apply(changed_files); - } - void OnTeamDrivesChanged(const FileChange& changed_team_drives) override { - changed_team_drives_.Apply(changed_team_drives); - } - void OnLoadFromServerComplete() override { - ++load_from_server_complete_count_; - } - void OnInitialLoadComplete() override { ++initial_load_complete_count_; } - - private: - ChangeListLoader* loader_; - FileChange changed_files_; - FileChange changed_team_drives_; - int load_from_server_complete_count_; - int initial_load_complete_count_; - - DISALLOW_COPY_AND_ASSIGN(TestChangeListLoaderObserver); -}; - -class ChangeListLoaderTest : public testing::Test { - protected: - void SetUp() override { - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - BuildTestObjects(); - } - - void BuildTestObjects() { - pref_service_ = std::make_unique<TestingPrefServiceSimple>(); - test_util::RegisterDrivePrefs(pref_service_->registry()); - - logger_ = std::make_unique<EventLogger>(); - - drive_service_ = std::make_unique<FakeDriveService>(); - ASSERT_TRUE(test_util::SetUpTestEntries(drive_service_.get())); - - network::TestNetworkConnectionTracker::GetInstance()->SetConnectionType( - network::mojom::ConnectionType::CONNECTION_WIFI); - scheduler_ = std::make_unique<JobScheduler>( - pref_service_.get(), logger_.get(), drive_service_.get(), - network::TestNetworkConnectionTracker::GetInstance(), - base::ThreadTaskRunnerHandle::Get().get(), mojo::NullRemote()); - metadata_storage_.reset(new ResourceMetadataStorage( - temp_dir_.GetPath(), base::ThreadTaskRunnerHandle::Get().get())); - ASSERT_TRUE(metadata_storage_->Initialize()); - - cache_.reset(new FileCache(metadata_storage_.get(), temp_dir_.GetPath(), - base::ThreadTaskRunnerHandle::Get().get(), - nullptr /* free_disk_space_getter */)); - ASSERT_TRUE(cache_->Initialize()); - - metadata_.reset(new ResourceMetadata( - metadata_storage_.get(), cache_.get(), - base::ThreadTaskRunnerHandle::Get().get())); - ASSERT_EQ(FILE_ERROR_OK, metadata_->Initialize()); - - about_resource_loader_ = - std::make_unique<AboutResourceLoader>(scheduler_.get()); - root_folder_id_loader_ = std::make_unique<AboutResourceRootFolderIdLoader>( - about_resource_loader_.get()); - start_page_token_loader_ = std::make_unique<StartPageTokenLoader>( - drive::util::kTeamDriveIdDefaultCorpus, scheduler_.get()); - loader_controller_ = std::make_unique<LoaderController>(); - change_list_loader_ = std::make_unique<ChangeListLoader>( - logger_.get(), base::ThreadTaskRunnerHandle::Get().get(), - metadata_.get(), scheduler_.get(), root_folder_id_loader_.get(), - start_page_token_loader_.get(), loader_controller_.get(), - util::kTeamDriveIdDefaultCorpus, util::GetDriveMyDriveRootPath()); - } - - // Adds a new file to the root directory of the service. - std::unique_ptr<google_apis::FileResource> AddNewFile( - const std::string& title) { - google_apis::DriveApiErrorCode error = google_apis::DRIVE_FILE_ERROR; - std::unique_ptr<google_apis::FileResource> entry; - drive_service_->AddNewFile( - "text/plain", - "content text", - drive_service_->GetRootResourceId(), - title, - false, // shared_with_me - google_apis::test_util::CreateCopyResultCallback(&error, &entry)); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(google_apis::HTTP_CREATED, error); - return entry; - } - - content::BrowserTaskEnvironment task_environment_; - base::ScopedTempDir temp_dir_; - std::unique_ptr<TestingPrefServiceSimple> pref_service_; - std::unique_ptr<EventLogger> logger_; - std::unique_ptr<FakeDriveService> drive_service_; - std::unique_ptr<JobScheduler> scheduler_; - std::unique_ptr<ResourceMetadataStorage, test_util::DestroyHelperForTests> - metadata_storage_; - std::unique_ptr<FileCache, test_util::DestroyHelperForTests> cache_; - std::unique_ptr<ResourceMetadata, test_util::DestroyHelperForTests> metadata_; - std::unique_ptr<AboutResourceLoader> about_resource_loader_; - std::unique_ptr<StartPageTokenLoader> start_page_token_loader_; - std::unique_ptr<LoaderController> loader_controller_; - std::unique_ptr<ChangeListLoader> change_list_loader_; - std::unique_ptr<AboutResourceRootFolderIdLoader> root_folder_id_loader_; -}; - -TEST_F(ChangeListLoaderTest, Load) { - EXPECT_FALSE(change_list_loader_->IsRefreshing()); - - // Start initial load. - TestChangeListLoaderObserver observer(change_list_loader_.get()); - - EXPECT_EQ(0, drive_service_->about_resource_load_count()); - - FileError error = FILE_ERROR_FAILED; - change_list_loader_->LoadIfNeeded( - google_apis::test_util::CreateCopyResultCallback(&error)); - EXPECT_TRUE(change_list_loader_->IsRefreshing()); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - EXPECT_FALSE(change_list_loader_->IsRefreshing()); - std::string start_page_token; - EXPECT_EQ(FILE_ERROR_OK, metadata_->GetStartPageToken(&start_page_token)); - EXPECT_FALSE(start_page_token.empty()); - EXPECT_EQ(0, drive_service_->team_drive_list_load_count()); - EXPECT_EQ(1, drive_service_->file_list_load_count()); - EXPECT_EQ(1, drive_service_->about_resource_load_count()); - EXPECT_EQ(1, observer.initial_load_complete_count()); - EXPECT_EQ(1, observer.load_from_server_complete_count()); - EXPECT_TRUE(observer.changed_files().empty()); - - base::FilePath file_path = - util::GetDriveMyDriveRootPath().AppendASCII("File 1.txt"); - ResourceEntry entry; - EXPECT_EQ(FILE_ERROR_OK, - metadata_->GetResourceEntryByPath(file_path, &entry)); - - // Calling LoadIfNeeded a second time is a no-op, ensure that the - // callback is called. - error = FILE_ERROR_FAILED; - change_list_loader_->LoadIfNeeded( - google_apis::test_util::CreateCopyResultCallback(&error)); - EXPECT_FALSE(change_list_loader_->IsRefreshing()); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); -} - -TEST_F(ChangeListLoaderTest, Load_LocalMetadataAvailable) { - // Prepare metadata. - FileError error = FILE_ERROR_FAILED; - change_list_loader_->LoadIfNeeded( - google_apis::test_util::CreateCopyResultCallback(&error)); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Reset loader. - about_resource_loader_ = - std::make_unique<AboutResourceLoader>(scheduler_.get()); - root_folder_id_loader_ = std::make_unique<AboutResourceRootFolderIdLoader>( - about_resource_loader_.get()); - start_page_token_loader_ = std::make_unique<StartPageTokenLoader>( - drive::util::kTeamDriveIdDefaultCorpus, scheduler_.get()); - change_list_loader_ = std::make_unique<ChangeListLoader>( - logger_.get(), base::ThreadTaskRunnerHandle::Get().get(), metadata_.get(), - scheduler_.get(), root_folder_id_loader_.get(), - start_page_token_loader_.get(), loader_controller_.get(), - util::kTeamDriveIdDefaultCorpus, util::GetDriveMyDriveRootPath()); - - // Add a file to the service. - std::unique_ptr<google_apis::FileResource> gdata_entry = - AddNewFile("New File"); - ASSERT_TRUE(gdata_entry); - - // Start loading. Because local metadata is available, the load results in - // returning FILE_ERROR_OK without fetching full list of resources. - const int previous_file_list_load_count = - drive_service_->file_list_load_count(); - TestChangeListLoaderObserver observer(change_list_loader_.get()); - - change_list_loader_->LoadIfNeeded( - google_apis::test_util::CreateCopyResultCallback(&error)); - EXPECT_TRUE(change_list_loader_->IsRefreshing()); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - EXPECT_EQ(previous_file_list_load_count, - drive_service_->file_list_load_count()); - EXPECT_EQ(1, observer.initial_load_complete_count()); - - // Update should be checked by Load(). - std::string start_page_token; - EXPECT_EQ(FILE_ERROR_OK, metadata_->GetStartPageToken(&start_page_token)); - EXPECT_EQ(drive_service_->start_page_token().start_page_token(), - start_page_token); - EXPECT_EQ(1, drive_service_->change_list_load_count()); - EXPECT_EQ(1, observer.load_from_server_complete_count()); - EXPECT_TRUE( - observer.changed_files().CountDirectory(util::GetDriveMyDriveRootPath())); - - base::FilePath file_path = - util::GetDriveMyDriveRootPath().AppendASCII(gdata_entry->title()); - ResourceEntry entry; - EXPECT_EQ(FILE_ERROR_OK, - metadata_->GetResourceEntryByPath(file_path, &entry)); -} - -TEST_F(ChangeListLoaderTest, CheckForUpdates) { - // CheckForUpdates() results in no-op before load. - FileError check_for_updates_error = FILE_ERROR_FAILED; - change_list_loader_->CheckForUpdates( - google_apis::test_util::CreateCopyResultCallback( - &check_for_updates_error)); - EXPECT_FALSE(change_list_loader_->IsRefreshing()); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_FAILED, - check_for_updates_error); // Callback was not run. - std::string start_page_token; - EXPECT_EQ(FILE_ERROR_OK, metadata_->GetStartPageToken(&start_page_token)); - EXPECT_TRUE(start_page_token.empty()); - EXPECT_EQ(0, drive_service_->file_list_load_count()); - EXPECT_EQ(0, drive_service_->about_resource_load_count()); - - // Start initial load. - FileError load_error = FILE_ERROR_FAILED; - change_list_loader_->LoadIfNeeded( - google_apis::test_util::CreateCopyResultCallback(&load_error)); - EXPECT_TRUE(change_list_loader_->IsRefreshing()); - - // CheckForUpdates() while loading. - change_list_loader_->CheckForUpdates( - google_apis::test_util::CreateCopyResultCallback( - &check_for_updates_error)); - - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(change_list_loader_->IsRefreshing()); - EXPECT_EQ(FILE_ERROR_OK, load_error); - EXPECT_EQ(FILE_ERROR_OK, check_for_updates_error); - EXPECT_EQ(FILE_ERROR_OK, metadata_->GetStartPageToken(&start_page_token)); - EXPECT_FALSE(start_page_token.empty()); - EXPECT_EQ(1, drive_service_->file_list_load_count()); - - std::string previous_start_page_token = start_page_token; - // CheckForUpdates() results in no update. - change_list_loader_->CheckForUpdates( - google_apis::test_util::CreateCopyResultCallback( - &check_for_updates_error)); - EXPECT_TRUE(change_list_loader_->IsRefreshing()); - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(change_list_loader_->IsRefreshing()); - EXPECT_EQ(FILE_ERROR_OK, metadata_->GetStartPageToken(&start_page_token)); - EXPECT_EQ(previous_start_page_token, start_page_token); - - // Add a file to the service. - std::unique_ptr<google_apis::FileResource> gdata_entry = - AddNewFile("New File"); - ASSERT_TRUE(gdata_entry); - - // CheckForUpdates() results in update. - TestChangeListLoaderObserver observer(change_list_loader_.get()); - change_list_loader_->CheckForUpdates( - google_apis::test_util::CreateCopyResultCallback( - &check_for_updates_error)); - EXPECT_TRUE(change_list_loader_->IsRefreshing()); - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(change_list_loader_->IsRefreshing()); - EXPECT_EQ(FILE_ERROR_OK, metadata_->GetStartPageToken(&start_page_token)); - EXPECT_NE(previous_start_page_token, start_page_token); - EXPECT_EQ(1, observer.load_from_server_complete_count()); - EXPECT_TRUE( - observer.changed_files().CountDirectory(util::GetDriveMyDriveRootPath())); - - // The new file is found in the local metadata. - base::FilePath new_file_path = - util::GetDriveMyDriveRootPath().AppendASCII(gdata_entry->title()); - ResourceEntry entry; - EXPECT_EQ(FILE_ERROR_OK, - metadata_->GetResourceEntryByPath(new_file_path, &entry)); -} - -TEST_F(ChangeListLoaderTest, Lock) { - FileError error = FILE_ERROR_FAILED; - change_list_loader_->LoadIfNeeded( - google_apis::test_util::CreateCopyResultCallback(&error)); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Add a new file. - std::unique_ptr<google_apis::FileResource> file = AddNewFile("New File"); - ASSERT_TRUE(file); - - // Lock the loader. - std::unique_ptr<base::ScopedClosureRunner> lock = - loader_controller_->GetLock(); - - // Start update. - TestChangeListLoaderObserver observer(change_list_loader_.get()); - FileError check_for_updates_error = FILE_ERROR_FAILED; - change_list_loader_->CheckForUpdates( - google_apis::test_util::CreateCopyResultCallback( - &check_for_updates_error)); - base::RunLoop().RunUntilIdle(); - - // Update is pending due to the lock. - EXPECT_TRUE(observer.changed_files().empty()); - - // Unlock the loader, this should resume the pending update. - lock.reset(); - base::RunLoop().RunUntilIdle(); - EXPECT_TRUE( - observer.changed_files().CountDirectory(util::GetDriveMyDriveRootPath())); -} - -TEST_F(ChangeListLoaderTest, AddTeamDrive) { - FileError error = FILE_ERROR_FAILED; - change_list_loader_->LoadIfNeeded( - google_apis::test_util::CreateCopyResultCallback(&error)); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Add a new team drive - { - drive_service_->AddTeamDrive("team_drive_id", "team_drive_name"); - base::RunLoop().RunUntilIdle(); - } - - // Start update. - TestChangeListLoaderObserver observer(change_list_loader_.get()); - FileError check_for_updates_error = FILE_ERROR_FAILED; - change_list_loader_->CheckForUpdates( - google_apis::test_util::CreateCopyResultCallback( - &check_for_updates_error)); - base::RunLoop().RunUntilIdle(); - - EXPECT_FALSE(observer.changed_files().empty()); - EXPECT_FALSE(observer.changed_team_drives().empty()); - EXPECT_EQ(1UL, observer.changed_files().CountDirectory( - util::GetDriveTeamDrivesRootPath())); - EXPECT_EQ(1UL, observer.changed_team_drives().CountDirectory( - util::GetDriveTeamDrivesRootPath())); -} -} // namespace internal -} // namespace drive
diff --git a/components/drive/chromeos/about_resource_loader.cc b/components/drive/chromeos/about_resource_loader.cc deleted file mode 100644 index 5971e9e..0000000 --- a/components/drive/chromeos/about_resource_loader.cc +++ /dev/null
@@ -1,110 +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 "components/drive/chromeos/about_resource_loader.h" - -#include <memory> -#include <vector> - -#include "base/bind.h" -#include "base/threading/thread_task_runner_handle.h" -#include "components/drive/job_scheduler.h" - -namespace drive { -namespace internal { - -namespace { -// The time period that we will cache the result of UpdateAboutResource. -constexpr base::TimeDelta kCacheEvictionTimeout = - base::TimeDelta::FromMinutes(1); -} // namespace - -AboutResourceLoader::AboutResourceLoader(JobScheduler* scheduler, - const base::TickClock* clock) - : scheduler_(scheduler), current_update_task_id_(-1) { - cache_eviction_timer_ = std::make_unique<base::RetainingOneShotTimer>( - FROM_HERE, kCacheEvictionTimeout, - base::BindRepeating(&AboutResourceLoader::EvictCachedAboutResource, - base::Unretained(this)), - clock); -} - -AboutResourceLoader::~AboutResourceLoader() = default; - -void AboutResourceLoader::GetAboutResource( - const google_apis::AboutResourceCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - // If the latest UpdateAboutResource task is still running. Wait for it, - if (pending_callbacks_.count(current_update_task_id_)) { - pending_callbacks_[current_update_task_id_].emplace_back(callback); - return; - } - - if (cached_about_resource_) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(callback, google_apis::HTTP_NO_CONTENT, - std::make_unique<google_apis::AboutResource>( - *cached_about_resource_))); - } else { - UpdateAboutResource(callback); - } -} - -void AboutResourceLoader::UpdateAboutResource( - const google_apis::AboutResourceCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - ++current_update_task_id_; - pending_callbacks_[current_update_task_id_].emplace_back(callback); - - scheduler_->GetAboutResource(base::BindRepeating( - &AboutResourceLoader::UpdateAboutResourceAfterGetAbout, - weak_ptr_factory_.GetWeakPtr(), current_update_task_id_)); -} - -void AboutResourceLoader::UpdateAboutResourceAfterGetAbout( - int task_id, - google_apis::DriveApiErrorCode status, - std::unique_ptr<google_apis::AboutResource> about_resource) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - FileError error = GDataToFileError(status); - - const std::vector<google_apis::AboutResourceCallback> callbacks = - pending_callbacks_[task_id]; - pending_callbacks_.erase(task_id); - - if (error != FILE_ERROR_OK) { - for (auto& callback : callbacks) - callback.Run(status, nullptr); - return; - } - - // Updates the cache when the resource is successfully obtained. - if (cached_about_resource_ && cached_about_resource_->largest_change_id() > - about_resource->largest_change_id()) { - LOG(WARNING) << "Local cached about resource is fresher than server, " - << "local = " << cached_about_resource_->largest_change_id() - << ", server = " << about_resource->largest_change_id(); - } - cached_about_resource_ = - std::make_unique<google_apis::AboutResource>(*about_resource); - - cache_eviction_timer_->Reset(); - - for (auto& callback : callbacks) { - callback.Run(status, - std::make_unique<google_apis::AboutResource>(*about_resource)); - } -} - -void AboutResourceLoader::EvictCachedAboutResource() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - cached_about_resource_.reset(); -} - -} // namespace internal -} // namespace drive
diff --git a/components/drive/chromeos/about_resource_loader.h b/components/drive/chromeos/about_resource_loader.h deleted file mode 100644 index d2b513a..0000000 --- a/components/drive/chromeos/about_resource_loader.h +++ /dev/null
@@ -1,86 +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 COMPONENTS_DRIVE_CHROMEOS_ABOUT_RESOURCE_LOADER_H_ -#define COMPONENTS_DRIVE_CHROMEOS_ABOUT_RESOURCE_LOADER_H_ - -#include <map> -#include <memory> -#include <vector> - -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "base/threading/thread_checker.h" -#include "base/time/default_tick_clock.h" -#include "base/timer/timer.h" -#include "google_apis/drive/drive_common_callbacks.h" - -namespace drive { - -class JobScheduler; - -namespace internal { - -// This class is responsible to load AboutResource from the server and cache it. -class AboutResourceLoader { - public: - // |clock| can be injected for testing. - explicit AboutResourceLoader( - JobScheduler* scheduler, - const base::TickClock* clock = base::DefaultTickClock::GetInstance()); - ~AboutResourceLoader(); - - // Returns the cached about resource. - // NULL is returned if the cache is not available. - const google_apis::AboutResource* cached_about_resource() const { - return cached_about_resource_.get(); - } - - // Gets the 'latest' about resource and asynchronously runs |callback|. I.e., - // 1) If the last call to UpdateAboutResource call is in-flight, wait for it. - // 2) Otherwise, if the resource is cached, just returns the cached value. - // 3) If neither of the above hold, queries the API server by calling - // |UpdateAboutResource|. - void GetAboutResource(const google_apis::AboutResourceCallback& callback); - - // Gets the about resource from the server, and caches it if successful. This - // function calls JobScheduler::GetAboutResource internally. The cache will be - // used in |GetAboutResource|. - void UpdateAboutResource(const google_apis::AboutResourceCallback& callback); - - private: - // Part of UpdateAboutResource(). - // This function should be called when the latest about resource is being - // fetched from the server. The retrieved about resource is cloned, and one is - // cached and the other is passed to callbacks associated with |task_id|. - void UpdateAboutResourceAfterGetAbout( - int task_id, - google_apis::DriveApiErrorCode status, - std::unique_ptr<google_apis::AboutResource> about_resource); - - void EvictCachedAboutResource(); - - JobScheduler* scheduler_; - std::unique_ptr<google_apis::AboutResource> cached_about_resource_; - - // Identifier to denote the latest UpdateAboutResource call. - int current_update_task_id_; - // Mapping from each UpdateAboutResource task ID to the corresponding - // callbacks. Note that there will be multiple callbacks for a single task - // when GetAboutResource is called before the task completes. - std::map<int, std::vector<google_apis::AboutResourceCallback>> - pending_callbacks_; - - std::unique_ptr<base::RetainingOneShotTimer> cache_eviction_timer_; - - THREAD_CHECKER(thread_checker_); - - base::WeakPtrFactory<AboutResourceLoader> weak_ptr_factory_{this}; - DISALLOW_COPY_AND_ASSIGN(AboutResourceLoader); -}; - -} // namespace internal -} // namespace drive - -#endif // COMPONENTS_DRIVE_CHROMEOS_ABOUT_RESOURCE_LOADER_H_
diff --git a/components/drive/chromeos/about_resource_root_folder_id_loader.cc b/components/drive/chromeos/about_resource_root_folder_id_loader.cc deleted file mode 100644 index 5308c6f6..0000000 --- a/components/drive/chromeos/about_resource_root_folder_id_loader.cc +++ /dev/null
@@ -1,57 +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 "components/drive/chromeos/about_resource_root_folder_id_loader.h" - -#include <memory> - -#include "base/bind.h" -#include "components/drive/chromeos/about_resource_loader.h" -#include "google_apis/drive/drive_api_parser.h" - -namespace drive { -namespace internal { - -AboutResourceRootFolderIdLoader::AboutResourceRootFolderIdLoader( - AboutResourceLoader* about_resource_loader) - : about_resource_loader_(about_resource_loader) {} - -AboutResourceRootFolderIdLoader::~AboutResourceRootFolderIdLoader() = default; - -void AboutResourceRootFolderIdLoader::GetRootFolderId( - const RootFolderIdCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - // If we have already read the root folder id, then we can simply return it. - if (!root_folder_id_.empty()) { - callback.Run(FILE_ERROR_OK, root_folder_id_); - return; - } - - about_resource_loader_->GetAboutResource( - base::BindRepeating(&AboutResourceRootFolderIdLoader::OnGetAboutResource, - weak_ptr_factory_.GetWeakPtr(), callback)); -} - -void AboutResourceRootFolderIdLoader::OnGetAboutResource( - const RootFolderIdCallback& callback, - google_apis::DriveApiErrorCode status, - std::unique_ptr<google_apis::AboutResource> about_resource) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - FileError error = GDataToFileError(status); - - if (error != FILE_ERROR_OK) { - callback.Run(error, base::nullopt); - return; - } - - DCHECK(about_resource); - - // The root folder id is immutable so we can save it for subsequent calls. - root_folder_id_ = about_resource->root_folder_id(); - callback.Run(error, root_folder_id_); -} - -} // namespace internal -} // namespace drive
diff --git a/components/drive/chromeos/about_resource_root_folder_id_loader.h b/components/drive/chromeos/about_resource_root_folder_id_loader.h deleted file mode 100644 index 96978ed..0000000 --- a/components/drive/chromeos/about_resource_root_folder_id_loader.h +++ /dev/null
@@ -1,55 +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 COMPONENTS_DRIVE_CHROMEOS_ABOUT_RESOURCE_ROOT_FOLDER_ID_LOADER_H_ -#define COMPONENTS_DRIVE_CHROMEOS_ABOUT_RESOURCE_ROOT_FOLDER_ID_LOADER_H_ - -#include <memory> -#include <string> - -#include "base/memory/weak_ptr.h" -#include "base/threading/thread_checker.h" -#include "components/drive/chromeos/root_folder_id_loader.h" -#include "google_apis/drive/drive_api_error_codes.h" - -namespace google_apis { -class AboutResource; -} // namespace google_apis - -namespace drive { -namespace internal { - -class AboutResourceLoader; - -// Retrieves the root folder id from the about resource loader. This is used -// to get the root folder ID for the users default corpus. As the value is -// constant we just use GetAboutResource which will usually retrieve a -// cached value. -class AboutResourceRootFolderIdLoader : public RootFolderIdLoader { - public: - explicit AboutResourceRootFolderIdLoader( - AboutResourceLoader* about_resource_loader); - ~AboutResourceRootFolderIdLoader() override; - - void GetRootFolderId(const RootFolderIdCallback& callback) override; - - private: - void OnGetAboutResource( - const RootFolderIdCallback& callback, - google_apis::DriveApiErrorCode error, - std::unique_ptr<google_apis::AboutResource> about_resource); - - AboutResourceLoader* about_resource_loader_; // Not owned. - std::string root_folder_id_; - - THREAD_CHECKER(thread_checker_); - - base::WeakPtrFactory<AboutResourceRootFolderIdLoader> weak_ptr_factory_{this}; - DISALLOW_COPY_AND_ASSIGN(AboutResourceRootFolderIdLoader); -}; - -} // namespace internal -} // namespace drive - -#endif // COMPONENTS_DRIVE_CHROMEOS_ABOUT_RESOURCE_ROOT_FOLDER_ID_LOADER_H_
diff --git a/components/drive/chromeos/change_list_loader.cc b/components/drive/chromeos/change_list_loader.cc deleted file mode 100644 index 78b9e12f..0000000 --- a/components/drive/chromeos/change_list_loader.cc +++ /dev/null
@@ -1,519 +0,0 @@ -// Copyright (c) 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. - -#include "components/drive/chromeos/change_list_loader.h" - -#include <stddef.h> - -#include <memory> -#include <set> -#include <utility> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/callback.h" -#include "base/macros.h" -#include "base/metrics/histogram_macros.h" -#include "base/strings/strcat.h" -#include "base/strings/string_number_conversions.h" -#include "base/synchronization/atomic_flag.h" -#include "base/threading/thread_task_runner_handle.h" -#include "base/time/time.h" -#include "components/drive/chromeos/change_list_loader_observer.h" -#include "components/drive/chromeos/change_list_processor.h" -#include "components/drive/chromeos/drive_file_util.h" -#include "components/drive/chromeos/loader_controller.h" -#include "components/drive/chromeos/resource_metadata.h" -#include "components/drive/chromeos/root_folder_id_loader.h" -#include "components/drive/chromeos/start_page_token_loader.h" -#include "components/drive/drive_api_util.h" -#include "components/drive/event_logger.h" -#include "components/drive/file_change.h" -#include "components/drive/file_system_core_util.h" -#include "components/drive/job_scheduler.h" -#include "google_apis/drive/drive_api_parser.h" -#include "url/gurl.h" - -namespace drive { -namespace internal { - -typedef base::Callback<void(FileError, - std::vector<std::unique_ptr<ChangeList>>)> - FeedFetcherCallback; - -class ChangeListLoader::FeedFetcher { - public: - virtual ~FeedFetcher() = default; - virtual void Run(const FeedFetcherCallback& callback) = 0; -}; - -namespace { - -constexpr char kDefaultCorpusMsg[] = "default corpus"; - -// Fetches all the (currently available) resource entries from the server. -class FullFeedFetcher : public ChangeListLoader::FeedFetcher { - public: - FullFeedFetcher(JobScheduler* scheduler, const std::string& team_drive_id) - : scheduler_(scheduler), team_drive_id_(team_drive_id) {} - - ~FullFeedFetcher() override = default; - - void Run(const FeedFetcherCallback& callback) override { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - // Remember the time stamp for usage stats. - start_time_ = base::TimeTicks::Now(); - // This is full resource list fetch. - // - // NOTE: Because we already know the largest change ID, here we can use - // files.list instead of changes.list for speed. crbug.com/287602 - scheduler_->GetAllFileList( - team_drive_id_, base::Bind(&FullFeedFetcher::OnFileListFetched, - weak_ptr_factory_.GetWeakPtr(), callback)); - } - - private: - void OnFileListFetched(const FeedFetcherCallback& callback, - google_apis::DriveApiErrorCode status, - std::unique_ptr<google_apis::FileList> file_list) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - FileError error = GDataToFileError(status); - if (error != FILE_ERROR_OK) { - callback.Run(error, std::vector<std::unique_ptr<ChangeList>>()); - return; - } - - DCHECK(file_list); - change_lists_.push_back(std::make_unique<ChangeList>(*file_list)); - - if (!file_list->next_link().is_empty()) { - // There is the remaining result so fetch it. - scheduler_->GetRemainingFileList( - file_list->next_link(), - base::Bind(&FullFeedFetcher::OnFileListFetched, - weak_ptr_factory_.GetWeakPtr(), callback)); - return; - } - - base::TimeDelta duration = base::TimeTicks::Now() - start_time_; - if (team_drive_id_.empty()) { - UMA_HISTOGRAM_LONG_TIMES("Drive.FullFeedLoadTime", duration); - } else { - UMA_HISTOGRAM_LONG_TIMES("Drive.FullFeedLoadTime.TeamDrives", duration); - } - - // Note: The fetcher is managed by ChangeListLoader, and the instance - // will be deleted in the callback. Do not touch the fields after this - // invocation. - callback.Run(FILE_ERROR_OK, std::move(change_lists_)); - } - - JobScheduler* scheduler_; - const std::string team_drive_id_; - std::vector<std::unique_ptr<ChangeList>> change_lists_; - base::TimeTicks start_time_; - THREAD_CHECKER(thread_checker_); - base::WeakPtrFactory<FullFeedFetcher> weak_ptr_factory_{this}; - DISALLOW_COPY_AND_ASSIGN(FullFeedFetcher); -}; - -// Fetches the delta changes since |start_change_id|. -class DeltaFeedFetcher : public ChangeListLoader::FeedFetcher { - public: - DeltaFeedFetcher(JobScheduler* scheduler, - const std::string& team_drive_id, - const std::string& start_page_token) - : scheduler_(scheduler), - team_drive_id_(team_drive_id), - start_page_token_(start_page_token) {} - - ~DeltaFeedFetcher() override = default; - - void Run(const FeedFetcherCallback& callback) override { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - // Remember the time stamp for usage stats. - start_time_ = base::TimeTicks::Now(); - - scheduler_->GetChangeList( - team_drive_id_, start_page_token_, - base::Bind(&DeltaFeedFetcher::OnChangeListFetched, - weak_ptr_factory_.GetWeakPtr(), callback)); - } - - private: - void OnChangeListFetched( - const FeedFetcherCallback& callback, - google_apis::DriveApiErrorCode status, - std::unique_ptr<google_apis::ChangeList> change_list) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - FileError error = GDataToFileError(status); - if (error != FILE_ERROR_OK) { - callback.Run(error, std::vector<std::unique_ptr<ChangeList>>()); - return; - } - - DCHECK(change_list); - change_lists_.push_back(std::make_unique<ChangeList>(*change_list)); - - if (!change_list->next_link().is_empty()) { - // There is the remaining result so fetch it. - scheduler_->GetRemainingChangeList( - change_list->next_link(), - base::Bind(&DeltaFeedFetcher::OnChangeListFetched, - weak_ptr_factory_.GetWeakPtr(), callback)); - return; - } - - base::TimeDelta duration = base::TimeTicks::Now() - start_time_; - if (team_drive_id_.empty()) { - UMA_HISTOGRAM_LONG_TIMES("Drive.DeltaFeedLoadTime", duration); - } else { - UMA_HISTOGRAM_LONG_TIMES("Drive.DeltaFeedLoadTime.TeamDrives", duration); - } - - // Note: The fetcher is managed by ChangeListLoader, and the instance - // will be deleted in the callback. Do not touch the fields after this - // invocation. - callback.Run(FILE_ERROR_OK, std::move(change_lists_)); - } - - JobScheduler* scheduler_; - const std::string team_drive_id_; - const std::string start_page_token_; - std::vector<std::unique_ptr<ChangeList>> change_lists_; - base::TimeTicks start_time_; - THREAD_CHECKER(thread_checker_); - base::WeakPtrFactory<DeltaFeedFetcher> weak_ptr_factory_{this}; - DISALLOW_COPY_AND_ASSIGN(DeltaFeedFetcher); -}; - -} // namespace - -ChangeListLoader::ChangeListLoader( - EventLogger* logger, - base::SequencedTaskRunner* blocking_task_runner, - ResourceMetadata* resource_metadata, - JobScheduler* scheduler, - RootFolderIdLoader* root_folder_id_loader, - StartPageTokenLoader* start_page_token_loader, - LoaderController* loader_controller, - const std::string& team_drive_id, - const base::FilePath& root_entry_path) - : logger_(logger), - blocking_task_runner_(blocking_task_runner), - in_shutdown_(new base::AtomicFlag), - resource_metadata_(resource_metadata), - scheduler_(scheduler), - root_folder_id_loader_(root_folder_id_loader), - start_page_token_loader_(start_page_token_loader), - loader_controller_(loader_controller), - loaded_(false), - team_drive_id_(team_drive_id), - team_drive_msg_(team_drive_id_.empty() - ? kDefaultCorpusMsg - : base::StrCat({"team drive id: ", team_drive_id_})), - root_entry_path_(root_entry_path) {} - -ChangeListLoader::~ChangeListLoader() { - in_shutdown_->Set(); - // Delete |in_shutdown_| with the blocking task runner so that it gets deleted - // after all active ChangeListProcessors. - blocking_task_runner_->DeleteSoon(FROM_HERE, in_shutdown_.release()); -} - -bool ChangeListLoader::IsRefreshing() const { - // Callback for change list loading is stored in pending_load_callback_. - // It is non-empty if and only if there is an in-flight loading operation. - return !pending_load_callback_.empty(); -} - -void ChangeListLoader::AddObserver(ChangeListLoaderObserver* observer) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - observers_.AddObserver(observer); -} - -void ChangeListLoader::RemoveObserver(ChangeListLoaderObserver* observer) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - observers_.RemoveObserver(observer); -} - -void ChangeListLoader::CheckForUpdates(const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - // We only start to check for updates iff the load is done. - // I.e., we ignore checking updates if not loaded to avoid starting the - // load without user's explicit interaction (such as opening Drive). - if (!loaded_ && !IsRefreshing()) - return; - - // For each CheckForUpdates() request, always refresh the start_page_token. - start_page_token_loader_->UpdateStartPageToken( - base::Bind(&ChangeListLoader::OnStartPageTokenLoaderUpdated, - weak_ptr_factory_.GetWeakPtr())); - - if (IsRefreshing()) { - // There is in-flight loading. So keep the callback here, and check for - // updates when the in-flight loading is completed. - pending_update_check_callback_ = callback; - return; - } - - DCHECK(loaded_); - logger_->Log(logging::LOG_INFO, "Checking for updates (%s)", - team_drive_msg_.c_str()); - Load(callback); -} - -void ChangeListLoader::LoadIfNeeded(const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - // If the metadata is not yet loaded, start loading. - if (!loaded_ && !IsRefreshing()) - Load(callback); - else - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(callback, FILE_ERROR_OK)); -} - -void ChangeListLoader::Load(const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - // Check if this is the first time this ChangeListLoader do loading. - // Note: IsRefreshing() depends on pending_load_callback_ so check in advance. - const bool is_initial_load = (!loaded_ && !IsRefreshing()); - - // Register the callback function to be called when it is loaded. - pending_load_callback_.push_back(callback); - - // If loading task is already running, do nothing. - if (pending_load_callback_.size() > 1) - return; - - // Check the current status of local metadata, and start loading if needed. - std::string* start_page_token = new std::string(); - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), FROM_HERE, - base::Bind(&GetStartPageToken, base::Unretained(resource_metadata_), - team_drive_id_, start_page_token), - base::Bind(&ChangeListLoader::LoadAfterGetLocalStartPageToken, - weak_ptr_factory_.GetWeakPtr(), is_initial_load, - base::Owned(start_page_token))); -} - -void ChangeListLoader::LoadAfterGetLocalStartPageToken( - bool is_initial_load, - const std::string* local_start_page_token, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(local_start_page_token); - - if (error != FILE_ERROR_OK) { - OnChangeListLoadComplete(error); - return; - } - - if (is_initial_load && !local_start_page_token->empty()) { - // The local data is usable. Flush callbacks to tell loading was successful. - OnChangeListLoadComplete(FILE_ERROR_OK); - - // Continues to load from server in background. - // Put dummy callbacks to indicate that fetching is still continuing. - pending_load_callback_.push_back(base::DoNothing()); - } - - root_folder_id_loader_->GetRootFolderId( - base::Bind(&ChangeListLoader::LoadAfterGetRootFolderId, - weak_ptr_factory_.GetWeakPtr(), *local_start_page_token)); -} - -void ChangeListLoader::LoadAfterGetRootFolderId( - const std::string& local_start_page_token, - FileError error, - base::Optional<std::string> root_folder_id) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(!change_feed_fetcher_); - - if (error != FILE_ERROR_OK) { - OnChangeListLoadComplete(error); - return; - } - - DCHECK(root_folder_id); - - start_page_token_loader_->GetStartPageToken( - base::Bind(&ChangeListLoader::LoadAfterGetStartPageToken, - weak_ptr_factory_.GetWeakPtr(), local_start_page_token, - std::move(root_folder_id.value()))); -} - -void ChangeListLoader::LoadAfterGetStartPageToken( - const std::string& local_start_page_token, - const std::string& root_folder_id, - google_apis::DriveApiErrorCode status, - std::unique_ptr<google_apis::StartPageToken> start_page_token) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - FileError error = GDataToFileError(status); - if (error != FILE_ERROR_OK) { - OnChangeListLoadComplete(error); - return; - } - - DCHECK(start_page_token); - - LoadChangeListFromServer(start_page_token->start_page_token(), - local_start_page_token, root_folder_id); -} - -void ChangeListLoader::OnChangeListLoadComplete(FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - if (!loaded_ && error == FILE_ERROR_OK) { - loaded_ = true; - for (auto& observer : observers_) - observer.OnInitialLoadComplete(); - } - - for (auto& callback : pending_load_callback_) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(callback, error)); - } - pending_load_callback_.clear(); - - // If there is pending update check, try to load the change from the server - // again, because there may exist an update during the completed loading. - if (pending_update_check_callback_) { - auto cb = std::move(pending_update_check_callback_); - // TODO(dcheng): Rewrite this to use OnceCallback. Load() currently takes a - // callback by const ref, so std::move() won't do anything. :( - Load(cb); - } -} - -void ChangeListLoader::OnStartPageTokenLoaderUpdated( - google_apis::DriveApiErrorCode error, - std::unique_ptr<google_apis::StartPageToken> start_page_token) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - if (drive::GDataToFileError(error) != drive::FILE_ERROR_OK) { - logger_->Log(logging::LOG_ERROR, - "Failed to update the start page token (%s) (Error: %s)", - team_drive_msg_.c_str(), - google_apis::DriveApiErrorCodeToString(error).c_str()); - return; - } - logger_->Log(logging::LOG_INFO, "Start page token updated (%s) (value: %s)", - team_drive_msg_.c_str(), - start_page_token->start_page_token().c_str()); -} - -void ChangeListLoader::LoadChangeListFromServer( - const std::string& remote_start_page_token, - const std::string& local_start_page_token, - const std::string& root_resource_id) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - if (local_start_page_token == remote_start_page_token) { - // No changes detected, tell the client that the loading was successful. - OnChangeListLoadComplete(FILE_ERROR_OK); - return; - } - - // Set up feed fetcher. - bool is_delta_update = !local_start_page_token.empty(); - if (is_delta_update) { - change_feed_fetcher_ = std::make_unique<DeltaFeedFetcher>( - scheduler_, team_drive_id_, local_start_page_token); - } else { - change_feed_fetcher_ = - std::make_unique<FullFeedFetcher>(scheduler_, team_drive_id_); - } - - change_feed_fetcher_->Run( - base::Bind(&ChangeListLoader::LoadChangeListFromServerAfterLoadChangeList, - weak_ptr_factory_.GetWeakPtr(), remote_start_page_token, - root_resource_id, is_delta_update)); -} - -void ChangeListLoader::LoadChangeListFromServerAfterLoadChangeList( - const std::string& start_page_token, - const std::string& root_resource_id, - bool is_delta_update, - FileError error, - std::vector<std::unique_ptr<ChangeList>> change_lists) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - // Delete the fetcher first. - change_feed_fetcher_.reset(); - - if (error != FILE_ERROR_OK) { - OnChangeListLoadComplete(error); - return; - } - - ChangeListProcessor* change_list_processor = new ChangeListProcessor( - team_drive_id_, root_entry_path_, resource_metadata_, in_shutdown_.get()); - // Don't send directory content change notification while performing - // the initial content retrieval. - const bool should_notify_changed_directories = is_delta_update; - - logger_->Log(logging::LOG_INFO, "Apply change lists (%s) (is delta: %d)", - team_drive_msg_.c_str(), is_delta_update); - loader_controller_->ScheduleRun(base::BindOnce( - &drive::util::RunAsyncTask, base::RetainedRef(blocking_task_runner_), - FROM_HERE, - base::BindOnce(&ChangeListProcessor::ApplyUserChangeList, - base::Unretained(change_list_processor), start_page_token, - root_resource_id, std::move(change_lists), - is_delta_update), - base::BindOnce(&ChangeListLoader::LoadChangeListFromServerAfterUpdate, - weak_ptr_factory_.GetWeakPtr(), - base::Owned(change_list_processor), - should_notify_changed_directories, base::Time::Now()))); -} - -void ChangeListLoader::LoadChangeListFromServerAfterUpdate( - ChangeListProcessor* change_list_processor, - bool should_notify_changed_directories, - base::Time start_time, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - const base::TimeDelta elapsed = base::Time::Now() - start_time; - logger_->Log(logging::LOG_INFO, - "Change lists applied (%s) (elapsed time: %sms)", - team_drive_msg_.c_str(), - base::NumberToString(elapsed.InMilliseconds()).c_str()); - - if (should_notify_changed_directories) { - for (auto& observer : observers_) - observer.OnFileChanged(change_list_processor->changed_files()); - } - - if (!change_list_processor->changed_team_drives().empty()) { - for (auto& observer : observers_) { - observer.OnTeamDrivesChanged( - change_list_processor->changed_team_drives()); - } - } - - OnChangeListLoadComplete(error); - - for (auto& observer : observers_) - observer.OnLoadFromServerComplete(); -} - -} // namespace internal -} // namespace drive
diff --git a/components/drive/chromeos/change_list_loader.h b/components/drive/chromeos/change_list_loader.h deleted file mode 100644 index 1362052d..0000000 --- a/components/drive/chromeos/change_list_loader.h +++ /dev/null
@@ -1,198 +0,0 @@ -// Copyright (c) 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. - -#ifndef COMPONENTS_DRIVE_CHROMEOS_CHANGE_LIST_LOADER_H_ -#define COMPONENTS_DRIVE_CHROMEOS_CHANGE_LIST_LOADER_H_ - -#include <stdint.h> - -#include <memory> -#include <string> -#include <vector> - -#include "base/callback.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/observer_list.h" -#include "base/threading/thread_checker.h" -#include "components/drive/file_errors.h" -#include "google_apis/drive/drive_api_error_codes.h" -#include "google_apis/drive/drive_common_callbacks.h" - -namespace base { -class AtomicFlag; -class SequencedTaskRunner; -class Time; -} // namespace base - -namespace google_apis { -class StartPageToken; -} // namespace google_apis - -namespace drive { - -class EventLogger; -class JobScheduler; - -namespace internal { - -class RootFolderIdLoader; -class ChangeList; -class ChangeListLoaderObserver; -class ChangeListProcessor; -class LoaderController; -class ResourceMetadata; -class StartPageTokenLoader; - -// ChangeListLoader is used to load the change list, the full resource list, -// and directory contents, from Google Drive API. The class also updates the -// resource metadata with the change list loaded from the server. -// -// Note that the difference between "resource list" and "change list" is -// subtle hence the two words are often used interchangeably. To be precise, -// "resource list" refers to metadata from the server when fetching the full -// resource metadata, or fetching directory contents, whereas "change list" -// refers to metadata from the server when fetching changes (delta). -class ChangeListLoader { - public: - // Resource feed fetcher from the server. - class FeedFetcher; - - ChangeListLoader(EventLogger* logger, - base::SequencedTaskRunner* blocking_task_runner, - ResourceMetadata* resource_metadata, - JobScheduler* scheduler, - RootFolderIdLoader* root_folder_id_loader, - StartPageTokenLoader* start_page_token_loader, - LoaderController* apply_task_controller, - const std::string& team_drive_id, - const base::FilePath& root_entry_path); - ~ChangeListLoader(); - - // Indicates whether there is a request for full resource list or change - // list fetching is in flight (i.e. directory contents fetching does not - // count). - bool IsRefreshing() const; - - // Adds and removes the observer. - void AddObserver(ChangeListLoaderObserver* observer); - void RemoveObserver(ChangeListLoaderObserver* observer); - - // Checks for updates on the server. Does nothing if the change list is now - // being loaded or refreshed. |callback| must not be null. - // Note: |callback| will be called if the check for updates actually - // runs, i.e. it may NOT be called if the checking is ignored. - void CheckForUpdates(const FileOperationCallback& callback); - - // Starts the change list loading if needed. If the locally stored metadata is - // available, runs |callback| immediately and starts checking server for - // updates in background. If the locally stored metadata is not available, - // starts loading from the server, and runs |callback| to tell the result to - // the caller when it is finished. - // - // |callback| must not be null. - void LoadIfNeeded(const FileOperationCallback& callback); - - private: - // Starts the resource metadata loading and calls |callback| when it's done. - void Load(const FileOperationCallback& callback); - void LoadAfterGetLocalStartPageToken( - bool is_initial_load, - const std::string* local_start_page_token, - FileError error); - void LoadAfterGetRootFolderId(const std::string& local_start_page_token, - FileError error, - base::Optional<std::string> root_folder_id); - - void LoadAfterGetStartPageToken( - const std::string& local_start_page_token, - const std::string& root_folder_id, - google_apis::DriveApiErrorCode status, - std::unique_ptr<google_apis::StartPageToken> start_page_token); - - // Part of Load(). - // This function should be called when the change list load is complete. - // Flushes the callbacks for change list loading and all directory loading. - void OnChangeListLoadComplete(FileError error); - - // Called when loading the start page token is completed. - void OnStartPageTokenLoaderUpdated( - google_apis::DriveApiErrorCode error, - std::unique_ptr<google_apis::StartPageToken> start_page_token); - - // ================= Implementation for change list loading ================= - - // Part of LoadFromServerIfNeeded(). - // Starts loading the change list since |local_start_page_token|, or the full - // resource list if |local_start_page_token| is empty. If there's no changes - // since then, and there are no new team drives changes to apply from - // team_drives_change_lists, finishes early. - // TODO(sashab): Currently, team_drives_change_lists always contains all of - // the team drives. Update this so team_drives_change_lists is only filled - // when the TD flag is newly turned on or local data cleared. crbug.com/829154 - void LoadChangeListFromServer(const std::string& remote_start_page_token, - const std::string& local_start_page_token, - const std::string& root_resource_id); - - // Part of LoadChangeListFromServer(). - // Called when the entire change list is loaded. - void LoadChangeListFromServerAfterLoadChangeList( - const std::string& start_page_token, - const std::string& root_resource_id, - bool is_delta_update, - FileError error, - std::vector<std::unique_ptr<ChangeList>> change_lists); - - // Part of LoadChangeListFromServer(). - // Called when the resource metadata is updated. - void LoadChangeListFromServerAfterUpdate( - ChangeListProcessor* change_list_processor, - bool should_notify_changed_directories, - base::Time start_time, - FileError error); - - EventLogger* logger_; // Not owned. - scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; - std::unique_ptr<base::AtomicFlag> in_shutdown_; - ResourceMetadata* resource_metadata_; // Not owned. - JobScheduler* scheduler_; // Not owned. - RootFolderIdLoader* root_folder_id_loader_; // Not owned. - StartPageTokenLoader* start_page_token_loader_; // Not owned. - LoaderController* loader_controller_; // Not owned. - base::ObserverList<ChangeListLoaderObserver>::Unchecked observers_; - std::vector<FileOperationCallback> pending_load_callback_; - FileOperationCallback pending_update_check_callback_; - - // Running feed fetcher. - // TODO(slangley): Do not make this stateful by changing the feed_fetcher - // to be base::Owned by the callback. - std::unique_ptr<FeedFetcher> change_feed_fetcher_; - - // True if the full resource list is loaded (i.e. the resource metadata is - // stored locally). - bool loaded_; - - // The team drive id for the changes being loaded by this change list loader. - const std::string team_drive_id_; - - // The formatted team drive id message used for logging. - const std::string team_drive_msg_; - - // The root entry path for changes being loaded by this change list loader. - // Can be a team drive root entry or for the users default corpus will be the - // drive root entry. - const base::FilePath root_entry_path_; - - THREAD_CHECKER(thread_checker_); - - // Note: This should remain the last member so it'll be destroyed and - // invalidate its weak pointers before any other members are destroyed. - base::WeakPtrFactory<ChangeListLoader> weak_ptr_factory_{this}; - DISALLOW_COPY_AND_ASSIGN(ChangeListLoader); -}; - -} // namespace internal -} // namespace drive - -#endif // COMPONENTS_DRIVE_CHROMEOS_CHANGE_LIST_LOADER_H_
diff --git a/components/drive/chromeos/change_list_loader_observer.h b/components/drive/chromeos/change_list_loader_observer.h deleted file mode 100644 index bfbc69e..0000000 --- a/components/drive/chromeos/change_list_loader_observer.h +++ /dev/null
@@ -1,47 +0,0 @@ -// Copyright (c) 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. - -#ifndef COMPONENTS_DRIVE_CHROMEOS_CHANGE_LIST_LOADER_OBSERVER_H_ -#define COMPONENTS_DRIVE_CHROMEOS_CHANGE_LIST_LOADER_OBSERVER_H_ - -namespace base { -class FilePath; -} // namespace base - -namespace drive { -class FileChange; -namespace internal { - -// Interface for classes that need to observe events from ChangeListLoader. -// All events are notified on UI thread. -class ChangeListLoaderObserver { - public: - // Triggered when the content of a directory is reloaded. The content may - // changed. |directory_path| is a virtual directory path representing the - // reloaded directory. - virtual void OnDirectoryReloaded(const base::FilePath& directory_path) {} - - // Triggered when content(s) in drive has been changed. - virtual void OnFileChanged(const FileChange& changed_files) {} - - // Triggered when the users accessible team drives has changed. - virtual void OnTeamDrivesChanged(const FileChange& changed_team_drives) {} - - // Triggered when loading from the server is complete. - virtual void OnLoadFromServerComplete() {} - - // Triggered when loading is complete for the first time, either from the - // the server or the cache. To be precise, for the latter case, we do not - // load anything from the cache. We just check that the resource metadata - // is stored locally thus can be used. - virtual void OnInitialLoadComplete() {} - - protected: - virtual ~ChangeListLoaderObserver() = default; -}; - -} // namespace internal -} // namespace drive - -#endif // COMPONENTS_DRIVE_CHROMEOS_CHANGE_LIST_LOADER_OBSERVER_H_
diff --git a/components/drive/chromeos/default_corpus_change_list_loader.cc b/components/drive/chromeos/default_corpus_change_list_loader.cc deleted file mode 100644 index 79b10320..0000000 --- a/components/drive/chromeos/default_corpus_change_list_loader.cc +++ /dev/null
@@ -1,131 +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 "components/drive/chromeos/default_corpus_change_list_loader.h" - -#include <memory> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/time/clock.h" -#include "components/drive/chromeos/about_resource_root_folder_id_loader.h" -#include "components/drive/file_system_core_util.h" - -namespace drive { -namespace internal { - -DefaultCorpusChangeListLoader::DefaultCorpusChangeListLoader( - EventLogger* logger, - base::SequencedTaskRunner* blocking_task_runner, - ResourceMetadata* resource_metadata, - JobScheduler* scheduler, - AboutResourceLoader* about_resource_loader, - LoaderController* apply_task_controller, - const base::Clock* clock) - : logger_(logger), - blocking_task_runner_(blocking_task_runner), - resource_metadata_(resource_metadata), - scheduler_(scheduler), - loader_controller_(apply_task_controller) { - DCHECK(clock); - - root_folder_id_loader_ = - std::make_unique<AboutResourceRootFolderIdLoader>(about_resource_loader); - - start_page_token_loader_ = std::make_unique<StartPageTokenLoader>( - util::kTeamDriveIdDefaultCorpus, scheduler_); - - change_list_loader_ = std::make_unique<ChangeListLoader>( - logger_, blocking_task_runner_.get(), resource_metadata_, scheduler_, - root_folder_id_loader_.get(), start_page_token_loader_.get(), - loader_controller_, util::kTeamDriveIdDefaultCorpus, - util::GetDriveMyDriveRootPath()); - - directory_loader_ = std::make_unique<DirectoryLoader>( - logger_, blocking_task_runner_.get(), resource_metadata_, scheduler_, - root_folder_id_loader_.get(), start_page_token_loader_.get(), - loader_controller_, util::GetDriveMyDriveRootPath(), - util::kTeamDriveIdDefaultCorpus, clock); - - team_drive_list_loader_ = std::make_unique<TeamDriveListLoader>( - logger_, blocking_task_runner_.get(), resource_metadata, scheduler_, - loader_controller_); -} - -DefaultCorpusChangeListLoader::~DefaultCorpusChangeListLoader() = default; - -void DefaultCorpusChangeListLoader::AddChangeListLoaderObserver( - ChangeListLoaderObserver* observer) { - change_list_loader_->AddObserver(observer); - directory_loader_->AddObserver(observer); -} - -void DefaultCorpusChangeListLoader::RemoveChangeListLoaderObserver( - ChangeListLoaderObserver* observer) { - change_list_loader_->RemoveObserver(observer); - directory_loader_->RemoveObserver(observer); -} - -void DefaultCorpusChangeListLoader::AddTeamDriveListObserver( - TeamDriveListObserver* observer) { - team_drive_list_loader_->AddObserver(observer); -} - -void DefaultCorpusChangeListLoader::RemoveTeamDriveListObserver( - TeamDriveListObserver* observer) { - team_drive_list_loader_->RemoveObserver(observer); -} - -bool DefaultCorpusChangeListLoader::IsRefreshing() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - return team_drive_list_loader_->IsRefreshing() || - change_list_loader_->IsRefreshing(); -} - -void DefaultCorpusChangeListLoader::LoadIfNeeded( - const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - // We execute the change list loader and then the team drive loader when it - // is completed. If the change list loader detects that it has previously - // loaded from the server, then it is a no-op. If it is a fresh load then it - // uses GetAllFiles which does not read any change lists with team drive info. - change_list_loader_->LoadIfNeeded(base::BindRepeating( - &DefaultCorpusChangeListLoader::OnChangeListLoadIfNeeded, - weak_ptr_factory_.GetWeakPtr(), callback)); -} - -void DefaultCorpusChangeListLoader::OnChangeListLoadIfNeeded( - const FileOperationCallback& callback, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - if (error != FILE_ERROR_OK) { - callback.Run(error); - return; - } - - team_drive_list_loader_->LoadIfNeeded(callback); -} - -void DefaultCorpusChangeListLoader::ReadDirectory( - const base::FilePath& directory_path, - ReadDirectoryEntriesCallback entries_callback, - const FileOperationCallback& completion_callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - directory_loader_->ReadDirectory(directory_path, std::move(entries_callback), - completion_callback); - - // Also start loading all of the user's contents. - LoadIfNeeded(base::DoNothing()); -} - -void DefaultCorpusChangeListLoader::CheckForUpdates( - const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - change_list_loader_->CheckForUpdates(callback); -} - -} // namespace internal -} // namespace drive
diff --git a/components/drive/chromeos/default_corpus_change_list_loader.h b/components/drive/chromeos/default_corpus_change_list_loader.h deleted file mode 100644 index 6bc15c9..0000000 --- a/components/drive/chromeos/default_corpus_change_list_loader.h +++ /dev/null
@@ -1,90 +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 COMPONENTS_DRIVE_CHROMEOS_DEFAULT_CORPUS_CHANGE_LIST_LOADER_H_ -#define COMPONENTS_DRIVE_CHROMEOS_DEFAULT_CORPUS_CHANGE_LIST_LOADER_H_ - -#include <memory> - -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "base/time/default_clock.h" -#include "components/drive/chromeos/about_resource_root_folder_id_loader.h" -#include "components/drive/chromeos/change_list_loader.h" -#include "components/drive/chromeos/directory_loader.h" -#include "components/drive/chromeos/drive_change_list_loader.h" -#include "components/drive/chromeos/start_page_token_loader.h" -#include "components/drive/chromeos/team_drive_list_loader.h" - -namespace drive { - -class EventLogger; -class JobScheduler; - -namespace internal { - -class AboutResourceLoader; -class ChangeListLoader; -class DirectoryLoader; -class LoaderController; -class ResourceMetadata; - -// Loads change lists, the full resource list, and directory contents for the -// users default corpus. -class DefaultCorpusChangeListLoader : public DriveChangeListLoader { - public: - // |clock| can be mocked for testing. - DefaultCorpusChangeListLoader( - EventLogger* logger, - base::SequencedTaskRunner* blocking_task_runner, - ResourceMetadata* resource_metadata, - JobScheduler* scheduler, - AboutResourceLoader* about_resource_loader, - LoaderController* apply_task_controller, - const base::Clock* clock = base::DefaultClock::GetInstance()); - - ~DefaultCorpusChangeListLoader() override; - - // DriveChangeListLoader overrides - void AddChangeListLoaderObserver(ChangeListLoaderObserver* observer) override; - void RemoveChangeListLoaderObserver( - ChangeListLoaderObserver* observer) override; - void AddTeamDriveListObserver(TeamDriveListObserver* observer) override; - void RemoveTeamDriveListObserver(TeamDriveListObserver* observer) override; - - bool IsRefreshing() override; - void LoadIfNeeded(const FileOperationCallback& callback) override; - void ReadDirectory(const base::FilePath& directory_path, - ReadDirectoryEntriesCallback entries_callback, - const FileOperationCallback& completion_callback) override; - void CheckForUpdates(const FileOperationCallback& callback) override; - - private: - // Called after calling LoadIfNeeded on team drives. - void OnChangeListLoadIfNeeded(const FileOperationCallback& callback, - FileError error); - - std::unique_ptr<internal::AboutResourceRootFolderIdLoader> - root_folder_id_loader_; - std::unique_ptr<internal::ChangeListLoader> change_list_loader_; - std::unique_ptr<internal::DirectoryLoader> directory_loader_; - std::unique_ptr<internal::StartPageTokenLoader> start_page_token_loader_; - std::unique_ptr<TeamDriveListLoader> team_drive_list_loader_; - - EventLogger* logger_; // Not owned. - scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; - ResourceMetadata* resource_metadata_; // Not owned. - JobScheduler* scheduler_; // Not owned. - LoaderController* loader_controller_; // Not owned. - - THREAD_CHECKER(thread_checker_); - - base::WeakPtrFactory<DefaultCorpusChangeListLoader> weak_ptr_factory_{this}; - DISALLOW_COPY_AND_ASSIGN(DefaultCorpusChangeListLoader); -}; - -} // namespace internal -} // namespace drive - -#endif // COMPONENTS_DRIVE_CHROMEOS_DEFAULT_CORPUS_CHANGE_LIST_LOADER_H_
diff --git a/components/drive/chromeos/directory_loader.cc b/components/drive/chromeos/directory_loader.cc deleted file mode 100644 index 383624624..0000000 --- a/components/drive/chromeos/directory_loader.cc +++ /dev/null
@@ -1,656 +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 "components/drive/chromeos/directory_loader.h" - -#include <stddef.h> - -#include <utility> - -#include "base/bind.h" -#include "base/callback.h" -#include "base/callback_helpers.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/metrics/histogram_macros.h" -#include "base/strings/string_number_conversions.h" -#include "base/time/clock.h" -#include "base/time/time.h" -#include "components/drive/chromeos/change_list_loader_observer.h" -#include "components/drive/chromeos/change_list_processor.h" -#include "components/drive/chromeos/drive_file_util.h" -#include "components/drive/chromeos/loader_controller.h" -#include "components/drive/chromeos/resource_metadata.h" -#include "components/drive/chromeos/root_folder_id_loader.h" -#include "components/drive/chromeos/start_page_token_loader.h" -#include "components/drive/drive_api_util.h" -#include "components/drive/event_logger.h" -#include "components/drive/file_system_core_util.h" -#include "components/drive/job_scheduler.h" -#include "google_apis/drive/drive_api_parser.h" -#include "url/gurl.h" - -namespace drive { -namespace internal { - -namespace { - -// Minimum changestamp gap required to start loading directory. -constexpr int kMinimumChangestampGap = 50; - -constexpr base::TimeDelta kMinimumPerDirectoryFetchTimeGap = - base::TimeDelta::FromSeconds(30); - -FileError CheckLocalState(ResourceMetadata* resource_metadata, - const base::FilePath& root_entry_path, - const std::string& team_drive_id, - const std::string& root_folder_id, - const std::string& local_id, - ResourceEntry* entry, - std::string* start_page_token) { - DCHECK(start_page_token); - // Fill My Drive resource ID. - ResourceEntry mydrive; - FileError error = - resource_metadata->GetResourceEntryByPath(root_entry_path, &mydrive); - if (error != FILE_ERROR_OK) - return error; - - if (mydrive.resource_id().empty()) { - mydrive.set_resource_id(root_folder_id); - error = resource_metadata->RefreshEntry(mydrive); - if (error != FILE_ERROR_OK) - return error; - } - - // Get entry. - error = resource_metadata->GetResourceEntryById(local_id, entry); - if (error != FILE_ERROR_OK) - return error; - - // Get the local start page token.. - return GetStartPageToken(resource_metadata, team_drive_id, start_page_token); -} - -FileError UpdateStartPageToken(ResourceMetadata* resource_metadata, - const DirectoryFetchInfo& directory_fetch_info, - base::FilePath* directory_path, - const base::Clock* clock) { - DCHECK(clock); - // Update the directory start page token. - ResourceEntry directory; - FileError error = resource_metadata->GetResourceEntryById( - directory_fetch_info.local_id(), &directory); - if (error != FILE_ERROR_OK) - return error; - - if (!directory.file_info().is_directory()) - return FILE_ERROR_NOT_A_DIRECTORY; - - DirectorySpecificInfo* directory_specific_info = - directory.mutable_directory_specific_info(); - - directory_specific_info->set_start_page_token( - directory_fetch_info.start_page_token()); - directory_specific_info->set_last_read_time_ms( - clock->Now().ToDeltaSinceWindowsEpoch().InMilliseconds()); - - error = resource_metadata->RefreshEntry(directory); - if (error != FILE_ERROR_OK) - return error; - - // Get the directory path. - return resource_metadata->GetFilePath(directory_fetch_info.local_id(), - directory_path); -} - -} // namespace - -struct DirectoryLoader::ReadDirectoryCallbackState { - explicit ReadDirectoryCallbackState( - ReadDirectoryEntriesCallback entries_callback) - : entries_callback(std::move(entries_callback)) {} - - ReadDirectoryEntriesCallback entries_callback; - FileOperationCallback completion_callback; - std::set<std::string> sent_entry_names; -}; - -// Fetches the resource entries in the directory with |directory_resource_id|. -class DirectoryLoader::FeedFetcher { - public: - FeedFetcher(DirectoryLoader* loader, - const DirectoryFetchInfo& directory_fetch_info, - const std::string& root_folder_id) - : loader_(loader), - directory_fetch_info_(directory_fetch_info), - root_folder_id_(root_folder_id) {} - - ~FeedFetcher() = default; - - void Run(const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - DCHECK(!directory_fetch_info_.resource_id().empty()); - - // Remember the time stamp for usage stats. - start_time_ = base::TimeTicks::Now(); - - loader_->scheduler_->GetFileListInDirectory( - directory_fetch_info_.resource_id(), - base::Bind(&FeedFetcher::OnFileListFetched, - weak_ptr_factory_.GetWeakPtr(), callback)); - } - - private: - void OnFileListFetched(const FileOperationCallback& callback, - google_apis::DriveApiErrorCode status, - std::unique_ptr<google_apis::FileList> file_list) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - FileError error = GDataToFileError(status); - if (error != FILE_ERROR_OK) { - callback.Run(error); - return; - } - - DCHECK(file_list); - std::unique_ptr<ChangeList> change_list(new ChangeList(*file_list)); - GURL next_url = file_list->next_link(); - - ResourceEntryVector* entries = new ResourceEntryVector; - loader_->loader_controller_->ScheduleRun(base::BindOnce( - &drive::util::RunAsyncTask, - base::RetainedRef(loader_->blocking_task_runner_), FROM_HERE, - base::BindOnce(&ChangeListProcessor::RefreshDirectory, - loader_->resource_metadata_, directory_fetch_info_, - std::move(change_list), entries), - base::BindOnce(&FeedFetcher::OnDirectoryRefreshed, - weak_ptr_factory_.GetWeakPtr(), callback, next_url, - base::Owned(entries)))); - } - - void OnDirectoryRefreshed( - const FileOperationCallback& callback, - const GURL& next_url, - const std::vector<ResourceEntry>* refreshed_entries, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - if (error != FILE_ERROR_OK) { - callback.Run(error); - return; - } - - loader_->SendEntries(directory_fetch_info_.local_id(), *refreshed_entries); - - if (!next_url.is_empty()) { - // There is the remaining result so fetch it. - loader_->scheduler_->GetRemainingFileList( - next_url, - base::Bind(&FeedFetcher::OnFileListFetched, - weak_ptr_factory_.GetWeakPtr(), callback)); - return; - } - - base::TimeDelta duration = base::TimeTicks::Now() - start_time_; - if (util::IsTeamDrivesPath(directory_fetch_info_.root_entry_path())) { - UMA_HISTOGRAM_TIMES("Drive.DirectoryFeedLoadTime.TeamDrives", duration); - } else { - UMA_HISTOGRAM_TIMES("Drive.DirectoryFeedLoadTime", duration); - } - - // Note: The fetcher is managed by DirectoryLoader, and the instance - // will be deleted in the callback. Do not touch the fields after this - // invocation. - callback.Run(FILE_ERROR_OK); - } - - DirectoryLoader* loader_; - DirectoryFetchInfo directory_fetch_info_; - std::string root_folder_id_; - base::TimeTicks start_time_; - THREAD_CHECKER(thread_checker_); - base::WeakPtrFactory<FeedFetcher> weak_ptr_factory_{this}; - DISALLOW_COPY_AND_ASSIGN(FeedFetcher); -}; - -DirectoryLoader::DirectoryLoader( - EventLogger* logger, - base::SequencedTaskRunner* blocking_task_runner, - ResourceMetadata* resource_metadata, - JobScheduler* scheduler, - RootFolderIdLoader* root_folder_id_loader, - StartPageTokenLoader* start_page_token_loader, - LoaderController* loader_controller, - const base::FilePath& root_entry_path, - const std::string& team_drive_id, - const base::Clock* clock) - : logger_(logger), - blocking_task_runner_(blocking_task_runner), - resource_metadata_(resource_metadata), - scheduler_(scheduler), - root_folder_id_loader_(root_folder_id_loader), - start_page_token_loader_(start_page_token_loader), - loader_controller_(loader_controller), - root_entry_path_(root_entry_path), - team_drive_id_(team_drive_id), - clock_(clock) {} - -DirectoryLoader::~DirectoryLoader() = default; - -void DirectoryLoader::AddObserver(ChangeListLoaderObserver* observer) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - observers_.AddObserver(observer); -} - -void DirectoryLoader::RemoveObserver(ChangeListLoaderObserver* observer) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - observers_.RemoveObserver(observer); -} - -void DirectoryLoader::ReadDirectory( - const base::FilePath& directory_path, - ReadDirectoryEntriesCallback entries_callback, - const FileOperationCallback& completion_callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(completion_callback); - - ResourceEntry* entry = new ResourceEntry; - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), FROM_HERE, - base::Bind(&ResourceMetadata::GetResourceEntryByPath, - base::Unretained(resource_metadata_), directory_path, entry), - base::Bind(&DirectoryLoader::ReadDirectoryAfterGetEntry, - weak_ptr_factory_.GetWeakPtr(), directory_path, - base::Passed(std::move(entries_callback)), completion_callback, - true, // should_try_loading_parent - base::Owned(entry))); -} - -void DirectoryLoader::ReadDirectoryAfterGetEntry( - const base::FilePath& directory_path, - ReadDirectoryEntriesCallback entries_callback, - const FileOperationCallback& completion_callback, - bool should_try_loading_parent, - const ResourceEntry* entry, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(completion_callback); - - if (error == FILE_ERROR_NOT_FOUND && - should_try_loading_parent && - util::GetDriveGrandRootPath().IsParent(directory_path)) { - // This entry may be found after loading the parent. - ReadDirectory(directory_path.DirName(), ReadDirectoryEntriesCallback(), - base::Bind(&DirectoryLoader::ReadDirectoryAfterLoadParent, - weak_ptr_factory_.GetWeakPtr(), directory_path, - base::Passed(std::move(entries_callback)), - completion_callback)); - return; - } - if (error != FILE_ERROR_OK) { - completion_callback.Run(error); - return; - } - - if (!entry->file_info().is_directory()) { - completion_callback.Run(FILE_ERROR_NOT_A_DIRECTORY); - return; - } - - DirectoryFetchInfo directory_fetch_info( - entry->local_id(), entry->resource_id(), - entry->directory_specific_info().start_page_token(), root_entry_path_, - directory_path); - - // Register the callback function to be called when it is loaded. - const std::string& local_id = directory_fetch_info.local_id(); - ReadDirectoryCallbackState callback_state(std::move(entries_callback)); - callback_state.completion_callback = completion_callback; - pending_load_callback_[local_id].emplace_back(std::move(callback_state)); - - // If loading task for |local_id| is already running, do nothing. - if (pending_load_callback_[local_id].size() > 1) - return; - - root_folder_id_loader_->GetRootFolderId( - base::Bind(&DirectoryLoader::ReadDirectoryAfterGetRootFolderId, - weak_ptr_factory_.GetWeakPtr(), directory_path, local_id)); -} - -void DirectoryLoader::ReadDirectoryAfterLoadParent( - const base::FilePath& directory_path, - ReadDirectoryEntriesCallback entries_callback, - const FileOperationCallback& completion_callback, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(completion_callback); - - if (error != FILE_ERROR_OK) { - completion_callback.Run(error); - return; - } - - ResourceEntry* entry = new ResourceEntry; - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), FROM_HERE, - base::Bind(&ResourceMetadata::GetResourceEntryByPath, - base::Unretained(resource_metadata_), directory_path, entry), - base::Bind(&DirectoryLoader::ReadDirectoryAfterGetEntry, - weak_ptr_factory_.GetWeakPtr(), directory_path, - base::Passed(std::move(entries_callback)), completion_callback, - false, // should_try_loading_parent - base::Owned(entry))); -} - -void DirectoryLoader::ReadDirectoryAfterGetRootFolderId( - const base::FilePath& directory_path, - const std::string& local_id, - FileError error, - base::Optional<std::string> root_folder_id) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - if (error != FILE_ERROR_OK) { - OnDirectoryLoadComplete(local_id, error); - return; - } - - DCHECK(root_folder_id); - - start_page_token_loader_->GetStartPageToken( - base::Bind(&DirectoryLoader::ReadDirectoryAfterGetStartPageToken, - weak_ptr_factory_.GetWeakPtr(), directory_path, local_id, - root_folder_id.value())); -} - -void DirectoryLoader::ReadDirectoryAfterGetStartPageToken( - const base::FilePath& directory_path, - const std::string& local_id, - const std::string& root_folder_id, - google_apis::DriveApiErrorCode status, - std::unique_ptr<google_apis::StartPageToken> start_page_token) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - FileError error = GDataToFileError(status); - if (error != FILE_ERROR_OK) { - OnDirectoryLoadComplete(local_id, error); - return; - } - - DCHECK(start_page_token); - - // Check the current status of local metadata, and start loading if needed. - ResourceEntry* entry = new ResourceEntry; - std::string* local_start_page_token = new std::string(); - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), FROM_HERE, - base::BindOnce(&CheckLocalState, resource_metadata_, root_entry_path_, - team_drive_id_, root_folder_id, local_id, entry, - local_start_page_token), - base::BindOnce(&DirectoryLoader::ReadDirectoryAfterCheckLocalState, - weak_ptr_factory_.GetWeakPtr(), directory_path, - start_page_token->start_page_token(), local_id, - root_folder_id, base::Owned(entry), - base::Owned(local_start_page_token))); -} - -void DirectoryLoader::ReadDirectoryAfterCheckLocalState( - const base::FilePath& directory_path, - const std::string& remote_start_page_token, - const std::string& local_id, - const std::string& root_folder_id, - const ResourceEntry* entry, - const std::string* local_start_page_token, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(local_start_page_token); - - if (error != FILE_ERROR_OK) { - OnDirectoryLoadComplete(local_id, error); - return; - } - // This entry does not exist on the server. - if (entry->resource_id().empty()) { - OnDirectoryLoadComplete(local_id, FILE_ERROR_OK); - return; - } - - // Start loading the directory. - const std::string& directory_start_page_token = - entry->directory_specific_info().start_page_token(); - - DirectoryFetchInfo directory_fetch_info(local_id, entry->resource_id(), - remote_start_page_token, - root_entry_path_, directory_path); - - int64_t directory_changestamp = 0; - // The directory_specific_info may be enpty, so default changestamp to 0. - if (!directory_start_page_token.empty() && - !drive::util::ConvertStartPageTokenToChangestamp( - directory_start_page_token, &directory_changestamp)) { - logger_->Log( - logging::LOG_ERROR, - "Unable to convert directory start page tokens to changestamps, will " - "load directory from server %s; directory start page token: %s ", - directory_fetch_info.ToString().c_str(), - directory_start_page_token.c_str()); - LoadDirectoryFromServer(directory_fetch_info, root_folder_id); - return; - } - - // If we haven't finished loading the drive corpus, local_start_page_token - // will be empty. In this case we will keep track of the last time we loaded - // the directory, and only reload after an appropriate delay. - if (local_start_page_token->empty()) { - if (entry->directory_specific_info().has_last_read_time_ms()) { - base::Time last_read = base::Time::FromDeltaSinceWindowsEpoch( - base::TimeDelta::FromMilliseconds( - entry->directory_specific_info().last_read_time_ms())); - base::TimeDelta elapsed = clock_->Now() - last_read; - if (elapsed < kMinimumPerDirectoryFetchTimeGap) { - logger_->Log( - logging::LOG_INFO, - "Skipping read of directory (%s), contents considered fresh.", - directory_fetch_info.ToString().c_str()); - OnDirectoryLoadComplete(local_id, FILE_ERROR_OK); - return; - } - } - } - - int64_t remote_changestamp = 0; - int64_t local_changestamp = 0; - if (!drive::util::ConvertStartPageTokenToChangestamp(remote_start_page_token, - &remote_changestamp) || - !drive::util::ConvertStartPageTokenToChangestamp(*local_start_page_token, - &local_changestamp)) { - logger_->Log( - logging::LOG_ERROR, - "Unable to convert start page tokens to changestamps, will load " - "directory from server %s; local start page token: %s; " - "remote start page token: %s", - directory_fetch_info.ToString().c_str(), - local_start_page_token->c_str(), remote_start_page_token.c_str()); - LoadDirectoryFromServer(directory_fetch_info, root_folder_id); - return; - } - - // Start loading the directory. - directory_changestamp = std::max(directory_changestamp, local_changestamp); - - // If the directory's changestamp is up to date or the global changestamp or - // the metadata DB is new enough (which means the normal changelist loading - // should finish very soon), just schedule to run the callback, as there is no - // need to fetch the directory. - if (directory_changestamp >= remote_changestamp || - local_changestamp + kMinimumChangestampGap > remote_changestamp) { - OnDirectoryLoadComplete(local_id, FILE_ERROR_OK); - } else { - // Start fetching the directory content, and mark it with the changestamp - // |remote_changestamp|. - LoadDirectoryFromServer(directory_fetch_info, root_folder_id); - } -} - -void DirectoryLoader::OnDirectoryLoadComplete(const std::string& local_id, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - LoadCallbackMap::iterator it = pending_load_callback_.find(local_id); - if (it == pending_load_callback_.end()) - return; - - // No need to read metadata when no one needs entries. - bool needs_to_send_entries = false; - for (size_t i = 0; i < it->second.size(); ++i) { - const ReadDirectoryCallbackState& callback_state = it->second[i]; - if (callback_state.entries_callback) - needs_to_send_entries = true; - } - - if (!needs_to_send_entries) { - OnDirectoryLoadCompleteAfterRead(local_id, nullptr, FILE_ERROR_OK); - return; - } - - ResourceEntryVector* entries = new ResourceEntryVector; - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), - FROM_HERE, - base::Bind(&ResourceMetadata::ReadDirectoryById, - base::Unretained(resource_metadata_), local_id, entries), - base::Bind(&DirectoryLoader::OnDirectoryLoadCompleteAfterRead, - weak_ptr_factory_.GetWeakPtr(), - local_id, - base::Owned(entries))); -} - -void DirectoryLoader::OnDirectoryLoadCompleteAfterRead( - const std::string& local_id, - const ResourceEntryVector* entries, - FileError error) { - LoadCallbackMap::iterator it = pending_load_callback_.find(local_id); - if (it != pending_load_callback_.end()) { - DVLOG(1) << "Running callback for " << local_id; - - if (error == FILE_ERROR_OK && entries) - SendEntries(local_id, *entries); - - for (size_t i = 0; i < it->second.size(); ++i) { - const ReadDirectoryCallbackState& callback_state = it->second[i]; - callback_state.completion_callback.Run(error); - } - pending_load_callback_.erase(it); - } -} - -void DirectoryLoader::SendEntries(const std::string& local_id, - const ResourceEntryVector& entries) { - LoadCallbackMap::iterator it = pending_load_callback_.find(local_id); - DCHECK(it != pending_load_callback_.end()) << "local_id: " << local_id; - - for (size_t i = 0; i < it->second.size(); ++i) { - ReadDirectoryCallbackState* callback_state = &it->second[i]; - if (!callback_state->entries_callback) - continue; - - // Filter out entries which were already sent. - std::unique_ptr<ResourceEntryVector> entries_to_send( - new ResourceEntryVector); - for (size_t i = 0; i < entries.size(); ++i) { - const ResourceEntry& entry = entries[i]; - if (!callback_state->sent_entry_names.count(entry.base_name())) { - callback_state->sent_entry_names.insert(entry.base_name()); - entries_to_send->push_back(entry); - } - } - std::move(callback_state->entries_callback).Run(std::move(entries_to_send)); - } -} - -void DirectoryLoader::LoadDirectoryFromServer( - const DirectoryFetchInfo& directory_fetch_info, - const std::string& root_folder_id) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(!directory_fetch_info.empty()); - DVLOG(1) << "Start loading directory: " << directory_fetch_info.ToString(); - - const google_apis::StartPageToken* start_page_token = - start_page_token_loader_->cached_start_page_token(); - DCHECK(start_page_token); - - logger_->Log(logging::LOG_INFO, - "Fast-fetch start: %s; Server start page token: %s", - directory_fetch_info.ToString().c_str(), - start_page_token->start_page_token().c_str()); - - FeedFetcher* fetcher = - new FeedFetcher(this, directory_fetch_info, root_folder_id); - - fast_fetch_feed_fetcher_set_.insert(base::WrapUnique(fetcher)); - fetcher->Run( - base::Bind(&DirectoryLoader::LoadDirectoryFromServerAfterLoad, - weak_ptr_factory_.GetWeakPtr(), - directory_fetch_info, - fetcher)); -} - -void DirectoryLoader::LoadDirectoryFromServerAfterLoad( - const DirectoryFetchInfo& directory_fetch_info, - FeedFetcher* fetcher, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(!directory_fetch_info.empty()); - - // Delete the fetcher. - auto it = fast_fetch_feed_fetcher_set_.find(fetcher); - fast_fetch_feed_fetcher_set_.erase(it); - - logger_->Log(logging::LOG_INFO, - "Fast-fetch complete: %s => %s", - directory_fetch_info.ToString().c_str(), - FileErrorToString(error).c_str()); - - if (error != FILE_ERROR_OK) { - LOG(ERROR) << "Failed to load directory: " - << directory_fetch_info.local_id() - << ": " << FileErrorToString(error); - OnDirectoryLoadComplete(directory_fetch_info.local_id(), error); - return; - } - - // Update start page token and get the directory path. - base::FilePath* directory_path = new base::FilePath; - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), FROM_HERE, - base::Bind(&UpdateStartPageToken, resource_metadata_, - directory_fetch_info, directory_path, - base::Unretained(clock_)), - base::Bind( - &DirectoryLoader::LoadDirectoryFromServerAfterUpdateStartPageToken, - weak_ptr_factory_.GetWeakPtr(), directory_fetch_info, - base::Owned(directory_path))); -} - -void DirectoryLoader::LoadDirectoryFromServerAfterUpdateStartPageToken( - const DirectoryFetchInfo& directory_fetch_info, - const base::FilePath* directory_path, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - DVLOG(1) << "Directory loaded: " << directory_fetch_info.ToString(); - OnDirectoryLoadComplete(directory_fetch_info.local_id(), error); - - // Also notify the observers. - if (error == FILE_ERROR_OK && !directory_path->empty()) { - for (auto& observer : observers_) - observer.OnDirectoryReloaded(*directory_path); - } -} - -} // namespace internal -} // namespace drive
diff --git a/components/drive/chromeos/directory_loader.h b/components/drive/chromeos/directory_loader.h deleted file mode 100644 index 744cd84..0000000 --- a/components/drive/chromeos/directory_loader.h +++ /dev/null
@@ -1,181 +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 COMPONENTS_DRIVE_CHROMEOS_DIRECTORY_LOADER_H_ -#define COMPONENTS_DRIVE_CHROMEOS_DIRECTORY_LOADER_H_ - -#include <stdint.h> - -#include <map> -#include <memory> -#include <set> -#include <string> -#include <vector> - -#include "base/callback.h" -#include "base/containers/unique_ptr_adapters.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/observer_list.h" -#include "base/threading/thread_checker.h" -#include "base/time/default_clock.h" -#include "components/drive/chromeos/file_system_interface.h" -#include "components/drive/file_errors.h" -#include "google_apis/drive/drive_api_error_codes.h" -#include "google_apis/drive/drive_common_callbacks.h" - -namespace base { -class Clock; -class SequencedTaskRunner; -} // namespace base - -namespace drive { - -class EventLogger; -class JobScheduler; -class ResourceEntry; - -namespace internal { - -class RootFolderIdLoader; -class ChangeListLoaderObserver; -class DirectoryFetchInfo; -class LoaderController; -class ResourceMetadata; -class StartPageTokenLoader; - -// DirectoryLoader is used to load directory contents. -class DirectoryLoader { - public: - // |clock| can be mocked for testing - DirectoryLoader(EventLogger* logger, - base::SequencedTaskRunner* blocking_task_runner, - ResourceMetadata* resource_metadata, - JobScheduler* scheduler, - RootFolderIdLoader* root_folder_id_loader, - StartPageTokenLoader* start_page_token_loader, - LoaderController* apply_task_controller, - const base::FilePath& root_entry_path, - const std::string& team_drive_id, - const base::Clock* clock = base::DefaultClock::GetInstance()); - ~DirectoryLoader(); - - // Adds and removes the observer. - void AddObserver(ChangeListLoaderObserver* observer); - void RemoveObserver(ChangeListLoaderObserver* observer); - - // Reads the directory contents. - // |entries_callback| can be null. - // |completion_callback| must not be null. - void ReadDirectory(const base::FilePath& directory_path, - ReadDirectoryEntriesCallback entries_callback, - const FileOperationCallback& completion_callback); - - private: - class FeedFetcher; - struct ReadDirectoryCallbackState; - - // Part of ReadDirectory(). - void ReadDirectoryAfterGetEntry( - const base::FilePath& directory_path, - ReadDirectoryEntriesCallback entries_callback, - const FileOperationCallback& completion_callback, - bool should_try_loading_parent, - const ResourceEntry* entry, - FileError error); - void ReadDirectoryAfterLoadParent( - const base::FilePath& directory_path, - ReadDirectoryEntriesCallback entries_callback, - const FileOperationCallback& completion_callback, - FileError error); - void ReadDirectoryAfterGetRootFolderId( - const base::FilePath& directory_path, - const std::string& local_id, - FileError error, - base::Optional<std::string> root_folder_id); - void ReadDirectoryAfterGetStartPageToken( - const base::FilePath& directory_path, - const std::string& local_id, - const std::string& root_folder_id, - google_apis::DriveApiErrorCode status, - std::unique_ptr<google_apis::StartPageToken> start_page_token); - - void ReadDirectoryAfterCheckLocalState( - const base::FilePath& directory_path, - const std::string& remote_start_page_token, - const std::string& local_id, - const std::string& root_folder_id, - const ResourceEntry* entry, - const std::string* local_start_page_token, - FileError error); - - // Part of ReadDirectory(). - // This function should be called when the directory load is complete. - // Flushes the callbacks waiting for the directory to be loaded. - void OnDirectoryLoadComplete(const std::string& local_id, FileError error); - void OnDirectoryLoadCompleteAfterRead(const std::string& local_id, - const ResourceEntryVector* entries, - FileError error); - - // Sends |entries| to the callbacks. - void SendEntries(const std::string& local_id, - const ResourceEntryVector& entries); - - // ================= Implementation for directory loading ================= - // Loads the directory contents from server, and updates the local metadata. - // Runs |callback| when it is finished. - void LoadDirectoryFromServer(const DirectoryFetchInfo& directory_fetch_info, - const std::string& root_folder_id); - - // Part of LoadDirectoryFromServer() for a normal directory. - void LoadDirectoryFromServerAfterLoad( - const DirectoryFetchInfo& directory_fetch_info, - FeedFetcher* fetcher, - FileError error); - - // Part of LoadDirectoryFromServer(). - void LoadDirectoryFromServerAfterUpdateStartPageToken( - const DirectoryFetchInfo& directory_fetch_info, - const base::FilePath* directory_path, - FileError error); - - EventLogger* logger_; // Not owned. - scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; - ResourceMetadata* resource_metadata_; // Not owned. - JobScheduler* scheduler_; // Not owned. - RootFolderIdLoader* root_folder_id_loader_; // Not owned. - StartPageTokenLoader* start_page_token_loader_; // Not owned - LoaderController* loader_controller_; // Not owned. - base::ObserverList<ChangeListLoaderObserver>::Unchecked observers_; - typedef std::map<std::string, std::vector<ReadDirectoryCallbackState> > - LoadCallbackMap; - LoadCallbackMap pending_load_callback_; - - // Set of the running feed fetcher for the fast fetch. - std::set<std::unique_ptr<FeedFetcher>, base::UniquePtrComparator> - fast_fetch_feed_fetcher_set_; - - // The root entry path for changes being loaded by this directory loader. - // Can be a team drive root entry or for the users default corpus will be the - // drive root entry. - const base::FilePath root_entry_path_; - - // The team drive id for this directory loader. Used to retrieve the start - // page token when performing a fast fetch. - const std::string team_drive_id_; - - const base::Clock* clock_; // Not Owned - - THREAD_CHECKER(thread_checker_); - - // Note: This should remain the last member so it'll be destroyed and - // invalidate its weak pointers before any other members are destroyed. - base::WeakPtrFactory<DirectoryLoader> weak_ptr_factory_{this}; - DISALLOW_COPY_AND_ASSIGN(DirectoryLoader); -}; - -} // namespace internal -} // namespace drive - -#endif // COMPONENTS_DRIVE_CHROMEOS_DIRECTORY_LOADER_H_
diff --git a/components/drive/chromeos/drive_change_list_loader.h b/components/drive/chromeos/drive_change_list_loader.h deleted file mode 100644 index fcdbad2..0000000 --- a/components/drive/chromeos/drive_change_list_loader.h +++ /dev/null
@@ -1,62 +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 COMPONENTS_DRIVE_CHROMEOS_DRIVE_CHANGE_LIST_LOADER_H_ -#define COMPONENTS_DRIVE_CHROMEOS_DRIVE_CHANGE_LIST_LOADER_H_ - -#include "components/drive/chromeos/file_system_interface.h" -#include "components/drive/file_errors.h" - -namespace drive { -namespace internal { - -class ChangeListLoaderObserver; -class TeamDriveListObserver; - -// DriveChangeListLoader provides an abstraction for loading change lists, the -// full resource list amd directory contents, from Google Drive API. -// Implementations of the interface can, for example, include: -// - An implementation to retrieve from the users default corpus. -// - An implementation to retrieve from a specific team drive. -class DriveChangeListLoader { - public: - virtual ~DriveChangeListLoader() = default; - - // Adds and removes an observer for change list loading events. - virtual void AddChangeListLoaderObserver( - ChangeListLoaderObserver* observer) = 0; - virtual void RemoveChangeListLoaderObserver( - ChangeListLoaderObserver* observer) = 0; - - // Adds and removes an observer for team drive loading events. - virtual void AddTeamDriveListObserver(TeamDriveListObserver* observer) = 0; - virtual void RemoveTeamDriveListObserver(TeamDriveListObserver* observer) = 0; - - // Indicates whether there is a request for full resource list or change - // list fetching is in flight (i.e. directory contents fetching does not - // count). - virtual bool IsRefreshing() = 0; - - // Starts the change list loading if needed. - // |callback| must not be null. - virtual void LoadIfNeeded(const FileOperationCallback& callback) = 0; - - // Check for updates on the server. May do nothing if a change list is - // already in the process of being loaded. - // |callback| must not be null. - virtual void CheckForUpdates(const FileOperationCallback& callback) = 0; - - // Reads the given directory contents. - // |entries_callback| can be null. - // |completion_callback| must not be null. - virtual void ReadDirectory( - const base::FilePath& directory_path, - ReadDirectoryEntriesCallback entries_callback, - const FileOperationCallback& completion_callback) = 0; -}; - -} // namespace internal -} // namespace drive - -#endif // COMPONENTS_DRIVE_CHROMEOS_DRIVE_CHANGE_LIST_LOADER_H_
diff --git a/components/drive/chromeos/dummy_file_system.cc b/components/drive/chromeos/dummy_file_system.cc deleted file mode 100644 index b284bcb38..0000000 --- a/components/drive/chromeos/dummy_file_system.cc +++ /dev/null
@@ -1,18 +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 "components/drive/chromeos/dummy_file_system.h" -#include "base/bind_helpers.h" - -namespace drive { - -base::Closure DummyFileSystem::GetFileContent( - const base::FilePath& file_path, - GetFileContentInitializedCallback initialized_callback, - const google_apis::GetContentCallback& get_content_callback, - const FileOperationCallback& completion_callback) { - return base::DoNothing(); -} - -} // namespace drive
diff --git a/components/drive/chromeos/dummy_file_system.h b/components/drive/chromeos/dummy_file_system.h deleted file mode 100644 index 52a5a7ca..0000000 --- a/components/drive/chromeos/dummy_file_system.h +++ /dev/null
@@ -1,117 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_DRIVE_CHROMEOS_DUMMY_FILE_SYSTEM_H_ -#define COMPONENTS_DRIVE_CHROMEOS_DUMMY_FILE_SYSTEM_H_ - -#include <stdint.h> -#include <set> -#include <string> - -#include "components/drive/chromeos/file_system_interface.h" - -namespace drive { - -// Dummy implementation of FileSystemInterface. All functions do nothing. -class DummyFileSystem : public FileSystemInterface { - public: - ~DummyFileSystem() override = default; - void AddObserver(FileSystemObserver* observer) override {} - void RemoveObserver(FileSystemObserver* observer) override {} - void CheckForUpdates() override {} - void CheckForUpdates(const std::set<std::string>& ids) override {} - void TransferFileFromLocalToRemote( - const base::FilePath& local_src_file_path, - const base::FilePath& remote_dest_file_path, - const FileOperationCallback& callback) override {} - void OpenFile(const base::FilePath& file_path, - OpenMode open_mode, - const std::string& mime_type, - OpenFileCallback callback) override {} - void Copy(const base::FilePath& src_file_path, - const base::FilePath& dest_file_path, - bool preserve_last_modified, - const FileOperationCallback& callback) override {} - void Move(const base::FilePath& src_file_path, - const base::FilePath& dest_file_path, - const FileOperationCallback& callback) override {} - void Remove(const base::FilePath& file_path, - bool is_recursive, - const FileOperationCallback& callback) override {} - void CreateDirectory(const base::FilePath& directory_path, - bool is_exclusive, - bool is_recursive, - const FileOperationCallback& callback) override {} - void CreateFile(const base::FilePath& file_path, - bool is_exclusive, - const std::string& mime_type, - const FileOperationCallback& callback) override {} - void TouchFile(const base::FilePath& file_path, - const base::Time& last_access_time, - const base::Time& last_modified_time, - const FileOperationCallback& callback) override {} - void TruncateFile(const base::FilePath& file_path, - int64_t length, - const FileOperationCallback& callback) override {} - void Pin(const base::FilePath& file_path, - const FileOperationCallback& callback) override {} - void Unpin(const base::FilePath& file_path, - const FileOperationCallback& callback) override {} - void GetFile(const base::FilePath& file_path, - GetFileCallback callback) override {} - void GetFileForSaving(const base::FilePath& file_path, - GetFileCallback callback) override {} - base::Closure GetFileContent( - const base::FilePath& file_path, - GetFileContentInitializedCallback initialized_callback, - const google_apis::GetContentCallback& get_content_callback, - const FileOperationCallback& completion_callback) override; - void GetResourceEntry(const base::FilePath& file_path, - GetResourceEntryCallback callback) override {} - void ReadDirectory( - const base::FilePath& file_path, - ReadDirectoryEntriesCallback entries_callback, - const FileOperationCallback& completion_callback) override {} - void Search(const std::string& search_query, - const GURL& next_link, - SearchCallback callback) override {} - void SearchMetadata(const std::string& query, - int options, - int at_most_num_matches, - MetadataSearchOrder order, - SearchMetadataCallback callback) override {} - void SearchByHashes(const std::set<std::string>& hashes, - SearchByHashesCallback callback) override {} - void GetAvailableSpace(GetAvailableSpaceCallback callback) override {} - void GetMetadata(GetFilesystemMetadataCallback callback) override {} - void MarkCacheFileAsMounted(const base::FilePath& drive_file_path, - MarkMountedCallback callback) override {} - void MarkCacheFileAsUnmounted( - const base::FilePath& cache_file_path, - const FileOperationCallback& callback) override {} - void IsCacheFileMarkedAsMounted(const base::FilePath& drive_file_path, - IsMountedCallback callback) override {} - void AddPermission(const base::FilePath& drive_file_path, - const std::string& email, - google_apis::drive::PermissionRole role, - const FileOperationCallback& callback) override {} - void SetProperty(const base::FilePath& drive_file_path, - google_apis::drive::Property::Visibility visibility, - const std::string& key, - const std::string& value, - const FileOperationCallback& callback) override {} - void Reset(const FileOperationCallback& callback) override {} - void GetPathFromResourceId(const std::string& resource_id, - const GetFilePathCallback& callback) override {} - void FreeDiskSpaceIfNeededFor( - int64_t num_bytes, - const FreeDiskSpaceCallback& callback) override {} - void CalculateCacheSize(const CacheSizeCallback& callback) override {} - void CalculateEvictableCacheSize( - const CacheSizeCallback& callback) override {} -}; - -} // namespace drive - -#endif // COMPONENTS_DRIVE_CHROMEOS_DUMMY_FILE_SYSTEM_H_
diff --git a/components/drive/chromeos/fake_file_system.cc b/components/drive/chromeos/fake_file_system.cc deleted file mode 100644 index ac201f1..0000000 --- a/components/drive/chromeos/fake_file_system.cc +++ /dev/null
@@ -1,428 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/drive/chromeos/fake_file_system.h" - -#include <stddef.h> - -#include <memory> -#include <set> -#include <utility> -#include <vector> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/callback.h" -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/logging.h" -#include "components/drive/drive.pb.h" -#include "components/drive/file_errors.h" -#include "components/drive/file_system_core_util.h" -#include "components/drive/resource_entry_conversion.h" -#include "components/drive/service/drive_service_interface.h" -#include "content/public/browser/browser_thread.h" -#include "google_apis/drive/drive_api_parser.h" - -namespace drive { -namespace test_util { - -using content::BrowserThread; - -FakeFileSystem::FakeFileSystem(DriveServiceInterface* drive_service) - : drive_service_(drive_service) { - CHECK(cache_dir_.CreateUniqueTempDir()); -} - -FakeFileSystem::~FakeFileSystem() = default; - -void FakeFileSystem::AddObserver(FileSystemObserver* observer) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); -} - -void FakeFileSystem::RemoveObserver(FileSystemObserver* observer) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); -} - -void FakeFileSystem::CheckForUpdates() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); -} - -void FakeFileSystem::CheckForUpdates(const std::set<std::string>& ids) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); -} - -void FakeFileSystem::TransferFileFromLocalToRemote( - const base::FilePath& local_src_file_path, - const base::FilePath& remote_dest_file_path, - const FileOperationCallback& callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); -} - -void FakeFileSystem::OpenFile(const base::FilePath& file_path, - OpenMode open_mode, - const std::string& mime_type, - OpenFileCallback callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); -} - -void FakeFileSystem::Copy(const base::FilePath& src_file_path, - const base::FilePath& dest_file_path, - bool preserve_last_modified, - const FileOperationCallback& callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); -} - -void FakeFileSystem::Move(const base::FilePath& src_file_path, - const base::FilePath& dest_file_path, - const FileOperationCallback& callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); -} - -void FakeFileSystem::Remove(const base::FilePath& file_path, - bool is_recursive, - const FileOperationCallback& callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); -} - -void FakeFileSystem::CreateDirectory( - const base::FilePath& directory_path, - bool is_exclusive, - bool is_recursive, - const FileOperationCallback& callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); -} - -void FakeFileSystem::CreateFile(const base::FilePath& file_path, - bool is_exclusive, - const std::string& mime_type, - const FileOperationCallback& callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); -} - -void FakeFileSystem::TouchFile(const base::FilePath& file_path, - const base::Time& last_access_time, - const base::Time& last_modified_time, - const FileOperationCallback& callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); -} - -void FakeFileSystem::TruncateFile(const base::FilePath& file_path, - int64_t length, - const FileOperationCallback& callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); -} - -void FakeFileSystem::Pin(const base::FilePath& file_path, - const FileOperationCallback& callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); -} - -void FakeFileSystem::Unpin(const base::FilePath& file_path, - const FileOperationCallback& callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); -} - -void FakeFileSystem::GetFile(const base::FilePath& file_path, - GetFileCallback callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); -} - -void FakeFileSystem::GetFileForSaving(const base::FilePath& file_path, - GetFileCallback callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); -} - -void FakeFileSystem::IsCacheFileMarkedAsMounted( - const base::FilePath& drive_file_path, - IsMountedCallback callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); -} - -base::Closure FakeFileSystem::GetFileContent( - const base::FilePath& file_path, - GetFileContentInitializedCallback initialized_callback, - const google_apis::GetContentCallback& get_content_callback, - const FileOperationCallback& completion_callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - GetResourceEntry( - file_path, - base::Bind(&FakeFileSystem::GetFileContentAfterGetResourceEntry, - weak_ptr_factory_.GetWeakPtr(), - base::Passed(std::move(initialized_callback)), - get_content_callback, completion_callback)); - return base::DoNothing(); -} - -void FakeFileSystem::GetResourceEntry(const base::FilePath& file_path, - GetResourceEntryCallback callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - if (file_path == util::GetDriveMyDriveRootPath()) { - // Specialized for the root entry. - drive_service_->GetAboutResource(base::Bind( - &FakeFileSystem::GetResourceEntryAfterGetAboutResource, - weak_ptr_factory_.GetWeakPtr(), base::Passed(std::move(callback)))); - return; - } - - // Now, we only support files under my drive. - DCHECK(util::GetDriveMyDriveRootPath().IsParent(file_path)); - GetResourceEntry( - file_path.DirName(), - base::BindOnce(&FakeFileSystem::GetResourceEntryAfterGetParentEntryInfo, - weak_ptr_factory_.GetWeakPtr(), file_path.BaseName(), - std::move(callback))); -} - -void FakeFileSystem::ReadDirectory( - const base::FilePath& file_path, - ReadDirectoryEntriesCallback entries_callback, - const FileOperationCallback& completion_callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); -} - -void FakeFileSystem::Search(const std::string& search_query, - const GURL& next_link, - SearchCallback callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); -} - -void FakeFileSystem::SearchMetadata(const std::string& query, - int options, - int at_most_num_matches, - MetadataSearchOrder order, - SearchMetadataCallback callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); -} - -void FakeFileSystem::SearchByHashes(const std::set<std::string>& hashes, - SearchByHashesCallback callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); -} - -void FakeFileSystem::GetAvailableSpace(GetAvailableSpaceCallback callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); -} - -void FakeFileSystem::GetMetadata(GetFilesystemMetadataCallback callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); -} - -void FakeFileSystem::MarkCacheFileAsMounted( - const base::FilePath& drive_file_path, - MarkMountedCallback callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); -} - -void FakeFileSystem::MarkCacheFileAsUnmounted( - const base::FilePath& cache_file_path, - const FileOperationCallback& callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); -} - -void FakeFileSystem::AddPermission(const base::FilePath& drive_file_path, - const std::string& email, - google_apis::drive::PermissionRole role, - const FileOperationCallback& callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); -} - -void FakeFileSystem::SetProperty( - const base::FilePath& drive_file_path, - google_apis::drive::Property::Visibility visibility, - const std::string& key, - const std::string& value, - const FileOperationCallback& callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); -} - -void FakeFileSystem::Reset(const FileOperationCallback& callback) { -} - -void FakeFileSystem::GetPathFromResourceId( - const std::string& resource_id, - const GetFilePathCallback& callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); -} - -void FakeFileSystem::FreeDiskSpaceIfNeededFor( - int64_t num_bytes, - const FreeDiskSpaceCallback& callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); -} - -void FakeFileSystem::CalculateCacheSize(const CacheSizeCallback& callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); -} - -void FakeFileSystem::CalculateEvictableCacheSize( - const CacheSizeCallback& callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); -} - -// Implementation of GetFileContent. -void FakeFileSystem::GetFileContentAfterGetResourceEntry( - GetFileContentInitializedCallback initialized_callback, - const google_apis::GetContentCallback& get_content_callback, - const FileOperationCallback& completion_callback, - FileError error, - std::unique_ptr<ResourceEntry> entry) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - if (error != FILE_ERROR_OK) { - completion_callback.Run(error); - return; - } - DCHECK(entry); - - // We're only interested in a file. - if (entry->file_info().is_directory()) { - completion_callback.Run(FILE_ERROR_NOT_A_FILE); - return; - } - - // Fetch google_apis::FileResource for its |download_url|. - drive_service_->GetFileResource( - entry->resource_id(), - base::Bind(&FakeFileSystem::GetFileContentAfterGetFileResource, - weak_ptr_factory_.GetWeakPtr(), - base::Passed(std::move(initialized_callback)), - get_content_callback, completion_callback)); -} - -void FakeFileSystem::GetFileContentAfterGetFileResource( - GetFileContentInitializedCallback initialized_callback, - const google_apis::GetContentCallback& get_content_callback, - const FileOperationCallback& completion_callback, - google_apis::DriveApiErrorCode gdata_error, - std::unique_ptr<google_apis::FileResource> gdata_entry) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - FileError error = GDataToFileError(gdata_error); - if (error != FILE_ERROR_OK) { - completion_callback.Run(error); - return; - } - DCHECK(gdata_entry); - - std::unique_ptr<ResourceEntry> entry(new ResourceEntry); - std::string parent_resource_id; - ConvertFileResourceToResourceEntry(*gdata_entry, entry.get(), - &parent_resource_id); - entry->set_parent_local_id(parent_resource_id); - - base::FilePath cache_path = - cache_dir_.GetPath().AppendASCII(entry->resource_id()); - if (entry->file_specific_info().is_hosted_document()) { - // For hosted documents return a dummy cache without server request. - int result = base::WriteFile(cache_path, "", 0); - DCHECK_EQ(0, result); - } - if (base::PathExists(cache_path)) { - // Cache file is found. - std::move(initialized_callback) - .Run(FILE_ERROR_OK, cache_path, std::move(entry)); - completion_callback.Run(FILE_ERROR_OK); - return; - } - - std::move(initialized_callback) - .Run(FILE_ERROR_OK, base::FilePath(), std::move(entry)); - drive_service_->DownloadFile( - cache_path, - gdata_entry->file_id(), - base::Bind(&FakeFileSystem::GetFileContentAfterDownloadFile, - weak_ptr_factory_.GetWeakPtr(), - completion_callback), - get_content_callback, - google_apis::ProgressCallback()); -} - -void FakeFileSystem::GetFileContentAfterDownloadFile( - const FileOperationCallback& completion_callback, - google_apis::DriveApiErrorCode gdata_error, - const base::FilePath& temp_file) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - completion_callback.Run(GDataToFileError(gdata_error)); -} - -// Implementation of GetResourceEntry. -void FakeFileSystem::GetResourceEntryAfterGetAboutResource( - GetResourceEntryCallback callback, - google_apis::DriveApiErrorCode gdata_error, - std::unique_ptr<google_apis::AboutResource> about_resource) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - FileError error = GDataToFileError(gdata_error); - if (error != FILE_ERROR_OK) { - std::move(callback).Run(error, std::unique_ptr<ResourceEntry>()); - return; - } - - DCHECK(about_resource); - std::unique_ptr<ResourceEntry> root(new ResourceEntry); - root->mutable_file_info()->set_is_directory(true); - root->set_resource_id(about_resource->root_folder_id()); - root->set_title(util::kDriveMyDriveRootDirName); - std::move(callback).Run(error, std::move(root)); -} - -void FakeFileSystem::GetResourceEntryAfterGetParentEntryInfo( - const base::FilePath& base_name, - GetResourceEntryCallback callback, - FileError error, - std::unique_ptr<ResourceEntry> parent_entry) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - if (error != FILE_ERROR_OK) { - std::move(callback).Run(error, std::unique_ptr<ResourceEntry>()); - return; - } - - DCHECK(parent_entry); - drive_service_->GetFileListInDirectory( - parent_entry->resource_id(), - base::Bind(&FakeFileSystem::GetResourceEntryAfterGetFileList, - weak_ptr_factory_.GetWeakPtr(), base_name, - base::Passed(std::move(callback)))); -} - -void FakeFileSystem::GetResourceEntryAfterGetFileList( - const base::FilePath& base_name, - GetResourceEntryCallback callback, - google_apis::DriveApiErrorCode gdata_error, - std::unique_ptr<google_apis::FileList> file_list) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - FileError error = GDataToFileError(gdata_error); - if (error != FILE_ERROR_OK) { - std::move(callback).Run(error, std::unique_ptr<ResourceEntry>()); - return; - } - - DCHECK(file_list); - const std::vector<std::unique_ptr<google_apis::FileResource>>& entries = - file_list->items(); - for (size_t i = 0; i < entries.size(); ++i) { - std::unique_ptr<ResourceEntry> entry(new ResourceEntry); - std::string parent_resource_id; - ConvertFileResourceToResourceEntry(*entries[i], entry.get(), - &parent_resource_id); - entry->set_parent_local_id(parent_resource_id); - - if (entry->base_name() == base_name.AsUTF8Unsafe()) { - // Found the target entry. - std::move(callback).Run(FILE_ERROR_OK, std::move(entry)); - return; - } - } - - std::move(callback).Run(FILE_ERROR_NOT_FOUND, - std::unique_ptr<ResourceEntry>()); -} - -} // namespace test_util -} // namespace drive
diff --git a/components/drive/chromeos/fake_file_system.h b/components/drive/chromeos/fake_file_system.h deleted file mode 100644 index 4940a03..0000000 --- a/components/drive/chromeos/fake_file_system.h +++ /dev/null
@@ -1,201 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_DRIVE_CHROMEOS_FAKE_FILE_SYSTEM_H_ -#define COMPONENTS_DRIVE_CHROMEOS_FAKE_FILE_SYSTEM_H_ - -#include <stdint.h> - -#include <memory> -#include <set> -#include <string> - -#include "base/callback_forward.h" -#include "base/files/scoped_temp_dir.h" -#include "base/macros.h" -#include "components/drive/chromeos/file_system_interface.h" -#include "components/drive/file_errors.h" -#include "google_apis/drive/drive_api_error_codes.h" - -namespace google_apis { - -class AboutResource; -class FileResource; - -} // namespace google_apis - -namespace drive { - -class DriveServiceInterface; -class FileSystemObserver; -class ResourceEntry; - -namespace test_util { - -// This class implements a fake FileSystem which acts like a real Drive -// file system with FakeDriveService, for testing purpose. -// Note that this class doesn't support "caching" at the moment, so the number -// of interactions to the FakeDriveService may be bigger than the real -// implementation. -// Currently most methods are empty (not implemented). -class FakeFileSystem : public FileSystemInterface { - public: - explicit FakeFileSystem(DriveServiceInterface* drive_service); - ~FakeFileSystem() override; - - // FileSystemInterface Overrides. - void AddObserver(FileSystemObserver* observer) override; - void RemoveObserver(FileSystemObserver* observer) override; - void CheckForUpdates() override; - void CheckForUpdates(const std::set<std::string>& ids) override; - void TransferFileFromLocalToRemote( - const base::FilePath& local_src_file_path, - const base::FilePath& remote_dest_file_path, - const FileOperationCallback& callback) override; - void OpenFile(const base::FilePath& file_path, - OpenMode open_mode, - const std::string& mime_type, - OpenFileCallback callback) override; - void Copy(const base::FilePath& src_file_path, - const base::FilePath& dest_file_path, - bool preserve_last_modified, - const FileOperationCallback& callback) override; - void Move(const base::FilePath& src_file_path, - const base::FilePath& dest_file_path, - const FileOperationCallback& callback) override; - void Remove(const base::FilePath& file_path, - bool is_recursive, - const FileOperationCallback& callback) override; - void CreateDirectory(const base::FilePath& directory_path, - bool is_exclusive, - bool is_recursive, - const FileOperationCallback& callback) override; - void CreateFile(const base::FilePath& file_path, - bool is_exclusive, - const std::string& mime_type, - const FileOperationCallback& callback) override; - void TouchFile(const base::FilePath& file_path, - const base::Time& last_access_time, - const base::Time& last_modified_time, - const FileOperationCallback& callback) override; - void TruncateFile(const base::FilePath& file_path, - int64_t length, - const FileOperationCallback& callback) override; - void Pin(const base::FilePath& file_path, - const FileOperationCallback& callback) override; - void Unpin(const base::FilePath& file_path, - const FileOperationCallback& callback) override; - void GetFile(const base::FilePath& file_path, - GetFileCallback callback) override; - void GetFileForSaving(const base::FilePath& file_path, - GetFileCallback callback) override; - base::Closure GetFileContent( - const base::FilePath& file_path, - GetFileContentInitializedCallback initialized_callback, - const google_apis::GetContentCallback& get_content_callback, - const FileOperationCallback& completion_callback) override; - void GetResourceEntry(const base::FilePath& file_path, - GetResourceEntryCallback callback) override; - void ReadDirectory(const base::FilePath& file_path, - ReadDirectoryEntriesCallback entries_callback, - const FileOperationCallback& completion_callback) override; - void Search(const std::string& search_query, - const GURL& next_link, - SearchCallback callback) override; - void SearchMetadata(const std::string& query, - int options, - int at_most_num_matches, - MetadataSearchOrder order, - SearchMetadataCallback callback) override; - void SearchByHashes(const std::set<std::string>& hashes, - SearchByHashesCallback callback) override; - void GetAvailableSpace(GetAvailableSpaceCallback callback) override; - void GetMetadata(GetFilesystemMetadataCallback callback) override; - void MarkCacheFileAsMounted(const base::FilePath& drive_file_path, - MarkMountedCallback callback) override; - void MarkCacheFileAsUnmounted(const base::FilePath& cache_file_path, - const FileOperationCallback& callback) override; - void IsCacheFileMarkedAsMounted(const base::FilePath& drive_file_path, - IsMountedCallback callback) override; - void AddPermission(const base::FilePath& drive_file_path, - const std::string& email, - google_apis::drive::PermissionRole role, - const FileOperationCallback& callback) override; - void SetProperty(const base::FilePath& drive_file_path, - google_apis::drive::Property::Visibility visibility, - const std::string& key, - const std::string& value, - const FileOperationCallback& callback) override; - void Reset(const FileOperationCallback& callback) override; - void GetPathFromResourceId(const std::string& resource_id, - const GetFilePathCallback& callback) override; - void FreeDiskSpaceIfNeededFor(int64_t num_bytes, - const FreeDiskSpaceCallback& callback) override; - void CalculateCacheSize(const CacheSizeCallback& callback) override; - void CalculateEvictableCacheSize(const CacheSizeCallback& callback) override; - - private: - // Helpers of GetFileContent. - // How the method works: - // 1) Gets ResourceEntry of the path. - // 2) Look at if there is a cache file or not. If found return it. - // 3) Otherwise start DownloadFile. - // 4) Runs the |completion_callback| upon the download completion. - void GetFileContentAfterGetResourceEntry( - GetFileContentInitializedCallback initialized_callback, - const google_apis::GetContentCallback& get_content_callback, - const FileOperationCallback& completion_callback, - FileError error, - std::unique_ptr<ResourceEntry> entry); - void GetFileContentAfterGetFileResource( - GetFileContentInitializedCallback initialized_callback, - const google_apis::GetContentCallback& get_content_callback, - const FileOperationCallback& completion_callback, - google_apis::DriveApiErrorCode gdata_error, - std::unique_ptr<google_apis::FileResource> gdata_entry); - void GetFileContentAfterDownloadFile( - const FileOperationCallback& completion_callback, - google_apis::DriveApiErrorCode gdata_error, - const base::FilePath& temp_file); - - // Helpers of GetResourceEntry. - // How the method works: - // 1) If the path is root, gets AboutResrouce from the drive service - // and create ResourceEntry. - // 2-1) Otherwise, gets the parent's ResourceEntry by recursive call. - // 2-2) Then, gets the resource list by restricting the parent with its id. - // 2-3) Search the results based on title, and return the ResourceEntry. - // Note that adding suffix (e.g. " (2)") for files sharing a same name is - // not supported in FakeFileSystem. Thus, even if the server has - // files sharing the same name under a directory, the second (or later) - // file cannot be taken with the suffixed name. - void GetResourceEntryAfterGetAboutResource( - GetResourceEntryCallback callback, - google_apis::DriveApiErrorCode gdata_error, - std::unique_ptr<google_apis::AboutResource> about_resource); - void GetResourceEntryAfterGetParentEntryInfo( - const base::FilePath& base_name, - GetResourceEntryCallback callback, - FileError error, - std::unique_ptr<ResourceEntry> parent_entry); - void GetResourceEntryAfterGetFileList( - const base::FilePath& base_name, - GetResourceEntryCallback callback, - google_apis::DriveApiErrorCode gdata_error, - std::unique_ptr<google_apis::FileList> file_list); - - DriveServiceInterface* drive_service_; // Not owned. - base::ScopedTempDir cache_dir_; - - // Note: This should remain the last member so it'll be destroyed and - // invalidate the weak pointers before any other members are destroyed. - base::WeakPtrFactory<FakeFileSystem> weak_ptr_factory_{this}; - - DISALLOW_COPY_AND_ASSIGN(FakeFileSystem); -}; - -} // namespace test_util -} // namespace drive - -#endif // COMPONENTS_DRIVE_CHROMEOS_FAKE_FILE_SYSTEM_H_
diff --git a/components/drive/chromeos/file_system.cc b/components/drive/chromeos/file_system.cc deleted file mode 100644 index a691dcb..0000000 --- a/components/drive/chromeos/file_system.cc +++ /dev/null
@@ -1,1167 +0,0 @@ -// Copyright (c) 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. - -#include "components/drive/chromeos/file_system.h" - -#include <stddef.h> -#include <limits> -#include <map> -#include <set> -#include <utility> - -#include "base/barrier_closure.h" -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/files/file_util.h" -#include "base/sequenced_task_runner.h" -#include "base/single_thread_task_runner.h" -#include "components/drive/chromeos/about_resource_loader.h" -#include "components/drive/chromeos/default_corpus_change_list_loader.h" -#include "components/drive/chromeos/drive_file_util.h" -#include "components/drive/chromeos/file_cache.h" -#include "components/drive/chromeos/file_system/copy_operation.h" -#include "components/drive/chromeos/file_system/create_directory_operation.h" -#include "components/drive/chromeos/file_system/create_file_operation.h" -#include "components/drive/chromeos/file_system/download_operation.h" -#include "components/drive/chromeos/file_system/get_file_for_saving_operation.h" -#include "components/drive/chromeos/file_system/move_operation.h" -#include "components/drive/chromeos/file_system/open_file_operation.h" -#include "components/drive/chromeos/file_system/remove_operation.h" -#include "components/drive/chromeos/file_system/search_operation.h" -#include "components/drive/chromeos/file_system/set_property_operation.h" -#include "components/drive/chromeos/file_system/touch_operation.h" -#include "components/drive/chromeos/file_system/truncate_operation.h" -#include "components/drive/chromeos/file_system_observer.h" -#include "components/drive/chromeos/loader_controller.h" -#include "components/drive/chromeos/remove_stale_cache_files.h" -#include "components/drive/chromeos/search_metadata.h" -#include "components/drive/chromeos/start_page_token_loader.h" -#include "components/drive/chromeos/sync_client.h" -#include "components/drive/drive.pb.h" -#include "components/drive/drive_pref_names.h" -#include "components/drive/file_change.h" -#include "components/drive/file_system_core_util.h" -#include "components/drive/job_scheduler.h" -#include "components/drive/resource_entry_conversion.h" -#include "google_apis/drive/drive_api_parser.h" - -namespace drive { -namespace { - -// Desired QPS for team drive background operations (update checking etc) -constexpr int kTeamDriveBackgroundOperationQPS = 10; - -// Gets a ResourceEntry from the metadata, and overwrites its file info when the -// cached file is dirty. -FileError GetLocallyStoredResourceEntry( - internal::ResourceMetadata* resource_metadata, - internal::FileCache* cache, - const base::FilePath& file_path, - ResourceEntry* entry) { - std::string local_id; - FileError error = resource_metadata->GetIdByPath(file_path, &local_id); - if (error != FILE_ERROR_OK) - return error; - - error = resource_metadata->GetResourceEntryById(local_id, entry); - if (error != FILE_ERROR_OK) - return error; - - // For entries that will never be cached, use the original resource entry - // as is. - if (!entry->has_file_specific_info() || - entry->file_specific_info().is_hosted_document()) - return FILE_ERROR_OK; - - // When cache is not found, use the original resource entry as is. - if (!entry->file_specific_info().has_cache_state()) - return FILE_ERROR_OK; - - // When cache is non-dirty and obsolete (old hash), use the original entry. - if (!entry->file_specific_info().cache_state().is_dirty() && - entry->file_specific_info().md5() != - entry->file_specific_info().cache_state().md5()) - return FILE_ERROR_OK; - - // If there's a valid cache, obtain the file info from the cache file itself. - base::FilePath local_cache_path; - error = cache->GetFile(local_id, &local_cache_path); - if (error != FILE_ERROR_OK) - return error; - - base::File::Info file_info; - if (!base::GetFileInfo(local_cache_path, &file_info)) - return FILE_ERROR_NOT_FOUND; - - entry->mutable_file_info()->set_size(file_info.size); - return FILE_ERROR_OK; -} - -// Runs the callback with parameters. -void RunGetResourceEntryCallback(GetResourceEntryCallback callback, - std::unique_ptr<ResourceEntry> entry, - FileError error) { - DCHECK(callback); - - if (error != FILE_ERROR_OK) - entry.reset(); - std::move(callback).Run(error, std::move(entry)); -} - -// Used to implement Pin(). -FileError PinInternal(internal::ResourceMetadata* resource_metadata, - internal::FileCache* cache, - const base::FilePath& file_path, - std::string* local_id) { - FileError error = resource_metadata->GetIdByPath(file_path, local_id); - if (error != FILE_ERROR_OK) - return error; - - ResourceEntry entry; - error = resource_metadata->GetResourceEntryById(*local_id, &entry); - if (error != FILE_ERROR_OK) - return error; - - // TODO(hashimoto): Support pinning directories. crbug.com/127831 - if (entry.file_info().is_directory()) - return FILE_ERROR_NOT_A_FILE; - - return cache->Pin(*local_id); -} - -// Used to implement Unpin(). -FileError UnpinInternal(internal::ResourceMetadata* resource_metadata, - internal::FileCache* cache, - const base::FilePath& file_path, - std::string* local_id) { - FileError error = resource_metadata->GetIdByPath(file_path, local_id); - if (error != FILE_ERROR_OK) - return error; - - return cache->Unpin(*local_id); -} - -// Used to implement MarkCacheFileAsMounted(). -FileError MarkCacheFileAsMountedInternal( - internal::ResourceMetadata* resource_metadata, - internal::FileCache* cache, - const base::FilePath& drive_file_path, - base::FilePath* cache_file_path) { - std::string local_id; - FileError error = resource_metadata->GetIdByPath(drive_file_path, &local_id); - if (error != FILE_ERROR_OK) - return error; - - return cache->MarkAsMounted(local_id, cache_file_path); -} - -// Used to implement IsCacheFileMarkedAsMounted(). -FileError IsCacheFileMarkedAsMountedInternal( - internal::ResourceMetadata* resource_metadata, - internal::FileCache* cache, - const base::FilePath& drive_file_path, - bool* result) { - std::string local_id; - FileError error = resource_metadata->GetIdByPath(drive_file_path, &local_id); - if (error != FILE_ERROR_OK) - return error; - - *result = cache->IsMarkedAsMounted(local_id); - return FILE_ERROR_OK; -} - -// Runs the callback with arguments. -void RunMarkMountedCallback(MarkMountedCallback callback, - base::FilePath* cache_file_path, - FileError error) { - DCHECK(callback); - std::move(callback).Run(error, *cache_file_path); -} - -// Runs the callback with arguments. -void RunIsMountedCallback(IsMountedCallback callback, - bool* result, - FileError error) { - DCHECK(callback); - std::move(callback).Run(error, *result); -} - -// Callback for internals::GetStartPageToken. -// |closure| must not be null. -void OnGetStartPageToken(const base::RepeatingClosure& closure, - FileError error) { - DCHECK(closure); - closure.Run(); -} - -// Thin adapter to map GetFileCallback to FileOperationCallback. -void GetFileCallbackToFileOperationCallbackAdapter( - const FileOperationCallback& callback, - FileError error, - const base::FilePath& unused_file_path, - std::unique_ptr<ResourceEntry> unused_entry) { - callback.Run(error); -} - -// Clears |resource_metadata| and |cache|. -FileError ResetOnBlockingPool(internal::ResourceMetadata* resource_metadata, - internal::FileCache* cache) { - FileError error = resource_metadata->Reset(); - if (error != FILE_ERROR_OK) - return error; - return cache->ClearAll() ? FILE_ERROR_OK : FILE_ERROR_FAILED; -} - -// Part of GetPathFromResourceId(). -// Obtains |file_path| from |resource_id|. The function should be run on the -// blocking pool. -FileError GetPathFromResourceIdOnBlockingPool( - internal::ResourceMetadata* resource_metadata, - const std::string& resource_id, - base::FilePath* file_path) { - std::string local_id; - const FileError error = - resource_metadata->GetIdByResourceId(resource_id, &local_id); - if (error != FILE_ERROR_OK) - return error; - return resource_metadata->GetFilePath(local_id, file_path); -} - -// Part of GetPathFromResourceId(). -// Called when GetPathFromResourceIdInBlockingPool is complete. -void GetPathFromResourceIdAfterGetPath(base::FilePath* file_path, - const GetFilePathCallback& callback, - FileError error) { - callback.Run(error, *file_path); -} - -bool FreeDiskSpaceIfNeededForOnBlockingPool(internal::FileCache* cache, - int64_t num_bytes) { - return cache->FreeDiskSpaceIfNeededFor(num_bytes); -} - -int64_t CalculateCacheSizeOnBlockingPool(internal::FileCache* cache) { - return cache->CalculateCacheSize(); -} - -int64_t CalculateEvictableCacheSizeOnBlockingPool(internal::FileCache* cache) { - return cache->CalculateEvictableCacheSize(); -} - -// Adapter for using FileOperationCallback as google_apis::EntryActionCallback. -void RunFileOperationCallbackAsEntryActionCallback( - const FileOperationCallback& callback, - google_apis::DriveApiErrorCode error) { - callback.Run(GDataToFileError(error)); -} - -// Checks if the |entry|'s hash is included in |hashes|. -bool CheckHashes(const std::set<std::string>& hashes, - const ResourceEntry& entry) { - return hashes.find(entry.file_specific_info().md5()) != hashes.end(); -} - -// Runs |callback| with |error| and the list of HashAndFilePath obtained from -// |original_result|. -void RunSearchByHashesCallback( - SearchByHashesCallback callback, - FileError error, - std::unique_ptr<MetadataSearchResultVector> original_result) { - std::vector<HashAndFilePath> result; - if (error != FILE_ERROR_OK) { - std::move(callback).Run(error, result); - return; - } - for (const auto& search_result : *original_result) { - HashAndFilePath hash_and_path; - hash_and_path.hash = search_result.md5; - hash_and_path.path = search_result.path; - result.push_back(hash_and_path); - } - std::move(callback).Run(FILE_ERROR_OK, result); -} - -} // namespace - -struct FileSystem::CreateDirectoryParams { - base::FilePath directory_path; - bool is_exclusive; - bool is_recursive; - FileOperationCallback callback; -}; - -FileSystem::FileSystem(EventLogger* logger, - internal::FileCache* cache, - JobScheduler* scheduler, - internal::ResourceMetadata* resource_metadata, - base::SequencedTaskRunner* blocking_task_runner, - const base::FilePath& temporary_file_directory, - const base::Clock* clock) - : logger_(logger), - cache_(cache), - scheduler_(scheduler), - resource_metadata_(resource_metadata), - blocking_task_runner_(blocking_task_runner), - temporary_file_directory_(temporary_file_directory), - clock_(clock) { - ResetComponents(); -} - -FileSystem::~FileSystem() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - default_corpus_change_list_loader_->RemoveChangeListLoaderObserver(this); - default_corpus_change_list_loader_->RemoveTeamDriveListObserver(this); -} - -void FileSystem::Reset(const FileOperationCallback& callback) { - // Discard the current loader and operation objects and renew them. This is to - // avoid that changes initiated before the metadata reset is applied after the - // reset, which may cause an inconsistent state. - // TODO(kinaba): callbacks held in the subcomponents are discarded. We might - // want to have a way to abort and flush callbacks in in-flight operations. - ResetComponents(); - - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), - FROM_HERE, - base::Bind(&ResetOnBlockingPool, resource_metadata_, cache_), - callback); -} - -void FileSystem::ResetComponents() { - file_system::OperationDelegate* delegate = this; - - about_resource_loader_ = - std::make_unique<internal::AboutResourceLoader>(scheduler_); - loader_controller_ = std::make_unique<internal::LoaderController>(); - - default_corpus_change_list_loader_ = - std::make_unique<internal::DefaultCorpusChangeListLoader>( - logger_, blocking_task_runner_.get(), resource_metadata_, scheduler_, - about_resource_loader_.get(), loader_controller_.get(), clock_); - - default_corpus_change_list_loader_->AddChangeListLoaderObserver(this); - default_corpus_change_list_loader_->AddTeamDriveListObserver(this); - - sync_client_ = std::make_unique<internal::SyncClient>( - blocking_task_runner_.get(), delegate, scheduler_, resource_metadata_, - cache_, loader_controller_.get(), temporary_file_directory_); - - team_drive_operation_queue_ = - std::make_unique<internal::DriveBackgroundOperationQueue< - internal::TeamDriveChangeListLoader>>( - kTeamDriveBackgroundOperationQPS); - - copy_operation_ = std::make_unique<file_system::CopyOperation>( - blocking_task_runner_.get(), delegate, scheduler_, resource_metadata_, - cache_); - create_directory_operation_ = - std::make_unique<file_system::CreateDirectoryOperation>( - blocking_task_runner_.get(), delegate, resource_metadata_); - create_file_operation_ = std::make_unique<file_system::CreateFileOperation>( - blocking_task_runner_.get(), delegate, resource_metadata_); - move_operation_ = std::make_unique<file_system::MoveOperation>( - blocking_task_runner_.get(), delegate, resource_metadata_); - open_file_operation_ = std::make_unique<file_system::OpenFileOperation>( - blocking_task_runner_.get(), delegate, scheduler_, resource_metadata_, - cache_, temporary_file_directory_); - remove_operation_ = std::make_unique<file_system::RemoveOperation>( - blocking_task_runner_.get(), delegate, resource_metadata_, cache_); - touch_operation_ = std::make_unique<file_system::TouchOperation>( - blocking_task_runner_.get(), delegate, resource_metadata_); - truncate_operation_ = std::make_unique<file_system::TruncateOperation>( - blocking_task_runner_.get(), delegate, scheduler_, resource_metadata_, - cache_, temporary_file_directory_); - download_operation_ = std::make_unique<file_system::DownloadOperation>( - blocking_task_runner_.get(), delegate, scheduler_, resource_metadata_, - cache_, temporary_file_directory_); - search_operation_ = std::make_unique<file_system::SearchOperation>( - blocking_task_runner_.get(), scheduler_, resource_metadata_, - loader_controller_.get()); - get_file_for_saving_operation_ = - std::make_unique<file_system::GetFileForSavingOperation>( - - logger_, blocking_task_runner_.get(), delegate, scheduler_, - resource_metadata_, cache_, temporary_file_directory_); - set_property_operation_ = std::make_unique<file_system::SetPropertyOperation>( - blocking_task_runner_.get(), delegate, resource_metadata_); -} - -void FileSystem::CheckForUpdates() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DVLOG(1) << "CheckForUpdates"; - - size_t num_callbacks = team_drive_change_list_loaders_.size() + 1; - - base::RepeatingClosure closure = base::BarrierClosure( - num_callbacks, base::BindOnce(&FileSystem::OnUpdateCompleted, - weak_ptr_factory_.GetWeakPtr())); - - for (auto& team_drive : team_drive_change_list_loaders_) { - auto update_checked_closure = - base::Bind(&FileSystem::OnUpdateChecked, weak_ptr_factory_.GetWeakPtr(), - team_drive.first, closure); - if (!team_drive.second->IsRefreshing()) { - team_drive_operation_queue_->AddOperation( - team_drive.second->GetWeakPtr(), - base::BindOnce(&internal::TeamDriveChangeListLoader::CheckForUpdates, - team_drive.second->GetWeakPtr()), - update_checked_closure); - } else { - // If the change list loader is refreshing, then calling CheckForUpdates - // will just add the callback to a queue to be called when the refresh - // is complete. - team_drive.second->CheckForUpdates(update_checked_closure); - } - } - - default_corpus_change_list_loader_->CheckForUpdates( - base::Bind(&FileSystem::OnUpdateChecked, weak_ptr_factory_.GetWeakPtr(), - std::string(), closure)); -} - -void FileSystem::CheckForUpdates(const std::set<std::string>& ids) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - base::RepeatingClosure closure = base::BarrierClosure( - ids.size(), base::BindOnce(&FileSystem::OnUpdateCompleted, - weak_ptr_factory_.GetWeakPtr())); - - for (const auto& id : ids) { - if (id.empty()) { - default_corpus_change_list_loader_->CheckForUpdates( - base::Bind(&FileSystem::OnUpdateChecked, - weak_ptr_factory_.GetWeakPtr(), std::string(), closure)); - } else { - auto it = team_drive_change_list_loaders_.find(id); - - // It is possible for the team drive to have been deleted by the time we - // receive the push notification. - if (it != team_drive_change_list_loaders_.end()) { - auto update_checked_closure = - base::Bind(&FileSystem::OnUpdateChecked, - weak_ptr_factory_.GetWeakPtr(), it->first, closure); - if (!it->second->IsRefreshing()) { - team_drive_operation_queue_->AddOperation( - it->second->GetWeakPtr(), - base::BindOnce( - &internal::TeamDriveChangeListLoader::CheckForUpdates, - it->second->GetWeakPtr()), - update_checked_closure); - } else { - // If the change list loader is refreshing, then calling - // CheckForUpdates will just add the callback to a queue to be called - // when the refresh is complete. - it->second->CheckForUpdates(update_checked_closure); - } - } else { - closure.Run(); - } - } - } -} - -void FileSystem::OnUpdateChecked(const std::string& team_drive_id, - const base::RepeatingClosure& closure, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DVLOG(1) << "CheckForUpdates finished: " << FileErrorToString(error); - - last_update_metadata_[team_drive_id].last_update_check_error = error; - last_update_metadata_[team_drive_id].last_update_check_time = - base::Time::Now(); - closure.Run(); -} - -void FileSystem::OnUpdateCompleted() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); -} - -void FileSystem::AddObserver(FileSystemObserver* observer) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - observers_.AddObserver(observer); -} - -void FileSystem::RemoveObserver(FileSystemObserver* observer) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - observers_.RemoveObserver(observer); -} - -void FileSystem::TransferFileFromLocalToRemote( - const base::FilePath& local_src_file_path, - const base::FilePath& remote_dest_file_path, - const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - copy_operation_->TransferFileFromLocalToRemote(local_src_file_path, - remote_dest_file_path, - callback); -} - -void FileSystem::Copy(const base::FilePath& src_file_path, - const base::FilePath& dest_file_path, - bool preserve_last_modified, - const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - copy_operation_->Copy( - src_file_path, dest_file_path, preserve_last_modified, callback); -} - -void FileSystem::Move(const base::FilePath& src_file_path, - const base::FilePath& dest_file_path, - const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - move_operation_->Move(src_file_path, dest_file_path, callback); -} - -void FileSystem::Remove(const base::FilePath& file_path, - bool is_recursive, - const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - remove_operation_->Remove(file_path, is_recursive, callback); -} - -void FileSystem::CreateDirectory( - const base::FilePath& directory_path, - bool is_exclusive, - bool is_recursive, - const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - CreateDirectoryParams params; - params.directory_path = directory_path; - params.is_exclusive = is_exclusive; - params.is_recursive = is_recursive; - params.callback = callback; - - // Ensure its parent directory is loaded to the local metadata. - ReadDirectory(directory_path.DirName(), - ReadDirectoryEntriesCallback(), - base::Bind(&FileSystem::CreateDirectoryAfterRead, - weak_ptr_factory_.GetWeakPtr(), params)); -} - -void FileSystem::CreateDirectoryAfterRead(const CreateDirectoryParams& params, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(params.callback); - - DVLOG_IF(1, error != FILE_ERROR_OK) << "ReadDirectory failed. " - << FileErrorToString(error); - - create_directory_operation_->CreateDirectory( - params.directory_path, params.is_exclusive, params.is_recursive, - params.callback); -} - -void FileSystem::CreateFile(const base::FilePath& file_path, - bool is_exclusive, - const std::string& mime_type, - const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - create_file_operation_->CreateFile( - file_path, is_exclusive, mime_type, callback); -} - -void FileSystem::TouchFile(const base::FilePath& file_path, - const base::Time& last_access_time, - const base::Time& last_modified_time, - const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - touch_operation_->TouchFile( - file_path, last_access_time, last_modified_time, callback); -} - -void FileSystem::TruncateFile(const base::FilePath& file_path, - int64_t length, - const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - truncate_operation_->Truncate(file_path, length, callback); -} - -void FileSystem::Pin(const base::FilePath& file_path, - const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - std::string* local_id = new std::string; - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), - FROM_HERE, - base::Bind(&PinInternal, resource_metadata_, cache_, file_path, local_id), - base::Bind(&FileSystem::FinishPin, - weak_ptr_factory_.GetWeakPtr(), - callback, - base::Owned(local_id))); -} - -void FileSystem::FinishPin(const FileOperationCallback& callback, - const std::string* local_id, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - if (error == FILE_ERROR_OK) - sync_client_->AddFetchTask(*local_id); - callback.Run(error); -} - -void FileSystem::Unpin(const base::FilePath& file_path, - const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - std::string* local_id = new std::string; - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), - FROM_HERE, - base::Bind( - &UnpinInternal, resource_metadata_, cache_, file_path, local_id), - base::Bind(&FileSystem::FinishUnpin, - weak_ptr_factory_.GetWeakPtr(), - callback, - base::Owned(local_id))); -} - -void FileSystem::FinishUnpin(const FileOperationCallback& callback, - const std::string* local_id, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - if (error == FILE_ERROR_OK) - sync_client_->RemoveFetchTask(*local_id); - callback.Run(error); -} - -void FileSystem::GetFile(const base::FilePath& file_path, - GetFileCallback callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - download_operation_->EnsureFileDownloadedByPath( - file_path, ClientContext(USER_INITIATED), - GetFileContentInitializedCallback(), google_apis::GetContentCallback(), - std::move(callback)); -} - -void FileSystem::GetFileForSaving(const base::FilePath& file_path, - GetFileCallback callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - get_file_for_saving_operation_->GetFileForSaving(file_path, - std::move(callback)); -} - -base::Closure FileSystem::GetFileContent( - const base::FilePath& file_path, - GetFileContentInitializedCallback initialized_callback, - const google_apis::GetContentCallback& get_content_callback, - const FileOperationCallback& completion_callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(initialized_callback); - DCHECK(get_content_callback); - DCHECK(completion_callback); - - return download_operation_->EnsureFileDownloadedByPath( - file_path, ClientContext(USER_INITIATED), std::move(initialized_callback), - get_content_callback, - base::Bind(&GetFileCallbackToFileOperationCallbackAdapter, - completion_callback)); -} - -void FileSystem::GetResourceEntry(const base::FilePath& file_path, - GetResourceEntryCallback callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - ReadDirectory(file_path.DirName(), ReadDirectoryEntriesCallback(), - base::Bind(&FileSystem::GetResourceEntryAfterRead, - weak_ptr_factory_.GetWeakPtr(), file_path, - base::Passed(std::move(callback)))); -} - -void FileSystem::GetResourceEntryAfterRead(const base::FilePath& file_path, - GetResourceEntryCallback callback, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - DVLOG_IF(1, error != FILE_ERROR_OK) << "ReadDirectory failed. " - << FileErrorToString(error); - - std::unique_ptr<ResourceEntry> entry(new ResourceEntry); - ResourceEntry* entry_ptr = entry.get(); - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), FROM_HERE, - base::BindOnce(&GetLocallyStoredResourceEntry, resource_metadata_, cache_, - file_path, entry_ptr), - base::BindOnce(&RunGetResourceEntryCallback, std::move(callback), - std::move(entry))); -} - -void FileSystem::ReadDirectory( - const base::FilePath& directory_path, - ReadDirectoryEntriesCallback entries_callback, - const FileOperationCallback& completion_callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(completion_callback); - - if (util::GetDriveTeamDrivesRootPath().IsParent(directory_path)) { - // If we do not match a single team drive then we will run the default - // corpus loader to read the directory. - for (auto& team_drive_loader : team_drive_change_list_loaders_) { - const base::FilePath& team_drive_path = - team_drive_loader.second->root_entry_path(); - if (team_drive_path == directory_path || - team_drive_path.IsParent(directory_path)) { - team_drive_loader.second->ReadDirectory( - directory_path, std::move(entries_callback), completion_callback); - return; - } - } - } - // Fall through to the default corpus loader if no team drive loader is found. - // We do not refresh the list of team drives from the server until the first - // ReadDirectory is called on the default corpus change list loader. - default_corpus_change_list_loader_->ReadDirectory( - directory_path, std::move(entries_callback), completion_callback); -} - -void FileSystem::GetAvailableSpace(GetAvailableSpaceCallback callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - about_resource_loader_->GetAboutResource(base::Bind( - &FileSystem::OnGetAboutResource, weak_ptr_factory_.GetWeakPtr(), - base::Passed(std::move(callback)))); -} - -void FileSystem::OnGetAboutResource( - GetAvailableSpaceCallback callback, - google_apis::DriveApiErrorCode status, - std::unique_ptr<google_apis::AboutResource> about_resource) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - FileError error = GDataToFileError(status); - if (error != FILE_ERROR_OK) { - std::move(callback).Run(error, -1, -1); - return; - } - DCHECK(about_resource); - - std::move(callback).Run(FILE_ERROR_OK, about_resource->quota_bytes_total(), - about_resource->quota_bytes_used_aggregate()); -} - -void FileSystem::Search(const std::string& search_query, - const GURL& next_link, - SearchCallback callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - search_operation_->Search(search_query, next_link, std::move(callback)); -} - -void FileSystem::SearchMetadata(const std::string& query, - int options, - int at_most_num_matches, - MetadataSearchOrder order, - SearchMetadataCallback callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - drive::internal::SearchMetadata( - blocking_task_runner_, resource_metadata_, query, - base::Bind(&drive::internal::MatchesType, options), at_most_num_matches, - order, std::move(callback)); -} - -void FileSystem::SearchByHashes(const std::set<std::string>& hashes, - SearchByHashesCallback callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - drive::internal::SearchMetadata( - blocking_task_runner_, resource_metadata_, - /* any file name */ "", base::Bind(&CheckHashes, hashes), - std::numeric_limits<size_t>::max(), - drive::MetadataSearchOrder::LAST_ACCESSED, - base::BindOnce(&RunSearchByHashesCallback, std::move(callback))); -} - -void FileSystem::OnFileChangedByOperation(const FileChange& changed_files) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - for (auto& observer : observers_) - observer.OnFileChanged(changed_files); -} - -void FileSystem::OnEntryUpdatedByOperation(const ClientContext& context, - const std::string& local_id) { - sync_client_->AddUpdateTask(context, local_id); -} - -void FileSystem::OnDriveSyncError(file_system::DriveSyncErrorType type, - const std::string& local_id) { - base::FilePath* file_path = new base::FilePath; - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), - FROM_HERE, - base::Bind(&internal::ResourceMetadata::GetFilePath, - base::Unretained(resource_metadata_), - local_id, - file_path), - base::Bind(&FileSystem::OnDriveSyncErrorAfterGetFilePath, - weak_ptr_factory_.GetWeakPtr(), - type, - base::Owned(file_path))); -} - -void FileSystem::OnDriveSyncErrorAfterGetFilePath( - file_system::DriveSyncErrorType type, - const base::FilePath* file_path, - FileError error) { - if (error != FILE_ERROR_OK) - return; - for (auto& observer : observers_) - observer.OnDriveSyncError(type, *file_path); -} - -bool FileSystem::WaitForSyncComplete(const std::string& local_id, - const FileOperationCallback& callback) { - return sync_client_->WaitForUpdateTaskToComplete(local_id, callback); -} - -void FileSystem::OnDirectoryReloaded(const base::FilePath& directory_path) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - for (auto& observer : observers_) - observer.OnDirectoryChanged(directory_path); -} - -void FileSystem::OnFileChanged(const FileChange& changed_files) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - for (auto& observer : observers_) - observer.OnFileChanged(changed_files); -} - -void FileSystem::OnTeamDrivesChanged(const FileChange& changed_team_drives) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - std::set<std::string> added_team_drives; - std::set<std::string> removed_team_drives; - - for (const auto& entry : changed_team_drives.map()) { - for (const auto& change : entry.second.list()) { - DCHECK(!change.team_drive_id().empty()); - if (change.IsDelete()) { - if (team_drive_change_list_loaders_.erase(change.team_drive_id()) > 0) { - // If we were tracking the update status we can remove that as well. - last_update_metadata_.erase(change.team_drive_id()); - removed_team_drives.insert(change.team_drive_id()); - } - } else if (change.IsAddOrUpdate()) { - // If this is an update (e.g. a renamed team drive), then just erase the - // existing entry so we can re-add it with the new path. - team_drive_change_list_loaders_.erase(change.team_drive_id()); - - auto loader = std::make_unique<internal::TeamDriveChangeListLoader>( - change.team_drive_id(), entry.first, logger_, - blocking_task_runner_.get(), resource_metadata_, scheduler_, - loader_controller_.get()); - loader->AddChangeListLoaderObserver(this); - team_drive_operation_queue_->AddOperation( - loader->GetWeakPtr(), - base::BindOnce(&internal::TeamDriveChangeListLoader::LoadIfNeeded, - loader->GetWeakPtr()), - base::DoNothing()); - team_drive_change_list_loaders_.emplace(change.team_drive_id(), - std::move(loader)); - added_team_drives.insert(change.team_drive_id()); - } - } - } - for (auto& observer : observers_) { - observer.OnTeamDrivesUpdated(added_team_drives, removed_team_drives); - } -} - -void FileSystem::OnLoadFromServerComplete() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - sync_client_->StartCheckingExistingPinnedFiles(); -} - -void FileSystem::OnInitialLoadComplete() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - blocking_task_runner_->PostTask( - FROM_HERE, base::BindOnce(&internal::RemoveStaleCacheFiles, cache_, - resource_metadata_)); - sync_client_->StartProcessingBacklog(); -} - -void FileSystem::OnTeamDriveListLoaded( - const std::vector<internal::TeamDrive>& team_drives_list, - const std::vector<internal::TeamDrive>& added_team_drives, - const std::vector<internal::TeamDrive>& removed_team_drives) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - for (auto& team_drive_loader : team_drive_change_list_loaders_) { - team_drive_loader.second->RemoveChangeListLoaderObserver(this); - } - team_drive_change_list_loaders_.clear(); - - std::set<std::string> added_team_drives_ids; - for (const auto& team_drive : team_drives_list) { - auto loader = std::make_unique<internal::TeamDriveChangeListLoader>( - team_drive.team_drive_id(), team_drive.team_drive_path(), logger_, - blocking_task_runner_.get(), resource_metadata_, scheduler_, - loader_controller_.get()); - loader->AddChangeListLoaderObserver(this); - team_drive_operation_queue_->AddOperation( - loader->GetWeakPtr(), - base::BindOnce(&internal::TeamDriveChangeListLoader::LoadIfNeeded, - loader->GetWeakPtr()), - base::DoNothing()); - team_drive_change_list_loaders_.emplace(team_drive.team_drive_id(), - std::move(loader)); - added_team_drives_ids.insert(team_drive.team_drive_id()); - } - for (auto& observer : observers_) { - observer.OnTeamDrivesUpdated(added_team_drives_ids, {}); - } -} - -void FileSystem::GetMetadata(GetFilesystemMetadataCallback callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - FileSystemMetadata* metadata = new FileSystemMetadata(); - std::map<std::string, FileSystemMetadata>* team_drive_metadata = - new std::map<std::string, FileSystemMetadata>(); - - size_t num_callbacks = team_drive_change_list_loaders_.size() + 1; - - base::RepeatingClosure closure = base::BarrierClosure( - num_callbacks, - base::BindOnce(&FileSystem::OnGetMetadata, weak_ptr_factory_.GetWeakPtr(), - std::move(callback), base::Owned(metadata), - base::Owned(team_drive_metadata))); - - metadata->refreshing = default_corpus_change_list_loader_->IsRefreshing(); - metadata->path = util::GetDriveGrandRootPath().value(); - metadata->last_update_check_time = - last_update_metadata_[util::kTeamDriveIdDefaultCorpus] - .last_update_check_time; - metadata->last_update_check_error = - last_update_metadata_[util::kTeamDriveIdDefaultCorpus] - .last_update_check_error; - - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), FROM_HERE, - base::Bind(&internal::GetStartPageToken, - base::Unretained(resource_metadata_), - util::kTeamDriveIdDefaultCorpus, - base::Unretained(&(metadata->start_page_token))), - base::Bind(&OnGetStartPageToken, closure)); - - for (auto& team_drive : team_drive_change_list_loaders_) { - const FileSystemMetadata& last_update_metadata = - last_update_metadata_[team_drive.first]; - FileSystemMetadata& md = (*team_drive_metadata)[team_drive.first]; - - md.refreshing = team_drive.second->IsRefreshing(); - md.path = team_drive.second->root_entry_path().value(); - md.last_update_check_time = last_update_metadata.last_update_check_time; - md.last_update_check_error = last_update_metadata.last_update_check_error; - - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), FROM_HERE, - base::Bind(&internal::GetStartPageToken, - base::Unretained(resource_metadata_), team_drive.first, - base::Unretained(&(md.start_page_token))), - base::Bind(&OnGetStartPageToken, closure)); - } -} - -void FileSystem::OnGetMetadata( - GetFilesystemMetadataCallback callback, - drive::FileSystemMetadata* default_corpus_metadata, - std::map<std::string, drive::FileSystemMetadata>* team_drive_metadata) { - DCHECK(callback); - DCHECK(default_corpus_metadata); - DCHECK(team_drive_metadata); - - std::move(callback).Run(*default_corpus_metadata, *team_drive_metadata); -} - -void FileSystem::MarkCacheFileAsMounted(const base::FilePath& drive_file_path, - MarkMountedCallback callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - base::FilePath* cache_file_path = new base::FilePath; - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), FROM_HERE, - base::BindOnce(&MarkCacheFileAsMountedInternal, resource_metadata_, - cache_, drive_file_path, cache_file_path), - base::BindOnce(&RunMarkMountedCallback, std::move(callback), - base::Owned(cache_file_path))); -} - -void FileSystem::IsCacheFileMarkedAsMounted( - const base::FilePath& drive_file_path, - IsMountedCallback callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - bool* is_mounted = new bool(false); - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), FROM_HERE, - base::BindOnce(&IsCacheFileMarkedAsMountedInternal, resource_metadata_, - cache_, drive_file_path, is_mounted), - base::BindOnce(&RunIsMountedCallback, std::move(callback), - base::Owned(is_mounted))); -} - -void FileSystem::MarkCacheFileAsUnmounted( - const base::FilePath& cache_file_path, - const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - if (!cache_->IsUnderFileCacheDirectory(cache_file_path)) { - callback.Run(FILE_ERROR_FAILED); - return; - } - - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), - FROM_HERE, - base::Bind(&internal::FileCache::MarkAsUnmounted, - base::Unretained(cache_), - cache_file_path), - callback); -} - -void FileSystem::AddPermission(const base::FilePath& drive_file_path, - const std::string& email, - google_apis::drive::PermissionRole role, - const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - // Resolve the resource id. - ResourceEntry* const entry = new ResourceEntry; - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), - FROM_HERE, - base::Bind(&internal::ResourceMetadata::GetResourceEntryByPath, - base::Unretained(resource_metadata_), - drive_file_path, - entry), - base::Bind(&FileSystem::AddPermissionAfterGetResourceEntry, - weak_ptr_factory_.GetWeakPtr(), - email, - role, - callback, - base::Owned(entry))); -} - -void FileSystem::AddPermissionAfterGetResourceEntry( - const std::string& email, - google_apis::drive::PermissionRole role, - const FileOperationCallback& callback, - ResourceEntry* entry, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - if (error != FILE_ERROR_OK) { - callback.Run(error); - return; - } - - scheduler_->AddPermission( - entry->resource_id(), - email, - role, - base::Bind(&RunFileOperationCallbackAsEntryActionCallback, callback)); -} - -void FileSystem::SetProperty( - const base::FilePath& drive_file_path, - google_apis::drive::Property::Visibility visibility, - const std::string& key, - const std::string& value, - const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - set_property_operation_->SetProperty(drive_file_path, visibility, key, value, - callback); -} - -void FileSystem::OpenFile(const base::FilePath& file_path, - OpenMode open_mode, - const std::string& mime_type, - OpenFileCallback callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - open_file_operation_->OpenFile(file_path, open_mode, mime_type, - std::move(callback)); -} - -void FileSystem::GetPathFromResourceId(const std::string& resource_id, - const GetFilePathCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - base::FilePath* const file_path = new base::FilePath(); - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), - FROM_HERE, - base::Bind(&GetPathFromResourceIdOnBlockingPool, - resource_metadata_, - resource_id, - file_path), - base::Bind(&GetPathFromResourceIdAfterGetPath, - base::Owned(file_path), - callback)); -} - -void FileSystem::FreeDiskSpaceIfNeededFor( - int64_t num_bytes, - const FreeDiskSpaceCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), FROM_HERE, - base::Bind(&FreeDiskSpaceIfNeededForOnBlockingPool, cache_, num_bytes), - callback); -} - -void FileSystem::CalculateCacheSize(const CacheSizeCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), FROM_HERE, - base::Bind(&CalculateCacheSizeOnBlockingPool, cache_), callback); -} - -void FileSystem::CalculateEvictableCacheSize( - const CacheSizeCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), FROM_HERE, - base::Bind(&CalculateEvictableCacheSizeOnBlockingPool, cache_), callback); -} -} // namespace drive
diff --git a/components/drive/chromeos/file_system.h b/components/drive/chromeos/file_system.h deleted file mode 100644 index 6a238f3c3..0000000 --- a/components/drive/chromeos/file_system.h +++ /dev/null
@@ -1,336 +0,0 @@ -// Copyright (c) 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. - -#ifndef COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_H_ -#define COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_H_ - -#include <stdint.h> - -#include <map> -#include <memory> -#include <set> -#include <string> -#include <vector> - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "base/observer_list.h" -#include "base/threading/thread_checker.h" -#include "base/time/default_clock.h" -#include "components/drive/chromeos/change_list_loader_observer.h" -#include "components/drive/chromeos/drive_operation_queue.h" -#include "components/drive/chromeos/file_system/operation_delegate.h" -#include "components/drive/chromeos/file_system_interface.h" -#include "components/drive/chromeos/team_drive_change_list_loader.h" -#include "components/drive/chromeos/team_drive_list_observer.h" -#include "google_apis/drive/drive_api_error_codes.h" - -namespace base { -class SequencedTaskRunner; -} // namespace base - -namespace google_apis { -class AboutResource; -class ResourceEntry; -} // namespace google_apis - -namespace drive { -struct ClientContext; -class EventLogger; -class FileSystemObserver; -class JobScheduler; - -namespace internal { -class AboutResourceLoader; -class DriveChangeListLoader; -class FileCache; -class LoaderController; -class ResourceMetadata; -class SyncClient; -class TeamDrive; -} // namespace internal - -namespace file_system { -class CopyOperation; -class CreateDirectoryOperation; -class CreateFileOperation; -class DownloadOperation; -class GetFileForSavingOperation; -class MoveOperation; -class OpenFileOperation; -class RemoveOperation; -class SearchOperation; -class SetPropertyOperation; -class TouchOperation; -class TruncateOperation; -} // namespace file_system - -// The production implementation of FileSystemInterface. -class FileSystem : public FileSystemInterface, - public internal::ChangeListLoaderObserver, - public internal::TeamDriveListObserver, - public file_system::OperationDelegate { - public: - // |clock| can be mocked for testing. - FileSystem(EventLogger* logger, - internal::FileCache* cache, - JobScheduler* scheduler, - internal::ResourceMetadata* resource_metadata, - base::SequencedTaskRunner* blocking_task_runner, - const base::FilePath& temporary_file_directory, - const base::Clock* clock = base::DefaultClock::GetInstance()); - ~FileSystem() override; - - // FileSystemInterface overrides. - void AddObserver(FileSystemObserver* observer) override; - void RemoveObserver(FileSystemObserver* observer) override; - void CheckForUpdates() override; - void CheckForUpdates(const std::set<std::string>& ids) override; - void Search(const std::string& search_query, - const GURL& next_link, - SearchCallback callback) override; - void SearchMetadata(const std::string& query, - int options, - int at_most_num_matches, - MetadataSearchOrder order, - SearchMetadataCallback callback) override; - void SearchByHashes(const std::set<std::string>& hashes, - SearchByHashesCallback callback) override; - void TransferFileFromLocalToRemote( - const base::FilePath& local_src_file_path, - const base::FilePath& remote_dest_file_path, - const FileOperationCallback& callback) override; - void OpenFile(const base::FilePath& file_path, - OpenMode open_mode, - const std::string& mime_type, - OpenFileCallback callback) override; - void Copy(const base::FilePath& src_file_path, - const base::FilePath& dest_file_path, - bool preserve_last_modified, - const FileOperationCallback& callback) override; - void Move(const base::FilePath& src_file_path, - const base::FilePath& dest_file_path, - const FileOperationCallback& callback) override; - void Remove(const base::FilePath& file_path, - bool is_recursive, - const FileOperationCallback& callback) override; - void CreateDirectory(const base::FilePath& directory_path, - bool is_exclusive, - bool is_recursive, - const FileOperationCallback& callback) override; - void CreateFile(const base::FilePath& file_path, - bool is_exclusive, - const std::string& mime_type, - const FileOperationCallback& callback) override; - void TouchFile(const base::FilePath& file_path, - const base::Time& last_access_time, - const base::Time& last_modified_time, - const FileOperationCallback& callback) override; - void TruncateFile(const base::FilePath& file_path, - int64_t length, - const FileOperationCallback& callback) override; - void Pin(const base::FilePath& file_path, - const FileOperationCallback& callback) override; - void Unpin(const base::FilePath& file_path, - const FileOperationCallback& callback) override; - void GetFile(const base::FilePath& file_path, - GetFileCallback callback) override; - void GetFileForSaving(const base::FilePath& file_path, - GetFileCallback callback) override; - base::Closure GetFileContent( - const base::FilePath& file_path, - GetFileContentInitializedCallback initialized_callback, - const google_apis::GetContentCallback& get_content_callback, - const FileOperationCallback& completion_callback) override; - void GetResourceEntry(const base::FilePath& file_path, - GetResourceEntryCallback callback) override; - void ReadDirectory(const base::FilePath& directory_path, - ReadDirectoryEntriesCallback entries_callback, - const FileOperationCallback& completion_callback) override; - void GetAvailableSpace(GetAvailableSpaceCallback callback) override; - void GetMetadata(GetFilesystemMetadataCallback callback) override; - void MarkCacheFileAsMounted(const base::FilePath& drive_file_path, - MarkMountedCallback callback) override; - void IsCacheFileMarkedAsMounted(const base::FilePath& drive_file_path, - IsMountedCallback callback) override; - void MarkCacheFileAsUnmounted(const base::FilePath& cache_file_path, - const FileOperationCallback& callback) override; - void AddPermission(const base::FilePath& drive_file_path, - const std::string& email, - google_apis::drive::PermissionRole role, - const FileOperationCallback& callback) override; - void SetProperty(const base::FilePath& drive_file_path, - google_apis::drive::Property::Visibility visibility, - const std::string& key, - const std::string& value, - const FileOperationCallback& callback) override; - void Reset(const FileOperationCallback& callback) override; - void GetPathFromResourceId(const std::string& resource_id, - const GetFilePathCallback& callback) override; - void FreeDiskSpaceIfNeededFor(int64_t num_bytes, - const FreeDiskSpaceCallback& callback) override; - void CalculateCacheSize(const CacheSizeCallback& callback) override; - void CalculateEvictableCacheSize(const CacheSizeCallback& callback) override; - - // file_system::OperationDelegate overrides. - void OnFileChangedByOperation(const FileChange& changed_files) override; - void OnEntryUpdatedByOperation(const ClientContext& context, - const std::string& local_id) override; - void OnDriveSyncError(file_system::DriveSyncErrorType type, - const std::string& local_id) override; - bool WaitForSyncComplete(const std::string& local_id, - const FileOperationCallback& callback) override; - - // ChangeListLoader::Observer overrides. - // Used to propagate events from ChangeListLoader. - void OnDirectoryReloaded(const base::FilePath& directory_path) override; - void OnFileChanged(const FileChange& changed_files) override; - void OnTeamDrivesChanged(const FileChange& changed_team_drives) override; - void OnLoadFromServerComplete() override; - void OnInitialLoadComplete() override; - - // TeamDriveListObserver overrides. - void OnTeamDriveListLoaded( - const std::vector<internal::TeamDrive>& team_drives_list, - const std::vector<internal::TeamDrive>& added_team_drives, - const std::vector<internal::TeamDrive>& removed_team_drives) override; - - // Used by tests. - internal::DriveChangeListLoader* change_list_loader_for_testing() { - return default_corpus_change_list_loader_.get(); - } - internal::SyncClient* sync_client_for_testing() { return sync_client_.get(); } - - internal::DriveBackgroundOperationQueue<internal::TeamDriveChangeListLoader>* - team_drive_operation_queue_for_testing() { - return team_drive_operation_queue_.get(); - } - - private: - struct CreateDirectoryParams; - - // Used for initialization and Reset(). (Re-)initializes sub components that - // need to be recreated during the reset of resource metadata and the cache. - void ResetComponents(); - - // Part of CreateDirectory(). Called after ReadDirectory() - // is called and made sure that the resource metadata is loaded. - void CreateDirectoryAfterRead(const CreateDirectoryParams& params, - FileError error); - - void FinishPin(const FileOperationCallback& callback, - const std::string* local_id, - FileError error); - - void FinishUnpin(const FileOperationCallback& callback, - const std::string* local_id, - FileError error); - - // Callback for handling about resource fetch. - void OnGetAboutResource( - GetAvailableSpaceCallback callback, - google_apis::DriveApiErrorCode status, - std::unique_ptr<google_apis::AboutResource> about_resource); - - // Stores any file error as a result of Checking updates. - void OnUpdateChecked(const std::string& team_drive_id, - const base::RepeatingClosure& closure, - FileError error); - - // Part of CheckForUpdates(). Called when - // ChangeListLoader::CheckForUpdates() is complete. - void OnUpdateCompleted(); - - // Part of GetResourceEntry(). - // Called when ReadDirectory() is complete. - void GetResourceEntryAfterRead(const base::FilePath& file_path, - GetResourceEntryCallback callback, - FileError error); - - void OnGetMetadata( - GetFilesystemMetadataCallback callback, - drive::FileSystemMetadata* default_corpus_metadata, - std::map<std::string, drive::FileSystemMetadata>* team_drive_metadata); - - // Part of AddPermission. - void AddPermissionAfterGetResourceEntry( - const std::string& email, - google_apis::drive::PermissionRole role, - const FileOperationCallback& callback, - ResourceEntry* entry, - FileError error); - - // Part of OnDriveSyncError(). - virtual void OnDriveSyncErrorAfterGetFilePath( - file_system::DriveSyncErrorType type, - const base::FilePath* file_path, - FileError error); - - // Sub components owned by DriveIntegrationService. - EventLogger* logger_; - internal::FileCache* cache_; - JobScheduler* scheduler_; - internal::ResourceMetadata* resource_metadata_; - - // Stores debug update metadata for default corpus and team drive. - std::map<std::string, FileSystemMetadata> last_update_metadata_; - - // Used to load about resource. - std::unique_ptr<internal::AboutResourceLoader> about_resource_loader_; - - // Used to control ChangeListLoader. - std::unique_ptr<internal::LoaderController> loader_controller_; - - // Used to retrieve changelists from the default corpus. - std::unique_ptr<internal::DriveChangeListLoader> - default_corpus_change_list_loader_; - - std::unique_ptr<internal::DriveBackgroundOperationQueue< - internal::TeamDriveChangeListLoader>> - team_drive_operation_queue_; - - // Used to retrieve changelists for team drives. The key for the map is the - // team_drive_id. - std::map<std::string, std::unique_ptr<internal::TeamDriveChangeListLoader>> - team_drive_change_list_loaders_; - - std::unique_ptr<internal::SyncClient> sync_client_; - - base::ObserverList<FileSystemObserver>::Unchecked observers_; - - scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; - - base::FilePath temporary_file_directory_; - - const base::Clock* clock_; // Not owned. - - // Implementation of each file system operation. - std::unique_ptr<file_system::CopyOperation> copy_operation_; - std::unique_ptr<file_system::CreateDirectoryOperation> - create_directory_operation_; - std::unique_ptr<file_system::CreateFileOperation> create_file_operation_; - std::unique_ptr<file_system::MoveOperation> move_operation_; - std::unique_ptr<file_system::OpenFileOperation> open_file_operation_; - std::unique_ptr<file_system::RemoveOperation> remove_operation_; - std::unique_ptr<file_system::TouchOperation> touch_operation_; - std::unique_ptr<file_system::TruncateOperation> truncate_operation_; - std::unique_ptr<file_system::DownloadOperation> download_operation_; - std::unique_ptr<file_system::SearchOperation> search_operation_; - std::unique_ptr<file_system::GetFileForSavingOperation> - get_file_for_saving_operation_; - std::unique_ptr<file_system::SetPropertyOperation> set_property_operation_; - - THREAD_CHECKER(thread_checker_); - - // Note: This should remain the last member so it'll be destroyed and - // invalidate the weak pointers before any other members are destroyed. - base::WeakPtrFactory<FileSystem> weak_ptr_factory_{this}; - - DISALLOW_COPY_AND_ASSIGN(FileSystem); -}; - -} // namespace drive - -#endif // COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_H_
diff --git a/components/drive/chromeos/file_system/copy_operation.cc b/components/drive/chromeos/file_system/copy_operation.cc deleted file mode 100644 index 168c28c3..0000000 --- a/components/drive/chromeos/file_system/copy_operation.cc +++ /dev/null
@@ -1,677 +0,0 @@ -// Copyright (c) 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. - -#include "components/drive/chromeos/file_system/copy_operation.h" - -#include <stdint.h> - -#include <string> -#include <utility> - -#include "base/bind.h" -#include "base/task_runner_util.h" -#include "components/drive/chromeos/file_cache.h" -#include "components/drive/chromeos/file_system/create_file_operation.h" -#include "components/drive/chromeos/file_system/operation_delegate.h" -#include "components/drive/chromeos/resource_metadata.h" -#include "components/drive/drive.pb.h" -#include "components/drive/drive_api_util.h" -#include "components/drive/file_change.h" -#include "components/drive/file_system_core_util.h" -#include "components/drive/job_scheduler.h" -#include "components/drive/resource_entry_conversion.h" -#include "google_apis/drive/drive_api_parser.h" - -namespace drive { -namespace file_system { - -struct CopyOperation::CopyParams { - base::FilePath src_file_path; - base::FilePath dest_file_path; - bool preserve_last_modified; - FileOperationCallback callback; - ResourceEntry src_entry; - ResourceEntry parent_entry; -}; - -// Enum for categorizing where a gdoc represented by a JSON file exists. -enum JsonGdocLocationType { - NOT_IN_METADATA, - IS_ORPHAN, - HAS_PARENT, -}; - -struct CopyOperation::TransferJsonGdocParams { - TransferJsonGdocParams(const FileOperationCallback& callback, - const std::string& resource_id, - const ResourceEntry& parent_entry, - const std::string& new_title) - : callback(callback), - resource_id(resource_id), - parent_resource_id(parent_entry.resource_id()), - parent_local_id(parent_entry.local_id()), - new_title(new_title), - location_type(NOT_IN_METADATA) { - } - // Parameters supplied or calculated from operation arguments. - const FileOperationCallback callback; - const std::string resource_id; - const std::string parent_resource_id; - const std::string parent_local_id; - const std::string new_title; - - // Values computed during operation. - JsonGdocLocationType location_type; // types where the gdoc file is located. - std::string local_id; // the local_id of the file (if exists in metadata.) - base::FilePath changed_path; -}; - -namespace { - -FileError TryToCopyLocally(internal::ResourceMetadata* metadata, - internal::FileCache* cache, - CopyOperation::CopyParams* params, - std::vector<std::string>* updated_local_ids, - bool* directory_changed, - bool* should_copy_on_server) { - FileError error = metadata->GetResourceEntryByPath(params->src_file_path, - ¶ms->src_entry); - if (error != FILE_ERROR_OK) - return error; - - error = metadata->GetResourceEntryByPath(params->dest_file_path.DirName(), - ¶ms->parent_entry); - if (error != FILE_ERROR_OK) - return error; - - if (!params->parent_entry.file_info().is_directory()) - return FILE_ERROR_NOT_A_DIRECTORY; - - // Drive File System doesn't support recursive copy. - if (params->src_entry.file_info().is_directory()) - return FILE_ERROR_NOT_A_FILE; - - // Check destination. - ResourceEntry dest_entry; - error = metadata->GetResourceEntryByPath(params->dest_file_path, &dest_entry); - switch (error) { - case FILE_ERROR_OK: - // File API spec says it is an error to try to "copy a file to a path - // occupied by a directory". - if (dest_entry.file_info().is_directory()) - return FILE_ERROR_INVALID_OPERATION; - - // Move the existing entry to the trash. - dest_entry.set_parent_local_id(util::kDriveTrashDirLocalId); - error = metadata->RefreshEntry(dest_entry); - if (error != FILE_ERROR_OK) - return error; - updated_local_ids->push_back(dest_entry.local_id()); - *directory_changed = true; - break; - case FILE_ERROR_NOT_FOUND: - break; - default: - return error; - } - - // If the cache file is not present and the entry exists on the server, - // server side copy should be used. - if (!params->src_entry.file_specific_info().cache_state().is_present() && - !params->src_entry.resource_id().empty()) { - *should_copy_on_server = true; - return FILE_ERROR_OK; - } - - // Copy locally. - ResourceEntry entry; - const int64_t now = base::Time::Now().ToInternalValue(); - const int64_t last_modified = - params->preserve_last_modified - ? params->src_entry.file_info().last_modified() - : now; - entry.set_title(params->dest_file_path.BaseName().AsUTF8Unsafe()); - entry.set_parent_local_id(params->parent_entry.local_id()); - entry.mutable_file_specific_info()->set_content_mime_type( - params->src_entry.file_specific_info().content_mime_type()); - entry.set_metadata_edit_state(ResourceEntry::DIRTY); - entry.set_modification_date(base::Time::Now().ToInternalValue()); - entry.mutable_file_info()->set_last_modified(last_modified); - // preserve_last_modified=true preserves last_modified only. - // Regardless of preserve_last_modified's value, last_modified_by_me is - // always set to the same value as last_modified. - // This means that, even if preserve_last_modified=true, last_modified_by_me - // of the new file may differ from that of the original file. - // This behavior is due to the limitation in Drive API that we can not - // set different timestamps to last_modified and last_modified_by_me. - entry.set_last_modified_by_me(last_modified); - entry.mutable_file_info()->set_last_accessed(now); - - std::string local_id; - error = metadata->AddEntry(entry, &local_id); - if (error != FILE_ERROR_OK) - return error; - updated_local_ids->push_back(local_id); - *directory_changed = true; - - if (!params->src_entry.file_specific_info().cache_state().is_present()) { - DCHECK(params->src_entry.resource_id().empty()); - // Locally created empty file may have no cache file. - return FILE_ERROR_OK; - } - - base::FilePath cache_file_path; - error = cache->GetFile(params->src_entry.local_id(), &cache_file_path); - if (error != FILE_ERROR_OK) - return error; - - return cache->Store(local_id, std::string(), cache_file_path, - internal::FileCache::FILE_OPERATION_COPY); -} - -// Stores the entry returned from the server and returns its path. -FileError UpdateLocalStateForServerSideOperation( - internal::ResourceMetadata* metadata, - std::unique_ptr<google_apis::FileResource> file_resource, - ResourceEntry* entry, - base::FilePath* file_path) { - DCHECK(file_resource); - - std::string parent_resource_id; - ConvertFileResourceToResourceEntry(*file_resource, entry, - &parent_resource_id); - - if (parent_resource_id.empty()) - return FILE_ERROR_NOT_A_FILE; - - std::string parent_local_id; - FileError error = metadata->GetIdByResourceId(parent_resource_id, - &parent_local_id); - if (error != FILE_ERROR_OK) - return error; - entry->set_parent_local_id(parent_local_id); - - std::string local_id; - error = metadata->AddEntry(*entry, &local_id); - // Depending on timing, the metadata may have inserted via change list - // already. So, FILE_ERROR_EXISTS is not an error. - if (error == FILE_ERROR_EXISTS) - error = metadata->GetIdByResourceId(entry->resource_id(), &local_id); - - if (error != FILE_ERROR_OK) - return error; - - return metadata->GetFilePath(local_id, file_path); -} - -// Stores the file at |local_file_path| to the cache as a content of entry at -// |remote_dest_path|, and marks it dirty. -FileError UpdateLocalStateForScheduleTransfer( - internal::ResourceMetadata* metadata, - internal::FileCache* cache, - const base::FilePath& local_src_path, - const base::FilePath& remote_dest_path, - ResourceEntry* entry, - std::string* local_id) { - FileError error = metadata->GetIdByPath(remote_dest_path, local_id); - if (error != FILE_ERROR_OK) - return error; - - error = metadata->GetResourceEntryById(*local_id, entry); - if (error != FILE_ERROR_OK) - return error; - - return cache->Store(*local_id, std::string(), local_src_path, - internal::FileCache::FILE_OPERATION_COPY); -} - -// Gets the file size of the |local_path|, and the ResourceEntry for the parent -// of |remote_path| to prepare the necessary information for transfer. -FileError PrepareTransferFileFromLocalToRemote( - internal::ResourceMetadata* metadata, - const base::FilePath& local_src_path, - const base::FilePath& remote_dest_path, - std::string* gdoc_resource_id, - ResourceEntry* parent_entry) { - FileError error = metadata->GetResourceEntryByPath( - remote_dest_path.DirName(), parent_entry); - if (error != FILE_ERROR_OK) - return error; - - // The destination's parent must be a directory. - if (!parent_entry->file_info().is_directory()) - return FILE_ERROR_NOT_A_DIRECTORY; - - // Try to parse GDoc File and extract the resource id, if necessary. - // Failing isn't problem. It'd be handled as a regular file, then. - if (util::HasHostedDocumentExtension(local_src_path)) - *gdoc_resource_id = util::ReadResourceIdFromGDocFile(local_src_path); - return FILE_ERROR_OK; -} - -// Performs local work before server-side work for transferring JSON-represented -// gdoc files. -FileError LocalWorkForTransferJsonGdocFile( - internal::ResourceMetadata* metadata, - CopyOperation::TransferJsonGdocParams* params) { - std::string local_id; - FileError error = metadata->GetIdByResourceId(params->resource_id, &local_id); - if (error != FILE_ERROR_OK) { - params->location_type = NOT_IN_METADATA; - return error == FILE_ERROR_NOT_FOUND ? FILE_ERROR_OK : error; - } - - ResourceEntry entry; - error = metadata->GetResourceEntryById(local_id, &entry); - if (error != FILE_ERROR_OK) - return error; - params->local_id = entry.local_id(); - - if (entry.parent_local_id() == util::kDriveOtherDirLocalId) { - params->location_type = IS_ORPHAN; - entry.set_title(params->new_title); - entry.set_parent_local_id(params->parent_local_id); - entry.set_metadata_edit_state(ResourceEntry::DIRTY); - entry.set_modification_date(base::Time::Now().ToInternalValue()); - error = metadata->RefreshEntry(entry); - if (error != FILE_ERROR_OK) - return error; - return metadata->GetFilePath(local_id, ¶ms->changed_path); - } - - params->location_type = HAS_PARENT; - return FILE_ERROR_OK; -} - -} // namespace - -CopyOperation::CopyOperation(base::SequencedTaskRunner* blocking_task_runner, - OperationDelegate* delegate, - JobScheduler* scheduler, - internal::ResourceMetadata* metadata, - internal::FileCache* cache) - : blocking_task_runner_(blocking_task_runner), - delegate_(delegate), - scheduler_(scheduler), - metadata_(metadata), - cache_(cache), - create_file_operation_( - new CreateFileOperation(blocking_task_runner, delegate, metadata)) {} - -CopyOperation::~CopyOperation() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); -} - -void CopyOperation::Copy(const base::FilePath& src_file_path, - const base::FilePath& dest_file_path, - bool preserve_last_modified, - const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - CopyParams* params = new CopyParams; - params->src_file_path = src_file_path; - params->dest_file_path = dest_file_path; - params->preserve_last_modified = preserve_last_modified; - params->callback = callback; - - std::vector<std::string>* updated_local_ids = new std::vector<std::string>; - bool* directory_changed = new bool(false); - bool* should_copy_on_server = new bool(false); - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), - FROM_HERE, - base::Bind(&TryToCopyLocally, metadata_, cache_, params, - updated_local_ids, directory_changed, should_copy_on_server), - base::Bind(&CopyOperation::CopyAfterTryToCopyLocally, - weak_ptr_factory_.GetWeakPtr(), base::Owned(params), - base::Owned(updated_local_ids), base::Owned(directory_changed), - base::Owned(should_copy_on_server))); -} - -void CopyOperation::CopyAfterTryToCopyLocally( - const CopyParams* params, - const std::vector<std::string>* updated_local_ids, - const bool* directory_changed, - const bool* should_copy_on_server, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(params->callback); - - for (const auto& id : *updated_local_ids) { - // Syncing for copy should be done in background, so pass the BACKGROUND - // context. See: crbug.com/420278. - delegate_->OnEntryUpdatedByOperation(ClientContext(BACKGROUND), id); - } - - if (*directory_changed) { - FileChange changed_file; - DCHECK(!params->src_entry.file_info().is_directory()); - changed_file.Update(params->dest_file_path, FileChange::FILE_TYPE_FILE, - FileChange::CHANGE_TYPE_ADD_OR_UPDATE); - delegate_->OnFileChangedByOperation(changed_file); - } - - if (error != FILE_ERROR_OK || !*should_copy_on_server) { - params->callback.Run(error); - return; - } - - if (params->parent_entry.resource_id().empty()) { - // Parent entry may be being synced. - const bool waiting = delegate_->WaitForSyncComplete( - params->parent_entry.local_id(), - base::Bind(&CopyOperation::CopyAfterParentSync, - weak_ptr_factory_.GetWeakPtr(), *params)); - if (!waiting) - params->callback.Run(FILE_ERROR_NOT_FOUND); - } else { - CopyAfterGetParentResourceId(*params, ¶ms->parent_entry, FILE_ERROR_OK); - } -} - -void CopyOperation::CopyAfterParentSync(const CopyParams& params, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(params.callback); - - if (error != FILE_ERROR_OK) { - params.callback.Run(error); - return; - } - - ResourceEntry* parent = new ResourceEntry; - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), - FROM_HERE, - base::Bind(&internal::ResourceMetadata::GetResourceEntryById, - base::Unretained(metadata_), - params.parent_entry.local_id(), - parent), - base::Bind(&CopyOperation::CopyAfterGetParentResourceId, - weak_ptr_factory_.GetWeakPtr(), - params, - base::Owned(parent))); -} - -void CopyOperation::CopyAfterGetParentResourceId(const CopyParams& params, - const ResourceEntry* parent, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(params.callback); - - if (error != FILE_ERROR_OK) { - params.callback.Run(error); - return; - } - - base::FilePath new_title = params.dest_file_path.BaseName(); - if (params.src_entry.file_specific_info().is_hosted_document()) { - // Drop the document extension, which should not be in the title. - // TODO(yoshiki): Remove this code with crbug.com/223304. - new_title = new_title.RemoveExtension(); - } - - base::Time last_modified = - params.preserve_last_modified ? - base::Time::FromInternalValue( - params.src_entry.file_info().last_modified()) : base::Time(); - - CopyResourceOnServer( - params.src_entry.resource_id(), parent->resource_id(), - new_title.AsUTF8Unsafe(), last_modified, params.callback); -} - -void CopyOperation::TransferFileFromLocalToRemote( - const base::FilePath& local_src_path, - const base::FilePath& remote_dest_path, - const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - std::string* gdoc_resource_id = new std::string; - ResourceEntry* parent_entry = new ResourceEntry; - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), - FROM_HERE, - base::Bind( - &PrepareTransferFileFromLocalToRemote, - metadata_, local_src_path, remote_dest_path, - gdoc_resource_id, parent_entry), - base::Bind( - &CopyOperation::TransferFileFromLocalToRemoteAfterPrepare, - weak_ptr_factory_.GetWeakPtr(), - local_src_path, remote_dest_path, callback, - base::Owned(gdoc_resource_id), base::Owned(parent_entry))); -} - -void CopyOperation::TransferFileFromLocalToRemoteAfterPrepare( - const base::FilePath& local_src_path, - const base::FilePath& remote_dest_path, - const FileOperationCallback& callback, - std::string* gdoc_resource_id, - ResourceEntry* parent_entry, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - if (error != FILE_ERROR_OK) { - callback.Run(error); - return; - } - - // For regular files, schedule the transfer. - if (gdoc_resource_id->empty()) { - ScheduleTransferRegularFile(local_src_path, remote_dest_path, callback); - return; - } - - // GDoc file may contain a resource ID in the old format. - const std::string canonicalized_resource_id = - util::CanonicalizeResourceId(*gdoc_resource_id); - - // Drop the document extension, which should not be in the title. - // TODO(yoshiki): Remove this code with crbug.com/223304. - const std::string new_title = - remote_dest_path.BaseName().RemoveExtension().AsUTF8Unsafe(); - - // This is uploading a JSON file representing a hosted document. - TransferJsonGdocParams* params = new TransferJsonGdocParams( - callback, canonicalized_resource_id, *parent_entry, new_title); - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), - FROM_HERE, - base::Bind(&LocalWorkForTransferJsonGdocFile, metadata_, params), - base::Bind(&CopyOperation::TransferJsonGdocFileAfterLocalWork, - weak_ptr_factory_.GetWeakPtr(), base::Owned(params))); -} - -void CopyOperation::TransferJsonGdocFileAfterLocalWork( - TransferJsonGdocParams* params, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - if (error != FILE_ERROR_OK) { - params->callback.Run(error); - return; - } - - switch (params->location_type) { - // When |resource_id| is found in the local metadata and it has a specific - // parent folder, we assume the user's intention is to copy the document and - // thus perform the server-side copy operation. - case HAS_PARENT: - CopyResourceOnServer(params->resource_id, - params->parent_resource_id, - params->new_title, - base::Time(), - params->callback); - break; - // When |resource_id| has no parent, we just set the new destination folder - // as the parent, for sharing the document between the original source. - // This reparenting is already done in LocalWorkForTransferJsonGdocFile(). - case IS_ORPHAN: { - DCHECK(!params->changed_path.empty()); - // Syncing for copy should be done in background, so pass the BACKGROUND - // context. See: crbug.com/420278. - delegate_->OnEntryUpdatedByOperation(ClientContext(BACKGROUND), - params->local_id); - - FileChange changed_file; - changed_file.Update( - params->changed_path, - FileChange::FILE_TYPE_FILE, // This must be a hosted document. - FileChange::CHANGE_TYPE_ADD_OR_UPDATE); - delegate_->OnFileChangedByOperation(changed_file); - params->callback.Run(error); - break; - } - // When the |resource_id| is not in the local metadata, assume it to be a - // document just now shared on the server but not synced locally. - // Same as the IS_ORPHAN case, we want to deal the case by setting parent, - // but this time we need to resort to server side operation. - case NOT_IN_METADATA: - scheduler_->UpdateResource( - params->resource_id, params->parent_resource_id, params->new_title, - base::Time(), base::Time(), google_apis::drive::Properties(), - ClientContext(USER_INITIATED), - base::Bind(&CopyOperation::UpdateAfterServerSideOperation, - weak_ptr_factory_.GetWeakPtr(), params->callback)); - break; - } -} - -void CopyOperation::CopyResourceOnServer( - const std::string& resource_id, - const std::string& parent_resource_id, - const std::string& new_title, - const base::Time& last_modified, - const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - scheduler_->CopyResource( - resource_id, parent_resource_id, new_title, last_modified, - base::Bind(&CopyOperation::UpdateAfterServerSideOperation, - weak_ptr_factory_.GetWeakPtr(), - callback)); -} - -void CopyOperation::UpdateAfterServerSideOperation( - const FileOperationCallback& callback, - google_apis::DriveApiErrorCode status, - std::unique_ptr<google_apis::FileResource> entry) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - FileError error = GDataToFileError(status); - if (error != FILE_ERROR_OK) { - callback.Run(error); - return; - } - - ResourceEntry* resource_entry = new ResourceEntry; - - // The copy on the server side is completed successfully. Update the local - // metadata. - base::FilePath* file_path = new base::FilePath; - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), FROM_HERE, - base::BindOnce(&UpdateLocalStateForServerSideOperation, metadata_, - std::move(entry), resource_entry, file_path), - base::BindOnce(&CopyOperation::UpdateAfterLocalStateUpdate, - weak_ptr_factory_.GetWeakPtr(), callback, - base::Owned(file_path), base::Owned(resource_entry))); -} - -void CopyOperation::UpdateAfterLocalStateUpdate( - const FileOperationCallback& callback, - base::FilePath* file_path, - const ResourceEntry* entry, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - if (error == FILE_ERROR_OK) { - FileChange changed_file; - changed_file.Update(*file_path, *entry, - FileChange::CHANGE_TYPE_ADD_OR_UPDATE); - delegate_->OnFileChangedByOperation(changed_file); - } - callback.Run(error); -} - -void CopyOperation::ScheduleTransferRegularFile( - const base::FilePath& local_src_path, - const base::FilePath& remote_dest_path, - const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - create_file_operation_->CreateFile( - remote_dest_path, - false, // Not exclusive (OK even if a file already exists). - std::string(), // no specific mime type; CreateFile should guess it. - base::Bind(&CopyOperation::ScheduleTransferRegularFileAfterCreate, - weak_ptr_factory_.GetWeakPtr(), - local_src_path, remote_dest_path, callback)); -} - -void CopyOperation::ScheduleTransferRegularFileAfterCreate( - const base::FilePath& local_src_path, - const base::FilePath& remote_dest_path, - const FileOperationCallback& callback, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - if (error != FILE_ERROR_OK) { - callback.Run(error); - return; - } - - std::string* local_id = new std::string; - ResourceEntry* entry = new ResourceEntry; - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), - FROM_HERE, - base::Bind(&UpdateLocalStateForScheduleTransfer, - metadata_, - cache_, - local_src_path, - remote_dest_path, - entry, - local_id), - base::Bind( - &CopyOperation::ScheduleTransferRegularFileAfterUpdateLocalState, - weak_ptr_factory_.GetWeakPtr(), - callback, - remote_dest_path, - base::Owned(entry), - base::Owned(local_id))); -} - -void CopyOperation::ScheduleTransferRegularFileAfterUpdateLocalState( - const FileOperationCallback& callback, - const base::FilePath& remote_dest_path, - const ResourceEntry* entry, - std::string* local_id, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - if (error == FILE_ERROR_OK) { - FileChange changed_file; - changed_file.Update(remote_dest_path, *entry, - FileChange::CHANGE_TYPE_ADD_OR_UPDATE); - delegate_->OnFileChangedByOperation(changed_file); - // Syncing for copy should be done in background, so pass the BACKGROUND - // context. See: crbug.com/420278. - delegate_->OnEntryUpdatedByOperation(ClientContext(BACKGROUND), *local_id); - } - callback.Run(error); -} - -} // namespace file_system -} // namespace drive
diff --git a/components/drive/chromeos/file_system/copy_operation.h b/components/drive/chromeos/file_system/copy_operation.h deleted file mode 100644 index c1854ee..0000000 --- a/components/drive/chromeos/file_system/copy_operation.h +++ /dev/null
@@ -1,183 +0,0 @@ -// Copyright (c) 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. - -#ifndef COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_COPY_OPERATION_H_ -#define COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_COPY_OPERATION_H_ - -#include <memory> -#include <string> -#include <vector> - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "base/threading/thread_checker.h" -#include "components/drive/file_errors.h" -#include "google_apis/drive/drive_api_error_codes.h" - -namespace base { -class FilePath; -class SequencedTaskRunner; -class Time; -} // namespace base - -namespace google_apis { -class FileResource; -} // namespace google_apis - -namespace drive { - -class JobScheduler; -class ResourceEntry; - -namespace internal { -class FileCache; -class ResourceMetadata; -} // namespace internal - -namespace file_system { - -class CreateFileOperation; -class OperationDelegate; - -// This class encapsulates the drive Copy function. It is responsible for -// sending the request to the drive API, then updating the local state and -// metadata to reflect the new state. -class CopyOperation { - public: - CopyOperation(base::SequencedTaskRunner* blocking_task_runner, - OperationDelegate* delegate, - JobScheduler* scheduler, - internal::ResourceMetadata* metadata, - internal::FileCache* cache); - ~CopyOperation(); - - // Performs the copy operation on the file at drive path |src_file_path| - // with a target of |dest_file_path|. - // If |preserve_last_modified| is set to true, this tries to preserve - // last modified time stamp. This is supported only on Drive API v2. - // Regardless of preserve_last_modified's value, last_modified_by_me timestamp - // will always be set to the same timestamp as last_modified. - // Invokes |callback| when finished with the result of the operation. - // |callback| must not be null. - void Copy(const base::FilePath& src_file_path, - const base::FilePath& dest_file_path, - bool preserve_last_modified, - const FileOperationCallback& callback); - - // Initiates transfer of |local_src_file_path| to |remote_dest_file_path|. - // |local_src_file_path| must be a file from the local file system. - // |remote_dest_file_path| is the virtual destination path within Drive file - // system. - // - // |callback| must not be null. - void TransferFileFromLocalToRemote( - const base::FilePath& local_src_file_path, - const base::FilePath& remote_dest_file_path, - const FileOperationCallback& callback); - - // Params for Copy(). - struct CopyParams; - - // Params for TransferJsonGdocFileAfterLocalWork. - struct TransferJsonGdocParams; - - private: - // Part of Copy(). Called after trying to copy locally. - void CopyAfterTryToCopyLocally( - const CopyParams* params, - const std::vector<std::string>* updated_local_ids, - const bool* directory_changed, - const bool* should_copy_on_server, - FileError error); - - // Part of Copy(). Called after the parent entry gets synced. - void CopyAfterParentSync(const CopyParams& params, FileError error); - - // Part of Copy(). Called after the parent resource ID is resolved. - void CopyAfterGetParentResourceId(const CopyParams& params, - const ResourceEntry* parent, - FileError error); - - // Part of TransferFileFromLocalToRemote(). Called after preparation is done. - // |gdoc_resource_id| and |parent_resource_id| is available only if the file - // is JSON GDoc file. - void TransferFileFromLocalToRemoteAfterPrepare( - const base::FilePath& local_src_path, - const base::FilePath& remote_dest_path, - const FileOperationCallback& callback, - std::string* gdoc_resource_id, - ResourceEntry* parent_entry, - FileError error); - - // Part of TransferFileFromLocalToRemote(). - void TransferJsonGdocFileAfterLocalWork(TransferJsonGdocParams* params, - FileError error); - - // Copies resource with |resource_id| into the directory |parent_resource_id| - // with renaming it to |new_title|. - void CopyResourceOnServer(const std::string& resource_id, - const std::string& parent_resource_id, - const std::string& new_title, - const base::Time& last_modified, - const FileOperationCallback& callback); - - // Part of CopyResourceOnServer and TransferFileFromLocalToRemote. - // Called after server side operation is done. - void UpdateAfterServerSideOperation( - const FileOperationCallback& callback, - google_apis::DriveApiErrorCode status, - std::unique_ptr<google_apis::FileResource> entry); - - // Part of CopyResourceOnServer and TransferFileFromLocalToRemote. - // Called after local state update is done. - void UpdateAfterLocalStateUpdate(const FileOperationCallback& callback, - base::FilePath* file_path, - const ResourceEntry* entry, - FileError error); - - // Creates an empty file on the server at |remote_dest_path| to ensure - // the location, stores a file at |local_file_path| in cache and marks it - // dirty, so that SyncClient will upload the data later. - void ScheduleTransferRegularFile(const base::FilePath& local_src_path, - const base::FilePath& remote_dest_path, - const FileOperationCallback& callback); - - // Part of ScheduleTransferRegularFile(). Called after file creation. - void ScheduleTransferRegularFileAfterCreate( - const base::FilePath& local_src_path, - const base::FilePath& remote_dest_path, - const FileOperationCallback& callback, - FileError error); - - // Part of ScheduleTransferRegularFile(). Called after updating local state - // is completed. - void ScheduleTransferRegularFileAfterUpdateLocalState( - const FileOperationCallback& callback, - const base::FilePath& remote_dest_path, - const ResourceEntry* entry, - std::string* local_id, - FileError error); - - scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; - OperationDelegate* delegate_; - JobScheduler* scheduler_; - internal::ResourceMetadata* metadata_; - internal::FileCache* cache_; - - // Uploading a new file is internally implemented by creating a dirty file. - std::unique_ptr<CreateFileOperation> create_file_operation_; - - THREAD_CHECKER(thread_checker_); - - // Note: This should remain the last member so it'll be destroyed and - // invalidate the weak pointers before any other members are destroyed. - base::WeakPtrFactory<CopyOperation> weak_ptr_factory_{this}; - DISALLOW_COPY_AND_ASSIGN(CopyOperation); -}; - -} // namespace file_system -} // namespace drive - -#endif // COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_COPY_OPERATION_H_
diff --git a/components/drive/chromeos/file_system/create_directory_operation.cc b/components/drive/chromeos/file_system/create_directory_operation.cc deleted file mode 100644 index 464c55d..0000000 --- a/components/drive/chromeos/file_system/create_directory_operation.cc +++ /dev/null
@@ -1,184 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/drive/chromeos/file_system/create_directory_operation.h" - -#include <stddef.h> - -#include "base/bind.h" -#include "components/drive/chromeos/file_system/operation_delegate.h" -#include "components/drive/chromeos/resource_metadata.h" -#include "components/drive/drive.pb.h" -#include "components/drive/file_change.h" -#include "components/drive/file_system_core_util.h" -#include "components/drive/job_scheduler.h" - -namespace drive { -namespace file_system { - -namespace { - -FileError CreateDirectoryRecursively(internal::ResourceMetadata* metadata, - const std::string& parent_local_id, - const base::FilePath& relative_file_path, - std::set<std::string>* updated_local_ids, - FileChange* changed_files) { - // Split the first component and remaining ones of |relative_file_path|. - std::vector<base::FilePath::StringType> components; - relative_file_path.GetComponents(&components); - DCHECK(!components.empty()); - base::FilePath title(components[0]); - base::FilePath remaining_path; - title.AppendRelativePath(relative_file_path, &remaining_path); - - ResourceEntry entry; - const int64_t now = base::Time::Now().ToInternalValue(); - entry.set_title(title.AsUTF8Unsafe()); - entry.mutable_file_info()->set_is_directory(true); - entry.mutable_file_info()->set_last_modified(now); - entry.set_last_modified_by_me(now); - entry.mutable_file_info()->set_last_accessed(now); - entry.set_parent_local_id(parent_local_id); - entry.set_metadata_edit_state(ResourceEntry::DIRTY); - entry.set_modification_date(base::Time::Now().ToInternalValue()); - - std::string local_id; - FileError error = metadata->AddEntry(entry, &local_id); - if (error != FILE_ERROR_OK) - return error; - - base::FilePath path; - error = metadata->GetFilePath(local_id, &path); - if (error != FILE_ERROR_OK) - return error; - - updated_local_ids->insert(local_id); - DCHECK(changed_files); - changed_files->Update(path, FileChange::FILE_TYPE_DIRECTORY, - FileChange::CHANGE_TYPE_ADD_OR_UPDATE); - - if (remaining_path.empty()) // All directories are created successfully. - return FILE_ERROR_OK; - - // Create descendant directories. - return CreateDirectoryRecursively( - metadata, local_id, remaining_path, updated_local_ids, changed_files); -} - -FileError UpdateLocalState(internal::ResourceMetadata* metadata, - const base::FilePath& directory_path, - bool is_exclusive, - bool is_recursive, - std::set<std::string>* updated_local_ids, - FileChange* changed_files) { - // Get the existing deepest entry. - std::vector<base::FilePath::StringType> components; - directory_path.GetComponents(&components); - - if (components.empty() || - components[0] != util::GetDriveGrandRootPath().value()) - return FILE_ERROR_NOT_FOUND; - - base::FilePath existing_deepest_path(components[0]); - std::string local_id = util::kDriveGrandRootLocalId; - for (size_t i = 1; i < components.size(); ++i) { - const std::string component = base::FilePath(components[i]).AsUTF8Unsafe(); - std::string child_local_id; - FileError error = - metadata->GetChildId(local_id, component, &child_local_id); - if (error == FILE_ERROR_NOT_FOUND) - break; - if (error != FILE_ERROR_OK) - return error; - existing_deepest_path = existing_deepest_path.Append(components[i]); - local_id = child_local_id; - } - - ResourceEntry entry; - FileError error = metadata->GetResourceEntryById(local_id, &entry); - if (error != FILE_ERROR_OK) - return error; - - if (!entry.file_info().is_directory()) - return FILE_ERROR_NOT_A_DIRECTORY; - - if (directory_path == existing_deepest_path) - return is_exclusive ? FILE_ERROR_EXISTS : FILE_ERROR_OK; - - // If it is not recursive creation, the found directory must be the direct - // parent of |directory_path| to ensure creating exact one directory. - if (!is_recursive && existing_deepest_path != directory_path.DirName()) - return FILE_ERROR_NOT_FOUND; - - // Create directories under the found directory. - base::FilePath remaining_path; - existing_deepest_path.AppendRelativePath(directory_path, &remaining_path); - return CreateDirectoryRecursively(metadata, - entry.local_id(), - remaining_path, - updated_local_ids, - changed_files); -} - -} // namespace - -CreateDirectoryOperation::CreateDirectoryOperation( - base::SequencedTaskRunner* blocking_task_runner, - OperationDelegate* delegate, - internal::ResourceMetadata* metadata) - : blocking_task_runner_(blocking_task_runner), - delegate_(delegate), - metadata_(metadata) {} - -CreateDirectoryOperation::~CreateDirectoryOperation() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); -} - -void CreateDirectoryOperation::CreateDirectory( - const base::FilePath& directory_path, - bool is_exclusive, - bool is_recursive, - const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - std::set<std::string>* updated_local_ids = new std::set<std::string>; - FileChange* changed_files(new FileChange); - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), - FROM_HERE, - base::Bind(&UpdateLocalState, - metadata_, - directory_path, - is_exclusive, - is_recursive, - updated_local_ids, - changed_files), - base::Bind( - &CreateDirectoryOperation::CreateDirectoryAfterUpdateLocalState, - weak_ptr_factory_.GetWeakPtr(), - callback, - base::Owned(updated_local_ids), - base::Owned(changed_files))); -} - -void CreateDirectoryOperation::CreateDirectoryAfterUpdateLocalState( - const FileOperationCallback& callback, - const std::set<std::string>* updated_local_ids, - const FileChange* changed_files, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - for (const auto& id : *updated_local_ids) { - delegate_->OnEntryUpdatedByOperation(ClientContext(USER_INITIATED), id); - } - - delegate_->OnFileChangedByOperation(*changed_files); - - callback.Run(error); -} - -} // namespace file_system -} // namespace drive
diff --git a/components/drive/chromeos/file_system/create_directory_operation.h b/components/drive/chromeos/file_system/create_directory_operation.h deleted file mode 100644 index bf16bbb..0000000 --- a/components/drive/chromeos/file_system/create_directory_operation.h +++ /dev/null
@@ -1,78 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_CREATE_DIRECTORY_OPERATION_H_ -#define COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_CREATE_DIRECTORY_OPERATION_H_ - -#include <set> - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "base/threading/thread_checker.h" -#include "components/drive/file_errors.h" - -namespace base { -class FilePath; -class SequencedTaskRunner; -} // namespace base - -namespace drive { - -class FileChange; - -namespace internal { -class ResourceMetadata; -} // namespace internal - -namespace file_system { - -class OperationDelegate; - -// This class encapsulates the drive Create Directory function. It is -// responsible for sending the request to the drive API, then updating the -// local state and metadata to reflect the new state. -class CreateDirectoryOperation { - public: - CreateDirectoryOperation(base::SequencedTaskRunner* blocking_task_runner, - OperationDelegate* delegate, - internal::ResourceMetadata* metadata); - ~CreateDirectoryOperation(); - - // Creates a new directory at |directory_path|. - // If |is_exclusive| is true, an error is raised in case a directory exists - // already at the |directory_path|. - // If |is_recursive| is true, the invocation creates parent directories as - // needed just like mkdir -p does. - // Invokes |callback| when finished with the result of the operation. - // |callback| must not be null. - void CreateDirectory(const base::FilePath& directory_path, - bool is_exclusive, - bool is_recursive, - const FileOperationCallback& callback); - - private: - // Part of CreateDirectory(). Called after UpdateLocalState(). - void CreateDirectoryAfterUpdateLocalState( - const FileOperationCallback& callback, - const std::set<std::string>* updated_local_ids, - const FileChange* changed_directories, - FileError error); - - scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; - OperationDelegate* delegate_; - internal::ResourceMetadata* metadata_; - - THREAD_CHECKER(thread_checker_); - - // Note: This should remain the last member so it'll be destroyed and - // invalidate the weak pointers before any other members are destroyed. - base::WeakPtrFactory<CreateDirectoryOperation> weak_ptr_factory_{this}; - DISALLOW_COPY_AND_ASSIGN(CreateDirectoryOperation); -}; - -} // namespace file_system -} // namespace drive - -#endif // COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_CREATE_DIRECTORY_OPERATION_H_
diff --git a/components/drive/chromeos/file_system/create_file_operation.cc b/components/drive/chromeos/file_system/create_file_operation.cc deleted file mode 100644 index 657a9db..0000000 --- a/components/drive/chromeos/file_system/create_file_operation.cc +++ /dev/null
@@ -1,139 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/drive/chromeos/file_system/create_file_operation.h" - -#include <string> - -#include "base/bind.h" -#include "base/files/file_util.h" -#include "components/drive/chromeos/file_system/operation_delegate.h" -#include "components/drive/chromeos/resource_metadata.h" -#include "components/drive/drive.pb.h" -#include "components/drive/file_change.h" -#include "components/drive/job_scheduler.h" -#include "net/base/mime_util.h" - -namespace drive { -namespace file_system { - -namespace { - -const char kMimeTypeOctetStream[] = "application/octet-stream"; - -// Updates local state. -FileError UpdateLocalState(internal::ResourceMetadata* metadata, - const base::FilePath& file_path, - const std::string& mime_type_in, - ResourceEntry* entry) { - DCHECK(metadata); - - FileError error = metadata->GetResourceEntryByPath(file_path, entry); - if (error == FILE_ERROR_OK) - return FILE_ERROR_EXISTS; - - if (error != FILE_ERROR_NOT_FOUND) - return error; - - // If parent path is not a directory, it is an error. - ResourceEntry parent; - if (metadata->GetResourceEntryByPath( - file_path.DirName(), &parent) != FILE_ERROR_OK || - !parent.file_info().is_directory()) - return FILE_ERROR_NOT_A_DIRECTORY; - - // If mime_type is not set or "application/octet-stream", guess from the - // |file_path|. If it is still unsure, use octet-stream by default. - std::string mime_type = mime_type_in; - if ((mime_type.empty() || mime_type == kMimeTypeOctetStream) && - !net::GetMimeTypeFromFile(file_path, &mime_type)) - mime_type = kMimeTypeOctetStream; - - // Add the entry to the local resource metadata. - const int64_t now = base::Time::Now().ToInternalValue(); - entry->mutable_file_info()->set_last_modified(now); - entry->set_last_modified_by_me(now); - entry->mutable_file_info()->set_last_accessed(now); - entry->set_title(file_path.BaseName().AsUTF8Unsafe()); - entry->set_parent_local_id(parent.local_id()); - entry->set_metadata_edit_state(ResourceEntry::DIRTY); - entry->set_modification_date(base::Time::Now().ToInternalValue()); - entry->mutable_file_specific_info()->set_content_mime_type(mime_type); - - std::string local_id; - error = metadata->AddEntry(*entry, &local_id); - entry->set_local_id(local_id); - return error; -} - -} // namespace - -CreateFileOperation::CreateFileOperation( - base::SequencedTaskRunner* blocking_task_runner, - OperationDelegate* delegate, - internal::ResourceMetadata* metadata) - : blocking_task_runner_(blocking_task_runner), - delegate_(delegate), - metadata_(metadata) {} - -CreateFileOperation::~CreateFileOperation() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); -} - -void CreateFileOperation::CreateFile(const base::FilePath& file_path, - bool is_exclusive, - const std::string& mime_type, - const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - ResourceEntry* entry = new ResourceEntry; - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), - FROM_HERE, - base::Bind(&UpdateLocalState, - metadata_, - file_path, - mime_type, - entry), - base::Bind(&CreateFileOperation::CreateFileAfterUpdateLocalState, - weak_ptr_factory_.GetWeakPtr(), - callback, - file_path, - is_exclusive, - base::Owned(entry))); -} - -void CreateFileOperation::CreateFileAfterUpdateLocalState( - const FileOperationCallback& callback, - const base::FilePath& file_path, - bool is_exclusive, - ResourceEntry* entry, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - if (error == FILE_ERROR_EXISTS) { - // Error if an exclusive mode is requested, or the entry is not a file. - error = (is_exclusive || - entry->file_info().is_directory() || - entry->file_specific_info().is_hosted_document()) ? - FILE_ERROR_EXISTS : FILE_ERROR_OK; - } else if (error == FILE_ERROR_OK) { - DCHECK(!entry->file_info().is_directory()); - - // Notify delegate if the file was newly created. - FileChange changed_file; - changed_file.Update(file_path, FileChange::FILE_TYPE_FILE, - FileChange::CHANGE_TYPE_ADD_OR_UPDATE); - delegate_->OnFileChangedByOperation(changed_file); - // Synchronize in the background. - delegate_->OnEntryUpdatedByOperation(ClientContext(BACKGROUND), - entry->local_id()); - } - callback.Run(error); -} - -} // namespace file_system -} // namespace drive
diff --git a/components/drive/chromeos/file_system/create_file_operation.h b/components/drive/chromeos/file_system/create_file_operation.h deleted file mode 100644 index 2d8ca6d..0000000 --- a/components/drive/chromeos/file_system/create_file_operation.h +++ /dev/null
@@ -1,76 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_CREATE_FILE_OPERATION_H_ -#define COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_CREATE_FILE_OPERATION_H_ - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "base/threading/thread_checker.h" -#include "components/drive/file_errors.h" - -namespace base { -class FilePath; -class SequencedTaskRunner; -} // namespace base - -namespace drive { - -namespace internal { -class ResourceMetadata; -} // namespace internal - -class ResourceEntry; - -namespace file_system { - -class OperationDelegate; - -// This class encapsulates the drive CreateFile function. It is responsible for -// sending the request to the drive API, then updating the local state and -// metadata to reflect the new state. -class CreateFileOperation { - public: - CreateFileOperation(base::SequencedTaskRunner* blocking_task_runner, - OperationDelegate* delegate, - internal::ResourceMetadata* metadata); - ~CreateFileOperation(); - - // Creates an empty file at |file_path|. When the file - // already exists at that path, the operation fails if |is_exclusive| is true, - // and it succeeds without doing anything if the flag is false. - // If |mime_type| is non-empty, it is used as the mime type of the entry. If - // the parameter is empty, the type is guessed from |file_path|. - // - // |callback| must not be null. - void CreateFile(const base::FilePath& file_path, - bool is_exclusive, - const std::string& mime_type, - const FileOperationCallback& callback); - - private: - // Part of CreateFile(). Called after the updating local state is completed. - void CreateFileAfterUpdateLocalState(const FileOperationCallback& callback, - const base::FilePath& file_path, - bool is_exclusive, - ResourceEntry* entry, - FileError error); - - scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; - OperationDelegate* delegate_; - internal::ResourceMetadata* metadata_; - - THREAD_CHECKER(thread_checker_); - - // Note: This should remain the last member so it'll be destroyed and - // invalidate the weak pointers before any other members are destroyed. - base::WeakPtrFactory<CreateFileOperation> weak_ptr_factory_{this}; - DISALLOW_COPY_AND_ASSIGN(CreateFileOperation); -}; - -} // namespace file_system -} // namespace drive - -#endif // COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_CREATE_FILE_OPERATION_H_
diff --git a/components/drive/chromeos/file_system/download_operation.cc b/components/drive/chromeos/file_system/download_operation.cc deleted file mode 100644 index 5c84c74..0000000 --- a/components/drive/chromeos/file_system/download_operation.cc +++ /dev/null
@@ -1,523 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/drive/chromeos/file_system/download_operation.h" - -#include <stdint.h> - -#include <utility> - -#include "base/bind.h" -#include "base/callback_helpers.h" -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/logging.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/task_runner_util.h" -#include "components/drive/chromeos/file_cache.h" -#include "components/drive/chromeos/file_system/operation_delegate.h" -#include "components/drive/chromeos/resource_metadata.h" -#include "components/drive/drive.pb.h" -#include "components/drive/file_change.h" -#include "components/drive/file_errors.h" -#include "components/drive/file_system_core_util.h" -#include "components/drive/job_scheduler.h" -#include "google_apis/drive/drive_api_error_codes.h" - -namespace drive { -namespace file_system { -namespace { - -// Generates an unused file path with |extension| to |out_path|, as a descendant -// of |dir|, with its parent directory created. -bool GeneratesUniquePathWithExtension( - const base::FilePath& dir, - const base::FilePath::StringType& extension, - base::FilePath* out_path) { - base::FilePath subdir; - if (!base::CreateTemporaryDirInDir(dir, base::FilePath::StringType(), - &subdir)) { - return false; - } - *out_path = subdir.Append(FILE_PATH_LITERAL("tmp") + extension); - return true; -} - -// Prepares for downloading the file. Allocates the enough space for the file -// in the cache. -// If succeeded, returns FILE_ERROR_OK with |temp_download_file| storing the -// path to the file in the cache. -FileError PrepareForDownloadFile(internal::FileCache* cache, - int64_t expected_file_size, - const base::FilePath& temporary_file_directory, - base::FilePath* temp_download_file) { - DCHECK(cache); - DCHECK(temp_download_file); - - // Ensure enough space in the cache. - if (!cache->FreeDiskSpaceIfNeededFor(expected_file_size)) - return FILE_ERROR_NO_LOCAL_SPACE; - - return base::CreateTemporaryFileInDir( - temporary_file_directory, - temp_download_file) ? FILE_ERROR_OK : FILE_ERROR_FAILED; -} - -// If the resource is a hosted document, creates a JSON file representing the -// resource locally, and returns FILE_ERROR_OK with |cache_file_path| storing -// the path to the JSON file. -// If the resource is a regular file and its local cache is available, -// returns FILE_ERROR_OK with |cache_file_path| storing the path to the -// cache file. -// If the resource is a regular file but its local cache is NOT available, -// returns FILE_ERROR_OK, but |cache_file_path| is kept empty. -// Otherwise returns error code. -FileError CheckPreConditionForEnsureFileDownloaded( - internal::ResourceMetadata* metadata, - internal::FileCache* cache, - const base::FilePath& temporary_file_directory, - const std::string& local_id, - ResourceEntry* entry, - base::FilePath* cache_file_path, - base::FilePath* temp_download_file_path) { - DCHECK(metadata); - DCHECK(cache); - DCHECK(cache_file_path); - - FileError error = metadata->GetResourceEntryById(local_id, entry); - if (error != FILE_ERROR_OK) - return error; - - if (entry->file_info().is_directory()) - return FILE_ERROR_NOT_A_FILE; - - // For a hosted document, we create a special JSON file to represent the - // document instead of fetching the document content in one of the exported - // formats. The JSON file contains the edit URL and resource ID of the - // document. - if (entry->file_specific_info().is_hosted_document()) { - base::FilePath::StringType extension = base::FilePath::FromUTF8Unsafe( - entry->file_specific_info().document_extension()).value(); - base::FilePath gdoc_file_path; - base::File::Info file_info; - // We add the gdoc file extension in the temporary file, so that in cross - // profile drag-and-drop between Drive folders, the destination profiles's - // CopyOperation can detect the special JSON file only by the path. - if (!GeneratesUniquePathWithExtension(temporary_file_directory, extension, - &gdoc_file_path) || - !util::CreateGDocFile(gdoc_file_path, GURL(entry->alternate_url()), - entry->resource_id()) || - !base::GetFileInfo(gdoc_file_path, - reinterpret_cast<base::File::Info*>(&file_info))) - return FILE_ERROR_FAILED; - - *cache_file_path = gdoc_file_path; - entry->mutable_file_info()->set_size(file_info.size); - return FILE_ERROR_OK; - } - - if (!entry->file_specific_info().cache_state().is_present()) { - // This file has no cache file. - if (!entry->resource_id().empty()) { - // This entry exists on the server, leave |cache_file_path| empty to - // start download. - return PrepareForDownloadFile(cache, entry->file_info().size(), - temporary_file_directory, - temp_download_file_path); - } - - // This entry does not exist on the server, store an empty file and mark it - // as dirty. - base::FilePath empty_file; - if (!base::CreateTemporaryFileInDir(temporary_file_directory, &empty_file)) - return FILE_ERROR_FAILED; - error = cache->Store(local_id, std::string(), empty_file, - internal::FileCache::FILE_OPERATION_MOVE); - if (error != FILE_ERROR_OK) - return error; - - error = metadata->GetResourceEntryById(local_id, entry); - if (error != FILE_ERROR_OK) - return error; - } - - // Leave |cache_file_path| empty when the stored file is obsolete and has no - // local modification. - if (!entry->file_specific_info().cache_state().is_dirty() && - entry->file_specific_info().md5() != - entry->file_specific_info().cache_state().md5()) { - return PrepareForDownloadFile(cache, entry->file_info().size(), - temporary_file_directory, - temp_download_file_path); - } - - // Fill |cache_file_path| with the path to the cached file. - error = cache->GetFile(local_id, cache_file_path); - if (error != FILE_ERROR_OK) - return error; - - // If the cache file is to be returned as the download result, the file info - // of the cache needs to be returned via |entry|. - // TODO(kinaba): crbug.com/246469. The logic below is similar to that in - // drive::FileSystem::CheckLocalModificationAndRun. We should merge them. - base::File::Info file_info; - if (base::GetFileInfo(*cache_file_path, &file_info)) - entry->mutable_file_info()->set_size(file_info.size); - - return FILE_ERROR_OK; -} - -struct CheckPreconditionForEnsureFileDownloadedParams { - internal::ResourceMetadata* metadata; - internal::FileCache* cache; - base::FilePath temporary_file_directory; -}; - -// Calls CheckPreConditionForEnsureFileDownloaded() with the entry specified by -// the given ID. Also fills |drive_file_path| with the path of the entry. -FileError CheckPreConditionForEnsureFileDownloadedByLocalId( - const CheckPreconditionForEnsureFileDownloadedParams& params, - const std::string& local_id, - base::FilePath* drive_file_path, - base::FilePath* cache_file_path, - base::FilePath* temp_download_file_path, - ResourceEntry* entry) { - FileError error = params.metadata->GetFilePath(local_id, drive_file_path); - if (error != FILE_ERROR_OK) - return error; - return CheckPreConditionForEnsureFileDownloaded( - params.metadata, params.cache, params.temporary_file_directory, local_id, - entry, cache_file_path, temp_download_file_path); -} - -// Calls CheckPreConditionForEnsureFileDownloaded() with the entry specified by -// the given file path. -FileError CheckPreConditionForEnsureFileDownloadedByPath( - const CheckPreconditionForEnsureFileDownloadedParams& params, - const base::FilePath& file_path, - base::FilePath* cache_file_path, - base::FilePath* temp_download_file_path, - ResourceEntry* entry) { - std::string local_id; - FileError error = params.metadata->GetIdByPath(file_path, &local_id); - if (error != FILE_ERROR_OK) - return error; - return CheckPreConditionForEnsureFileDownloaded( - params.metadata, params.cache, params.temporary_file_directory, local_id, - entry, cache_file_path, temp_download_file_path); -} - -// Stores the downloaded file at |downloaded_file_path| into |cache|. -// If succeeded, returns FILE_ERROR_OK with |cache_file_path| storing the -// path to the cache file. -// If failed, returns an error code with deleting |downloaded_file_path|. -FileError UpdateLocalStateForDownloadFile( - internal::ResourceMetadata* metadata, - internal::FileCache* cache, - const ResourceEntry& entry_before_download, - google_apis::DriveApiErrorCode gdata_error, - const base::FilePath& downloaded_file_path, - ResourceEntry* entry_after_update, - base::FilePath* cache_file_path) { - DCHECK(cache); - - // Downloaded file should be deleted on errors. - base::ScopedClosureRunner file_deleter( - base::BindOnce(base::IgnoreResult(&base::DeleteFile), - downloaded_file_path, false /* recursive */)); - - FileError error = GDataToFileError(gdata_error); - if (error != FILE_ERROR_OK) - return error; - - const std::string& local_id = entry_before_download.local_id(); - - // Do not overwrite locally edited file with server side contents. - ResourceEntry entry; - error = metadata->GetResourceEntryById(local_id, &entry); - if (error != FILE_ERROR_OK) - return error; - if (entry.file_specific_info().cache_state().is_dirty()) - return FILE_ERROR_IN_USE; - - // Here the download is completed successfully, so store it into the cache. - error = cache->Store(local_id, - entry_before_download.file_specific_info().md5(), - downloaded_file_path, - internal::FileCache::FILE_OPERATION_MOVE); - if (error != FILE_ERROR_OK) - return error; - base::OnceClosure unused_file_deleter_closure = file_deleter.Release(); - - error = metadata->GetResourceEntryById(local_id, entry_after_update); - if (error != FILE_ERROR_OK) - return error; - - return cache->GetFile(local_id, cache_file_path); -} - -} // namespace - -class DownloadOperation::DownloadParams { - public: - DownloadParams(GetFileContentInitializedCallback initialized_callback, - const google_apis::GetContentCallback get_content_callback, - GetFileCallback completion_callback, - std::unique_ptr<ResourceEntry> entry) - : initialized_callback_(std::move(initialized_callback)), - get_content_callback_(get_content_callback), - completion_callback_(std::move(completion_callback)), - entry_(std::move(entry)), - was_cancelled_(false) { - DCHECK(!completion_callback_.is_null()); - DCHECK(entry_); - } - - base::Closure GetCancelClosure() { - return base::Bind(&DownloadParams::Cancel, weak_ptr_factory_.GetWeakPtr()); - } - - void OnCacheFileFound(const base::FilePath& cache_file_path) { - if (!initialized_callback_.is_null()) { - std::move(initialized_callback_) - .Run(FILE_ERROR_OK, cache_file_path, - std::make_unique<ResourceEntry>(*entry_)); - } - std::move(completion_callback_) - .Run(FILE_ERROR_OK, cache_file_path, std::move(entry_)); - } - - void OnStartDownloading(const base::Closure& cancel_download_closure) { - cancel_download_closure_ = cancel_download_closure; - if (initialized_callback_.is_null()) { - return; - } - - DCHECK(entry_); - std::move(initialized_callback_) - .Run(FILE_ERROR_OK, base::FilePath(), - std::make_unique<ResourceEntry>(*entry_)); - } - - void OnError(FileError error) { - std::move(completion_callback_) - .Run(error, base::FilePath(), std::unique_ptr<ResourceEntry>()); - } - - void OnDownloadCompleted(const base::FilePath& cache_file_path, - std::unique_ptr<ResourceEntry> entry) { - std::move(completion_callback_) - .Run(FILE_ERROR_OK, cache_file_path, std::move(entry)); - } - - const google_apis::GetContentCallback& get_content_callback() const { - return get_content_callback_; - } - - const ResourceEntry& entry() const { return *entry_; } - - bool was_cancelled() const { return was_cancelled_; } - - private: - void Cancel() { - was_cancelled_ = true; - if (!cancel_download_closure_.is_null()) - cancel_download_closure_.Run(); - } - - GetFileContentInitializedCallback initialized_callback_; - const google_apis::GetContentCallback get_content_callback_; - GetFileCallback completion_callback_; - - std::unique_ptr<ResourceEntry> entry_; - base::Closure cancel_download_closure_; - bool was_cancelled_; - - base::WeakPtrFactory<DownloadParams> weak_ptr_factory_{this}; - DISALLOW_COPY_AND_ASSIGN(DownloadParams); -}; - -DownloadOperation::DownloadOperation( - base::SequencedTaskRunner* blocking_task_runner, - OperationDelegate* delegate, - JobScheduler* scheduler, - internal::ResourceMetadata* metadata, - internal::FileCache* cache, - const base::FilePath& temporary_file_directory) - : blocking_task_runner_(blocking_task_runner), - delegate_(delegate), - scheduler_(scheduler), - metadata_(metadata), - cache_(cache), - temporary_file_directory_(temporary_file_directory) {} - -DownloadOperation::~DownloadOperation() = default; - -base::Closure DownloadOperation::EnsureFileDownloadedByLocalId( - const std::string& local_id, - const ClientContext& context, - GetFileContentInitializedCallback initialized_callback, - const google_apis::GetContentCallback& get_content_callback, - GetFileCallback completion_callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(!completion_callback.is_null()); - - CheckPreconditionForEnsureFileDownloadedParams params; - params.metadata = metadata_; - params.cache = cache_; - params.temporary_file_directory = temporary_file_directory_; - base::FilePath* drive_file_path = new base::FilePath; - base::FilePath* cache_file_path = new base::FilePath; - base::FilePath* temp_download_file_path = new base::FilePath; - ResourceEntry* entry = new ResourceEntry; - std::unique_ptr<DownloadParams> download_params(new DownloadParams( - std::move(initialized_callback), get_content_callback, - std::move(completion_callback), base::WrapUnique(entry))); - base::Closure cancel_closure = download_params->GetCancelClosure(); - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), FROM_HERE, - base::BindOnce(&CheckPreConditionForEnsureFileDownloadedByLocalId, params, - local_id, drive_file_path, cache_file_path, - temp_download_file_path, entry), - base::BindOnce( - &DownloadOperation::EnsureFileDownloadedAfterCheckPreCondition, - weak_ptr_factory_.GetWeakPtr(), std::move(download_params), context, - base::Owned(drive_file_path), base::Owned(cache_file_path), - base::Owned(temp_download_file_path))); - return cancel_closure; -} - -base::Closure DownloadOperation::EnsureFileDownloadedByPath( - const base::FilePath& file_path, - const ClientContext& context, - GetFileContentInitializedCallback initialized_callback, - const google_apis::GetContentCallback& get_content_callback, - GetFileCallback completion_callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(!completion_callback.is_null()); - - CheckPreconditionForEnsureFileDownloadedParams params; - params.metadata = metadata_; - params.cache = cache_; - params.temporary_file_directory = temporary_file_directory_; - base::FilePath* drive_file_path = new base::FilePath(file_path); - base::FilePath* cache_file_path = new base::FilePath; - base::FilePath* temp_download_file_path = new base::FilePath; - ResourceEntry* entry = new ResourceEntry; - std::unique_ptr<DownloadParams> download_params(new DownloadParams( - std::move(initialized_callback), get_content_callback, - std::move(completion_callback), base::WrapUnique(entry))); - base::Closure cancel_closure = download_params->GetCancelClosure(); - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), FROM_HERE, - base::BindOnce(&CheckPreConditionForEnsureFileDownloadedByPath, params, - file_path, cache_file_path, temp_download_file_path, - entry), - base::BindOnce( - &DownloadOperation::EnsureFileDownloadedAfterCheckPreCondition, - weak_ptr_factory_.GetWeakPtr(), std::move(download_params), context, - base::Owned(drive_file_path), base::Owned(cache_file_path), - base::Owned(temp_download_file_path))); - return cancel_closure; -} - -void DownloadOperation::EnsureFileDownloadedAfterCheckPreCondition( - std::unique_ptr<DownloadParams> params, - const ClientContext& context, - base::FilePath* drive_file_path, - base::FilePath* cache_file_path, - base::FilePath* temp_download_file_path, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(params); - DCHECK(drive_file_path); - DCHECK(cache_file_path); - - if (error != FILE_ERROR_OK) { - // During precondition check, an error is found. - params->OnError(error); - return; - } - - if (!cache_file_path->empty()) { - // The cache file is found. - params->OnCacheFileFound(*cache_file_path); - return; - } - - if (params->was_cancelled()) { - params->OnError(FILE_ERROR_ABORT); - return; - } - - DCHECK(!params->entry().resource_id().empty()); - DownloadParams* params_ptr = params.get(); - JobID id = scheduler_->DownloadFile( - *drive_file_path, - params_ptr->entry().file_info().size(), - *temp_download_file_path, - params_ptr->entry().resource_id(), - context, - base::Bind(&DownloadOperation::EnsureFileDownloadedAfterDownloadFile, - weak_ptr_factory_.GetWeakPtr(), - *drive_file_path, - base::Passed(¶ms)), - params_ptr->get_content_callback()); - - // Notify via |initialized_callback| if necessary. - params_ptr->OnStartDownloading( - base::Bind(&DownloadOperation::CancelJob, - weak_ptr_factory_.GetWeakPtr(), id)); -} - -void DownloadOperation::EnsureFileDownloadedAfterDownloadFile( - const base::FilePath& drive_file_path, - std::unique_ptr<DownloadParams> params, - google_apis::DriveApiErrorCode gdata_error, - const base::FilePath& downloaded_file_path) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - DownloadParams* params_ptr = params.get(); - ResourceEntry* entry_after_update = new ResourceEntry; - base::FilePath* cache_file_path = new base::FilePath; - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), FROM_HERE, - base::BindOnce(&UpdateLocalStateForDownloadFile, metadata_, cache_, - params_ptr->entry(), gdata_error, downloaded_file_path, - entry_after_update, cache_file_path), - base::BindOnce( - &DownloadOperation::EnsureFileDownloadedAfterUpdateLocalState, - weak_ptr_factory_.GetWeakPtr(), drive_file_path, std::move(params), - base::WrapUnique(entry_after_update), base::Owned(cache_file_path))); -} - -void DownloadOperation::EnsureFileDownloadedAfterUpdateLocalState( - const base::FilePath& file_path, - std::unique_ptr<DownloadParams> params, - std::unique_ptr<ResourceEntry> entry_after_update, - base::FilePath* cache_file_path, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - if (error != FILE_ERROR_OK) { - params->OnError(error); - return; - } - DCHECK(!entry_after_update->file_info().is_directory()); - - FileChange changed_files; - changed_files.Update(file_path, FileChange::FILE_TYPE_FILE, - FileChange::CHANGE_TYPE_ADD_OR_UPDATE); - // Storing to cache changes the "offline available" status, hence notify. - delegate_->OnFileChangedByOperation(changed_files); - params->OnDownloadCompleted(*cache_file_path, std::move(entry_after_update)); -} - -void DownloadOperation::CancelJob(JobID job_id) { - scheduler_->CancelJob(job_id); -} - -} // namespace file_system -} // namespace drive
diff --git a/components/drive/chromeos/file_system/download_operation.h b/components/drive/chromeos/file_system/download_operation.h deleted file mode 100644 index 6c09e8b..0000000 --- a/components/drive/chromeos/file_system/download_operation.h +++ /dev/null
@@ -1,134 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_DOWNLOAD_OPERATION_H_ -#define COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_DOWNLOAD_OPERATION_H_ - -#include <memory> - -#include "base/macros.h" -#include "base/threading/thread_checker.h" -#include "components/drive/chromeos/file_system_interface.h" -#include "components/drive/file_errors.h" -#include "components/drive/job_list.h" -#include "google_apis/drive/drive_api_error_codes.h" - -namespace base { -class FilePath; -class SequencedTaskRunner; -} // namespace base - -namespace google_apis { -class ResourceEntry; -} // namespace google_apis - -namespace drive { - -class JobScheduler; -class ResourceEntry; -struct ClientContext; - -namespace internal { -class FileCache; -class ResourceMetadata; -} // namespace internal - -namespace file_system { - -class OperationDelegate; - -class DownloadOperation { - public: - DownloadOperation(base::SequencedTaskRunner* blocking_task_runner, - OperationDelegate* delegate, - JobScheduler* scheduler, - internal::ResourceMetadata* metadata, - internal::FileCache* cache, - const base::FilePath& temporary_file_directory); - ~DownloadOperation(); - - // Ensures that the file content specified by |local_id| is locally - // downloaded and returns a closure to cancel the task. - // For hosted documents, this method may create a JSON file representing the - // file. - // For regular files, if the locally cached file is found, returns it. - // If not found, start to download the file from the server. - // When a JSON file is created, the cache file is found or downloading is - // being started, |initialized_callback| is called with |local_file| - // for JSON file or the cache file, or with |cancel_download_closure| for - // downloading. - // During the downloading |get_content_callback| will be called periodically - // with the downloaded content. - // Upon completion or an error is found, |completion_callback| will be called. - // |initialized_callback| and |get_content_callback| can be null if not - // needed. - // |completion_callback| must not be null. - base::Closure EnsureFileDownloadedByLocalId( - const std::string& local_id, - const ClientContext& context, - GetFileContentInitializedCallback initialized_callback, - const google_apis::GetContentCallback& get_content_callback, - GetFileCallback completion_callback); - - // Does the same thing as EnsureFileDownloadedByLocalId for the file - // specified by |file_path|. - base::Closure EnsureFileDownloadedByPath( - const base::FilePath& file_path, - const ClientContext& context, - GetFileContentInitializedCallback initialized_callback, - const google_apis::GetContentCallback& get_content_callback, - GetFileCallback completion_callback); - - private: - // Parameters for EnsureFileDownloaded. - class DownloadParams; - - // Part of EnsureFileDownloaded(). Called upon the completion of precondition - // check. - void EnsureFileDownloadedAfterCheckPreCondition( - std::unique_ptr<DownloadParams> params, - const ClientContext& context, - base::FilePath* drive_file_path, - base::FilePath* cache_file_path, - base::FilePath* temp_download_file_path, - FileError error); - - // Part of EnsureFileDownloaded(). Called after the actual downloading. - void EnsureFileDownloadedAfterDownloadFile( - const base::FilePath& drive_file_path, - std::unique_ptr<DownloadParams> params, - google_apis::DriveApiErrorCode gdata_error, - const base::FilePath& downloaded_file_path); - - // Part of EnsureFileDownloaded(). Called after updating local state is - // completed. - void EnsureFileDownloadedAfterUpdateLocalState( - const base::FilePath& file_path, - std::unique_ptr<DownloadParams> params, - std::unique_ptr<ResourceEntry> entry_after_update, - base::FilePath* cache_file_path, - FileError error); - - // Cancels the job with |job_id| in the scheduler. - void CancelJob(JobID job_id); - - scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; - OperationDelegate* delegate_; - JobScheduler* scheduler_; - internal::ResourceMetadata* metadata_; - internal::FileCache* cache_; - const base::FilePath temporary_file_directory_; - - THREAD_CHECKER(thread_checker_); - - // Note: This should remain the last member so it'll be destroyed and - // invalidate its weak pointers before any other members are destroyed. - base::WeakPtrFactory<DownloadOperation> weak_ptr_factory_{this}; - DISALLOW_COPY_AND_ASSIGN(DownloadOperation); -}; - -} // namespace file_system -} // namespace drive - -#endif // COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_DOWNLOAD_OPERATION_H_
diff --git a/components/drive/chromeos/file_system/get_file_for_saving_operation.cc b/components/drive/chromeos/file_system/get_file_for_saving_operation.cc deleted file mode 100644 index 828a716..0000000 --- a/components/drive/chromeos/file_system/get_file_for_saving_operation.cc +++ /dev/null
@@ -1,194 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/drive/chromeos/file_system/get_file_for_saving_operation.h" - -#include <utility> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/callback_helpers.h" -#include "base/sequenced_task_runner.h" -#include "components/drive/chromeos/file_cache.h" -#include "components/drive/chromeos/file_system/create_file_operation.h" -#include "components/drive/chromeos/file_system/download_operation.h" -#include "components/drive/chromeos/file_system/operation_delegate.h" -#include "components/drive/event_logger.h" -#include "components/drive/file_write_watcher.h" -#include "components/drive/job_scheduler.h" - -namespace drive { -namespace file_system { - -namespace { - -FileError OpenCacheFileForWrite( - internal::ResourceMetadata* metadata, - internal::FileCache* cache, - const std::string& local_id, - std::unique_ptr<base::ScopedClosureRunner>* file_closer, - ResourceEntry* entry) { - FileError error = cache->OpenForWrite(local_id, file_closer); - if (error != FILE_ERROR_OK) - return error; - return metadata->GetResourceEntryById(local_id, entry); -} - -} // namespace - -GetFileForSavingOperation::GetFileForSavingOperation( - EventLogger* logger, - base::SequencedTaskRunner* blocking_task_runner, - OperationDelegate* delegate, - JobScheduler* scheduler, - internal::ResourceMetadata* metadata, - internal::FileCache* cache, - const base::FilePath& temporary_file_directory) - : logger_(logger), - create_file_operation_( - new CreateFileOperation(blocking_task_runner, delegate, metadata)), - download_operation_(new DownloadOperation(blocking_task_runner, - delegate, - scheduler, - metadata, - cache, - temporary_file_directory)), - file_write_watcher_(new internal::FileWriteWatcher(blocking_task_runner)), - blocking_task_runner_(blocking_task_runner), - delegate_(delegate), - metadata_(metadata), - cache_(cache) {} - -GetFileForSavingOperation::~GetFileForSavingOperation() = default; - -void GetFileForSavingOperation::GetFileForSaving( - const base::FilePath& file_path, - GetFileCallback callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - create_file_operation_->CreateFile( - file_path, - false, // error_if_already_exists - std::string(), // no specific mime type - base::Bind(&GetFileForSavingOperation::GetFileForSavingAfterCreate, - weak_ptr_factory_.GetWeakPtr(), file_path, - base::Passed(std::move(callback)))); -} - -void GetFileForSavingOperation::GetFileForSavingAfterCreate( - const base::FilePath& file_path, - GetFileCallback callback, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - if (error != FILE_ERROR_OK) { - std::move(callback).Run(error, base::FilePath(), - std::unique_ptr<ResourceEntry>()); - return; - } - - download_operation_->EnsureFileDownloadedByPath( - file_path, ClientContext(USER_INITIATED), - GetFileContentInitializedCallback(), google_apis::GetContentCallback(), - base::Bind(&GetFileForSavingOperation::GetFileForSavingAfterDownload, - weak_ptr_factory_.GetWeakPtr(), - base::Passed(std::move(callback)))); -} - -void GetFileForSavingOperation::GetFileForSavingAfterDownload( - GetFileCallback callback, - FileError error, - const base::FilePath& cache_path, - std::unique_ptr<ResourceEntry> entry) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - if (error != FILE_ERROR_OK) { - std::move(callback).Run(error, base::FilePath(), - std::unique_ptr<ResourceEntry>()); - return; - } - - const std::string& local_id = entry->local_id(); - ResourceEntry* entry_ptr = entry.get(); - std::unique_ptr<base::ScopedClosureRunner>* file_closer = - new std::unique_ptr<base::ScopedClosureRunner>; - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), FROM_HERE, - base::BindOnce(&OpenCacheFileForWrite, metadata_, cache_, local_id, - file_closer, entry_ptr), - base::BindOnce( - &GetFileForSavingOperation::GetFileForSavingAfterOpenForWrite, - weak_ptr_factory_.GetWeakPtr(), std::move(callback), cache_path, - std::move(entry), base::Owned(file_closer))); -} - -void GetFileForSavingOperation::GetFileForSavingAfterOpenForWrite( - GetFileCallback callback, - const base::FilePath& cache_path, - std::unique_ptr<ResourceEntry> entry, - std::unique_ptr<base::ScopedClosureRunner>* file_closer, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - if (error != FILE_ERROR_OK) { - std::move(callback).Run(error, base::FilePath(), - std::unique_ptr<ResourceEntry>()); - return; - } - - const std::string& local_id = entry->local_id(); - file_write_watcher_->StartWatch( - cache_path, - base::Bind(&GetFileForSavingOperation::GetFileForSavingAfterWatch, - weak_ptr_factory_.GetWeakPtr(), - base::Passed(std::move(callback)), cache_path, - base::Passed(&entry)), - base::Bind(&GetFileForSavingOperation::OnWriteEvent, - weak_ptr_factory_.GetWeakPtr(), local_id, - base::Passed(file_closer))); -} - -void GetFileForSavingOperation::GetFileForSavingAfterWatch( - GetFileCallback callback, - const base::FilePath& cache_path, - std::unique_ptr<ResourceEntry> entry, - bool success) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - logger_->Log(logging::LOG_INFO, "Started watching modification to %s [%s].", - entry->local_id().c_str(), - success ? "ok" : "fail"); - - if (!success) { - std::move(callback).Run(FILE_ERROR_FAILED, base::FilePath(), - std::unique_ptr<ResourceEntry>()); - return; - } - - std::move(callback).Run(FILE_ERROR_OK, cache_path, std::move(entry)); -} - -void GetFileForSavingOperation::OnWriteEvent( - const std::string& local_id, - std::unique_ptr<base::ScopedClosureRunner> file_closer) { - logger_->Log(logging::LOG_INFO, "Detected modification to %s.", - local_id.c_str()); - - delegate_->OnEntryUpdatedByOperation(ClientContext(USER_INITIATED), local_id); - - // Clients may have enlarged the file. By FreeDiskpSpaceIfNeededFor(0), - // we try to ensure (0 + the-minimum-safe-margin = 512MB as of now) space. - blocking_task_runner_->PostTask( - FROM_HERE, base::BindOnce(base::IgnoreResult( - base::Bind(&internal::FileCache::FreeDiskSpaceIfNeededFor, - base::Unretained(cache_), 0)))); -} - -} // namespace file_system -} // namespace drive
diff --git a/components/drive/chromeos/file_system/get_file_for_saving_operation.h b/components/drive/chromeos/file_system/get_file_for_saving_operation.h deleted file mode 100644 index 859a917..0000000 --- a/components/drive/chromeos/file_system/get_file_for_saving_operation.h +++ /dev/null
@@ -1,109 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_GET_FILE_FOR_SAVING_OPERATION_H_ -#define COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_GET_FILE_FOR_SAVING_OPERATION_H_ - -#include <memory> - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "base/threading/thread_checker.h" -#include "components/drive/chromeos/file_system_interface.h" -#include "components/drive/file_errors.h" - -namespace base { -class FilePath; -class ScopedClosureRunner; -class SequencedTaskRunner; -} // namespace base - -namespace drive { -namespace internal { -class FileCache; -class FileWriteWatcher; -class ResourceMetadata; -} // namespace internal - -class EventLogger; -class JobScheduler; -class ResourceEntry; - -namespace file_system { - -class CreateFileOperation; -class DownloadOperation; -class OperationDelegate; - -// Implements GetFileForSaving() operation that prepares a local cache for -// a Drive file whose next modification is monitored and notified to the -// OperationDelegate. -// TODO(kinaba): crbug.com/269424: we might want to monitor all the changes -// to the cache directory, not just the one immediately after the save dialog. -class GetFileForSavingOperation { - public: - GetFileForSavingOperation(EventLogger* logger, - base::SequencedTaskRunner* blocking_task_runner, - OperationDelegate* delegate, - JobScheduler* scheduler, - internal::ResourceMetadata* metadata, - internal::FileCache* cache, - const base::FilePath& temporary_file_directory); - ~GetFileForSavingOperation(); - - // Makes sure that |file_path| in the file system is available in the local - // cache, and marks it as dirty. The next modification to the cache file is - // watched and is automatically notified to the delegate. If the entry is not - // present in the file system, it is created. - void GetFileForSaving(const base::FilePath& file_path, - GetFileCallback callback); - - internal::FileWriteWatcher* file_write_watcher_for_testing() { - return file_write_watcher_.get(); - } - - private: - void GetFileForSavingAfterCreate(const base::FilePath& file_path, - GetFileCallback callback, - FileError error); - void GetFileForSavingAfterDownload(GetFileCallback callback, - FileError error, - const base::FilePath& cache_path, - std::unique_ptr<ResourceEntry> entry); - void GetFileForSavingAfterOpenForWrite( - GetFileCallback callback, - const base::FilePath& cache_path, - std::unique_ptr<ResourceEntry> entry, - std::unique_ptr<base::ScopedClosureRunner>* file_closer, - FileError error); - void GetFileForSavingAfterWatch(GetFileCallback callback, - const base::FilePath& cache_path, - std::unique_ptr<ResourceEntry> entry, - bool success); - // Called when the cache file for |local_id| is written. - void OnWriteEvent(const std::string& local_id, - std::unique_ptr<base::ScopedClosureRunner> file_closer); - - EventLogger* logger_; - std::unique_ptr<CreateFileOperation> create_file_operation_; - std::unique_ptr<DownloadOperation> download_operation_; - std::unique_ptr<internal::FileWriteWatcher> file_write_watcher_; - scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; - OperationDelegate* delegate_; - internal::ResourceMetadata* metadata_; - internal::FileCache* cache_; - - THREAD_CHECKER(thread_checker_); - - // Note: This should remain the last member so it'll be destroyed and - // invalidate the weak pointers before any other members are destroyed. - base::WeakPtrFactory<GetFileForSavingOperation> weak_ptr_factory_{this}; - DISALLOW_COPY_AND_ASSIGN(GetFileForSavingOperation); -}; - -} // namespace file_system -} // namespace drive - -#endif // COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_GET_FILE_FOR_SAVING_OPERATION_H_
diff --git a/components/drive/chromeos/file_system/move_operation.cc b/components/drive/chromeos/file_system/move_operation.cc deleted file mode 100644 index dc682cb..0000000 --- a/components/drive/chromeos/file_system/move_operation.cc +++ /dev/null
@@ -1,120 +0,0 @@ -// Copyright (c) 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. - -#include "components/drive/chromeos/file_system/move_operation.h" - -#include "base/bind.h" -#include "base/sequenced_task_runner.h" -#include "components/drive/chromeos/file_system/operation_delegate.h" -#include "components/drive/chromeos/resource_metadata.h" -#include "components/drive/drive.pb.h" -#include "components/drive/file_change.h" -#include "components/drive/job_scheduler.h" - -namespace drive { -namespace file_system { -namespace { - -// Looks up ResourceEntry for source entry and the destination directory. -FileError UpdateLocalState(internal::ResourceMetadata* metadata, - const base::FilePath& src_path, - const base::FilePath& dest_path, - FileChange* changed_files, - std::string* local_id) { - ResourceEntry entry; - FileError error = metadata->GetResourceEntryByPath(src_path, &entry); - if (error != FILE_ERROR_OK) - return error; - *local_id = entry.local_id(); - - ResourceEntry parent_entry; - error = metadata->GetResourceEntryByPath(dest_path.DirName(), &parent_entry); - if (error != FILE_ERROR_OK) - return error; - - // The parent must be a directory. - if (!parent_entry.file_info().is_directory()) - return FILE_ERROR_NOT_A_DIRECTORY; - - changed_files->Update(src_path, entry, FileChange::CHANGE_TYPE_DELETE); - - // Strip the extension for a hosted document if necessary. - const std::string new_extension = - base::FilePath(dest_path.Extension()).AsUTF8Unsafe(); - const bool has_hosted_document_extension = - entry.has_file_specific_info() && - entry.file_specific_info().is_hosted_document() && - new_extension == entry.file_specific_info().document_extension(); - const std::string new_title = - has_hosted_document_extension ? - dest_path.BaseName().RemoveExtension().AsUTF8Unsafe() : - dest_path.BaseName().AsUTF8Unsafe(); - - entry.set_title(new_title); - entry.set_parent_local_id(parent_entry.local_id()); - entry.set_metadata_edit_state(ResourceEntry::DIRTY); - entry.set_modification_date(base::Time::Now().ToInternalValue()); - error = metadata->RefreshEntry(entry); - if (error != FILE_ERROR_OK) - return error; - - changed_files->Update(dest_path, entry, - FileChange::CHANGE_TYPE_ADD_OR_UPDATE); - return FILE_ERROR_OK; -} - -} // namespace - -MoveOperation::MoveOperation(base::SequencedTaskRunner* blocking_task_runner, - OperationDelegate* delegate, - internal::ResourceMetadata* metadata) - : blocking_task_runner_(blocking_task_runner), - delegate_(delegate), - metadata_(metadata) {} - -MoveOperation::~MoveOperation() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); -} - -void MoveOperation::Move(const base::FilePath& src_file_path, - const base::FilePath& dest_file_path, - const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - FileChange* changed_files = new FileChange; - std::string* local_id = new std::string; - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), - FROM_HERE, - base::Bind(&UpdateLocalState, - metadata_, - src_file_path, - dest_file_path, - changed_files, - local_id), - base::Bind(&MoveOperation::MoveAfterUpdateLocalState, - weak_ptr_factory_.GetWeakPtr(), - callback, - base::Owned(changed_files), - base::Owned(local_id))); -} - -void MoveOperation::MoveAfterUpdateLocalState( - const FileOperationCallback& callback, - const FileChange* changed_files, - const std::string* local_id, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - if (error == FILE_ERROR_OK) { - // Notify the change of directory. - delegate_->OnFileChangedByOperation(*changed_files); - delegate_->OnEntryUpdatedByOperation(ClientContext(USER_INITIATED), - *local_id); - } - callback.Run(error); -} - -} // namespace file_system -} // namespace drive
diff --git a/components/drive/chromeos/file_system/move_operation.h b/components/drive/chromeos/file_system/move_operation.h deleted file mode 100644 index ede00a5..0000000 --- a/components/drive/chromeos/file_system/move_operation.h +++ /dev/null
@@ -1,79 +0,0 @@ -// Copyright (c) 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. - -#ifndef COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_MOVE_OPERATION_H_ -#define COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_MOVE_OPERATION_H_ - -#include <memory> -#include <set> - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "base/threading/thread_checker.h" -#include "components/drive/file_errors.h" -#include "google_apis/drive/drive_api_error_codes.h" - -namespace base { -class FilePath; -class SequencedTaskRunner; -} // namespace base - -namespace google_apis { -class ResourceEntry; -} // namespace google_apis - -namespace drive { - -class FileChange; -class ResourceEntry; - -namespace internal { -class ResourceMetadata; -} // namespace internal - -namespace file_system { - -class OperationDelegate; - -// This class encapsulates the drive Move function. It is responsible for -// updating the local metadata entry. -class MoveOperation { - public: - MoveOperation(base::SequencedTaskRunner* blocking_task_runner, - OperationDelegate* delegate, - internal::ResourceMetadata* metadata); - ~MoveOperation(); - - // Performs the move operation on the file at drive path |src_file_path| - // with a target of |dest_file_path|. - // Invokes |callback| when finished with the result of the operation. - // |callback| must not be null. - void Move(const base::FilePath& src_file_path, - const base::FilePath& dest_file_path, - const FileOperationCallback& callback); - - private: - // Part of Move(). Called after updating the local state. - void MoveAfterUpdateLocalState(const FileOperationCallback& callback, - const FileChange* changed_file, - const std::string* local_id, - FileError error); - - scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; - OperationDelegate* delegate_; - internal::ResourceMetadata* metadata_; - - THREAD_CHECKER(thread_checker_); - - // Note: This should remain the last member so it'll be destroyed and - // invalidate the weak pointers before any other members are destroyed. - base::WeakPtrFactory<MoveOperation> weak_ptr_factory_{this}; - DISALLOW_COPY_AND_ASSIGN(MoveOperation); -}; - -} // namespace file_system -} // namespace drive - -#endif // COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_MOVE_OPERATION_H_
diff --git a/components/drive/chromeos/file_system/open_file_operation.cc b/components/drive/chromeos/file_system/open_file_operation.cc deleted file mode 100644 index cbb3822..0000000 --- a/components/drive/chromeos/file_system/open_file_operation.cc +++ /dev/null
@@ -1,176 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/drive/chromeos/file_system/open_file_operation.h" - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/callback_helpers.h" -#include "base/files/file_path.h" -#include "base/logging.h" -#include "base/task_runner_util.h" -#include "base/threading/thread_task_runner_handle.h" -#include "components/drive/chromeos/file_cache.h" -#include "components/drive/chromeos/file_system/create_file_operation.h" -#include "components/drive/chromeos/file_system/download_operation.h" -#include "components/drive/chromeos/file_system/operation_delegate.h" -#include "components/drive/drive.pb.h" -#include "components/drive/file_errors.h" -#include "components/drive/job_scheduler.h" - -namespace drive { -namespace file_system { - -OpenFileOperation::OpenFileOperation( - base::SequencedTaskRunner* blocking_task_runner, - OperationDelegate* delegate, - JobScheduler* scheduler, - internal::ResourceMetadata* metadata, - internal::FileCache* cache, - const base::FilePath& temporary_file_directory) - : blocking_task_runner_(blocking_task_runner), - delegate_(delegate), - cache_(cache), - create_file_operation_( - new CreateFileOperation(blocking_task_runner, delegate, metadata)), - download_operation_(new DownloadOperation(blocking_task_runner, - delegate, - scheduler, - metadata, - cache, - temporary_file_directory)) {} - -OpenFileOperation::~OpenFileOperation() = default; - -void OpenFileOperation::OpenFile(const base::FilePath& file_path, - OpenMode open_mode, - const std::string& mime_type, - OpenFileCallback callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - switch (open_mode) { - case OPEN_FILE: - // It is not necessary to create a new file even if not exists. - // So call OpenFileAfterCreateFile directly with FILE_ERROR_OK - // to skip file creation. - OpenFileAfterCreateFile(file_path, std::move(callback), FILE_ERROR_OK); - break; - case CREATE_FILE: - create_file_operation_->CreateFile( - file_path, - true, // exclusive: fail if already exists - mime_type, - base::BindRepeating(&OpenFileOperation::OpenFileAfterCreateFile, - weak_ptr_factory_.GetWeakPtr(), file_path, - base::Passed(std::move(callback)))); - break; - case OPEN_OR_CREATE_FILE: - create_file_operation_->CreateFile( - file_path, - false, // not-exclusive - mime_type, - base::BindRepeating(&OpenFileOperation::OpenFileAfterCreateFile, - weak_ptr_factory_.GetWeakPtr(), file_path, - base::Passed(std::move(callback)))); - break; - } -} - -void OpenFileOperation::OpenFileAfterCreateFile(const base::FilePath& file_path, - OpenFileCallback callback, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - if (error != FILE_ERROR_OK) { - std::move(callback).Run(error, base::FilePath(), base::Closure()); - return; - } - - download_operation_->EnsureFileDownloadedByPath( - file_path, ClientContext(USER_INITIATED), - GetFileContentInitializedCallback(), google_apis::GetContentCallback(), - base::BindOnce(&OpenFileOperation::OpenFileAfterFileDownloaded, - weak_ptr_factory_.GetWeakPtr(), std::move(callback))); -} - -void OpenFileOperation::OpenFileAfterFileDownloaded( - OpenFileCallback callback, - FileError error, - const base::FilePath& local_file_path, - std::unique_ptr<ResourceEntry> entry) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - if (error == FILE_ERROR_OK) { - DCHECK(entry); - DCHECK(entry->has_file_specific_info()); - if (entry->file_specific_info().is_hosted_document()) - // No support for opening a hosted document. - error = FILE_ERROR_INVALID_OPERATION; - } - - if (error != FILE_ERROR_OK) { - std::move(callback).Run(error, base::FilePath(), base::Closure()); - return; - } - - std::unique_ptr<base::ScopedClosureRunner>* file_closer = - new std::unique_ptr<base::ScopedClosureRunner>; - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), FROM_HERE, - base::BindOnce(&internal::FileCache::OpenForWrite, - base::Unretained(cache_), entry->local_id(), file_closer), - base::BindOnce(&OpenFileOperation::OpenFileAfterOpenForWrite, - weak_ptr_factory_.GetWeakPtr(), local_file_path, - entry->local_id(), std::move(callback), - base::Owned(file_closer))); -} - -void OpenFileOperation::OpenFileAfterOpenForWrite( - const base::FilePath& local_file_path, - const std::string& local_id, - OpenFileCallback callback, - std::unique_ptr<base::ScopedClosureRunner>* file_closer, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - if (error != FILE_ERROR_OK) { - std::move(callback).Run(error, base::FilePath(), base::Closure()); - return; - } - - ++open_files_[local_id]; - std::move(callback).Run( - error, local_file_path, - base::BindRepeating(&OpenFileOperation::CloseFile, - weak_ptr_factory_.GetWeakPtr(), local_id, - base::Passed(file_closer))); -} - -void OpenFileOperation::CloseFile( - const std::string& local_id, - std::unique_ptr<base::ScopedClosureRunner> file_closer) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK_GT(open_files_[local_id], 0); - - if (--open_files_[local_id] == 0) { - // All clients closes this file, so notify to upload the file. - open_files_.erase(local_id); - delegate_->OnEntryUpdatedByOperation(ClientContext(USER_INITIATED), - local_id); - - // Clients may have enlarged the file. By FreeDiskpSpaceIfNeededFor(0), - // we try to ensure (0 + the-minimum-safe-margin = 512MB as of now) space. - blocking_task_runner_->PostTask( - FROM_HERE, base::BindOnce(base::IgnoreResult(base::Bind( - &internal::FileCache::FreeDiskSpaceIfNeededFor, - base::Unretained(cache_), 0)))); - } -} - -} // namespace file_system -} // namespace drive
diff --git a/components/drive/chromeos/file_system/open_file_operation.h b/components/drive/chromeos/file_system/open_file_operation.h deleted file mode 100644 index 81a693e..0000000 --- a/components/drive/chromeos/file_system/open_file_operation.h +++ /dev/null
@@ -1,109 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_OPEN_FILE_OPERATION_H_ -#define COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_OPEN_FILE_OPERATION_H_ - -#include <map> -#include <memory> - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "base/threading/thread_checker.h" -#include "components/drive/chromeos/file_system_interface.h" -#include "components/drive/file_errors.h" - -namespace base { -class FilePath; -class ScopedClosureRunner; -class SequencedTaskRunner; -} // namespace base - -namespace drive { - -class JobScheduler; -class ResourceEntry; - -namespace internal { -class ResourceMetadata; -class FileCache; -} // namespace internal - -namespace file_system { - -class CreateFileOperation; -class DownloadOperation; -class OperationDelegate; - -class OpenFileOperation { - public: - OpenFileOperation(base::SequencedTaskRunner* blocking_task_runner, - OperationDelegate* delegate, - JobScheduler* scheduler, - internal::ResourceMetadata* metadata, - internal::FileCache* cache, - const base::FilePath& temporary_file_directory); - ~OpenFileOperation(); - - // Opens the file at |file_path|. - // If the file is not actually downloaded, this method starts - // to download it to the cache, and then runs |callback| upon the - // completion with the path to the local cache file. - // See also the definition of OpenMode for its meaning. - // If |mime_type| is non empty and the file is created by this OpenFile() - // call, the mime type is used as the file's property. - // |callback| must not be null. - void OpenFile(const base::FilePath& file_path, - OpenMode open_mode, - const std::string& mime_type, - OpenFileCallback callback); - - private: - // Part of OpenFile(). Called after file creation is completed. - void OpenFileAfterCreateFile(const base::FilePath& file_path, - OpenFileCallback callback, - FileError error); - - // Part of OpenFile(). Called after file downloading is completed. - void OpenFileAfterFileDownloaded(OpenFileCallback callback, - FileError error, - const base::FilePath& local_file_path, - std::unique_ptr<ResourceEntry> entry); - - // Part of OpenFile(). Called after opening the cache file. - void OpenFileAfterOpenForWrite( - const base::FilePath& local_file_path, - const std::string& local_id, - OpenFileCallback callback, - std::unique_ptr<base::ScopedClosureRunner>* file_closer, - FileError error); - - // Closes the file with |local_id|. - void CloseFile(const std::string& local_id, - std::unique_ptr<base::ScopedClosureRunner> file_closer); - - scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; - OperationDelegate* delegate_; - internal::FileCache* cache_; - - std::unique_ptr<CreateFileOperation> create_file_operation_; - std::unique_ptr<DownloadOperation> download_operation_; - - // The map from local id for an opened file to the number how many times - // the file is opened. - std::map<std::string, int> open_files_; - - THREAD_CHECKER(thread_checker_); - - // Note: This should remain the last member so it'll be destroyed and - // invalidate its weak pointers before any other members are destroyed. - base::WeakPtrFactory<OpenFileOperation> weak_ptr_factory_{this}; - DISALLOW_COPY_AND_ASSIGN(OpenFileOperation); -}; - -} // namespace file_system -} // namespace drive - -#endif // COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_OPEN_FILE_OPERATION_H_
diff --git a/components/drive/chromeos/file_system/operation_delegate.cc b/components/drive/chromeos/file_system/operation_delegate.cc deleted file mode 100644 index 0570e4a..0000000 --- a/components/drive/chromeos/file_system/operation_delegate.cc +++ /dev/null
@@ -1,17 +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 "components/drive/chromeos/file_system/operation_delegate.h" - -namespace drive { -namespace file_system { - -bool OperationDelegate::WaitForSyncComplete( - const std::string& local_id, - const FileOperationCallback& callback) { - return false; -} - -} // namespace file_system -} // namespace drive
diff --git a/components/drive/chromeos/file_system/operation_delegate.h b/components/drive/chromeos/file_system/operation_delegate.h deleted file mode 100644 index edbcc6b..0000000 --- a/components/drive/chromeos/file_system/operation_delegate.h +++ /dev/null
@@ -1,57 +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 COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_OPERATION_DELEGATE_H_ -#define COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_OPERATION_DELEGATE_H_ - -#include "components/drive/file_errors.h" - -namespace drive { - -struct ClientContext; -class FileChange; - -namespace file_system { - -// Error type of sync client. -// Keep it synced with "DriveSyncErrorType" in file_manager_private.idl. -enum DriveSyncErrorType { - // Request to delete a file without permission. - DRIVE_SYNC_ERROR_DELETE_WITHOUT_PERMISSION, - // Google Drive is temporary unavailable. - DRIVE_SYNC_ERROR_SERVICE_UNAVAILABLE, - // There is no server space to sync a file. - DRIVE_SYNC_ERROR_NO_SERVER_SPACE, - // Errors other than above ones. No fallback is provided for the error. - DRIVE_SYNC_ERROR_MISC, -}; - -// Passes notifications from Drive operations back to the file system. -class OperationDelegate { - public: - // Sent when a content of a directory has been changed. - // |directory_path| is a virtual directory path representing the - // changed directory. - virtual void OnFileChangedByOperation(const FileChange& changed_files) {} - - // Sent when an entry is updated and sync is needed. The passed |context| is - // used for syncing. - virtual void OnEntryUpdatedByOperation(const ClientContext& context, - const std::string& local_id) {} - - // Sent when a specific drive sync error occurred. - // |local_id| is the local ID of the resource entry. - virtual void OnDriveSyncError(DriveSyncErrorType type, - const std::string& local_id) {} - - // Waits for the sync task to complete and runs the callback. - // Returns false if no task is found for the spcecified ID. - virtual bool WaitForSyncComplete(const std::string& local_id, - const FileOperationCallback& callback); -}; - -} // namespace file_system -} // namespace drive - -#endif // COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_OPERATION_DELEGATE_H_
diff --git a/components/drive/chromeos/file_system/remove_operation.cc b/components/drive/chromeos/file_system/remove_operation.cc deleted file mode 100644 index f676c96..0000000 --- a/components/drive/chromeos/file_system/remove_operation.cc +++ /dev/null
@@ -1,126 +0,0 @@ -// Copyright (c) 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. - -#include "components/drive/chromeos/file_system/remove_operation.h" - -#include "base/bind.h" -#include "base/sequenced_task_runner.h" -#include "components/drive/chromeos/file_cache.h" -#include "components/drive/chromeos/file_system/operation_delegate.h" -#include "components/drive/chromeos/resource_metadata.h" -#include "components/drive/drive.pb.h" -#include "components/drive/file_change.h" -#include "components/drive/file_system_core_util.h" -#include "components/drive/job_scheduler.h" - -namespace drive { -namespace file_system { - -namespace { - -// Removes cache file and moves the metadata entry to the trash. -FileError UpdateLocalState(internal::ResourceMetadata* metadata, - internal::FileCache* cache, - const base::FilePath& path, - bool is_recursive, - std::string* local_id, - ResourceEntry* entry, - base::FilePath* changed_path) { - FileError error = metadata->GetIdByPath(path, local_id); - if (error != FILE_ERROR_OK) - return error; - - error = metadata->GetResourceEntryById(*local_id, entry); - if (error != FILE_ERROR_OK) - return error; - - if (entry->file_info().is_directory() && !is_recursive) { - // Check emptiness of the directory. - ResourceEntryVector entries; - error = metadata->ReadDirectoryByPath(path, &entries); - if (error != FILE_ERROR_OK) - return error; - if (!entries.empty()) - return FILE_ERROR_NOT_EMPTY; - } - - error = cache->Remove(*local_id); - if (error != FILE_ERROR_OK) - return error; - - *changed_path = path; - - // Move to the trash. - entry->set_parent_local_id(util::kDriveTrashDirLocalId); - return metadata->RefreshEntry(*entry); -} - -} // namespace - -RemoveOperation::RemoveOperation( - base::SequencedTaskRunner* blocking_task_runner, - OperationDelegate* delegate, - internal::ResourceMetadata* metadata, - internal::FileCache* cache) - : blocking_task_runner_(blocking_task_runner), - delegate_(delegate), - metadata_(metadata), - cache_(cache) {} - -RemoveOperation::~RemoveOperation() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); -} - -void RemoveOperation::Remove(const base::FilePath& path, - bool is_recursive, - const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - std::string* local_id = new std::string; - base::FilePath* changed_path = new base::FilePath; - ResourceEntry* entry = new ResourceEntry; - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), - FROM_HERE, - base::Bind(&UpdateLocalState, - metadata_, - cache_, - path, - is_recursive, - local_id, - entry, - changed_path), - base::Bind(&RemoveOperation::RemoveAfterUpdateLocalState, - weak_ptr_factory_.GetWeakPtr(), - callback, - base::Owned(local_id), - base::Owned(entry), - base::Owned(changed_path))); -} - -void RemoveOperation::RemoveAfterUpdateLocalState( - const FileOperationCallback& callback, - const std::string* local_id, - const ResourceEntry* entry, - const base::FilePath* changed_path, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - if (!changed_path->empty()) { - FileChange changed_file; - changed_file.Update(*changed_path, *entry, FileChange::CHANGE_TYPE_DELETE); - if (error == FILE_ERROR_OK) { - delegate_->OnFileChangedByOperation(changed_file); - delegate_->OnEntryUpdatedByOperation(ClientContext(USER_INITIATED), - *local_id); - } - } - - callback.Run(error); -} - -} // namespace file_system -} // namespace drive
diff --git a/components/drive/chromeos/file_system/remove_operation.h b/components/drive/chromeos/file_system/remove_operation.h deleted file mode 100644 index 78ca914..0000000 --- a/components/drive/chromeos/file_system/remove_operation.h +++ /dev/null
@@ -1,78 +0,0 @@ -// Copyright (c) 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. - -#ifndef COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_REMOVE_OPERATION_H_ -#define COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_REMOVE_OPERATION_H_ - -#include <memory> - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "base/threading/thread_checker.h" -#include "components/drive/file_errors.h" -#include "google_apis/drive/drive_api_error_codes.h" - -namespace base { -class FilePath; -class SequencedTaskRunner; -} // namespace base - -namespace drive { - -class ResourceEntry; - -namespace internal { -class FileCache; -class ResourceMetadata; -} // namespace internal - -namespace file_system { - -class OperationDelegate; - -// This class encapsulates the drive Remove function. It is responsible for -// moving the removed entry to the trash. -class RemoveOperation { - public: - RemoveOperation(base::SequencedTaskRunner* blocking_task_runner, - OperationDelegate* delegate, - internal::ResourceMetadata* metadata, - internal::FileCache* cache); - ~RemoveOperation(); - - // Removes the resource at |path|. If |path| is a directory and |is_recursive| - // is set, it recursively removes all the descendants. If |is_recursive| is - // not set, it succeeds only when the directory is empty. - // - // |callback| must not be null. - void Remove(const base::FilePath& path, - bool is_recursive, - const FileOperationCallback& callback); - - private: - // Part of Remove(). Called after UpdateLocalState() completion. - void RemoveAfterUpdateLocalState(const FileOperationCallback& callback, - const std::string* local_id, - const ResourceEntry* entry, - const base::FilePath* changed_directory_path, - FileError error); - - scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; - OperationDelegate* delegate_; - internal::ResourceMetadata* metadata_; - internal::FileCache* cache_; - - THREAD_CHECKER(thread_checker_); - - // Note: This should remain the last member so it'll be destroyed and - // invalidate the weak pointers before any other members are destroyed. - base::WeakPtrFactory<RemoveOperation> weak_ptr_factory_{this}; - DISALLOW_COPY_AND_ASSIGN(RemoveOperation); -}; - -} // namespace file_system -} // namespace drive - -#endif // COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_REMOVE_OPERATION_H_
diff --git a/components/drive/chromeos/file_system/search_operation.cc b/components/drive/chromeos/file_system/search_operation.cc deleted file mode 100644 index 696722c4..0000000 --- a/components/drive/chromeos/file_system/search_operation.cc +++ /dev/null
@@ -1,176 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/drive/chromeos/file_system/search_operation.h" - -#include <stddef.h> - -#include <memory> -#include <string> -#include <utility> -#include <vector> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/callback.h" -#include "components/drive/chromeos/loader_controller.h" -#include "components/drive/chromeos/resource_metadata.h" -#include "components/drive/drive_api_util.h" -#include "components/drive/file_system_core_util.h" -#include "components/drive/job_scheduler.h" -#include "components/drive/resource_entry_conversion.h" -#include "google_apis/drive/drive_api_parser.h" -#include "url/gurl.h" - -namespace drive { -namespace file_system { -namespace { - -// Computes the path of each item in |file_list| returned from the server -// and stores to |result|, by using |resource_metadata|. If the metadata is not -// up to date and did not contain an item, adds the item to "drive/other" for -// temporally assigning a path. -FileError ResolveSearchResultOnBlockingPool( - internal::ResourceMetadata* resource_metadata, - std::unique_ptr<google_apis::FileList> file_list, - std::vector<SearchResultInfo>* result) { - DCHECK(resource_metadata); - DCHECK(result); - - const std::vector<std::unique_ptr<google_apis::FileResource>>& entries = - file_list->items(); - result->reserve(entries.size()); - for (size_t i = 0; i < entries.size(); ++i) { - std::string local_id; - FileError error = resource_metadata->GetIdByResourceId( - entries[i]->file_id(), &local_id); - - ResourceEntry entry; - if (error == FILE_ERROR_OK) - error = resource_metadata->GetResourceEntryById(local_id, &entry); - - if (error == FILE_ERROR_NOT_FOUND) { - std::string original_parent_id; - ConvertFileResourceToResourceEntry(*entries[i], &entry, - &original_parent_id); - - // The result is absent in local resource metadata. This can happen if - // the metadata is not synced to the latest server state yet. In that - // case, we temporarily add the file to the special "drive/other" - // directory in order to assign a path, which is needed to access the - // file through FileSystem API. - // - // It will be moved to the right place when the metadata gets synced - // in normal loading process in ChangeListProcessor. - entry.set_parent_local_id(util::kDriveOtherDirLocalId); - error = resource_metadata->AddEntry(entry, &local_id); - } - if (error != FILE_ERROR_OK) - return error; - base::FilePath path; - error = resource_metadata->GetFilePath(local_id, &path); - if (error != FILE_ERROR_OK) - return error; - result->push_back(SearchResultInfo(path, entry.file_info().is_directory())); - } - - return FILE_ERROR_OK; -} - -} // namespace - -SearchOperation::SearchOperation( - base::SequencedTaskRunner* blocking_task_runner, - JobScheduler* scheduler, - internal::ResourceMetadata* metadata, - internal::LoaderController* loader_controller) - : blocking_task_runner_(blocking_task_runner), - scheduler_(scheduler), - metadata_(metadata), - loader_controller_(loader_controller) {} - -SearchOperation::~SearchOperation() = default; - -void SearchOperation::Search(const std::string& search_query, - const GURL& next_link, - SearchCallback callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - if (next_link.is_empty()) { - // This is first request for the |search_query|. - scheduler_->Search(search_query, - base::Bind(&SearchOperation::SearchAfterGetFileList, - weak_ptr_factory_.GetWeakPtr(), - base::Passed(std::move(callback)))); - } else { - // There is the remaining result so fetch it. - scheduler_->GetRemainingFileList( - next_link, base::Bind(&SearchOperation::SearchAfterGetFileList, - weak_ptr_factory_.GetWeakPtr(), - base::Passed(std::move(callback)))); - } -} - -void SearchOperation::SearchAfterGetFileList( - SearchCallback callback, - google_apis::DriveApiErrorCode gdata_error, - std::unique_ptr<google_apis::FileList> file_list) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - FileError error = GDataToFileError(gdata_error); - if (error != FILE_ERROR_OK) { - std::move(callback).Run(error, GURL(), - std::unique_ptr<std::vector<SearchResultInfo>>()); - return; - } - - DCHECK(file_list); - - GURL next_url = file_list->next_link(); - - std::unique_ptr<std::vector<SearchResultInfo>> result( - new std::vector<SearchResultInfo>); - if (file_list->items().empty()) { - // Short cut. If the resource entry is empty, we don't need to refresh - // the resource metadata. - std::move(callback).Run(FILE_ERROR_OK, next_url, std::move(result)); - return; - } - - // ResolveSearchResultOnBlockingPool() may add entries newly created on the - // server to the local metadata. - // This may race with sync tasks so we should ask LoaderController here. - std::vector<SearchResultInfo>* result_ptr = result.get(); - loader_controller_->ScheduleRun(base::BindOnce( - &drive::util::RunAsyncTask, base::RetainedRef(blocking_task_runner_), - FROM_HERE, - base::BindOnce(&ResolveSearchResultOnBlockingPool, metadata_, - std::move(file_list), result_ptr), - base::BindOnce(&SearchOperation::SearchAfterResolveSearchResult, - weak_ptr_factory_.GetWeakPtr(), std::move(callback), - next_url, std::move(result)))); -} - -void SearchOperation::SearchAfterResolveSearchResult( - SearchCallback callback, - const GURL& next_link, - std::unique_ptr<std::vector<SearchResultInfo>> result, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - DCHECK(result); - - if (error != FILE_ERROR_OK) { - std::move(callback).Run(error, GURL(), - std::unique_ptr<std::vector<SearchResultInfo>>()); - return; - } - - std::move(callback).Run(error, next_link, std::move(result)); -} - -} // namespace file_system -} // namespace drive
diff --git a/components/drive/chromeos/file_system/search_operation.h b/components/drive/chromeos/file_system/search_operation.h deleted file mode 100644 index 2246974..0000000 --- a/components/drive/chromeos/file_system/search_operation.h +++ /dev/null
@@ -1,86 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_SEARCH_OPERATION_H_ -#define COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_SEARCH_OPERATION_H_ - -#include <memory> - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "base/threading/thread_checker.h" -#include "components/drive/chromeos/file_system_interface.h" -#include "components/drive/file_errors.h" -#include "google_apis/drive/drive_api_error_codes.h" - -namespace base { -class SequencedTaskRunner; -} // namespace base - -namespace google_apis { -class FileList; -} // namespace google_apis - -namespace drive { - -class JobScheduler; - -namespace internal { -class LoaderController; -class ResourceMetadata; -} // namespace internal - -namespace file_system { - -// This class encapsulates the drive Search function. It is responsible for -// sending the request to the drive API. -class SearchOperation { - public: - SearchOperation(base::SequencedTaskRunner* blocking_task_runner, - JobScheduler* scheduler, - internal::ResourceMetadata* metadata, - internal::LoaderController* loader_controller); - ~SearchOperation(); - - // Performs server side content search operation for |search_query|. If - // |next_link| is set, this is the search result url that will be fetched. - // Upon completion, |callback| will be called with the result. This is - // implementation of FileSystemInterface::Search() method. - // - // |callback| must not be null. - void Search(const std::string& search_query, - const GURL& next_link, - SearchCallback callback); - - private: - // Part of Search(), called after the FileList is fetched from the server. - void SearchAfterGetFileList(SearchCallback callback, - google_apis::DriveApiErrorCode gdata_error, - std::unique_ptr<google_apis::FileList> file_list); - - // Part of Search(), called after |result| is filled on the blocking pool. - void SearchAfterResolveSearchResult( - SearchCallback callback, - const GURL& next_link, - std::unique_ptr<std::vector<SearchResultInfo>> result, - FileError error); - - scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; - JobScheduler* scheduler_; - internal::ResourceMetadata* metadata_; - internal::LoaderController* loader_controller_; - - THREAD_CHECKER(thread_checker_); - - // Note: This should remain the last member so it'll be destroyed and - // invalidate the weak pointers before any other members are destroyed. - base::WeakPtrFactory<SearchOperation> weak_ptr_factory_{this}; - DISALLOW_COPY_AND_ASSIGN(SearchOperation); -}; - -} // namespace file_system -} // namespace drive - -#endif // COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_SEARCH_OPERATION_H_
diff --git a/components/drive/chromeos/file_system/set_property_operation.cc b/components/drive/chromeos/file_system/set_property_operation.cc deleted file mode 100644 index bc256c3..0000000 --- a/components/drive/chromeos/file_system/set_property_operation.cc +++ /dev/null
@@ -1,119 +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 "components/drive/chromeos/file_system/set_property_operation.h" - -#include "base/bind.h" -#include "base/files/file_path.h" -#include "base/sequenced_task_runner.h" -#include "components/drive/chromeos/file_system/operation_delegate.h" -#include "components/drive/chromeos/resource_metadata.h" -#include "components/drive/drive.pb.h" -#include "components/drive/file_errors.h" -#include "components/drive/job_scheduler.h" - -namespace drive { -namespace file_system { - -namespace { - -// Adds the property to resource entry. Overwrites existing property if exists. -// If no change has been made (same key, visibility and value is already added) -// then FILE_ERROR_EXISTS is returned. -FileError UpdateLocalState(internal::ResourceMetadata* metadata, - const base::FilePath& file_path, - google_apis::drive::Property::Visibility visibility, - const std::string& key, - const std::string& value, - ResourceEntry* entry) { - using google_apis::drive::Property; - FileError error = metadata->GetResourceEntryByPath(file_path, entry); - if (error != FILE_ERROR_OK) - return error; - - Property_Visibility proto_visibility = Property_Visibility_PRIVATE; - switch (visibility) { - case Property::VISIBILITY_PRIVATE: - proto_visibility = Property_Visibility_PRIVATE; - break; - case Property::VISIBILITY_PUBLIC: - proto_visibility = Property_Visibility_PUBLIC; - break; - } - - ::drive::Property* property_to_update = nullptr; - for (auto& property : *entry->mutable_new_properties()) { - if (property.visibility() == proto_visibility && property.key() == key) { - // Exactly the same property exists, so don't update the local state. - if (property.value() == value) - return FILE_ERROR_EXISTS; - property_to_update = &property; - break; - } - } - - // If no property to update has been found, then add a new one. - if (!property_to_update) - property_to_update = entry->mutable_new_properties()->Add(); - - property_to_update->set_visibility(proto_visibility); - property_to_update->set_key(key); - property_to_update->set_value(value); - entry->set_metadata_edit_state(ResourceEntry::DIRTY); - entry->set_modification_date(base::Time::Now().ToInternalValue()); - - return metadata->RefreshEntry(*entry); -} - -} // namespace - -SetPropertyOperation::SetPropertyOperation( - base::SequencedTaskRunner* blocking_task_runner, - OperationDelegate* delegate, - internal::ResourceMetadata* metadata) - : blocking_task_runner_(blocking_task_runner), - delegate_(delegate), - metadata_(metadata) {} - -SetPropertyOperation::~SetPropertyOperation() = default; - -void SetPropertyOperation::SetProperty( - const base::FilePath& file_path, - google_apis::drive::Property::Visibility visibility, - const std::string& key, - const std::string& value, - const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - ResourceEntry* entry = new ResourceEntry; - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), FROM_HERE, - base::Bind(&UpdateLocalState, metadata_, file_path, visibility, key, - value, entry), - base::Bind(&SetPropertyOperation::SetPropertyAfterUpdateLocalState, - weak_ptr_factory_.GetWeakPtr(), callback, base::Owned(entry))); -} - -void SetPropertyOperation::SetPropertyAfterUpdateLocalState( - const FileOperationCallback& callback, - const ResourceEntry* entry, - FileError result) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - if (result == FILE_ERROR_OK) { - // Do not notify about the file change, as properties are write only and - // cannot be read, so there is no visible change. - delegate_->OnEntryUpdatedByOperation(ClientContext(USER_INITIATED), - entry->local_id()); - } - - // Even if exists, return success, as the set property operation always - // overwrites existing values. - callback.Run(result == FILE_ERROR_EXISTS ? FILE_ERROR_OK : result); -} - -} // namespace file_system -} // namespace drive
diff --git a/components/drive/chromeos/file_system/set_property_operation.h b/components/drive/chromeos/file_system/set_property_operation.h deleted file mode 100644 index 9f0b729d..0000000 --- a/components/drive/chromeos/file_system/set_property_operation.h +++ /dev/null
@@ -1,70 +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 COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_SET_PROPERTY_OPERATION_H_ -#define COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_SET_PROPERTY_OPERATION_H_ - -#include <string> - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "base/threading/thread_checker.h" -#include "components/drive/file_errors.h" -#include "google_apis/drive/drive_api_requests.h" - -namespace base { -class FilePath; -class SequencedTaskRunner; -} // namespace base - -namespace drive { -namespace internal { -class ResourceMetadata; -} // namespace internal - -class ResourceEntry; - -namespace file_system { - -class OperationDelegate; - -class SetPropertyOperation { - public: - SetPropertyOperation(base::SequencedTaskRunner* blocking_task_runner, - OperationDelegate* delegate, - internal::ResourceMetadata* metadata); - ~SetPropertyOperation(); - - // Sets the |key| property on the entry at |drive_file_path| with the - // specified |visibility|. If the property already exists, it will be - // overwritten. - void SetProperty(const base::FilePath& drive_file_path, - google_apis::drive::Property::Visibility visibility, - const std::string& key, - const std::string& value, - const FileOperationCallback& callback); - - private: - // Part of SetProperty(). Runs after updating the local state. - void SetPropertyAfterUpdateLocalState(const FileOperationCallback& callback, - const ResourceEntry* entry, - FileError result); - - scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; - OperationDelegate* delegate_; - internal::ResourceMetadata* metadata_; - - THREAD_CHECKER(thread_checker_); - - // Note: This should remain the last member so it'll be destroyed and - // invalidate the weak pointers before any other members are destroyed. - base::WeakPtrFactory<SetPropertyOperation> weak_ptr_factory_{this}; - DISALLOW_COPY_AND_ASSIGN(SetPropertyOperation); -}; - -} // namespace file_system -} // namespace drive - -#endif // COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_SET_PROPERTY_OPERATION_H_
diff --git a/components/drive/chromeos/file_system/touch_operation.cc b/components/drive/chromeos/file_system/touch_operation.cc deleted file mode 100644 index 8249f679..0000000 --- a/components/drive/chromeos/file_system/touch_operation.cc +++ /dev/null
@@ -1,95 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/drive/chromeos/file_system/touch_operation.h" - -#include "base/bind.h" -#include "base/files/file_path.h" -#include "base/sequenced_task_runner.h" -#include "base/time/time.h" -#include "components/drive/chromeos/file_system/operation_delegate.h" -#include "components/drive/chromeos/resource_metadata.h" -#include "components/drive/file_change.h" -#include "components/drive/file_errors.h" -#include "components/drive/job_scheduler.h" - -namespace drive { -namespace file_system { - -namespace { - -// Updates the timestamps of the entry specified by |file_path|. -FileError UpdateLocalState(internal::ResourceMetadata* metadata, - const base::FilePath& file_path, - const base::Time& last_access_time, - const base::Time& last_modified_time, - ResourceEntry* entry) { - FileError error = metadata->GetResourceEntryByPath(file_path, entry); - if (error != FILE_ERROR_OK) - return error; - - PlatformFileInfoProto* file_info = entry->mutable_file_info(); - if (!last_access_time.is_null()) - file_info->set_last_accessed(last_access_time.ToInternalValue()); - if (!last_modified_time.is_null()) { - file_info->set_last_modified(last_modified_time.ToInternalValue()); - entry->set_last_modified_by_me(last_modified_time.ToInternalValue()); - } - entry->set_metadata_edit_state(ResourceEntry::DIRTY); - entry->set_modification_date(base::Time::Now().ToInternalValue()); - return metadata->RefreshEntry(*entry); -} - -} // namespace - -TouchOperation::TouchOperation(base::SequencedTaskRunner* blocking_task_runner, - OperationDelegate* delegate, - internal::ResourceMetadata* metadata) - : blocking_task_runner_(blocking_task_runner), - delegate_(delegate), - metadata_(metadata) {} - -TouchOperation::~TouchOperation() = default; - -void TouchOperation::TouchFile(const base::FilePath& file_path, - const base::Time& last_access_time, - const base::Time& last_modified_time, - const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - ResourceEntry* entry = new ResourceEntry; - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), FROM_HERE, - base::Bind(&UpdateLocalState, metadata_, file_path, last_access_time, - last_modified_time, entry), - base::Bind(&TouchOperation::TouchFileAfterUpdateLocalState, - weak_ptr_factory_.GetWeakPtr(), file_path, callback, - base::Owned(entry))); -} - -void TouchOperation::TouchFileAfterUpdateLocalState( - const base::FilePath& file_path, - const FileOperationCallback& callback, - const ResourceEntry* entry, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - FileChange changed_files; - changed_files.Update(file_path, entry->file_info().is_directory() - ? FileChange::FILE_TYPE_DIRECTORY - : FileChange::FILE_TYPE_FILE, - FileChange::CHANGE_TYPE_ADD_OR_UPDATE); - - if (error == FILE_ERROR_OK) { - delegate_->OnFileChangedByOperation(changed_files); - delegate_->OnEntryUpdatedByOperation(ClientContext(USER_INITIATED), - entry->local_id()); - } - callback.Run(error); -} - -} // namespace file_system -} // namespace drive
diff --git a/components/drive/chromeos/file_system/touch_operation.h b/components/drive/chromeos/file_system/touch_operation.h deleted file mode 100644 index 8712382..0000000 --- a/components/drive/chromeos/file_system/touch_operation.h +++ /dev/null
@@ -1,68 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_TOUCH_OPERATION_H_ -#define COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_TOUCH_OPERATION_H_ - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "base/threading/thread_checker.h" -#include "components/drive/file_errors.h" - -namespace base { -class FilePath; -class SequencedTaskRunner; -class Time; -} // namespace base - -namespace drive { -namespace internal { -class ResourceMetadata; -} // namespace internal - -class ResourceEntry; - -namespace file_system { - -class OperationDelegate; - -class TouchOperation { - public: - TouchOperation(base::SequencedTaskRunner* blocking_task_runner, - OperationDelegate* delegate, - internal::ResourceMetadata* metadata); - ~TouchOperation(); - - // Touches the file by updating last access time and last modified time. - // Upon completion, invokes |callback|. - // |last_access_time|, |last_modified_time| and |callback| must not be null. - void TouchFile(const base::FilePath& file_path, - const base::Time& last_access_time, - const base::Time& last_modified_time, - const FileOperationCallback& callback); - - private: - // Part of TouchFile(). Runs after updating the local state. - void TouchFileAfterUpdateLocalState(const base::FilePath& file_path, - const FileOperationCallback& callback, - const ResourceEntry* entry, - FileError error); - - scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; - OperationDelegate* delegate_; - internal::ResourceMetadata* metadata_; - - THREAD_CHECKER(thread_checker_); - - // Note: This should remain the last member so it'll be destroyed and - // invalidate the weak pointers before any other members are destroyed. - base::WeakPtrFactory<TouchOperation> weak_ptr_factory_{this}; - DISALLOW_COPY_AND_ASSIGN(TouchOperation); -}; - -} // namespace file_system -} // namespace drive - -#endif // COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_TOUCH_OPERATION_H_
diff --git a/components/drive/chromeos/file_system/truncate_operation.cc b/components/drive/chromeos/file_system/truncate_operation.cc deleted file mode 100644 index 6d13c66..0000000 --- a/components/drive/chromeos/file_system/truncate_operation.cc +++ /dev/null
@@ -1,141 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/drive/chromeos/file_system/truncate_operation.h" - -#include "base/bind.h" -#include "base/callback_helpers.h" -#include "base/files/file.h" -#include "base/files/file_path.h" -#include "base/logging.h" -#include "base/sequenced_task_runner.h" -#include "base/task_runner_util.h" -#include "base/threading/thread_task_runner_handle.h" -#include "components/drive/chromeos/file_cache.h" -#include "components/drive/chromeos/file_system/download_operation.h" -#include "components/drive/chromeos/file_system/operation_delegate.h" -#include "components/drive/drive.pb.h" -#include "components/drive/file_errors.h" -#include "components/drive/job_scheduler.h" - -namespace drive { -namespace file_system { -namespace { - -// Truncates the local file at |local_cache_path| to the |length| bytes, -// then marks the resource is dirty on |cache|. -FileError TruncateOnBlockingPool(internal::ResourceMetadata* metadata, - internal::FileCache* cache, - const std::string& local_id, - const base::FilePath& local_cache_path, - int64_t length) { - DCHECK(metadata); - DCHECK(cache); - - std::unique_ptr<base::ScopedClosureRunner> file_closer; - FileError error = cache->OpenForWrite(local_id, &file_closer); - if (error != FILE_ERROR_OK) - return error; - - base::File file(local_cache_path, - base::File::FLAG_OPEN | base::File::FLAG_WRITE); - if (!file.IsValid()) - return FILE_ERROR_FAILED; - - if (!file.SetLength(length)) - return FILE_ERROR_FAILED; - - return FILE_ERROR_OK; -} - -} // namespace - -TruncateOperation::TruncateOperation( - base::SequencedTaskRunner* blocking_task_runner, - OperationDelegate* delegate, - JobScheduler* scheduler, - internal::ResourceMetadata* metadata, - internal::FileCache* cache, - const base::FilePath& temporary_file_directory) - : blocking_task_runner_(blocking_task_runner), - delegate_(delegate), - metadata_(metadata), - cache_(cache), - download_operation_(new DownloadOperation(blocking_task_runner, - delegate, - scheduler, - metadata, - cache, - temporary_file_directory)) {} - -TruncateOperation::~TruncateOperation() = default; - -void TruncateOperation::Truncate(const base::FilePath& file_path, - int64_t length, - const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - if (length < 0) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(callback, FILE_ERROR_INVALID_OPERATION)); - return; - } - - // TODO(kinaba): http://crbug.com/132780. - // Optimize the cases for small |length|, at least for |length| == 0. - download_operation_->EnsureFileDownloadedByPath( - file_path, - ClientContext(USER_INITIATED), - GetFileContentInitializedCallback(), - google_apis::GetContentCallback(), - base::Bind(&TruncateOperation::TruncateAfterEnsureFileDownloadedByPath, - weak_ptr_factory_.GetWeakPtr(), length, callback)); -} - -void TruncateOperation::TruncateAfterEnsureFileDownloadedByPath( - int64_t length, - const FileOperationCallback& callback, - FileError error, - const base::FilePath& local_file_path, - std::unique_ptr<ResourceEntry> entry) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - if (error != FILE_ERROR_OK) { - callback.Run(error); - return; - } - DCHECK(entry); - DCHECK(entry->has_file_specific_info()); - - if (entry->file_specific_info().is_hosted_document()) { - callback.Run(FILE_ERROR_INVALID_OPERATION); - return; - } - - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), - FROM_HERE, - base::Bind(&TruncateOnBlockingPool, - metadata_, cache_, entry->local_id(), local_file_path, length), - base::Bind( - &TruncateOperation::TruncateAfterTruncateOnBlockingPool, - weak_ptr_factory_.GetWeakPtr(), entry->local_id(), callback)); -} - -void TruncateOperation::TruncateAfterTruncateOnBlockingPool( - const std::string& local_id, - const FileOperationCallback& callback, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - delegate_->OnEntryUpdatedByOperation(ClientContext(USER_INITIATED), local_id); - - callback.Run(error); -} - -} // namespace file_system -} // namespace drive
diff --git a/components/drive/chromeos/file_system/truncate_operation.h b/components/drive/chromeos/file_system/truncate_operation.h deleted file mode 100644 index d9fe24f..0000000 --- a/components/drive/chromeos/file_system/truncate_operation.h +++ /dev/null
@@ -1,92 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_TRUNCATE_OPERATION_H_ -#define COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_TRUNCATE_OPERATION_H_ - -#include <stdint.h> - -#include <memory> - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "base/threading/thread_checker.h" -#include "components/drive/file_errors.h" - -namespace base { -class FilePath; -class SequencedTaskRunner; -} // namespace base - -namespace drive { - -class JobScheduler; -class ResourceEntry; - -namespace internal { -class FileCache; -class ResourceMetadata; -} // namespace internal - -namespace file_system { - -class OperationDelegate; -class DownloadOperation; - -// This class encapsulates the drive Truncate function. It is responsible for -// fetching the content from the Drive server if necessary, truncating the -// file content actually, and then notifying the file is locally modified and -// that it is necessary to upload the file to the server. -class TruncateOperation { - public: - TruncateOperation(base::SequencedTaskRunner* blocking_task_runner, - OperationDelegate* delegate, - JobScheduler* scheduler, - internal::ResourceMetadata* metadata, - internal::FileCache* cache, - const base::FilePath& temporary_file_directory); - ~TruncateOperation(); - - // Performs the truncate operation on the file at drive path |file_path| to - // |length| bytes. Invokes |callback| when finished with the result of the - // operation. |callback| must not be null. - void Truncate(const base::FilePath& file_path, - int64_t length, - const FileOperationCallback& callback); - - private: - // Part of Truncate(). Called after EnsureFileDownloadedByPath() is complete. - void TruncateAfterEnsureFileDownloadedByPath( - int64_t length, - const FileOperationCallback& callback, - FileError error, - const base::FilePath& local_file_path, - std::unique_ptr<ResourceEntry> resource_entry); - - // Part of Truncate(). Called after TruncateOnBlockingPool() is complete. - void TruncateAfterTruncateOnBlockingPool( - const std::string& local_id, - const FileOperationCallback& callback, - FileError error); - - scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; - OperationDelegate* delegate_; - internal::ResourceMetadata* metadata_; - internal::FileCache* cache_; - - std::unique_ptr<DownloadOperation> download_operation_; - - THREAD_CHECKER(thread_checker_); - - // Note: This should remain the last member so it'll be destroyed and - // invalidate the weak pointers before any other members are destroyed. - base::WeakPtrFactory<TruncateOperation> weak_ptr_factory_{this}; - DISALLOW_COPY_AND_ASSIGN(TruncateOperation); -}; - -} // namespace file_system -} // namespace drive - -#endif // COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_TRUNCATE_OPERATION_H_
diff --git a/components/drive/chromeos/loader_controller.cc b/components/drive/chromeos/loader_controller.cc deleted file mode 100644 index 639824e..0000000 --- a/components/drive/chromeos/loader_controller.cc +++ /dev/null
@@ -1,54 +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 "components/drive/chromeos/loader_controller.h" - -#include <utility> - -#include "base/bind.h" -#include "base/callback_helpers.h" - -namespace drive { -namespace internal { - -LoaderController::LoaderController() : lock_count_(0) {} - -LoaderController::~LoaderController() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); -} - -std::unique_ptr<base::ScopedClosureRunner> LoaderController::GetLock() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - ++lock_count_; - return std::make_unique<base::ScopedClosureRunner>(base::BindOnce( - &LoaderController::Unlock, weak_ptr_factory_.GetWeakPtr())); -} - -void LoaderController::ScheduleRun(base::OnceClosure task) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(task); - - if (lock_count_ > 0) { - pending_tasks_.push_back(std::move(task)); - } else { - std::move(task).Run(); - } -} - -void LoaderController::Unlock() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK_LT(0, lock_count_); - - if (--lock_count_ > 0) - return; - - std::vector<base::OnceClosure> tasks; - tasks.swap(pending_tasks_); - for (auto& task : tasks) - std::move(task).Run(); -} - -} // namespace internal -} // namespace drive
diff --git a/components/drive/chromeos/loader_controller.h b/components/drive/chromeos/loader_controller.h deleted file mode 100644 index 551cbd23..0000000 --- a/components/drive/chromeos/loader_controller.h +++ /dev/null
@@ -1,61 +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 COMPONENTS_DRIVE_CHROMEOS_LOADER_CONTROLLER_H_ -#define COMPONENTS_DRIVE_CHROMEOS_LOADER_CONTROLLER_H_ - -#include <memory> -#include <vector> - -#include "base/callback_forward.h" -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "base/threading/thread_checker.h" - -namespace base { -class ScopedClosureRunner; -} - -namespace drive { -namespace internal { - -// Delays execution of tasks as long as more than one lock is alive. -// Used to ensure that ChangeListLoader does not cause race condition by adding -// new entries created by sync tasks before they do. -// All code which may add entries found on the server to the local metadata -// should use this class. -// TODO(slangley): Consider specific unit tests for LoaderController. Currently -// it is tested as an artifact of other unit tests. -class LoaderController { - public: - LoaderController(); - ~LoaderController(); - - // Increments the lock count and returns an object which decrements the count - // on its destruction. - // While the lock count is positive, tasks will be pending. - // TODO(slangley): Return ScopedClosureRunner directly, rather than one that - // is wrapped in a unique_ptr. - std::unique_ptr<base::ScopedClosureRunner> GetLock(); - - // Runs the task if the lock count is 0, otherwise it will be pending. - void ScheduleRun(base::OnceClosure task); - - private: - // Decrements the lock count. - void Unlock(); - - int lock_count_; - std::vector<base::OnceClosure> pending_tasks_; - - THREAD_CHECKER(thread_checker_); - - base::WeakPtrFactory<LoaderController> weak_ptr_factory_{this}; - DISALLOW_COPY_AND_ASSIGN(LoaderController); -}; - -} // namespace internal -} // namespace drive - -#endif // COMPONENTS_DRIVE_CHROMEOS_LOADER_CONTROLLER_H_
diff --git a/components/drive/chromeos/root_folder_id_loader.h b/components/drive/chromeos/root_folder_id_loader.h deleted file mode 100644 index d77eb25c..0000000 --- a/components/drive/chromeos/root_folder_id_loader.h +++ /dev/null
@@ -1,34 +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 COMPONENTS_DRIVE_CHROMEOS_ROOT_FOLDER_ID_LOADER_H_ -#define COMPONENTS_DRIVE_CHROMEOS_ROOT_FOLDER_ID_LOADER_H_ - -#include <string> - -#include "base/callback.h" -#include "base/optional.h" -#include "components/drive/file_errors.h" - -namespace drive { -namespace internal { - -using RootFolderIdCallback = - base::RepeatingCallback<void(FileError, base::Optional<std::string>)>; - -// RootFolderIdLoader is an interface that will load the root_folder_id for -// change list loader and directory loader. -class RootFolderIdLoader { - public: - virtual ~RootFolderIdLoader() = default; - - // Retrieve the root folder id, which may be obtained from the server or - // potentially could be a constant value. - virtual void GetRootFolderId(const RootFolderIdCallback& callback) = 0; -}; - -} // namespace internal -} // namespace drive - -#endif // COMPONENTS_DRIVE_CHROMEOS_ROOT_FOLDER_ID_LOADER_H_
diff --git a/components/drive/chromeos/start_page_token_loader.cc b/components/drive/chromeos/start_page_token_loader.cc deleted file mode 100644 index 647c4db1..0000000 --- a/components/drive/chromeos/start_page_token_loader.cc +++ /dev/null
@@ -1,93 +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 "components/drive/chromeos/start_page_token_loader.h" - -#include "base/bind.h" -#include "base/threading/thread_task_runner_handle.h" -#include "components/drive/job_scheduler.h" - -using google_apis::StartPageToken; -using google_apis::StartPageTokenCallback; - -namespace drive { -namespace internal { - -StartPageTokenLoader::StartPageTokenLoader(const std::string& team_drive_id, - JobScheduler* scheduler) - : team_drive_id_(team_drive_id), - scheduler_(scheduler), - current_update_task_id_(-1), - pending_update_callbacks_(), - cached_start_page_token_() {} - -StartPageTokenLoader::~StartPageTokenLoader() = default; - -const StartPageToken* StartPageTokenLoader::cached_start_page_token() const { - return cached_start_page_token_.get(); -} - -void StartPageTokenLoader::GetStartPageToken( - const StartPageTokenCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - // If the update task is running, then we will wait for it. - if (!pending_update_callbacks_[current_update_task_id_].empty()) { - pending_update_callbacks_[current_update_task_id_].emplace_back(callback); - return; - } - - if (cached_start_page_token_) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(callback, google_apis::HTTP_NO_CONTENT, - std::make_unique<StartPageToken>( - *cached_start_page_token_))); - } else { - UpdateStartPageToken(callback); - } -} - -void StartPageTokenLoader::UpdateStartPageToken( - const StartPageTokenCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - pending_update_callbacks_[++current_update_task_id_].emplace_back(callback); - - scheduler_->GetStartPageToken( - team_drive_id_, - base::BindRepeating(&StartPageTokenLoader::UpdateStartPageTokenAfterGet, - weak_ptr_factory_.GetWeakPtr(), - current_update_task_id_)); -} - -void StartPageTokenLoader::UpdateStartPageTokenAfterGet( - int task_id, - google_apis::DriveApiErrorCode status, - std::unique_ptr<StartPageToken> start_page_token) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - FileError error = GDataToFileError(status); - - std::vector<StartPageTokenCallback> callbacks = - pending_update_callbacks_[task_id]; - pending_update_callbacks_.erase(task_id); - - if (error != FILE_ERROR_OK) { - for (auto& callback : callbacks) { - callback.Run(status, nullptr); - } - return; - } - - cached_start_page_token_ = - std::make_unique<StartPageToken>(*start_page_token); - - for (auto& callback : callbacks) { - callback.Run(status, std::make_unique<StartPageToken>(*start_page_token)); - } -} - -} // namespace internal -} // namespace drive
diff --git a/components/drive/chromeos/start_page_token_loader.h b/components/drive/chromeos/start_page_token_loader.h deleted file mode 100644 index 2bc43f3..0000000 --- a/components/drive/chromeos/start_page_token_loader.h +++ /dev/null
@@ -1,84 +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 COMPONENTS_DRIVE_CHROMEOS_START_PAGE_TOKEN_LOADER_H_ -#define COMPONENTS_DRIVE_CHROMEOS_START_PAGE_TOKEN_LOADER_H_ - -#include <map> -#include <string> - -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "base/threading/thread_checker.h" -#include "google_apis/drive/drive_api_requests.h" - -namespace drive { - -class JobScheduler; - -namespace internal { - -// Loads from the server and caches the start page token for a given team drive -// id. This class is used to determine where to start retrieving changes from -// the server, and as an optimization will cache the result until an -// update is triggered using UpdateStartPageToken. -class StartPageTokenLoader { - public: - StartPageTokenLoader(const std::string& team_drive_id, - JobScheduler* scheduler); - ~StartPageTokenLoader(); - - // Returns the cached start page token. If there is no cached start page token - // then nullptr is returned. - const google_apis::StartPageToken* cached_start_page_token() const; - - // Gets the most recent start page token and asynchronously runs |callback|. - // How this works is: - // - If there is an UpdateStartPageToken in flight, wait for the result and - // return it. - // - It there is NOT an UpdateStartPageToken in flight, and there is a - // cached start page token, then return the cached value. - // - If neither of the above are true, then start an UpdateStartPageToken - // request and return the result. - void GetStartPageToken(const google_apis::StartPageTokenCallback& callback); - - // Gets the start page token from the server, and caches it if successful. - // This function calls JobScheduler::GetStartPageToken internally. The - // cached result will be used by GetStartPageToken. - void UpdateStartPageToken( - const google_apis::StartPageTokenCallback& callback); - - private: - // This callback is used when the result of UpdateStartPage token returns from - // the server. - void UpdateStartPageTokenAfterGet( - int task_id, - google_apis::DriveApiErrorCode status, - std::unique_ptr<google_apis::StartPageToken> start_page_token); - - // This start page token loader is bound to a single team_drive_id, and will - // always request the token for it. If team_drive_id_ is empty, then it - // retrieves the start page token for the users corpus. - const std::string team_drive_id_; - JobScheduler* scheduler_; // Not owned - THREAD_CHECKER(thread_checker_); - - // We may have more than one update in flight at any time (multiple calls - // to UpdateStartPageToken will produce this scenario). We ensure that any - // calls to GetStartPageToken are bound to the update that was in progress - // when the GetStartPageToken was called, using the callback map below. - int current_update_task_id_; - std::map<int, std::vector<google_apis::StartPageTokenCallback>> - pending_update_callbacks_; - std::unique_ptr<google_apis::StartPageToken> cached_start_page_token_; - - base::WeakPtrFactory<StartPageTokenLoader> weak_ptr_factory_{this}; - DISALLOW_COPY_AND_ASSIGN(StartPageTokenLoader); -}; - -} // namespace internal - -} // namespace drive - -#endif // COMPONENTS_DRIVE_CHROMEOS_START_PAGE_TOKEN_LOADER_H_
diff --git a/components/drive/chromeos/sync/entry_revert_performer.cc b/components/drive/chromeos/sync/entry_revert_performer.cc deleted file mode 100644 index 6786106..0000000 --- a/components/drive/chromeos/sync/entry_revert_performer.cc +++ /dev/null
@@ -1,171 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/drive/chromeos/sync/entry_revert_performer.h" - -#include <utility> - -#include "base/bind.h" -#include "components/drive/chromeos/change_list_processor.h" -#include "components/drive/chromeos/file_system/operation_delegate.h" -#include "components/drive/chromeos/resource_metadata.h" -#include "components/drive/drive.pb.h" -#include "components/drive/drive_api_util.h" -#include "components/drive/file_change.h" -#include "components/drive/job_scheduler.h" -#include "components/drive/resource_entry_conversion.h" -#include "google_apis/drive/drive_api_parser.h" - -namespace drive { -namespace internal { -namespace { - -FileError FinishRevert(ResourceMetadata* metadata, - const std::string& local_id, - google_apis::DriveApiErrorCode status, - std::unique_ptr<google_apis::FileResource> file_resource, - FileChange* changed_files) { - ResourceEntry entry; - std::string parent_resource_id; - FileError error = GDataToFileError(status); - switch (error) { - case FILE_ERROR_OK: - ConvertFileResourceToResourceEntry(*file_resource, &entry, - &parent_resource_id); - break; - - case FILE_ERROR_NOT_FOUND: - entry.set_deleted(true); - break; - - default: - return error; - } - - base::FilePath original_path; - error = metadata->GetFilePath(local_id, &original_path); - if (error != FILE_ERROR_OK) - return error; - - if (entry.deleted()) { - error = metadata->RemoveEntry(local_id); - if (error != FILE_ERROR_OK) - return error; - - changed_files->Update( - original_path, - FileChange::FILE_TYPE_NO_INFO, // Undetermined type for deleted file. - FileChange::CHANGE_TYPE_DELETE); - } else { - changed_files->Update(original_path, entry, FileChange::CHANGE_TYPE_DELETE); - - error = ChangeListProcessor::SetParentLocalIdOfEntry(metadata, &entry, - parent_resource_id); - if (error != FILE_ERROR_OK) - return error; - - entry.set_local_id(local_id); - error = metadata->RefreshEntry(entry); - if (error != FILE_ERROR_OK) - return error; - - base::FilePath new_path; - error = metadata->GetFilePath(local_id, &new_path); - if (error != FILE_ERROR_OK) - return error; - - changed_files->Update(new_path, entry, - FileChange::CHANGE_TYPE_ADD_OR_UPDATE); - } - return FILE_ERROR_OK; -} - -} // namespace - -EntryRevertPerformer::EntryRevertPerformer( - base::SequencedTaskRunner* blocking_task_runner, - file_system::OperationDelegate* delegate, - JobScheduler* scheduler, - ResourceMetadata* metadata) - : blocking_task_runner_(blocking_task_runner), - delegate_(delegate), - scheduler_(scheduler), - metadata_(metadata) {} - -EntryRevertPerformer::~EntryRevertPerformer() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); -} - -void EntryRevertPerformer::RevertEntry(const std::string& local_id, - const ClientContext& context, - const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - std::unique_ptr<ResourceEntry> entry(new ResourceEntry); - ResourceEntry* entry_ptr = entry.get(); - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), FROM_HERE, - base::BindOnce(&ResourceMetadata::GetResourceEntryById, - base::Unretained(metadata_), local_id, entry_ptr), - base::BindOnce(&EntryRevertPerformer::RevertEntryAfterPrepare, - weak_ptr_factory_.GetWeakPtr(), context, callback, - std::move(entry))); -} - -void EntryRevertPerformer::RevertEntryAfterPrepare( - const ClientContext& context, - const FileOperationCallback& callback, - std::unique_ptr<ResourceEntry> entry, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - if (error == FILE_ERROR_OK && entry->resource_id().empty()) - error = FILE_ERROR_INVALID_OPERATION; - - if (error != FILE_ERROR_OK) { - callback.Run(error); - return; - } - - scheduler_->GetFileResource( - entry->resource_id(), - context, - base::Bind(&EntryRevertPerformer::RevertEntryAfterGetFileResource, - weak_ptr_factory_.GetWeakPtr(), callback, entry->local_id())); -} - -void EntryRevertPerformer::RevertEntryAfterGetFileResource( - const FileOperationCallback& callback, - const std::string& local_id, - google_apis::DriveApiErrorCode status, - std::unique_ptr<google_apis::FileResource> entry) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - FileChange* changed_files = new FileChange; - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), FROM_HERE, - base::BindOnce(&FinishRevert, metadata_, local_id, status, - std::move(entry), changed_files), - base::BindOnce(&EntryRevertPerformer::RevertEntryAfterFinishRevert, - weak_ptr_factory_.GetWeakPtr(), callback, - base::Owned(changed_files))); -} - -void EntryRevertPerformer::RevertEntryAfterFinishRevert( - const FileOperationCallback& callback, - const FileChange* changed_files, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - delegate_->OnFileChangedByOperation(*changed_files); - - callback.Run(error); -} - -} // namespace internal -} // namespace drive
diff --git a/components/drive/chromeos/sync/entry_revert_performer.h b/components/drive/chromeos/sync/entry_revert_performer.h deleted file mode 100644 index f7ec6076..0000000 --- a/components/drive/chromeos/sync/entry_revert_performer.h +++ /dev/null
@@ -1,93 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_DRIVE_CHROMEOS_SYNC_ENTRY_REVERT_PERFORMER_H_ -#define COMPONENTS_DRIVE_CHROMEOS_SYNC_ENTRY_REVERT_PERFORMER_H_ - -#include <memory> -#include <set> - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "base/threading/thread_checker.h" -#include "components/drive/file_errors.h" -#include "google_apis/drive/drive_api_error_codes.h" - -namespace base { -class SequencedTaskRunner; -} // namespace base - -namespace google_apis { -class FileResource; -} // namespace google_apis - -namespace drive { - -class FileChange; -class JobScheduler; -class ResourceEntry; -struct ClientContext; - -namespace file_system { -class OperationDelegate; -} // namespace file_system - -namespace internal { - -class ResourceMetadata; - -// This class is responsible to revert local changes of an entry. -class EntryRevertPerformer { - public: - EntryRevertPerformer(base::SequencedTaskRunner* blocking_task_runner, - file_system::OperationDelegate* delegate, - JobScheduler* scheduler, - ResourceMetadata* metadata); - ~EntryRevertPerformer(); - - // Requests the server for metadata of the entry specified by |local_id| - // and overwrites the locally stored entry with it. - // Invokes |callback| when finished with the result of the operation. - // |callback| must not be null. - void RevertEntry(const std::string& local_id, - const ClientContext& context, - const FileOperationCallback& callback); - - private: - // Part of RevertEntry(). Called after local metadata look up. - void RevertEntryAfterPrepare(const ClientContext& context, - const FileOperationCallback& callback, - std::unique_ptr<ResourceEntry> entry, - FileError error); - - // Part of RevertEntry(). Called after GetFileResource is completed. - void RevertEntryAfterGetFileResource( - const FileOperationCallback& callback, - const std::string& local_id, - google_apis::DriveApiErrorCode status, - std::unique_ptr<google_apis::FileResource> entry); - - // Part of RevertEntry(). Called after local metadata is updated. - void RevertEntryAfterFinishRevert(const FileOperationCallback& callback, - const FileChange* changed_files, - FileError error); - - scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; - file_system::OperationDelegate* delegate_; - JobScheduler* scheduler_; - ResourceMetadata* metadata_; - - THREAD_CHECKER(thread_checker_); - - // Note: This should remain the last member so it'll be destroyed and - // invalidate the weak pointers before any other members are destroyed. - base::WeakPtrFactory<EntryRevertPerformer> weak_ptr_factory_{this}; - DISALLOW_COPY_AND_ASSIGN(EntryRevertPerformer); -}; - -} // namespace internal -} // namespace drive - -#endif // COMPONENTS_DRIVE_CHROMEOS_SYNC_ENTRY_REVERT_PERFORMER_H_
diff --git a/components/drive/chromeos/sync/entry_update_performer.cc b/components/drive/chromeos/sync/entry_update_performer.cc deleted file mode 100644 index 0a461f9..0000000 --- a/components/drive/chromeos/sync/entry_update_performer.cc +++ /dev/null
@@ -1,453 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/drive/chromeos/sync/entry_update_performer.h" - -#include <stdint.h> - -#include <set> - -#include "base/bind.h" -#include "base/callback_helpers.h" -#include "base/files/file_util.h" -#include "components/drive/chromeos/file_cache.h" -#include "components/drive/chromeos/file_system/operation_delegate.h" -#include "components/drive/chromeos/loader_controller.h" -#include "components/drive/chromeos/resource_metadata.h" -#include "components/drive/chromeos/sync/entry_revert_performer.h" -#include "components/drive/chromeos/sync/remove_performer.h" -#include "components/drive/drive.pb.h" -#include "components/drive/file_change.h" -#include "components/drive/file_system_core_util.h" -#include "components/drive/job_scheduler.h" -#include "google_apis/drive/drive_api_parser.h" - -namespace drive { -namespace internal { - -struct EntryUpdatePerformer::LocalState { - LocalState() : cache_file_size(0), should_content_update(false) {} - - ResourceEntry entry; - ResourceEntry parent_entry; - base::FilePath drive_file_path; - base::FilePath cache_file_path; - int64_t cache_file_size; - bool should_content_update; -}; - -namespace { - -struct PropertyCompare { - bool operator()(const drive::Property& x, const drive::Property& y) const { - if (x.key() < y.key()) - return true; - if (x.key() > y.key()) - return false; - if (x.value() < y.value()) - return true; - if (y.value() > y.value()) - return false; - return x.visibility() < y.visibility(); - } -}; - -// Looks up ResourceEntry for source entry and its parent. -FileError PrepareUpdate(ResourceMetadata* metadata, - FileCache* cache, - const std::string& local_id, - EntryUpdatePerformer::LocalState* local_state) { - FileError error = metadata->GetResourceEntryById(local_id, - &local_state->entry); - if (error != FILE_ERROR_OK) - return error; - - error = metadata->GetResourceEntryById(local_state->entry.parent_local_id(), - &local_state->parent_entry); - if (error != FILE_ERROR_OK) - return error; - - error = metadata->GetFilePath(local_id, &local_state->drive_file_path); - if (error != FILE_ERROR_OK) - return error; - - if (!local_state->entry.file_info().is_directory() && - !local_state->entry.file_specific_info().cache_state().is_present() && - local_state->entry.resource_id().empty()) { - // Locally created file with no cache file, store an empty file. - base::FilePath empty_file; - if (!base::CreateTemporaryFile(&empty_file)) - return FILE_ERROR_FAILED; - error = cache->Store(local_id, std::string(), empty_file, - FileCache::FILE_OPERATION_MOVE); - if (error != FILE_ERROR_OK) - return error; - error = metadata->GetResourceEntryById(local_id, &local_state->entry); - if (error != FILE_ERROR_OK) - return error; - } - - // Check if content update is needed or not. - if (local_state->entry.file_specific_info().cache_state().is_dirty() && - !cache->IsOpenedForWrite(local_id)) { - // Update cache entry's MD5 if needed. - if (local_state->entry.file_specific_info().cache_state().md5().empty()) { - error = cache->UpdateMd5(local_id); - if (error != FILE_ERROR_OK) - return error; - error = metadata->GetResourceEntryById(local_id, &local_state->entry); - if (error != FILE_ERROR_OK) - return error; - } - - if (local_state->entry.file_specific_info().cache_state().md5() == - local_state->entry.file_specific_info().md5()) { - error = cache->ClearDirty(local_id); - if (error != FILE_ERROR_OK) - return error; - } else { - error = cache->GetFile(local_id, &local_state->cache_file_path); - if (error != FILE_ERROR_OK) - return error; - const bool result = base::GetFileSize(local_state->cache_file_path, - &local_state->cache_file_size); - if (!result) - return FILE_ERROR_FAILED; - local_state->should_content_update = true; - } - } - - // Update metadata_edit_state. - switch (local_state->entry.metadata_edit_state()) { - case ResourceEntry::CLEAN: // Nothing to do. - case ResourceEntry::SYNCING: // Error during the last update. Go ahead. - break; - - case ResourceEntry::DIRTY: - local_state->entry.set_metadata_edit_state(ResourceEntry::SYNCING); - error = metadata->RefreshEntry(local_state->entry); - if (error != FILE_ERROR_OK) - return error; - break; - } - return FILE_ERROR_OK; -} - -FileError FinishUpdate( - ResourceMetadata* metadata, - FileCache* cache, - std::unique_ptr<EntryUpdatePerformer::LocalState> local_state, - std::unique_ptr<google_apis::FileResource> file_resource, - FileChange* changed_files) { - ResourceEntry entry; - FileError error = - metadata->GetResourceEntryById(local_state->entry.local_id(), &entry); - if (error != FILE_ERROR_OK) - return error; - - // When creating new entries, update check may add a new entry with the same - // resource ID before us. If such an entry exists, remove it. - std::string existing_local_id; - error = - metadata->GetIdByResourceId(file_resource->file_id(), &existing_local_id); - - switch (error) { - case FILE_ERROR_OK: - if (existing_local_id != local_state->entry.local_id()) { - base::FilePath existing_entry_path; - error = metadata->GetFilePath(existing_local_id, &existing_entry_path); - if (error != FILE_ERROR_OK) - return error; - error = metadata->RemoveEntry(existing_local_id); - if (error != FILE_ERROR_OK) - return error; - changed_files->Update(existing_entry_path, entry, - FileChange::CHANGE_TYPE_DELETE); - } - break; - case FILE_ERROR_NOT_FOUND: - break; - default: - return error; - } - - // Update metadata_edit_state and MD5. - switch (entry.metadata_edit_state()) { - case ResourceEntry::CLEAN: // Nothing to do. - case ResourceEntry::DIRTY: // Entry was edited again during the update. - break; - - case ResourceEntry::SYNCING: - entry.set_metadata_edit_state(ResourceEntry::CLEAN); - break; - } - if (!entry.file_info().is_directory()) - entry.mutable_file_specific_info()->set_md5(file_resource->md5_checksum()); - entry.set_resource_id(file_resource->file_id()); - - // Keep only those properties which have been added or changed in the proto - // during the update. - std::set<drive::Property, PropertyCompare> synced_properties( - local_state->entry.new_properties().begin(), - local_state->entry.new_properties().end()); - - google::protobuf::RepeatedPtrField<drive::Property> not_synced_properties; - for (const auto& property : entry.new_properties()) { - if (!synced_properties.count(property)) { - Property* const not_synced_property = not_synced_properties.Add(); - not_synced_property->CopyFrom(property); - } - } - entry.mutable_new_properties()->Swap(¬_synced_properties); - - error = metadata->RefreshEntry(entry); - if (error != FILE_ERROR_OK) - return error; - base::FilePath entry_path; - error = metadata->GetFilePath(local_state->entry.local_id(), &entry_path); - if (error != FILE_ERROR_OK) - return error; - changed_files->Update(entry_path, entry, - FileChange::CHANGE_TYPE_ADD_OR_UPDATE); - - // Clear dirty bit unless the file has been edited during update. - if (entry.file_specific_info().cache_state().is_dirty() && - entry.file_specific_info().cache_state().md5() == - entry.file_specific_info().md5()) { - error = cache->ClearDirty(local_state->entry.local_id()); - if (error != FILE_ERROR_OK) - return error; - } - return FILE_ERROR_OK; -} - -} // namespace - -EntryUpdatePerformer::EntryUpdatePerformer( - base::SequencedTaskRunner* blocking_task_runner, - file_system::OperationDelegate* delegate, - JobScheduler* scheduler, - ResourceMetadata* metadata, - FileCache* cache, - LoaderController* loader_controller) - : blocking_task_runner_(blocking_task_runner), - delegate_(delegate), - scheduler_(scheduler), - metadata_(metadata), - cache_(cache), - loader_controller_(loader_controller), - remove_performer_(new RemovePerformer(blocking_task_runner, - delegate, - scheduler, - metadata)), - entry_revert_performer_(new EntryRevertPerformer(blocking_task_runner, - delegate, - scheduler, - metadata)) {} - -EntryUpdatePerformer::~EntryUpdatePerformer() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); -} - -void EntryUpdatePerformer::UpdateEntry(const std::string& local_id, - const ClientContext& context, - const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - std::unique_ptr<LocalState> local_state(new LocalState); - LocalState* const local_state_ptr = local_state.get(); - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), - FROM_HERE, - base::Bind(&PrepareUpdate, metadata_, cache_, local_id, local_state_ptr), - base::Bind(&EntryUpdatePerformer::UpdateEntryAfterPrepare, - weak_ptr_factory_.GetWeakPtr(), context, callback, - base::Passed(&local_state))); -} - -void EntryUpdatePerformer::UpdateEntryAfterPrepare( - const ClientContext& context, - const FileOperationCallback& callback, - std::unique_ptr<LocalState> local_state, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - if (error != FILE_ERROR_OK) { - callback.Run(error); - return; - } - - // Trashed entry should be removed. - if (local_state->entry.parent_local_id() == util::kDriveTrashDirLocalId) { - remove_performer_->Remove(local_state->entry.local_id(), context, callback); - return; - } - - // Parent was locally created and needs update. Just return for now. - // This entry should be updated again after the parent update completes. - if (local_state->parent_entry.resource_id().empty() && - local_state->parent_entry.metadata_edit_state() != ResourceEntry::CLEAN) { - callback.Run(FILE_ERROR_OK); - return; - } - - base::Time last_modified = base::Time::FromInternalValue( - local_state->entry.file_info().last_modified()); - base::Time last_accessed = base::Time::FromInternalValue( - local_state->entry.file_info().last_accessed()); - - // Compose a list of new properties from the proto. - google_apis::drive::Properties properties; - for (const auto& proto_property : local_state->entry.new_properties()) { - google_apis::drive::Property property; - switch (proto_property.visibility()) { - case Property_Visibility_PRIVATE: - property.set_visibility( - google_apis::drive::Property::VISIBILITY_PRIVATE); - break; - case Property_Visibility_PUBLIC: - property.set_visibility( - google_apis::drive::Property::VISIBILITY_PUBLIC); - break; - } - property.set_key(proto_property.key()); - property.set_value(proto_property.value()); - properties.push_back(property); - } - - // Perform content update. - if (local_state->should_content_update) { - if (local_state->entry.resource_id().empty()) { - // Not locking the loader intentionally here to avoid making the UI - // unresponsive while uploading large files. - // FinishUpdate() is responsible to resolve conflicts caused by this. - std::unique_ptr<base::ScopedClosureRunner> null_loader_lock; - - UploadNewFileOptions options; - options.modified_date = last_modified; - options.last_viewed_by_me_date = last_accessed; - options.properties = properties; - LocalState* const local_state_ptr = local_state.get(); - scheduler_->UploadNewFile( - local_state_ptr->parent_entry.resource_id(), - local_state_ptr->cache_file_size, local_state_ptr->drive_file_path, - local_state_ptr->cache_file_path, local_state_ptr->entry.title(), - local_state_ptr->entry.file_specific_info().content_mime_type(), - options, context, - base::Bind(&EntryUpdatePerformer::UpdateEntryAfterUpdateResource, - weak_ptr_factory_.GetWeakPtr(), context, callback, - base::Passed(&local_state), - base::Passed(&null_loader_lock))); - } else { - UploadExistingFileOptions options; - options.title = local_state->entry.title(); - options.parent_resource_id = local_state->parent_entry.resource_id(); - options.modified_date = last_modified; - options.last_viewed_by_me_date = last_accessed; - options.properties = properties; - LocalState* const local_state_ptr = local_state.get(); - scheduler_->UploadExistingFile( - local_state_ptr->entry.resource_id(), - local_state_ptr->cache_file_size, local_state_ptr->drive_file_path, - local_state_ptr->cache_file_path, - local_state_ptr->entry.file_specific_info().content_mime_type(), - options, context, - base::Bind( - &EntryUpdatePerformer::UpdateEntryAfterUpdateResource, - weak_ptr_factory_.GetWeakPtr(), context, callback, - base::Passed(&local_state), - base::Passed(std::unique_ptr<base::ScopedClosureRunner>()))); - } - return; - } - - // Create directory. - if (local_state->entry.file_info().is_directory() && - local_state->entry.resource_id().empty()) { - // Lock the loader to avoid race conditions. - std::unique_ptr<base::ScopedClosureRunner> loader_lock = - loader_controller_->GetLock(); - - AddNewDirectoryOptions options; - options.modified_date = last_modified; - options.last_viewed_by_me_date = last_accessed; - options.properties = properties; - LocalState* const local_state_ptr = local_state.get(); - scheduler_->AddNewDirectory( - local_state_ptr->parent_entry.resource_id(), - local_state_ptr->entry.title(), options, context, - base::Bind(&EntryUpdatePerformer::UpdateEntryAfterUpdateResource, - weak_ptr_factory_.GetWeakPtr(), context, callback, - base::Passed(&local_state), base::Passed(&loader_lock))); - return; - } - - // No need to perform update. - if (local_state->entry.metadata_edit_state() == ResourceEntry::CLEAN || - local_state->entry.resource_id().empty()) { - callback.Run(FILE_ERROR_OK); - return; - } - - // Perform metadata update. - LocalState* const local_state_ptr = local_state.get(); - scheduler_->UpdateResource( - local_state_ptr->entry.resource_id(), - local_state_ptr->parent_entry.resource_id(), - local_state_ptr->entry.title(), last_modified, last_accessed, properties, - context, - base::Bind(&EntryUpdatePerformer::UpdateEntryAfterUpdateResource, - weak_ptr_factory_.GetWeakPtr(), context, callback, - base::Passed(&local_state), - base::Passed(std::unique_ptr<base::ScopedClosureRunner>()))); -} - -void EntryUpdatePerformer::UpdateEntryAfterUpdateResource( - const ClientContext& context, - const FileOperationCallback& callback, - std::unique_ptr<LocalState> local_state, - std::unique_ptr<base::ScopedClosureRunner> loader_lock, - google_apis::DriveApiErrorCode status, - std::unique_ptr<google_apis::FileResource> entry) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - if (status == google_apis::HTTP_FORBIDDEN) { - // Editing this entry is not allowed, revert local changes. - entry_revert_performer_->RevertEntry(local_state->entry.local_id(), context, - callback); - return; - } - - FileError error = GDataToFileError(status); - if (error != FILE_ERROR_OK) { - callback.Run(error); - return; - } - - FileChange* changed_files = new FileChange; - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), FROM_HERE, - base::Bind(&FinishUpdate, metadata_, cache_, base::Passed(&local_state), - base::Passed(&entry), changed_files), - base::Bind(&EntryUpdatePerformer::UpdateEntryAfterFinish, - weak_ptr_factory_.GetWeakPtr(), callback, - base::Owned(changed_files))); -} - -void EntryUpdatePerformer::UpdateEntryAfterFinish( - const FileOperationCallback& callback, - const FileChange* changed_files, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - delegate_->OnFileChangedByOperation(*changed_files); - callback.Run(error); -} - -} // namespace internal -} // namespace drive
diff --git a/components/drive/chromeos/sync/entry_update_performer.h b/components/drive/chromeos/sync/entry_update_performer.h deleted file mode 100644 index db97cc0..0000000 --- a/components/drive/chromeos/sync/entry_update_performer.h +++ /dev/null
@@ -1,106 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_DRIVE_CHROMEOS_SYNC_ENTRY_UPDATE_PERFORMER_H_ -#define COMPONENTS_DRIVE_CHROMEOS_SYNC_ENTRY_UPDATE_PERFORMER_H_ - -#include <memory> - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "base/threading/thread_checker.h" -#include "components/drive/file_errors.h" -#include "google_apis/drive/drive_api_error_codes.h" - -namespace base { -class ScopedClosureRunner; -class SequencedTaskRunner; -} // namespace base - -namespace google_apis { -class FileResource; -} // namespace google_apis - -namespace drive { - -class FileChange; -class JobScheduler; -struct ClientContext; - -namespace file_system { -class OperationDelegate; -} // namespace file_system - -namespace internal { - -class EntryRevertPerformer; -class FileCache; -class LoaderController; -class RemovePerformer; -class ResourceMetadata; - -// This class is responsible to perform server side update of an entry. -class EntryUpdatePerformer { - public: - EntryUpdatePerformer(base::SequencedTaskRunner* blocking_task_runner, - file_system::OperationDelegate* delegate, - JobScheduler* scheduler, - ResourceMetadata* metadata, - FileCache* cache, - LoaderController* loader_controller); - ~EntryUpdatePerformer(); - - // Requests the server to update the metadata of the entry specified by - // |local_id| with the locally stored one. - // Invokes |callback| when finished with the result of the operation. - // |callback| must not be null. - void UpdateEntry(const std::string& local_id, - const ClientContext& context, - const FileOperationCallback& callback); - - struct LocalState; - - private: - // Part of UpdateEntry(). Called after local metadata look up. - void UpdateEntryAfterPrepare(const ClientContext& context, - const FileOperationCallback& callback, - std::unique_ptr<LocalState> local_state, - FileError error); - - // Part of UpdateEntry(). Called after UpdateResource is completed. - void UpdateEntryAfterUpdateResource( - const ClientContext& context, - const FileOperationCallback& callback, - std::unique_ptr<LocalState> local_state, - std::unique_ptr<base::ScopedClosureRunner> loader_lock, - google_apis::DriveApiErrorCode status, - std::unique_ptr<google_apis::FileResource> entry); - - // Part of UpdateEntry(). Called after FinishUpdate is completed. - void UpdateEntryAfterFinish(const FileOperationCallback& callback, - const FileChange* changed_files, - FileError error); - - scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; - file_system::OperationDelegate* delegate_; - JobScheduler* scheduler_; - ResourceMetadata* metadata_; - FileCache* cache_; - LoaderController* loader_controller_; - std::unique_ptr<RemovePerformer> remove_performer_; - std::unique_ptr<EntryRevertPerformer> entry_revert_performer_; - - THREAD_CHECKER(thread_checker_); - - // Note: This should remain the last member so it'll be destroyed and - // invalidate the weak pointers before any other members are destroyed. - base::WeakPtrFactory<EntryUpdatePerformer> weak_ptr_factory_{this}; - DISALLOW_COPY_AND_ASSIGN(EntryUpdatePerformer); -}; - -} // namespace internal -} // namespace drive - -#endif // COMPONENTS_DRIVE_CHROMEOS_SYNC_ENTRY_UPDATE_PERFORMER_H_
diff --git a/components/drive/chromeos/sync/remove_performer.cc b/components/drive/chromeos/sync/remove_performer.cc deleted file mode 100644 index 744bb28..0000000 --- a/components/drive/chromeos/sync/remove_performer.cc +++ /dev/null
@@ -1,251 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/drive/chromeos/sync/remove_performer.h" - -#include "base/bind.h" -#include "base/sequenced_task_runner.h" -#include "components/drive/chromeos/file_system/operation_delegate.h" -#include "components/drive/chromeos/resource_metadata.h" -#include "components/drive/chromeos/sync/entry_revert_performer.h" -#include "components/drive/drive.pb.h" -#include "components/drive/drive_api_util.h" -#include "components/drive/file_system_core_util.h" -#include "components/drive/job_scheduler.h" -#include "components/drive/resource_entry_conversion.h" -#include "google_apis/drive/drive_api_parser.h" - -namespace drive { -namespace internal { - -namespace { - -// Updates local metadata and after remote unparenting. -FileError UpdateLocalStateAfterUnparent(ResourceMetadata* metadata, - const std::string& local_id) { - ResourceEntry entry; - FileError error = metadata->GetResourceEntryById(local_id, &entry); - if (error != FILE_ERROR_OK) - return error; - entry.set_parent_local_id(util::kDriveOtherDirLocalId); - return metadata->RefreshEntry(entry); -} - -// Utility function to run ResourceMetadata::RemoveEntry from UI thread. -void RemoveEntryOnUIThread(base::SequencedTaskRunner* blocking_task_runner, - ResourceMetadata* metadata, - const std::string& local_id, - const FileOperationCallback& callback) { - base::PostTaskAndReplyWithResult( - blocking_task_runner, - FROM_HERE, - base::Bind(&ResourceMetadata::RemoveEntry, - base::Unretained(metadata), local_id), - callback); -} - -} // namespace - -RemovePerformer::RemovePerformer( - base::SequencedTaskRunner* blocking_task_runner, - file_system::OperationDelegate* delegate, - JobScheduler* scheduler, - ResourceMetadata* metadata) - : blocking_task_runner_(blocking_task_runner), - delegate_(delegate), - scheduler_(scheduler), - metadata_(metadata), - entry_revert_performer_(new EntryRevertPerformer(blocking_task_runner, - delegate, - scheduler, - metadata)) {} - -RemovePerformer::~RemovePerformer() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); -} - -// Returns |entry| corresponding to |local_id|. -// Adding to that, removes the entry when it does not exist on the server. -FileError TryToRemoveLocally(ResourceMetadata* metadata, - const std::string& local_id, - ResourceEntry* entry) { - FileError error = metadata->GetResourceEntryById(local_id, entry); - if (error != FILE_ERROR_OK || !entry->resource_id().empty()) - return error; - return metadata->RemoveEntry(local_id); -} - -void RemovePerformer::Remove(const std::string& local_id, - const ClientContext& context, - const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - ResourceEntry* entry = new ResourceEntry; - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), - FROM_HERE, - base::Bind(&TryToRemoveLocally, metadata_, local_id, entry), - base::Bind(&RemovePerformer::RemoveAfterGetResourceEntry, - weak_ptr_factory_.GetWeakPtr(), - context, - callback, - base::Owned(entry))); -} - -void RemovePerformer::RemoveAfterGetResourceEntry( - const ClientContext& context, - const FileOperationCallback& callback, - const ResourceEntry* entry, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - if (error != FILE_ERROR_OK || entry->resource_id().empty()) { - callback.Run(error); - return; - } - - // To match with the behavior of drive.google.com: - // Removal of shared entries under MyDrive is just removing from the parent. - // The entry will stay in shared-with-me (in other words, in "drive/other".) - // - // TODO(kinaba): to be more precise, we might be better to branch by whether - // or not the current account is an owner of the file. The code below is - // written under the assumption that |shared_with_me| coincides with that. - if (entry->shared_with_me()) { - UnparentResource(context, callback, entry->resource_id(), - entry->local_id()); - } else { - // Otherwise try sending the entry to trash. - TrashResource(context, callback, entry->resource_id(), entry->local_id()); - } -} - -void RemovePerformer::TrashResource(const ClientContext& context, - const FileOperationCallback& callback, - const std::string& resource_id, - const std::string& local_id) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - scheduler_->TrashResource( - resource_id, - context, - base::Bind(&RemovePerformer::TrashResourceAfterUpdateRemoteState, - weak_ptr_factory_.GetWeakPtr(), context, callback, local_id)); -} - -void RemovePerformer::TrashResourceAfterUpdateRemoteState( - const ClientContext& context, - const FileOperationCallback& callback, - const std::string& local_id, - google_apis::DriveApiErrorCode status) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - if (status == google_apis::HTTP_FORBIDDEN) { - // Editing this entry is not allowed, revert local changes. - entry_revert_performer_->RevertEntry(local_id, context, callback); - delegate_->OnDriveSyncError( - file_system::DRIVE_SYNC_ERROR_DELETE_WITHOUT_PERMISSION, local_id); - return; - } - - FileError error = GDataToFileError(status); - if (error == FILE_ERROR_NOT_FOUND) { // Remove local entry when not found. - RemoveEntryOnUIThread(blocking_task_runner_.get(), metadata_, local_id, - callback); - return; - } - - // Now we're done. If the entry is trashed on the server, it'll be also - // deleted locally on the next update. - callback.Run(error); -} - -void RemovePerformer::UnparentResource(const ClientContext& context, - const FileOperationCallback& callback, - const std::string& resource_id, - const std::string& local_id) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - scheduler_->GetFileResource( - resource_id, - context, - base::Bind(&RemovePerformer::UnparentResourceAfterGetFileResource, - weak_ptr_factory_.GetWeakPtr(), context, callback, local_id)); -} - -void RemovePerformer::UnparentResourceAfterGetFileResource( - const ClientContext& context, - const FileOperationCallback& callback, - const std::string& local_id, - google_apis::DriveApiErrorCode status, - std::unique_ptr<google_apis::FileResource> file_resource) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - FileError error = GDataToFileError(status); - if (error == FILE_ERROR_NOT_FOUND) { // Remove local entry when not found. - RemoveEntryOnUIThread(blocking_task_runner_.get(), metadata_, local_id, - callback); - return; - } - - if (error != FILE_ERROR_OK) { - callback.Run(error); - return; - } - - ResourceEntry entry; - std::string parent_resource_id; - ConvertFileResourceToResourceEntry(*file_resource, &entry, - &parent_resource_id); - - if (!entry.shared_with_me()) { - // shared_with_me() has changed on the server. - UnparentResourceAfterUpdateRemoteState(callback, local_id, - google_apis::HTTP_CONFLICT); - return; - } - - if (parent_resource_id.empty()) { - // This entry is unparented already. - UnparentResourceAfterUpdateRemoteState(callback, local_id, - google_apis::HTTP_NO_CONTENT); - return; - } - - scheduler_->RemoveResourceFromDirectory( - parent_resource_id, - entry.resource_id(), - context, - base::Bind(&RemovePerformer::UnparentResourceAfterUpdateRemoteState, - weak_ptr_factory_.GetWeakPtr(), callback, local_id)); -} - -void RemovePerformer::UnparentResourceAfterUpdateRemoteState( - const FileOperationCallback& callback, - const std::string& local_id, - google_apis::DriveApiErrorCode status) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - FileError error = GDataToFileError(status); - if (error != FILE_ERROR_OK) { - callback.Run(error); - return; - } - - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), - FROM_HERE, - base::Bind(&UpdateLocalStateAfterUnparent, metadata_, local_id), - callback); -} - -} // namespace internal -} // namespace drive
diff --git a/components/drive/chromeos/sync/remove_performer.h b/components/drive/chromeos/sync/remove_performer.h deleted file mode 100644 index a043a95d..0000000 --- a/components/drive/chromeos/sync/remove_performer.h +++ /dev/null
@@ -1,115 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_DRIVE_CHROMEOS_SYNC_REMOVE_PERFORMER_H_ -#define COMPONENTS_DRIVE_CHROMEOS_SYNC_REMOVE_PERFORMER_H_ - -#include <memory> - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "base/threading/thread_checker.h" -#include "components/drive/file_errors.h" -#include "google_apis/drive/drive_api_error_codes.h" - -namespace base { -class SequencedTaskRunner; -} - -namespace google_apis { -class FileResource; -} - -namespace drive { - -class JobScheduler; -class ResourceEntry; -struct ClientContext; - -namespace file_system { -class OperationDelegate; -} // namespace file_system - -namespace internal { - -class EntryRevertPerformer; -class ResourceMetadata; - -// This class encapsulates the drive Remove function. It is responsible for -// sending the request to the drive API, then updating the local state and -// metadata to reflect the new state. -class RemovePerformer { - public: - RemovePerformer(base::SequencedTaskRunner* blocking_task_runner, - file_system::OperationDelegate* delegate, - JobScheduler* scheduler, - ResourceMetadata* metadata); - ~RemovePerformer(); - - // Removes the resource. - // - // |callback| must not be null. - void Remove(const std::string& local_id, - const ClientContext& context, - const FileOperationCallback& callback); - - private: - // Part of Remove(). Called after GetResourceEntry() completion. - void RemoveAfterGetResourceEntry(const ClientContext& context, - const FileOperationCallback& callback, - const ResourceEntry* entry, - FileError error); - - // Requests the server to move the specified resource to the trash. - void TrashResource(const ClientContext& context, - const FileOperationCallback& callback, - const std::string& resource_id, - const std::string& local_id); - - // Part of TrashResource(). Called after server-side removal is done. - void TrashResourceAfterUpdateRemoteState( - const ClientContext& context, - const FileOperationCallback& callback, - const std::string& local_id, - google_apis::DriveApiErrorCode status); - - // Requests the server to detach the specified resource from its parent. - void UnparentResource(const ClientContext& context, - const FileOperationCallback& callback, - const std::string& resource_id, - const std::string& local_id); - - // Part of UnparentResource(). - void UnparentResourceAfterGetFileResource( - const ClientContext& context, - const FileOperationCallback& callback, - const std::string& local_id, - google_apis::DriveApiErrorCode status, - std::unique_ptr<google_apis::FileResource> file_resource); - - // Part of UnparentResource(). - void UnparentResourceAfterUpdateRemoteState( - const FileOperationCallback& callback, - const std::string& local_id, - google_apis::DriveApiErrorCode status); - - scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; - file_system::OperationDelegate* delegate_; - JobScheduler* scheduler_; - ResourceMetadata* metadata_; - std::unique_ptr<EntryRevertPerformer> entry_revert_performer_; - - THREAD_CHECKER(thread_checker_); - - // Note: This should remain the last member so it'll be destroyed and - // invalidate the weak pointers before any other members are destroyed. - base::WeakPtrFactory<RemovePerformer> weak_ptr_factory_{this}; - DISALLOW_COPY_AND_ASSIGN(RemovePerformer); -}; - -} // namespace internal -} // namespace drive - -#endif // COMPONENTS_DRIVE_CHROMEOS_SYNC_REMOVE_PERFORMER_H_
diff --git a/components/drive/chromeos/sync_client.cc b/components/drive/chromeos/sync_client.cc deleted file mode 100644 index 523d94e0..0000000 --- a/components/drive/chromeos/sync_client.cc +++ /dev/null
@@ -1,493 +0,0 @@ -// Copyright (c) 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. - -#include "components/drive/chromeos/sync_client.h" - -#include <stddef.h> - -#include <vector> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/threading/thread_task_runner_handle.h" -#include "components/drive/chromeos/file_cache.h" -#include "components/drive/chromeos/file_system/download_operation.h" -#include "components/drive/chromeos/file_system/operation_delegate.h" -#include "components/drive/chromeos/sync/entry_update_performer.h" -#include "components/drive/drive.pb.h" -#include "components/drive/file_system_core_util.h" -#include "components/drive/job_scheduler.h" -#include "google_apis/drive/task_util.h" - -namespace drive { -namespace internal { - -namespace { - -// The delay constant is used to delay processing a sync task. We should not -// process SyncTasks immediately for the following reasons: -// -// 1) For fetching, the user may accidentally click on "Make available -// offline" checkbox on a file, and immediately cancel it in a second. -// It's a waste to fetch the file in this case. -// -// 2) For uploading, file writing via HTML5 file system API is performed in -// two steps: 1) truncate a file to 0 bytes, 2) write contents. We -// shouldn't start uploading right after the step 1). Besides, the user -// may edit the same file repeatedly in a short period of time. -// -// TODO(satorux): We should find a way to handle the upload case more nicely, -// and shorten the delay. crbug.com/134774 -const int kDelaySeconds = 1; - -// The delay constant is used to delay retrying a sync task on server errors. -const int kLongDelaySeconds = 600; - -// Iterates entries and appends IDs to |to_fetch| if the file is pinned but not -// fetched (not present locally), to |to_update| if the file needs update. -void CollectBacklog(ResourceMetadata* metadata, - std::vector<std::string>* to_fetch, - std::vector<std::string>* to_update) { - DCHECK(to_fetch); - DCHECK(to_update); - - std::unique_ptr<ResourceMetadata::Iterator> it = metadata->GetIterator(); - for (; !it->IsAtEnd(); it->Advance()) { - const std::string& local_id = it->GetID(); - const ResourceEntry& entry = it->GetValue(); - if (entry.parent_local_id() == util::kDriveTrashDirLocalId) { - to_update->push_back(local_id); - continue; - } - - bool should_update = false; - switch (entry.metadata_edit_state()) { - case ResourceEntry::CLEAN: - break; - case ResourceEntry::SYNCING: - case ResourceEntry::DIRTY: - should_update = true; - break; - } - - if (entry.file_specific_info().cache_state().is_pinned() && - !entry.file_specific_info().cache_state().is_present()) - to_fetch->push_back(local_id); - - if (entry.file_specific_info().cache_state().is_dirty()) - should_update = true; - - if (should_update) - to_update->push_back(local_id); - } - DCHECK(!it->HasError()); -} - -// Iterates cache entries and collects IDs of ones with obsolete cache files. -void CheckExistingPinnedFiles(ResourceMetadata* metadata, - FileCache* cache, - std::vector<std::string>* local_ids) { - std::unique_ptr<ResourceMetadata::Iterator> it = metadata->GetIterator(); - for (; !it->IsAtEnd(); it->Advance()) { - const ResourceEntry& entry = it->GetValue(); - const FileCacheEntry& cache_state = - entry.file_specific_info().cache_state(); - const std::string& local_id = it->GetID(); - if (!cache_state.is_pinned() || !cache_state.is_present()) - continue; - - // If MD5s don't match, it indicates the local cache file is stale, unless - // the file is dirty (the MD5 is "local"). We should never re-fetch the - // file when we have a locally modified version. - if (entry.file_specific_info().md5() == cache_state.md5() || - cache_state.is_dirty()) - continue; - - FileError error = cache->Remove(local_id); - if (error != FILE_ERROR_OK) { - LOG(WARNING) << "Failed to remove cache entry: " << local_id; - continue; - } - - error = cache->Pin(local_id); - if (error != FILE_ERROR_OK) { - LOG(WARNING) << "Failed to pin cache entry: " << local_id; - continue; - } - - local_ids->push_back(local_id); - } - DCHECK(!it->HasError()); -} - -// Gets the parent entry of the entry specified by the ID. -FileError GetParentResourceEntry(ResourceMetadata* metadata, - const std::string& local_id, - ResourceEntry* parent) { - ResourceEntry entry; - FileError error = metadata->GetResourceEntryById(local_id, &entry); - if (error != FILE_ERROR_OK) - return error; - return metadata->GetResourceEntryById(entry.parent_local_id(), parent); -} - -} // namespace - -SyncClient::SyncTask::SyncTask() - : state(SUSPENDED), context(BACKGROUND), should_run_again(false) {} -SyncClient::SyncTask::SyncTask(const SyncTask& other) = default; -SyncClient::SyncTask::~SyncTask() = default; - -SyncClient::SyncClient(base::SequencedTaskRunner* blocking_task_runner, - file_system::OperationDelegate* delegate, - JobScheduler* scheduler, - ResourceMetadata* metadata, - FileCache* cache, - LoaderController* loader_controller, - const base::FilePath& temporary_file_directory) - : blocking_task_runner_(blocking_task_runner), - operation_delegate_(delegate), - metadata_(metadata), - cache_(cache), - download_operation_( - new file_system::DownloadOperation(blocking_task_runner, - delegate, - scheduler, - metadata, - cache, - temporary_file_directory)), - entry_update_performer_(new EntryUpdatePerformer(blocking_task_runner, - delegate, - scheduler, - metadata, - cache, - loader_controller)), - delay_(base::TimeDelta::FromSeconds(kDelaySeconds)), - long_delay_(base::TimeDelta::FromSeconds(kLongDelaySeconds)) {} - -SyncClient::~SyncClient() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); -} - -void SyncClient::StartProcessingBacklog() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - std::vector<std::string>* to_fetch = new std::vector<std::string>; - std::vector<std::string>* to_update = new std::vector<std::string>; - blocking_task_runner_->PostTaskAndReply( - FROM_HERE, - base::BindOnce(&CollectBacklog, metadata_, to_fetch, to_update), - base::BindOnce(&SyncClient::OnGetLocalIdsOfBacklog, - weak_ptr_factory_.GetWeakPtr(), base::Owned(to_fetch), - base::Owned(to_update))); -} - -void SyncClient::StartCheckingExistingPinnedFiles() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - std::vector<std::string>* local_ids = new std::vector<std::string>; - blocking_task_runner_->PostTaskAndReply( - FROM_HERE, - base::BindOnce(&CheckExistingPinnedFiles, metadata_, cache_, local_ids), - base::BindOnce(&SyncClient::AddFetchTasks, weak_ptr_factory_.GetWeakPtr(), - base::Owned(local_ids))); -} - -void SyncClient::AddFetchTask(const std::string& local_id) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - AddFetchTaskInternal(local_id, delay_); -} - -void SyncClient::RemoveFetchTask(const std::string& local_id) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - SyncTasks::iterator it = tasks_.find(SyncTasks::key_type(FETCH, local_id)); - if (it == tasks_.end()) - return; - - SyncTask* task = &it->second; - switch (task->state) { - case SUSPENDED: - case PENDING: - OnTaskComplete(FETCH, local_id, FILE_ERROR_ABORT); - break; - case RUNNING: - if (task->cancel_closure) - task->cancel_closure.Run(); - break; - } -} - -void SyncClient::AddUpdateTask(const ClientContext& context, - const std::string& local_id) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - AddUpdateTaskInternal(context, local_id, delay_); -} - -bool SyncClient:: WaitForUpdateTaskToComplete( - const std::string& local_id, - const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - SyncTasks::iterator it = tasks_.find(SyncTasks::key_type(UPDATE, local_id)); - if (it == tasks_.end()) - return false; - - SyncTask* task = &it->second; - task->waiting_callbacks.push_back(callback); - return true; -} - -base::Closure SyncClient::PerformFetchTask(const std::string& local_id, - const ClientContext& context) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - return download_operation_->EnsureFileDownloadedByLocalId( - local_id, - context, - GetFileContentInitializedCallback(), - google_apis::GetContentCallback(), - base::Bind(&SyncClient::OnFetchFileComplete, - weak_ptr_factory_.GetWeakPtr(), - local_id)); -} - -void SyncClient::AddFetchTaskInternal(const std::string& local_id, - const base::TimeDelta& delay) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - SyncTask task; - task.state = PENDING; - task.context = ClientContext(BACKGROUND); - task.task = base::Bind(&SyncClient::PerformFetchTask, - base::Unretained(this), - local_id); - AddTask(SyncTasks::key_type(FETCH, local_id), task, delay); -} - -base::Closure SyncClient::PerformUpdateTask(const std::string& local_id, - const ClientContext& context) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - entry_update_performer_->UpdateEntry( - local_id, - context, - base::Bind(&SyncClient::OnTaskComplete, - weak_ptr_factory_.GetWeakPtr(), - UPDATE, - local_id)); - return base::Closure(); -} - -void SyncClient::AddUpdateTaskInternal(const ClientContext& context, - const std::string& local_id, - const base::TimeDelta& delay) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - SyncTask task; - task.state = PENDING; - task.context = context; - task.task = base::Bind(&SyncClient::PerformUpdateTask, - base::Unretained(this), - local_id); - AddTask(SyncTasks::key_type(UPDATE, local_id), task, delay); -} - -void SyncClient::AddTask(const SyncTasks::key_type& key, - const SyncTask& task, - const base::TimeDelta& delay) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - SyncTasks::iterator it = tasks_.find(key); - if (it != tasks_.end()) { - switch (it->second.state) { - case SUSPENDED: - // Activate the task. - it->second.state = PENDING; - break; - case PENDING: - // The same task will run, do nothing. - return; - case RUNNING: - // Something has changed since the task started. Schedule rerun. - it->second.should_run_again = true; - return; - } - } else { - tasks_[key] = task; - } - DCHECK_EQ(PENDING, task.state); - base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, - base::BindOnce(&SyncClient::StartTask, weak_ptr_factory_.GetWeakPtr(), - key), - delay); -} - -void SyncClient::StartTask(const SyncTasks::key_type& key) { - ResourceEntry* parent = new ResourceEntry; - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), - FROM_HERE, - base::Bind(&GetParentResourceEntry, metadata_, key.second, parent), - base::Bind(&SyncClient::StartTaskAfterGetParentResourceEntry, - weak_ptr_factory_.GetWeakPtr(), - key, - base::Owned(parent))); -} - -void SyncClient::StartTaskAfterGetParentResourceEntry( - const SyncTasks::key_type& key, - const ResourceEntry* parent, - FileError error) { - const SyncType type = key.first; - const std::string& local_id = key.second; - SyncTasks::iterator it = tasks_.find(key); - if (it == tasks_.end()) - return; - - SyncTask* task = &it->second; - switch (task->state) { - case SUSPENDED: - case PENDING: - break; - case RUNNING: // Do nothing. - return; - } - - if (error != FILE_ERROR_OK) { - OnTaskComplete(type, local_id, error); - return; - } - - if (type == UPDATE && - parent->resource_id().empty() && - parent->local_id() != util::kDriveTrashDirLocalId) { - // Parent entry needs to be synced to get a resource ID. - // Suspend the task and register it as a dependent task of the parent. - const SyncTasks::key_type key_parent(type, parent->local_id()); - SyncTasks::iterator it_parent = tasks_.find(key_parent); - if (it_parent == tasks_.end()) { - OnTaskComplete(type, local_id, FILE_ERROR_INVALID_OPERATION); - LOG(WARNING) << "Parent task not found: type = " << type << ", id = " - << local_id << ", parent_id = " << parent->local_id(); - return; - } - task->state = SUSPENDED; - it_parent->second.dependent_tasks.push_back(key); - return; - } - - // Run the task. - task->state = RUNNING; - task->cancel_closure = task->task.Run(task->context); -} - -void SyncClient::OnGetLocalIdsOfBacklog( - const std::vector<std::string>* to_fetch, - const std::vector<std::string>* to_update) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - // Give priority to upload tasks over fetch tasks, so that dirty files are - // uploaded as soon as possible. - for (size_t i = 0; i < to_update->size(); ++i) { - const std::string& local_id = (*to_update)[i]; - DVLOG(1) << "Queuing to update: " << local_id; - AddUpdateTask(ClientContext(BACKGROUND), local_id); - } - - for (size_t i = 0; i < to_fetch->size(); ++i) { - const std::string& local_id = (*to_fetch)[i]; - DVLOG(1) << "Queuing to fetch: " << local_id; - AddFetchTaskInternal(local_id, delay_); - } -} - -void SyncClient::AddFetchTasks(const std::vector<std::string>* local_ids) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - for (size_t i = 0; i < local_ids->size(); ++i) - AddFetchTask((*local_ids)[i]); -} - -void SyncClient::OnTaskComplete(SyncType type, - const std::string& local_id, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - const SyncTasks::key_type key(type, local_id); - SyncTasks::iterator it = tasks_.find(key); - DCHECK(it != tasks_.end()); - - base::TimeDelta retry_delay = base::TimeDelta::FromSeconds(0); - - switch (error) { - case FILE_ERROR_OK: - DVLOG(1) << "Completed: type = " << type << ", id = " << local_id; - break; - case FILE_ERROR_ABORT: - // Ignore it because this is caused by user's cancel operations. - break; - case FILE_ERROR_NO_CONNECTION: - // Run the task again so that we'll retry once the connection is back. - it->second.should_run_again = true; - it->second.context = ClientContext(BACKGROUND); - break; - case FILE_ERROR_SERVICE_UNAVAILABLE: - // Run the task again so that we'll retry once the service is back. - it->second.should_run_again = true; - it->second.context = ClientContext(BACKGROUND); - retry_delay = long_delay_; - operation_delegate_->OnDriveSyncError( - file_system::DRIVE_SYNC_ERROR_SERVICE_UNAVAILABLE, local_id); - break; - case FILE_ERROR_NO_SERVER_SPACE: - operation_delegate_->OnDriveSyncError( - file_system::DRIVE_SYNC_ERROR_NO_SERVER_SPACE, local_id); - break; - default: - operation_delegate_->OnDriveSyncError( - file_system::DRIVE_SYNC_ERROR_MISC, local_id); - LOG(WARNING) << "Failed: type = " << type << ", id = " << local_id - << ": " << FileErrorToString(error); - } - - for (size_t i = 0; i < it->second.waiting_callbacks.size(); ++i) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(it->second.waiting_callbacks[i], error)); - } - it->second.waiting_callbacks.clear(); - - if (it->second.should_run_again) { - DVLOG(1) << "Running again: type = " << type << ", id = " << local_id; - it->second.state = PENDING; - it->second.should_run_again = false; - base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, - base::BindOnce(&SyncClient::StartTask, weak_ptr_factory_.GetWeakPtr(), - key), - retry_delay); - } else { - for (size_t i = 0; i < it->second.dependent_tasks.size(); ++i) - StartTask(it->second.dependent_tasks[i]); - tasks_.erase(it); - } -} - -void SyncClient::OnFetchFileComplete(const std::string& local_id, - FileError error, - const base::FilePath& local_path, - std::unique_ptr<ResourceEntry> entry) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - OnTaskComplete(FETCH, local_id, error); - if (error == FILE_ERROR_ABORT) { - // If user cancels download, unpin the file so that we do not sync the file - // again. - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), FROM_HERE, - base::Bind(&FileCache::Unpin, base::Unretained(cache_), local_id), - base::DoNothing::Repeatedly<FileError>()); - } -} - -} // namespace internal -} // namespace drive
diff --git a/components/drive/chromeos/sync_client.h b/components/drive/chromeos/sync_client.h deleted file mode 100644 index 24d03e79..0000000 --- a/components/drive/chromeos/sync_client.h +++ /dev/null
@@ -1,199 +0,0 @@ -// Copyright (c) 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. - -#ifndef COMPONENTS_DRIVE_CHROMEOS_SYNC_CLIENT_H_ -#define COMPONENTS_DRIVE_CHROMEOS_SYNC_CLIENT_H_ - -#include <map> -#include <memory> -#include <string> -#include <vector> - -#include "base/callback.h" -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "base/threading/thread_checker.h" -#include "base/time/time.h" -#include "components/drive/chromeos/resource_metadata.h" -#include "components/drive/file_errors.h" -#include "components/drive/job_scheduler.h" - -namespace base { -class SequencedTaskRunner; -} - -namespace drive { - -class JobScheduler; -class ResourceEntry; -struct ClientContext; - -namespace file_system { -class DownloadOperation; -class OperationDelegate; -} - -namespace internal { - -class EntryUpdatePerformer; -class FileCache; -class LoaderController; -class ResourceMetadata; - -// The SyncClient is used to synchronize pinned files on Drive and the -// cache on the local drive. -// -// If the user logs out before fetching of the pinned files is complete, this -// client resumes fetching operations next time the user logs in, based on -// the states left in the cache. -class SyncClient { - public: - SyncClient(base::SequencedTaskRunner* blocking_task_runner, - file_system::OperationDelegate* delegate, - JobScheduler* scheduler, - ResourceMetadata* metadata, - FileCache* cache, - LoaderController* loader_controller, - const base::FilePath& temporary_file_directory); - virtual ~SyncClient(); - - // Adds a fetch task. - void AddFetchTask(const std::string& local_id); - - // Removes a fetch task. - void RemoveFetchTask(const std::string& local_id); - - // Adds a update task. - void AddUpdateTask(const ClientContext& context, const std::string& local_id); - - // Waits for the update task to complete and runs the callback. - // Returns false if no task is found for the spcecified ID. - bool WaitForUpdateTaskToComplete(const std::string& local_id, - const FileOperationCallback& callback); - - // Starts processing the backlog (i.e. pinned-but-not-filed files and - // dirty-but-not-uploaded files). Kicks off retrieval of the local - // IDs of these files, and then starts the sync loop. - void StartProcessingBacklog(); - - // Starts checking the existing pinned files to see if these are - // up to date. If stale files are detected, the local IDs of these files - // are added and the sync loop is started. - void StartCheckingExistingPinnedFiles(); - - // Sets a delay for testing. - void set_delay_for_testing(const base::TimeDelta& delay) { - delay_ = delay; - } - - private: - // Types of sync tasks. - enum SyncType { - FETCH, // Fetch a file from the Drive server. - UPDATE, // Updates an entry's metadata or content on the Drive server. - }; - - // States of sync tasks. - enum SyncState { - SUSPENDED, // Task is currently inactive. - PENDING, // Task is going to run. - RUNNING, // Task is running. - }; - - typedef std::pair<SyncType, std::string> SyncTaskKey; - - struct SyncTask { - SyncTask(); - SyncTask(const SyncTask& other); - ~SyncTask(); - SyncState state; - ClientContext context; - base::Callback<base::Closure(const ClientContext& context)> task; - bool should_run_again; - base::Closure cancel_closure; - std::vector<SyncTaskKey> dependent_tasks; - std::vector<FileOperationCallback> waiting_callbacks; - }; - - typedef std::map<SyncTaskKey, SyncTask> SyncTasks; - - // Performs a FETCH task. - base::Closure PerformFetchTask(const std::string& local_id, - const ClientContext& context); - - // Adds a FETCH task. - void AddFetchTaskInternal(const std::string& local_id, - const base::TimeDelta& delay); - - // Performs a UPDATE task. - base::Closure PerformUpdateTask(const std::string& local_id, - const ClientContext& context); - - // Adds a UPDATE task. - void AddUpdateTaskInternal(const ClientContext& context, - const std::string& local_id, - const base::TimeDelta& delay); - - // Adds the given task. If the same task is found, does nothing. - void AddTask(const SyncTasks::key_type& key, - const SyncTask& task, - const base::TimeDelta& delay); - - // Called when a task is ready to start. - void StartTask(const SyncTasks::key_type& key); - void StartTaskAfterGetParentResourceEntry(const SyncTasks::key_type& key, - const ResourceEntry* parent, - FileError error); - - // Called when the local IDs of files in the backlog are obtained. - void OnGetLocalIdsOfBacklog(const std::vector<std::string>* to_fetch, - const std::vector<std::string>* to_update); - - // Adds fetch tasks. - void AddFetchTasks(const std::vector<std::string>* local_ids); - - // Called when a task is completed. - void OnTaskComplete(SyncType type, - const std::string& local_id, - FileError error); - - // Called when the file for |local_id| is fetched. - void OnFetchFileComplete(const std::string& local_id, - FileError error, - const base::FilePath& local_path, - std::unique_ptr<ResourceEntry> entry); - - scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; - file_system::OperationDelegate* operation_delegate_; - ResourceMetadata* metadata_; - FileCache* cache_; - - // Used to fetch pinned files. - std::unique_ptr<file_system::DownloadOperation> download_operation_; - - // Used to update entry metadata. - std::unique_ptr<EntryUpdatePerformer> entry_update_performer_; - - // Sync tasks to be processed. - SyncTasks tasks_; - - // The delay is used for delaying processing tasks in AddTask(). - base::TimeDelta delay_; - - // The delay is used for delaying retry of tasks on server errors. - base::TimeDelta long_delay_; - - THREAD_CHECKER(thread_checker_); - - // Note: This should remain the last member so it'll be destroyed and - // invalidate its weak pointers before any other members are destroyed. - base::WeakPtrFactory<SyncClient> weak_ptr_factory_{this}; - - DISALLOW_COPY_AND_ASSIGN(SyncClient); -}; - -} // namespace internal -} // namespace drive - -#endif // COMPONENTS_DRIVE_CHROMEOS_SYNC_CLIENT_H_
diff --git a/components/drive/chromeos/team_drive_change_list_loader.cc b/components/drive/chromeos/team_drive_change_list_loader.cc deleted file mode 100644 index 0d57eff..0000000 --- a/components/drive/chromeos/team_drive_change_list_loader.cc +++ /dev/null
@@ -1,155 +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 "components/drive/chromeos/team_drive_change_list_loader.h" - -#include <memory> - -#include "base/sequenced_task_runner.h" -#include "components/drive/chromeos/change_list_loader.h" -#include "components/drive/chromeos/directory_loader.h" -#include "components/drive/chromeos/root_folder_id_loader.h" -#include "components/drive/chromeos/start_page_token_loader.h" - -namespace drive { -namespace internal { - -namespace { - -class ConstantRootFolderIdLoader : public RootFolderIdLoader { - public: - explicit ConstantRootFolderIdLoader(const std::string& team_drive_id) - : team_drive_id_(team_drive_id) {} - ~ConstantRootFolderIdLoader() override = default; - - void GetRootFolderId(const RootFolderIdCallback& callback) override { - callback.Run(FILE_ERROR_OK, team_drive_id_); - } - - private: - const std::string team_drive_id_; -}; - -} // namespace - -TeamDriveChangeListLoader::TeamDriveChangeListLoader( - const std::string& team_drive_id, - const base::FilePath& root_entry_path, - EventLogger* logger, - base::SequencedTaskRunner* blocking_task_runner, - ResourceMetadata* resource_metadata, - JobScheduler* scheduler, - LoaderController* apply_task_controller) - : team_drive_id_(team_drive_id), root_entry_path_(root_entry_path) { - root_folder_id_loader_ = - std::make_unique<ConstantRootFolderIdLoader>(team_drive_id_); - - start_page_token_loader_ = - std::make_unique<StartPageTokenLoader>(team_drive_id_, scheduler); - - change_list_loader_ = std::make_unique<ChangeListLoader>( - logger, blocking_task_runner, resource_metadata, scheduler, - root_folder_id_loader_.get(), start_page_token_loader_.get(), - apply_task_controller, team_drive_id_, root_entry_path_); - change_list_loader_->AddObserver(this); - - directory_loader_ = std::make_unique<DirectoryLoader>( - logger, blocking_task_runner, resource_metadata, scheduler, - root_folder_id_loader_.get(), start_page_token_loader_.get(), - apply_task_controller, root_entry_path_, team_drive_id); - directory_loader_->AddObserver(this); -} - -TeamDriveChangeListLoader::~TeamDriveChangeListLoader() = default; - -base::WeakPtr<TeamDriveChangeListLoader> -TeamDriveChangeListLoader::GetWeakPtr() { - return weak_ptr_factory_.GetWeakPtr(); -} - -// DriveChangeListLoader overrides -void TeamDriveChangeListLoader::AddChangeListLoaderObserver( - ChangeListLoaderObserver* observer) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - change_list_loader_observers_.AddObserver(observer); -} - -void TeamDriveChangeListLoader::RemoveChangeListLoaderObserver( - ChangeListLoaderObserver* observer) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - change_list_loader_observers_.RemoveObserver(observer); -} - -void TeamDriveChangeListLoader::AddTeamDriveListObserver( - TeamDriveListObserver* observer) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); -} - -void TeamDriveChangeListLoader::RemoveTeamDriveListObserver( - TeamDriveListObserver* observer) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); -} - -bool TeamDriveChangeListLoader::IsRefreshing() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - return change_list_loader_->IsRefreshing(); -} - -void TeamDriveChangeListLoader::LoadIfNeeded( - const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - change_list_loader_->LoadIfNeeded(callback); -} - -void TeamDriveChangeListLoader::ReadDirectory( - const base::FilePath& directory_path, - ReadDirectoryEntriesCallback entries_callback, - const FileOperationCallback& completion_callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(root_entry_path_ == directory_path || - root_entry_path_.IsParent(directory_path)) - << "Directory paths are not related: " << root_entry_path_.value() - << " -> " << directory_path.value(); - - directory_loader_->ReadDirectory(directory_path, std::move(entries_callback), - completion_callback); -} - -void TeamDriveChangeListLoader::CheckForUpdates( - const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - change_list_loader_->CheckForUpdates(callback); -} - -void TeamDriveChangeListLoader::OnDirectoryReloaded( - const base::FilePath& directory_path) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - for (auto& observer : change_list_loader_observers_) { - observer.OnDirectoryReloaded(directory_path); - } -} - -void TeamDriveChangeListLoader::OnFileChanged(const FileChange& changed_files) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - for (auto& observer : change_list_loader_observers_) { - observer.OnFileChanged(changed_files); - } -} - -void TeamDriveChangeListLoader::OnLoadFromServerComplete() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - for (auto& observer : change_list_loader_observers_) { - observer.OnLoadFromServerComplete(); - } -} - -void TeamDriveChangeListLoader::OnInitialLoadComplete() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - for (auto& observer : change_list_loader_observers_) { - observer.OnInitialLoadComplete(); - } -} - -} // namespace internal -} // namespace drive
diff --git a/components/drive/chromeos/team_drive_change_list_loader.h b/components/drive/chromeos/team_drive_change_list_loader.h deleted file mode 100644 index 8f0da7fa..0000000 --- a/components/drive/chromeos/team_drive_change_list_loader.h +++ /dev/null
@@ -1,90 +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 COMPONENTS_DRIVE_CHROMEOS_TEAM_DRIVE_CHANGE_LIST_LOADER_H_ -#define COMPONENTS_DRIVE_CHROMEOS_TEAM_DRIVE_CHANGE_LIST_LOADER_H_ - -#include <memory> -#include <string> - -#include "base/files/file_path.h" -#include "base/memory/weak_ptr.h" -#include "base/observer_list.h" -#include "components/drive/chromeos/change_list_loader_observer.h" -#include "components/drive/chromeos/drive_change_list_loader.h" - -namespace drive { - -class EventLogger; -class JobScheduler; - -namespace internal { - -class ChangeListLoader; -class DirectoryLoader; -class LoaderController; -class RootFolderIdLoader; -class StartPageTokenLoader; - -// TeamDriveChangeListLoader loads change lists for a specific team drive id. -// It uses directory loader and change list loader to retrieve change lists -// into resouce metadata. There should be one TeamDriveChangeListLoader created -// for every team drive that the user has access to. -class TeamDriveChangeListLoader : public DriveChangeListLoader, - public ChangeListLoaderObserver { - public: - TeamDriveChangeListLoader(const std::string& team_drive_id, - const base::FilePath& root_entry_path, - EventLogger* logger, - base::SequencedTaskRunner* blocking_task_runner, - ResourceMetadata* resource_metadata, - JobScheduler* scheduler, - LoaderController* apply_task_controller); - - ~TeamDriveChangeListLoader() override; - - const base::FilePath& root_entry_path() const { return root_entry_path_; } - base::WeakPtr<TeamDriveChangeListLoader> GetWeakPtr(); - - // DriveChangeListLoader overrides - void AddChangeListLoaderObserver(ChangeListLoaderObserver* observer) override; - void RemoveChangeListLoaderObserver( - ChangeListLoaderObserver* observer) override; - void AddTeamDriveListObserver(TeamDriveListObserver* observer) override; - void RemoveTeamDriveListObserver(TeamDriveListObserver* observer) override; - bool IsRefreshing() override; - void LoadIfNeeded(const FileOperationCallback& callback) override; - void ReadDirectory(const base::FilePath& directory_path, - ReadDirectoryEntriesCallback entries_callback, - const FileOperationCallback& completion_callback) override; - void CheckForUpdates(const FileOperationCallback& callback) override; - - // ChangeListLoaderObserver overrides - void OnDirectoryReloaded(const base::FilePath& directory_path) override; - void OnFileChanged(const FileChange& changed_files) override; - void OnLoadFromServerComplete() override; - void OnInitialLoadComplete() override; - - private: - std::unique_ptr<RootFolderIdLoader> root_folder_id_loader_; - std::unique_ptr<StartPageTokenLoader> start_page_token_loader_; - std::unique_ptr<ChangeListLoader> change_list_loader_; - std::unique_ptr<DirectoryLoader> directory_loader_; - - const std::string team_drive_id_; - const base::FilePath root_entry_path_; - base::ObserverList<ChangeListLoaderObserver>::Unchecked - change_list_loader_observers_; - - THREAD_CHECKER(thread_checker_); - - base::WeakPtrFactory<TeamDriveChangeListLoader> weak_ptr_factory_{this}; - - DISALLOW_COPY_AND_ASSIGN(TeamDriveChangeListLoader); -}; - -} // namespace internal -} // namespace drive - -#endif // COMPONENTS_DRIVE_CHROMEOS_TEAM_DRIVE_CHANGE_LIST_LOADER_H_
diff --git a/components/drive/chromeos/team_drive_list_loader.cc b/components/drive/chromeos/team_drive_list_loader.cc deleted file mode 100644 index 3c49b0bf..0000000 --- a/components/drive/chromeos/team_drive_list_loader.cc +++ /dev/null
@@ -1,347 +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 "components/drive/chromeos/team_drive_list_loader.h" - -#include <algorithm> -#include <map> -#include <memory> -#include <string> -#include <utility> - -#include "base/bind.h" -#include "base/sequenced_task_runner.h" -#include "base/synchronization/atomic_flag.h" -#include "components/drive/chromeos/change_list_loader.h" -#include "components/drive/chromeos/change_list_processor.h" -#include "components/drive/chromeos/loader_controller.h" -#include "components/drive/drive.pb.h" -#include "components/drive/drive_api_util.h" -#include "components/drive/event_logger.h" -#include "components/drive/file_change.h" -#include "components/drive/file_system_core_util.h" -#include "components/drive/job_scheduler.h" - -namespace drive { -namespace internal { - -namespace { - -// Add any new team drives, or update existing team drives in resource -// metadata. -FileError AddOrUpdateTeamDrives(ResourceEntryVector team_drives, - ResourceMetadata* metadata, - base::AtomicFlag* in_shutdown) { - DCHECK(metadata); - DCHECK(in_shutdown); - for (const auto& entry : team_drives) { - if (in_shutdown->IsSet()) { - return FILE_ERROR_ABORT; - } - DCHECK_EQ(entry.parent_local_id(), util::kDriveTeamDrivesDirLocalId); - - std::string local_id; - FileError error = - metadata->GetIdByResourceId(entry.resource_id(), &local_id); - - ResourceEntry existing_entry; - if (error == FILE_ERROR_OK) { - error = metadata->GetResourceEntryById(local_id, &existing_entry); - } - - switch (error) { - // Existing entry in metadata, see if we need to update it - case FILE_ERROR_OK: - if (entry.base_name() != existing_entry.base_name()) { - existing_entry.set_base_name(entry.base_name()); - error = metadata->RefreshEntry(existing_entry); - } - break; - // Add a new entry to metadata - case FILE_ERROR_NOT_FOUND: { - std::string local_id; - error = metadata->AddEntry(entry, &local_id); - break; - } - default: - return error; - } - if (error != FILE_ERROR_OK) { - return error; - } - } - return FILE_ERROR_OK; -} - -// Remove the supplied list of team drives from the resource metadata. -FileError RemoveTeamDrives(ResourceEntryVector team_drives, - ResourceMetadata* metadata, - base::AtomicFlag* in_shutdown) { - DCHECK(metadata); - DCHECK(in_shutdown); - FileError result = FILE_ERROR_OK; - for (const auto& entry : team_drives) { - if (in_shutdown->IsSet()) { - return FILE_ERROR_ABORT; - } - result = metadata->RemoveEntry(entry.local_id()); - if (result != FILE_ERROR_OK) { - return result; - } - } - return result; -} - -} // namespace - -// Used to notify observers of the result of loading the team drives. -struct TeamDriveListLoader::TeamDriveUpdateData { - std::vector<TeamDrive> all_team_drives; - std::vector<TeamDrive> added_team_drives; - std::vector<TeamDrive> removed_team_drives; -}; - -TeamDriveListLoader::TeamDriveListLoader( - EventLogger* logger, - base::SequencedTaskRunner* blocking_task_runner, - ResourceMetadata* resource_metadata, - JobScheduler* scheduler, - LoaderController* apply_task_controller) - : logger_(logger), - blocking_task_runner_(blocking_task_runner), - in_shutdown_(new base::AtomicFlag), - pending_load_callbacks_(), - resource_metadata_(resource_metadata), - scheduler_(scheduler), - loader_controller_(apply_task_controller) {} - -TeamDriveListLoader::~TeamDriveListLoader() { - in_shutdown_->Set(); - // Delete |in_shutdown_| with the blocking task runner so that it gets deleted - // after all active ChangeListProcessors. - blocking_task_runner_->DeleteSoon(FROM_HERE, in_shutdown_.release()); -} - -void TeamDriveListLoader::AddObserver(TeamDriveListObserver* observer) { - observers_.AddObserver(observer); -} - -void TeamDriveListLoader::RemoveObserver(TeamDriveListObserver* observer) { - observers_.RemoveObserver(observer); -} - -bool TeamDriveListLoader::IsRefreshing() const { - return !pending_load_callbacks_.empty(); -} - -void TeamDriveListLoader::CheckForUpdates( - const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - if (IsRefreshing()) { - pending_load_callbacks_.emplace_back(callback); - return; - } - - pending_load_callbacks_.emplace_back(callback); - scheduler_->GetAllTeamDriveList( - base::BindRepeating(&TeamDriveListLoader::OnTeamDriveListLoaded, - weak_ptr_factory_.GetWeakPtr())); -} - -void TeamDriveListLoader::LoadIfNeeded(const FileOperationCallback& callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(callback); - - if (!loaded_ && !IsRefreshing()) { - CheckForUpdates(callback); - } else { - callback.Run(FILE_ERROR_OK); - } -} - -void TeamDriveListLoader::OnTeamDriveListLoaded( - google_apis::DriveApiErrorCode status, - std::unique_ptr<google_apis::TeamDriveList> team_drives) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - FileError error = GDataToFileError(status); - if (error != FILE_ERROR_OK) { - logger_->Log(logging::LOG_ERROR, - "Failed to retrieve the list of team drives: %s", - google_apis::DriveApiErrorCodeToString(status).c_str()); - OnTeamDriveListLoadComplete(error); - return; - } - - change_lists_.push_back(std::make_unique<ChangeList>(*team_drives)); - - if (!team_drives->next_page_token().empty()) { - scheduler_->GetRemainingTeamDriveList( - team_drives->next_page_token(), - base::BindRepeating(&TeamDriveListLoader::OnTeamDriveListLoaded, - weak_ptr_factory_.GetWeakPtr())); - return; - } - - ResourceEntryVector team_drive_resource_vector; - for (auto& change_list : change_lists_) { - std::move(change_list->entries().begin(), change_list->entries().end(), - std::back_inserter(team_drive_resource_vector)); - } - - // We will store the current list of team drives in local_resources. - std::unique_ptr<ResourceEntryVector> local_resources = - std::make_unique<ResourceEntryVector>(); - - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), FROM_HERE, - base::BindRepeating(&ResourceMetadata::ReadDirectoryByPath, - base::Unretained(resource_metadata_), - util::GetDriveTeamDrivesRootPath(), - local_resources.get()), - base::BindRepeating(&TeamDriveListLoader::OnReadDirectoryByPath, - weak_ptr_factory_.GetWeakPtr(), - base::Owned(local_resources.release()), - base::Passed(std::move(team_drive_resource_vector)))); -} - -void TeamDriveListLoader::OnReadDirectoryByPath( - ResourceEntryVector* local_resources, - ResourceEntryVector remote_resources, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(local_resources); - - // We need to sort vectors to use std::set_difference - std::sort(local_resources->begin(), local_resources->end(), - [](const ResourceEntry& lhs, const ResourceEntry& rhs) { - return lhs.resource_id() < rhs.resource_id(); - }); - std::sort(remote_resources.begin(), remote_resources.end(), - [](const ResourceEntry& lhs, const ResourceEntry& rhs) { - return lhs.resource_id() < rhs.resource_id(); - }); - - // Removed team drives are the ResourceEntry's that are present in - // local_resources but missing from remote_resources. - ResourceEntryVector removed_team_drives; - std::set_difference(local_resources->begin(), local_resources->end(), - remote_resources.begin(), remote_resources.end(), - std::back_inserter(removed_team_drives), - [](const ResourceEntry& lhs, const ResourceEntry& rhs) { - return lhs.resource_id() < rhs.resource_id(); - }); - - // Added team drives are the ResourceEntry's that are present in - // remote_resources but missing from local_resources. - ResourceEntryVector added_team_drives; - std::set_difference(remote_resources.begin(), remote_resources.end(), - local_resources->begin(), local_resources->end(), - std::back_inserter(added_team_drives), - [](const ResourceEntry& lhs, const ResourceEntry& rhs) { - return lhs.resource_id() < rhs.resource_id(); - }); - - // We need to store the list of team drives, the added drives and the - // removed drives so we can notify observers on completion. - TeamDriveUpdateData team_drive_updates; - std::transform(remote_resources.begin(), remote_resources.end(), - std::back_inserter(team_drive_updates.all_team_drives), - [](const ResourceEntry& entry) -> TeamDrive { - return {entry.resource_id(), entry.base_name(), - drive::util::GetDriveTeamDrivesRootPath().Append( - util::NormalizeFileName(entry.base_name()))}; - }); - - // Create a copy of the added team drives list to notify observers. - std::transform(added_team_drives.begin(), added_team_drives.end(), - std::back_inserter(team_drive_updates.added_team_drives), - [](const ResourceEntry& entry) -> TeamDrive { - return {entry.resource_id(), entry.base_name(), - drive::util::GetDriveTeamDrivesRootPath().Append( - util::NormalizeFileName(entry.base_name()))}; - }); - - // Create a copy of the removed team drives list to notify observers. - std::transform(removed_team_drives.begin(), removed_team_drives.end(), - std::back_inserter(team_drive_updates.removed_team_drives), - [](const ResourceEntry& entry) -> TeamDrive { - return {entry.resource_id()}; - }); - - // Remove team drives that have been deleted. - loader_controller_->ScheduleRun(base::BindOnce( - &drive::util::RunAsyncTask, base::RetainedRef(blocking_task_runner_), - FROM_HERE, - base::BindOnce(&RemoveTeamDrives, std::move(removed_team_drives), - base::Unretained(resource_metadata_), - base::Unretained(in_shutdown_.get())), - base::BindOnce(&TeamDriveListLoader::OnTeamDrivesRemoved, - weak_ptr_factory_.GetWeakPtr(), - std::move(remote_resources), - std::move(team_drive_updates)))); -} - -void TeamDriveListLoader::OnTeamDrivesRemoved( - ResourceEntryVector remote_resources, - TeamDriveUpdateData team_drive_updates, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - if (error != FILE_ERROR_OK) { - logger_->Log(logging::LOG_ERROR, "Failed to remove team drives: %s", - drive::FileErrorToString(error).c_str()); - OnTeamDriveListLoadComplete(error); - return; - } - - loader_controller_->ScheduleRun(base::BindOnce( - &drive::util::RunAsyncTask, base::RetainedRef(blocking_task_runner_), - FROM_HERE, - base::BindOnce(&AddOrUpdateTeamDrives, std::move(remote_resources), - base::Unretained(resource_metadata_), - base::Unretained(in_shutdown_.get())), - base::BindOnce(&TeamDriveListLoader::OnAddOrUpdateTeamDrives, - weak_ptr_factory_.GetWeakPtr(), - std::move(team_drive_updates)))); -} - -void TeamDriveListLoader::OnAddOrUpdateTeamDrives( - TeamDriveUpdateData team_drive_updates, - FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - if (error != FILE_ERROR_OK) { - logger_->Log(logging::LOG_ERROR, "Failed to add or update team drives: %s", - drive::FileErrorToString(error).c_str()); - OnTeamDriveListLoadComplete(error); - return; - } - - for (auto& observer : observers_) { - observer.OnTeamDriveListLoaded(team_drive_updates.all_team_drives, - team_drive_updates.added_team_drives, - team_drive_updates.removed_team_drives); - } - - OnTeamDriveListLoadComplete(FILE_ERROR_OK); -} - -void TeamDriveListLoader::OnTeamDriveListLoadComplete(FileError error) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - if (error == FILE_ERROR_OK) { - loaded_ = true; - } - - for (auto& callback : pending_load_callbacks_) { - callback.Run(error); - } - pending_load_callbacks_.clear(); -} - -} // namespace internal -} // namespace drive
diff --git a/components/drive/chromeos/team_drive_list_loader.h b/components/drive/chromeos/team_drive_list_loader.h deleted file mode 100644 index bfda6021..0000000 --- a/components/drive/chromeos/team_drive_list_loader.h +++ /dev/null
@@ -1,107 +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 COMPONENTS_DRIVE_CHROMEOS_TEAM_DRIVE_LIST_LOADER_H_ -#define COMPONENTS_DRIVE_CHROMEOS_TEAM_DRIVE_LIST_LOADER_H_ - -#include <memory> -#include <string> -#include <vector> - -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "base/observer_list.h" -#include "base/threading/thread_checker.h" -#include "components/drive/chromeos/resource_metadata.h" -#include "components/drive/chromeos/team_drive_list_observer.h" -#include "components/drive/file_errors.h" -#include "google_apis/drive/drive_api_requests.h" - -namespace base { -class AtomicFlag; -class SequencedTaskRunner; -} // namespace base - -namespace drive { - -class EventLogger; -class JobScheduler; - -namespace internal { - -class ChangeList; -class LoaderController; - -// Loads from the server the complete list of the users team drives. This class -// is used to obtain the initial list of team drives that a user has access to, -// so that team drive specific change lists and XMPP notifications can be -// accessed. -// Upon loading the resource metadata will be updated to reflect the team drives -// that the user has access to. -class TeamDriveListLoader { - public: - TeamDriveListLoader(EventLogger* logger, - base::SequencedTaskRunner* blocking_task_runner, - ResourceMetadata* resource_metadata, - JobScheduler* scheduler, - LoaderController* apply_task_controller); - - ~TeamDriveListLoader(); - - // Indicates whether there is a request for the team drives list in progress. - bool IsRefreshing() const; - - // Gets the team drive list for the user from the server. |callback| must not - // be null. - void CheckForUpdates(const FileOperationCallback& callback); - - // Loads the state of the users team drives. |callback| must not be null. - void LoadIfNeeded(const FileOperationCallback& callback); - - // Adds or removes an observer for team drive related changes. - void AddObserver(TeamDriveListObserver* observer); - void RemoveObserver(TeamDriveListObserver* observer); - - private: - struct TeamDriveUpdateData; - - void OnTeamDriveListLoaded( - google_apis::DriveApiErrorCode status, - std::unique_ptr<google_apis::TeamDriveList> team_drives); - - void OnReadDirectoryByPath(ResourceEntryVector* local_resources, - ResourceEntryVector remote_resources, - FileError error); - - void OnTeamDrivesRemoved(ResourceEntryVector remote_resources, - TeamDriveUpdateData team_drive_updates, - FileError error); - - void OnAddOrUpdateTeamDrives(TeamDriveUpdateData team_drive_updates, - FileError error); - - void OnTeamDriveListLoadComplete(FileError error); - - EventLogger* logger_; // Not owned. - scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; - std::unique_ptr<base::AtomicFlag> in_shutdown_; - std::vector<std::unique_ptr<ChangeList>> change_lists_; - std::vector<FileOperationCallback> pending_load_callbacks_; - bool loaded_ = false; - base::ObserverList<TeamDriveListObserver>::Unchecked observers_; - - ResourceMetadata* resource_metadata_; // Not owned. - JobScheduler* scheduler_; // Not owned. - LoaderController* loader_controller_; // Not owned. - - THREAD_CHECKER(thread_checker_); - - base::WeakPtrFactory<TeamDriveListLoader> weak_ptr_factory_{this}; - DISALLOW_COPY_AND_ASSIGN(TeamDriveListLoader); -}; - -} // namespace internal -} // namespace drive - -#endif // COMPONENTS_DRIVE_CHROMEOS_TEAM_DRIVE_LIST_LOADER_H_
diff --git a/components/drive/directory_loader_unittest.cc b/components/drive/directory_loader_unittest.cc deleted file mode 100644 index a19503c..0000000 --- a/components/drive/directory_loader_unittest.cc +++ /dev/null
@@ -1,431 +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 "components/drive/chromeos/directory_loader.h" - -#include <memory> - -#include "base/bind.h" -#include "base/callback_helpers.h" -#include "base/files/scoped_temp_dir.h" -#include "base/macros.h" -#include "base/test/test_mock_time_task_runner.h" -#include "base/threading/thread_task_runner_handle.h" -#include "base/time/clock.h" -#include "components/drive/chromeos/about_resource_loader.h" -#include "components/drive/chromeos/about_resource_root_folder_id_loader.h" -#include "components/drive/chromeos/change_list_loader_observer.h" -#include "components/drive/chromeos/drive_test_util.h" -#include "components/drive/chromeos/file_cache.h" -#include "components/drive/chromeos/loader_controller.h" -#include "components/drive/chromeos/resource_metadata.h" -#include "components/drive/chromeos/root_folder_id_loader.h" -#include "components/drive/chromeos/start_page_token_loader.h" -#include "components/drive/event_logger.h" -#include "components/drive/file_system_core_util.h" -#include "components/drive/job_scheduler.h" -#include "components/drive/service/fake_drive_service.h" -#include "components/drive/service/test_util.h" -#include "components/prefs/testing_pref_service.h" -#include "content/public/test/browser_task_environment.h" -#include "google_apis/drive/drive_api_parser.h" -#include "google_apis/drive/test_util.h" -#include "mojo/public/cpp/bindings/pending_remote.h" -#include "services/network/test/test_network_connection_tracker.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace drive { -namespace internal { - -namespace { - -class TestDirectoryLoaderObserver : public ChangeListLoaderObserver { - public: - explicit TestDirectoryLoaderObserver(DirectoryLoader* loader) - : loader_(loader) { - loader_->AddObserver(this); - } - - ~TestDirectoryLoaderObserver() override { loader_->RemoveObserver(this); } - - const std::set<base::FilePath>& changed_directories() const { - return changed_directories_; - } - void clear_changed_directories() { changed_directories_.clear(); } - - // ChageListObserver overrides: - void OnDirectoryReloaded(const base::FilePath& directory_path) override { - changed_directories_.insert(directory_path); - } - - private: - DirectoryLoader* loader_; - std::set<base::FilePath> changed_directories_; - - DISALLOW_COPY_AND_ASSIGN(TestDirectoryLoaderObserver); -}; - -void AccumulateReadDirectoryResult( - ResourceEntryVector* out_entries, - std::unique_ptr<ResourceEntryVector> entries) { - ASSERT_TRUE(entries); - out_entries->insert(out_entries->end(), entries->begin(), entries->end()); -} - -class FakeRootFolderIdLoader : public RootFolderIdLoader { - public: - explicit FakeRootFolderIdLoader(const std::string& root_folder_id) - : root_folder_id_(root_folder_id) {} - - void GetRootFolderId(const RootFolderIdCallback& callback) override { - callback.Run(FILE_ERROR_OK, root_folder_id_); - } - - private: - const std::string root_folder_id_; -}; - -struct DestroyHelper { - template <typename T> - void operator()(T* object) const { - if (object) { - object->Destroy(); - } - } -}; - -} // namespace - -class DirectoryLoaderTest : public testing::Test { - protected: - void SetUp() override { - task_runner_ = base::MakeRefCounted<base::TestMockTimeTaskRunner>( - base::TestMockTimeTaskRunner::Type::kBoundToThread); - - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - pref_service_ = std::make_unique<TestingPrefServiceSimple>(); - test_util::RegisterDrivePrefs(pref_service_->registry()); - - logger_ = std::make_unique<EventLogger>(); - - drive_service_ = std::make_unique<FakeDriveService>(); - ASSERT_TRUE(test_util::SetUpTestEntries(drive_service_.get())); - - network::TestNetworkConnectionTracker::GetInstance()->SetConnectionType( - network::mojom::ConnectionType::CONNECTION_WIFI); - scheduler_ = std::make_unique<JobScheduler>( - pref_service_.get(), logger_.get(), drive_service_.get(), - network::TestNetworkConnectionTracker::GetInstance(), - task_runner_.get(), mojo::NullRemote()); - metadata_storage_.reset( - new ResourceMetadataStorage(temp_dir_.GetPath(), task_runner_.get())); - ASSERT_TRUE(metadata_storage_->Initialize()); - - cache_.reset(new FileCache(metadata_storage_.get(), temp_dir_.GetPath(), - task_runner_.get(), - nullptr /* free_disk_space_getter */)); - ASSERT_TRUE(cache_->Initialize()); - - metadata_.reset(new ResourceMetadata(metadata_storage_.get(), cache_.get(), - task_runner_.get())); - ASSERT_EQ(FILE_ERROR_OK, metadata_->Initialize()); - - about_resource_loader_ = - std::make_unique<AboutResourceLoader>(scheduler_.get()); - root_folder_id_loader_ = std::make_unique<AboutResourceRootFolderIdLoader>( - about_resource_loader_.get()); - start_page_token_loader_ = std::make_unique<StartPageTokenLoader>( - drive::util::kTeamDriveIdDefaultCorpus, scheduler_.get()); - loader_controller_ = std::make_unique<LoaderController>(); - directory_loader_ = std::make_unique<DirectoryLoader>( - logger_.get(), task_runner_.get(), metadata_.get(), scheduler_.get(), - root_folder_id_loader_.get(), start_page_token_loader_.get(), - loader_controller_.get(), util::GetDriveMyDriveRootPath(), - drive::util::kTeamDriveIdDefaultCorpus, task_runner_->GetMockClock()); - } - - void TearDown() override { - // We need to manually reset the objects that implement the Destroy idiom, - // that deletes the object on the |task_runner_|. This is simpler than - // introducing custom deleters that capture the |task_runner_| and - // invoke RunUntilIdle(). - metadata_.reset(); - cache_.reset(); - metadata_storage_.reset(); - task_runner_->RunUntilIdle(); - } - // Adds a new file to the root directory of the service. - std::unique_ptr<google_apis::FileResource> AddNewFile( - const std::string& title) { - google_apis::DriveApiErrorCode error = google_apis::DRIVE_FILE_ERROR; - std::unique_ptr<google_apis::FileResource> entry; - drive_service_->AddNewFile( - "text/plain", - "content text", - drive_service_->GetRootResourceId(), - title, - false, // shared_with_me - google_apis::test_util::CreateCopyResultCallback(&error, &entry)); - task_runner_->RunUntilIdle(); - EXPECT_EQ(google_apis::HTTP_CREATED, error); - return entry; - } - - // Creates a ResourceEntry for a directory with explicitly set resource_id. - ResourceEntry CreateDirectoryEntryWithResourceId( - const std::string& title, - const std::string& resource_id, - const std::string& parent_local_id) { - ResourceEntry entry; - entry.set_title(title); - entry.set_resource_id(resource_id); - entry.set_parent_local_id(parent_local_id); - entry.mutable_file_info()->set_is_directory(true); - entry.mutable_directory_specific_info()->set_start_page_token("0"); - return entry; - } - - void AddTeamDriveRootEntry(const std::string& team_drive_id, - const std::string& team_drive_name) { - std::string local_id; - ASSERT_EQ( - FILE_ERROR_OK, - metadata_->GetIdByPath(util::GetDriveTeamDrivesRootPath(), &local_id)); - - std::string root_local_id = local_id; - ASSERT_EQ( - FILE_ERROR_OK, - metadata_->AddEntry(CreateDirectoryEntryWithResourceId( - team_drive_name, team_drive_id, root_local_id), - &local_id)); - } - - scoped_refptr<base::TestMockTimeTaskRunner> task_runner_; - base::ScopedTempDir temp_dir_; - std::unique_ptr<TestingPrefServiceSimple> pref_service_; - std::unique_ptr<EventLogger> logger_; - std::unique_ptr<FakeDriveService> drive_service_; - std::unique_ptr<JobScheduler> scheduler_; - std::unique_ptr<ResourceMetadataStorage, DestroyHelper> metadata_storage_; - std::unique_ptr<FileCache, DestroyHelper> cache_; - std::unique_ptr<ResourceMetadata, DestroyHelper> metadata_; - std::unique_ptr<AboutResourceLoader> about_resource_loader_; - std::unique_ptr<StartPageTokenLoader> start_page_token_loader_; - std::unique_ptr<LoaderController> loader_controller_; - std::unique_ptr<DirectoryLoader> directory_loader_; - std::unique_ptr<AboutResourceRootFolderIdLoader> root_folder_id_loader_; -}; - -TEST_F(DirectoryLoaderTest, ReadDirectory_GrandRoot) { - TestDirectoryLoaderObserver observer(directory_loader_.get()); - - // Load grand root. - FileError error = FILE_ERROR_FAILED; - ResourceEntryVector entries; - directory_loader_->ReadDirectory( - util::GetDriveGrandRootPath(), - base::Bind(&AccumulateReadDirectoryResult, &entries), - google_apis::test_util::CreateCopyResultCallback(&error)); - task_runner_->RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - EXPECT_EQ(0U, observer.changed_directories().size()); - observer.clear_changed_directories(); - - // My Drive has resource ID. - ResourceEntry entry; - EXPECT_EQ(FILE_ERROR_OK, - metadata_->GetResourceEntryByPath(util::GetDriveMyDriveRootPath(), - &entry)); - EXPECT_EQ(drive_service_->GetRootResourceId(), entry.resource_id()); -} - -TEST_F(DirectoryLoaderTest, ReadDirectory_MyDrive) { - TestDirectoryLoaderObserver observer(directory_loader_.get()); - - // My Drive does not have resource ID yet. - ResourceEntry entry; - EXPECT_EQ(FILE_ERROR_OK, - metadata_->GetResourceEntryByPath(util::GetDriveMyDriveRootPath(), - &entry)); - EXPECT_TRUE(entry.resource_id().empty()); - - // Load My Drive. - FileError error = FILE_ERROR_FAILED; - ResourceEntryVector entries; - directory_loader_->ReadDirectory( - util::GetDriveMyDriveRootPath(), - base::Bind(&AccumulateReadDirectoryResult, &entries), - google_apis::test_util::CreateCopyResultCallback(&error)); - task_runner_->RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - EXPECT_EQ(1U, observer.changed_directories().count( - util::GetDriveMyDriveRootPath())); - - // My Drive has resource ID. - EXPECT_EQ(FILE_ERROR_OK, - metadata_->GetResourceEntryByPath(util::GetDriveMyDriveRootPath(), - &entry)); - EXPECT_EQ(drive_service_->GetRootResourceId(), entry.resource_id()); - EXPECT_EQ(drive_service_->start_page_token().start_page_token(), - entry.directory_specific_info().start_page_token()); - - // My Drive's child is present. - base::FilePath file_path = - util::GetDriveMyDriveRootPath().AppendASCII("File 1.txt"); - EXPECT_EQ(FILE_ERROR_OK, - metadata_->GetResourceEntryByPath(file_path, &entry)); -} - -// Ensure that multiple requests in succession do not hit the backend until the -// time to refresh expires. -TEST_F(DirectoryLoaderTest, ReadDirectory_MyDriveTimedCache) { - TestDirectoryLoaderObserver observer(directory_loader_.get()); - - // My Drive does not have resource ID yet. - ResourceEntry entry; - EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryByPath( - util::GetDriveMyDriveRootPath(), &entry)); - EXPECT_TRUE(entry.resource_id().empty()); - - // Load My Drive. - FileError error = FILE_ERROR_FAILED; - ResourceEntryVector entries; - directory_loader_->ReadDirectory( - util::GetDriveMyDriveRootPath(), - base::Bind(&AccumulateReadDirectoryResult, &entries), - google_apis::test_util::CreateCopyResultCallback(&error)); - task_runner_->RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - EXPECT_EQ(1U, observer.changed_directories().count( - util::GetDriveMyDriveRootPath())); - - // My Drive has resource ID. - EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryByPath( - util::GetDriveMyDriveRootPath(), &entry)); - EXPECT_EQ(drive_service_->GetRootResourceId(), entry.resource_id()); - EXPECT_EQ(drive_service_->start_page_token().start_page_token(), - entry.directory_specific_info().start_page_token()); - EXPECT_TRUE(entry.directory_specific_info().has_last_read_time_ms()); - int64_t read_time = entry.directory_specific_info().last_read_time_ms(); - - // Move forward 1 second, should not cause a new read of the backend. - observer.clear_changed_directories(); - task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(1)); - directory_loader_->ReadDirectory( - util::GetDriveMyDriveRootPath(), - base::Bind(&AccumulateReadDirectoryResult, &entries), - google_apis::test_util::CreateCopyResultCallback(&error)); - task_runner_->RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryByPath( - util::GetDriveMyDriveRootPath(), &entry)); - EXPECT_EQ(read_time, entry.directory_specific_info().last_read_time_ms()); - - // Move forward 60 seconds, should cause a new read of the backend. - observer.clear_changed_directories(); - task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(60)); - directory_loader_->ReadDirectory( - util::GetDriveMyDriveRootPath(), - base::Bind(&AccumulateReadDirectoryResult, &entries), - google_apis::test_util::CreateCopyResultCallback(&error)); - task_runner_->RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryByPath( - util::GetDriveMyDriveRootPath(), &entry)); - EXPECT_LT(read_time, entry.directory_specific_info().last_read_time_ms()); -} - -TEST_F(DirectoryLoaderTest, ReadDirectory_MultipleCalls) { - TestDirectoryLoaderObserver observer(directory_loader_.get()); - - // Load grand root. - FileError error = FILE_ERROR_FAILED; - ResourceEntryVector entries; - directory_loader_->ReadDirectory( - util::GetDriveGrandRootPath(), - base::Bind(&AccumulateReadDirectoryResult, &entries), - google_apis::test_util::CreateCopyResultCallback(&error)); - - // Load grand root again without waiting for the result. - FileError error2 = FILE_ERROR_FAILED; - ResourceEntryVector entries2; - directory_loader_->ReadDirectory( - util::GetDriveGrandRootPath(), - base::Bind(&AccumulateReadDirectoryResult, &entries2), - google_apis::test_util::CreateCopyResultCallback(&error2)); - task_runner_->RunUntilIdle(); - - // Callback is called for each method call. - EXPECT_EQ(FILE_ERROR_OK, error); - EXPECT_EQ(FILE_ERROR_OK, error2); -} - -TEST_F(DirectoryLoaderTest, Lock) { - // Lock the loader. - std::unique_ptr<base::ScopedClosureRunner> lock = - loader_controller_->GetLock(); - - // Start loading. - TestDirectoryLoaderObserver observer(directory_loader_.get()); - FileError error = FILE_ERROR_FAILED; - ResourceEntryVector entries; - directory_loader_->ReadDirectory( - util::GetDriveMyDriveRootPath(), - base::Bind(&AccumulateReadDirectoryResult, &entries), - google_apis::test_util::CreateCopyResultCallback(&error)); - task_runner_->RunUntilIdle(); - - // Update is pending due to the lock. - EXPECT_TRUE(observer.changed_directories().empty()); - - // Unlock the loader, this should resume the pending udpate. - lock.reset(); - task_runner_->RunUntilIdle(); - EXPECT_EQ(1U, observer.changed_directories().count( - util::GetDriveMyDriveRootPath())); -} - -TEST_F(DirectoryLoaderTest, TeamDrive) { - constexpr char kTeamDriveId[] = "team_drive_id"; - constexpr char kTeamDriveName[] = "Team Drive"; - constexpr char kTeamDriveStartPageToken[] = "12345"; - const base::FilePath team_drive_path = - util::GetDriveTeamDrivesRootPath().AppendASCII(kTeamDriveName); - - auto fake_root_folder_id_loader = - std::make_unique<FakeRootFolderIdLoader>(kTeamDriveId); - auto start_page_token_loader = - std::make_unique<StartPageTokenLoader>(kTeamDriveId, scheduler_.get()); - auto local_directory_loader = std::make_unique<DirectoryLoader>( - logger_.get(), base::ThreadTaskRunnerHandle::Get().get(), metadata_.get(), - scheduler_.get(), fake_root_folder_id_loader.get(), - start_page_token_loader.get(), loader_controller_.get(), team_drive_path, - kTeamDriveId); - - AddTeamDriveRootEntry(kTeamDriveId, kTeamDriveName); - - drive_service_->AddTeamDrive(kTeamDriveId, kTeamDriveName, - kTeamDriveStartPageToken); - - FileError error = FILE_ERROR_FAILED; - ResourceEntryVector entries; - - local_directory_loader->ReadDirectory( - team_drive_path, base::Bind(&AccumulateReadDirectoryResult, &entries), - google_apis::test_util::CreateCopyResultCallback(&error)); - task_runner_->RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - EXPECT_EQ(1, drive_service_->start_page_token_load_count()); - EXPECT_EQ(1, drive_service_->directory_load_count()); - - // If we checked the folder, we should see that it's start page token has been - // updated. - ResourceEntry entry; - EXPECT_EQ(FILE_ERROR_OK, - metadata_->GetResourceEntryByPath(team_drive_path, &entry)); - EXPECT_EQ(kTeamDriveStartPageToken, - entry.directory_specific_info().start_page_token()); -} -} // namespace internal -} // namespace drive
diff --git a/components/drive/fake_file_system_unittest.cc b/components/drive/fake_file_system_unittest.cc deleted file mode 100644 index 057f07c..0000000 --- a/components/drive/fake_file_system_unittest.cc +++ /dev/null
@@ -1,159 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/drive/chromeos/fake_file_system.h" - -#include <memory> - -#include "base/files/file_util.h" -#include "base/run_loop.h" -#include "components/drive/file_system_core_util.h" -#include "components/drive/service/fake_drive_service.h" -#include "components/drive/service/test_util.h" -#include "content/public/test/browser_task_environment.h" -#include "google_apis/drive/test_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace drive { -namespace test_util { - -class FakeFileSystemTest : public ::testing::Test { - protected: - void SetUp() override { - // Initialize FakeDriveService. - fake_drive_service_ = std::make_unique<FakeDriveService>(); - ASSERT_TRUE(SetUpTestEntries(fake_drive_service_.get())); - - // Create a testee instance. - fake_file_system_ = - std::make_unique<FakeFileSystem>(fake_drive_service_.get()); - } - - content::BrowserTaskEnvironment task_environment_; - std::unique_ptr<FakeDriveService> fake_drive_service_; - std::unique_ptr<FakeFileSystem> fake_file_system_; -}; - -TEST_F(FakeFileSystemTest, GetFileContent) { - FileError initialize_error = FILE_ERROR_FAILED; - std::unique_ptr<ResourceEntry> entry; - base::FilePath cache_file_path; - google_apis::test_util::TestGetContentCallback get_content_callback; - FileError completion_error = FILE_ERROR_FAILED; - - const base::FilePath kDriveFile = - util::GetDriveMyDriveRootPath().AppendASCII("File 1.txt"); - - // For the first time, the file should be downloaded from the service. - base::Closure cancel_download = fake_file_system_->GetFileContent( - kDriveFile, - google_apis::test_util::CreateCopyResultCallback( - &initialize_error, &cache_file_path, &entry), - get_content_callback.callback(), - google_apis::test_util::CreateCopyResultCallback(&completion_error)); - base::RunLoop().RunUntilIdle(); - - EXPECT_EQ(FILE_ERROR_OK, initialize_error); - EXPECT_TRUE(entry); - - // No cache file is available yet. - EXPECT_TRUE(cache_file_path.empty()); - - // The download should be happened so the |get_content_callback| - // should have the actual data. - std::string content = get_content_callback.GetConcatenatedData(); - EXPECT_EQ(26U, content.size()); - EXPECT_EQ(FILE_ERROR_OK, completion_error); - - initialize_error = FILE_ERROR_FAILED; - entry.reset(); - get_content_callback.mutable_data()->clear(); - completion_error = FILE_ERROR_FAILED; - - // For the second time, the cache file should be found. - cancel_download = fake_file_system_->GetFileContent( - kDriveFile, - google_apis::test_util::CreateCopyResultCallback( - &initialize_error, &cache_file_path, &entry), - get_content_callback.callback(), - google_apis::test_util::CreateCopyResultCallback(&completion_error)); - base::RunLoop().RunUntilIdle(); - - EXPECT_EQ(FILE_ERROR_OK, initialize_error); - EXPECT_TRUE(entry); - - // Cache file should be available. - ASSERT_FALSE(cache_file_path.empty()); - - // There should be a cache file so no data should be downloaded. - EXPECT_TRUE(get_content_callback.data().empty()); - EXPECT_EQ(FILE_ERROR_OK, completion_error); - - // Make sure the cached file's content. - std::string cache_file_content; - ASSERT_TRUE( - base::ReadFileToString(cache_file_path, &cache_file_content)); - EXPECT_EQ(content, cache_file_content); -} - -TEST_F(FakeFileSystemTest, GetFileContent_Directory) { - FileError initialize_error = FILE_ERROR_FAILED; - std::unique_ptr<ResourceEntry> entry; - base::FilePath cache_file_path; - google_apis::test_util::TestGetContentCallback get_content_callback; - FileError completion_error = FILE_ERROR_FAILED; - base::Closure cancel_download = fake_file_system_->GetFileContent( - util::GetDriveMyDriveRootPath(), - google_apis::test_util::CreateCopyResultCallback( - &initialize_error, &cache_file_path, &entry), - get_content_callback.callback(), - google_apis::test_util::CreateCopyResultCallback(&completion_error)); - base::RunLoop().RunUntilIdle(); - - EXPECT_EQ(FILE_ERROR_NOT_A_FILE, completion_error); -} - -TEST_F(FakeFileSystemTest, GetResourceEntry) { - FileError error = FILE_ERROR_FAILED; - std::unique_ptr<ResourceEntry> entry; - fake_file_system_->GetResourceEntry( - util::GetDriveMyDriveRootPath().AppendASCII( - "Directory 1/Sub Directory Folder"), - google_apis::test_util::CreateCopyResultCallback(&error, &entry)); - base::RunLoop().RunUntilIdle(); - - ASSERT_EQ(FILE_ERROR_OK, error); - ASSERT_TRUE(entry); - EXPECT_EQ("sub_dir_folder_resource_id", entry->resource_id()); -} - -TEST_F(FakeFileSystemTest, GetResourceEntry_Root) { - FileError error = FILE_ERROR_FAILED; - std::unique_ptr<ResourceEntry> entry; - fake_file_system_->GetResourceEntry( - util::GetDriveMyDriveRootPath(), - google_apis::test_util::CreateCopyResultCallback(&error, &entry)); - base::RunLoop().RunUntilIdle(); - - ASSERT_EQ(FILE_ERROR_OK, error); - ASSERT_TRUE(entry); - EXPECT_TRUE(entry->file_info().is_directory()); - EXPECT_EQ(fake_drive_service_->GetRootResourceId(), entry->resource_id()); - EXPECT_EQ(util::kDriveMyDriveRootDirName, entry->title()); -} - -TEST_F(FakeFileSystemTest, GetResourceEntry_Invalid) { - FileError error = FILE_ERROR_FAILED; - std::unique_ptr<ResourceEntry> entry; - fake_file_system_->GetResourceEntry( - util::GetDriveMyDriveRootPath().AppendASCII("Invalid File Name"), - google_apis::test_util::CreateCopyResultCallback(&error, &entry)); - base::RunLoop().RunUntilIdle(); - - ASSERT_EQ(FILE_ERROR_NOT_FOUND, error); - ASSERT_FALSE(entry); -} - -} // namespace test_util -} // namespace drive
diff --git a/components/drive/file_system/copy_operation_unittest.cc b/components/drive/file_system/copy_operation_unittest.cc deleted file mode 100644 index e2f0306..0000000 --- a/components/drive/file_system/copy_operation_unittest.cc +++ /dev/null
@@ -1,525 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/drive/chromeos/file_system/copy_operation.h" - -#include <memory> - -#include "base/bind.h" -#include "base/files/file_util.h" -#include "base/task_runner_util.h" -#include "components/drive/chromeos/file_cache.h" -#include "components/drive/chromeos/resource_metadata.h" -#include "components/drive/drive_api_util.h" -#include "components/drive/file_change.h" -#include "components/drive/file_system/operation_test_base.h" -#include "components/drive/file_system_core_util.h" -#include "components/drive/service/fake_drive_service.h" -#include "content/public/test/test_utils.h" -#include "google_apis/drive/drive_api_parser.h" -#include "google_apis/drive/test_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace drive { -namespace file_system { - -namespace { - -// Used to handle WaitForSyncComplete() calls. -bool CopyWaitForSyncCompleteArguments(std::string* out_local_id, - FileOperationCallback* out_callback, - const std::string& local_id, - const FileOperationCallback& callback) { - *out_local_id = local_id; - *out_callback = callback; - return true; -} - -} // namespace - -class CopyOperationTest : public OperationTestBase { - protected: - void SetUp() override { - OperationTestBase::SetUp(); - operation_ = std::make_unique<CopyOperation>( - blocking_task_runner(), delegate(), scheduler(), metadata(), cache()); - } - - std::unique_ptr<CopyOperation> operation_; -}; - -TEST_F(CopyOperationTest, TransferFileFromLocalToRemote_RegularFile) { - const base::FilePath local_src_path = temp_dir().AppendASCII("local.txt"); - const base::FilePath remote_dest_path( - FILE_PATH_LITERAL("drive/root/remote.txt")); - - // Prepare a local file. - ASSERT_TRUE( - google_apis::test_util::WriteStringToFile(local_src_path, "hello")); - // Confirm that the remote file does not exist. - ResourceEntry entry; - ASSERT_EQ(FILE_ERROR_NOT_FOUND, - GetLocalResourceEntry(remote_dest_path, &entry)); - - // Transfer the local file to Drive. - FileError error = FILE_ERROR_FAILED; - operation_->TransferFileFromLocalToRemote( - local_src_path, - remote_dest_path, - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // TransferFileFromLocalToRemote stores a copy of the local file in the cache, - // marks it dirty and requests the observer to upload the file. - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(remote_dest_path, &entry)); - EXPECT_EQ(1U, delegate()->updated_local_ids().count(entry.local_id())); - EXPECT_TRUE(entry.file_specific_info().cache_state().is_present()); - EXPECT_TRUE(entry.file_specific_info().cache_state().is_dirty()); - - EXPECT_EQ(1U, delegate()->get_changed_files().size()); - EXPECT_TRUE(delegate()->get_changed_files().count(remote_dest_path)); -} - -TEST_F(CopyOperationTest, TransferFileFromLocalToRemote_Overwrite) { - const base::FilePath local_src_path = temp_dir().AppendASCII("local.txt"); - const base::FilePath remote_dest_path( - FILE_PATH_LITERAL("drive/root/File 1.txt")); - - // Prepare a local file. - EXPECT_TRUE( - google_apis::test_util::WriteStringToFile(local_src_path, "hello")); - // Confirm that the remote file exists. - ResourceEntry entry; - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(remote_dest_path, &entry)); - - // Transfer the local file to Drive. - FileError error = FILE_ERROR_FAILED; - operation_->TransferFileFromLocalToRemote( - local_src_path, - remote_dest_path, - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // TransferFileFromLocalToRemote stores a copy of the local file in the cache, - // marks it dirty and requests the observer to upload the file. - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(remote_dest_path, &entry)); - EXPECT_EQ(1U, delegate()->updated_local_ids().count(entry.local_id())); - EXPECT_TRUE(entry.file_specific_info().cache_state().is_present()); - EXPECT_TRUE(entry.file_specific_info().cache_state().is_dirty()); - - EXPECT_EQ(1U, delegate()->get_changed_files().size()); - EXPECT_TRUE(delegate()->get_changed_files().count(remote_dest_path)); -} - -TEST_F(CopyOperationTest, - TransferFileFromLocalToRemote_ExistingHostedDocument) { - const base::FilePath local_src_path = temp_dir().AppendASCII("local.gdoc"); - const base::FilePath remote_dest_path(FILE_PATH_LITERAL( - "drive/root/Directory 1/copied.gdoc")); - - // Prepare a local file, which is a json file of a hosted document, which - // matches "drive/root/Document 1 excludeDir-test". - ASSERT_TRUE(util::CreateGDocFile( - local_src_path, - GURL("https://3_document_self_link/5_document_resource_id"), - "5_document_resource_id")); - - ResourceEntry entry; - ASSERT_EQ(FILE_ERROR_NOT_FOUND, - GetLocalResourceEntry(remote_dest_path, &entry)); - - // Transfer the local file to Drive. - FileError error = FILE_ERROR_FAILED; - operation_->TransferFileFromLocalToRemote( - local_src_path, - remote_dest_path, - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(remote_dest_path, &entry)); - - EXPECT_EQ(1U, delegate()->get_changed_files().size()); - EXPECT_TRUE(delegate()->get_changed_files().count(remote_dest_path)); - // New copy is created. - EXPECT_NE("5_document_resource_id", entry.resource_id()); -} - -TEST_F(CopyOperationTest, TransferFileFromLocalToRemote_OrphanHostedDocument) { - const base::FilePath local_src_path = temp_dir().AppendASCII("local.gdoc"); - const base::FilePath remote_dest_path(FILE_PATH_LITERAL( - "drive/root/Directory 1/moved.gdoc")); - - // Prepare a local file, which is a json file of a hosted document, which - // matches "drive/other/Orphan Document". - ASSERT_TRUE(util::CreateGDocFile( - local_src_path, - GURL("https://3_document_self_link/orphan_doc_1"), - "orphan_doc_1")); - - ResourceEntry entry; - ASSERT_EQ(FILE_ERROR_NOT_FOUND, - GetLocalResourceEntry(remote_dest_path, &entry)); - - // Transfer the local file to Drive. - FileError error = FILE_ERROR_FAILED; - operation_->TransferFileFromLocalToRemote( - local_src_path, - remote_dest_path, - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(remote_dest_path, &entry)); - EXPECT_EQ(ResourceEntry::DIRTY, entry.metadata_edit_state()); - EXPECT_TRUE(delegate()->updated_local_ids().count(entry.local_id())); - - EXPECT_EQ(1U, delegate()->get_changed_files().size()); - EXPECT_TRUE(delegate()->get_changed_files().count(remote_dest_path)); - // The original document got new parent. - EXPECT_EQ("orphan_doc_1", entry.resource_id()); -} - -TEST_F(CopyOperationTest, TransferFileFromLocalToRemote_NewHostedDocument) { - const base::FilePath local_src_path = temp_dir().AppendASCII("local.gdoc"); - const base::FilePath remote_dest_path(FILE_PATH_LITERAL( - "drive/root/Directory 1/moved.gdoc")); - - // Create a hosted document on the server that is not synced to local yet. - google_apis::DriveApiErrorCode gdata_error = google_apis::DRIVE_OTHER_ERROR; - std::unique_ptr<google_apis::FileResource> new_gdoc_entry; - fake_service()->AddNewFile( - "application/vnd.google-apps.document", "", "", "title", true, - google_apis::test_util::CreateCopyResultCallback(&gdata_error, - &new_gdoc_entry)); - content::RunAllTasksUntilIdle(); - ASSERT_EQ(google_apis::HTTP_CREATED, gdata_error); - - // Prepare a local file, which is a json file of the added hosted document. - ASSERT_TRUE(util::CreateGDocFile( - local_src_path, - GURL("https://3_document_self_link/" + new_gdoc_entry->file_id()), - new_gdoc_entry->file_id())); - - ResourceEntry entry; - ASSERT_EQ(FILE_ERROR_NOT_FOUND, - GetLocalResourceEntry(remote_dest_path, &entry)); - - // Transfer the local file to Drive. - FileError error = FILE_ERROR_FAILED; - operation_->TransferFileFromLocalToRemote( - local_src_path, - remote_dest_path, - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(remote_dest_path, &entry)); - - EXPECT_EQ(1U, delegate()->get_changed_files().size()); - EXPECT_TRUE(delegate()->get_changed_files().count(remote_dest_path)); - // The original document got new parent. - EXPECT_EQ(new_gdoc_entry->file_id(), entry.resource_id()); -} - -TEST_F(CopyOperationTest, CopyNotExistingFile) { - base::FilePath src_path(FILE_PATH_LITERAL("drive/root/Dummy file.txt")); - base::FilePath dest_path(FILE_PATH_LITERAL("drive/root/Test.log")); - - ResourceEntry entry; - ASSERT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntry(src_path, &entry)); - - FileError error = FILE_ERROR_OK; - operation_->Copy(src_path, - dest_path, - false, - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_NOT_FOUND, error); - - EXPECT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntry(src_path, &entry)); - EXPECT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntry(dest_path, &entry)); - EXPECT_TRUE(delegate()->get_changed_files().empty()); -} - -TEST_F(CopyOperationTest, CopyFileToNonExistingDirectory) { - base::FilePath src_path(FILE_PATH_LITERAL("drive/root/File 1.txt")); - base::FilePath dest_path(FILE_PATH_LITERAL("drive/root/Dummy/Test.log")); - - ResourceEntry entry; - ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &entry)); - ASSERT_EQ(FILE_ERROR_NOT_FOUND, - GetLocalResourceEntry(dest_path.DirName(), &entry)); - - FileError error = FILE_ERROR_OK; - operation_->Copy(src_path, - dest_path, - false, - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_NOT_FOUND, error); - - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &entry)); - EXPECT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntry(dest_path, &entry)); - EXPECT_TRUE(delegate()->get_changed_files().empty()); -} - -// Test the case where the parent of the destination path is an existing file, -// not a directory. -TEST_F(CopyOperationTest, CopyFileToInvalidPath) { - base::FilePath src_path(FILE_PATH_LITERAL( - "drive/root/Document 1 excludeDir-test.gdoc")); - base::FilePath dest_path(FILE_PATH_LITERAL( - "drive/root/Duplicate Name.txt/Document 1 excludeDir-test.gdoc")); - - ResourceEntry entry; - ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &entry)); - ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(dest_path.DirName(), &entry)); - ASSERT_FALSE(entry.file_info().is_directory()); - - FileError error = FILE_ERROR_OK; - operation_->Copy(src_path, - dest_path, - false, - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_NOT_A_DIRECTORY, error); - - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &entry)); - EXPECT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntry(dest_path, &entry)); - EXPECT_TRUE(delegate()->get_changed_files().empty()); -} - -TEST_F(CopyOperationTest, CopyDirtyFile) { - base::FilePath src_path(FILE_PATH_LITERAL("drive/root/File 1.txt")); - base::FilePath dest_path(FILE_PATH_LITERAL( - "drive/root/Directory 1/New File.txt")); - - ResourceEntry src_entry; - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &src_entry)); - - // Store a dirty cache file. - base::FilePath temp_file; - EXPECT_TRUE(base::CreateTemporaryFileInDir(temp_dir(), &temp_file)); - std::string contents = "test content"; - EXPECT_TRUE(google_apis::test_util::WriteStringToFile(temp_file, contents)); - FileError error = FILE_ERROR_FAILED; - base::PostTaskAndReplyWithResult( - blocking_task_runner(), - FROM_HERE, - base::Bind(&internal::FileCache::Store, - base::Unretained(cache()), - src_entry.local_id(), - std::string(), - temp_file, - internal::FileCache::FILE_OPERATION_MOVE), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Copy. - operation_->Copy(src_path, - dest_path, - false, - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - ResourceEntry dest_entry; - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(dest_path, &dest_entry)); - EXPECT_EQ(ResourceEntry::DIRTY, dest_entry.metadata_edit_state()); - - EXPECT_EQ(1u, delegate()->updated_local_ids().size()); - EXPECT_TRUE(delegate()->updated_local_ids().count(dest_entry.local_id())); - EXPECT_EQ(1u, delegate()->get_changed_files().size()); - EXPECT_TRUE(delegate()->get_changed_files().count(dest_path)); - - // Copied cache file should be dirty. - EXPECT_TRUE(dest_entry.file_specific_info().cache_state().is_dirty()); - - // File contents should match. - base::FilePath cache_file_path; - base::PostTaskAndReplyWithResult( - blocking_task_runner(), - FROM_HERE, - base::Bind(&internal::FileCache::GetFile, - base::Unretained(cache()), - dest_entry.local_id(), - &cache_file_path), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - std::string copied_contents; - EXPECT_TRUE(base::ReadFileToString(cache_file_path, &copied_contents)); - EXPECT_EQ(contents, copied_contents); -} - -TEST_F(CopyOperationTest, CopyFileOverwriteFile) { - base::FilePath src_path(FILE_PATH_LITERAL("drive/root/File 1.txt")); - base::FilePath dest_path(FILE_PATH_LITERAL( - "drive/root/Directory 1/SubDirectory File 1.txt")); - - ResourceEntry old_dest_entry; - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(dest_path, &old_dest_entry)); - - FileError error = FILE_ERROR_OK; - operation_->Copy(src_path, - dest_path, - false, - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - ResourceEntry new_dest_entry; - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(dest_path, &new_dest_entry)); - - EXPECT_EQ(1u, delegate()->updated_local_ids().size()); - EXPECT_TRUE(delegate()->updated_local_ids().count(old_dest_entry.local_id())); - EXPECT_EQ(1u, delegate()->get_changed_files().size()); - EXPECT_TRUE(delegate()->get_changed_files().count(dest_path)); -} - -TEST_F(CopyOperationTest, CopyFileOverwriteDirectory) { - base::FilePath src_path(FILE_PATH_LITERAL("drive/root/File 1.txt")); - base::FilePath dest_path(FILE_PATH_LITERAL("drive/root/Directory 1")); - - FileError error = FILE_ERROR_OK; - operation_->Copy(src_path, - dest_path, - false, - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_INVALID_OPERATION, error); -} - -TEST_F(CopyOperationTest, CopyDirectory) { - base::FilePath src_path(FILE_PATH_LITERAL("drive/root/Directory 1")); - base::FilePath dest_path(FILE_PATH_LITERAL("drive/root/New Directory")); - - ResourceEntry entry; - ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &entry)); - ASSERT_TRUE(entry.file_info().is_directory()); - ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(dest_path.DirName(), &entry)); - ASSERT_TRUE(entry.file_info().is_directory()); - - FileError error = FILE_ERROR_OK; - operation_->Copy(src_path, - dest_path, - false, - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_NOT_A_FILE, error); -} - -TEST_F(CopyOperationTest, PreserveLastModified) { - base::FilePath src_path(FILE_PATH_LITERAL("drive/root/File 1.txt")); - base::FilePath dest_path(FILE_PATH_LITERAL("drive/root/File 2.txt")); - - ResourceEntry entry; - ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &entry)); - ASSERT_EQ(FILE_ERROR_OK, - GetLocalResourceEntry(dest_path.DirName(), &entry)); - - FileError error = FILE_ERROR_OK; - operation_->Copy(src_path, - dest_path, - true, // Preserve last modified. - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - ResourceEntry entry2; - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &entry)); - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(dest_path, &entry2)); - - EXPECT_NE(entry.file_info().last_modified(), entry.last_modified_by_me()); - EXPECT_EQ(entry.file_info().last_modified(), - entry2.file_info().last_modified()); - // Even with preserve_last_modified enabled, last_modified_by_me is forced to - // the same value as last_modified. - EXPECT_EQ(entry.file_info().last_modified(), entry2.last_modified_by_me()); -} - -TEST_F(CopyOperationTest, WaitForSyncComplete) { - // Create a directory locally. - base::FilePath src_path(FILE_PATH_LITERAL("drive/root/File 1.txt")); - base::FilePath directory_path(FILE_PATH_LITERAL("drive/root/New Directory")); - base::FilePath dest_path = directory_path.AppendASCII("File 1.txt"); - - ResourceEntry directory_parent; - EXPECT_EQ(FILE_ERROR_OK, - GetLocalResourceEntry(directory_path.DirName(), &directory_parent)); - - ResourceEntry directory; - directory.set_parent_local_id(directory_parent.local_id()); - directory.set_title(directory_path.BaseName().AsUTF8Unsafe()); - directory.mutable_file_info()->set_is_directory(true); - directory.set_metadata_edit_state(ResourceEntry::DIRTY); - - std::string directory_local_id; - FileError error = FILE_ERROR_FAILED; - base::PostTaskAndReplyWithResult( - blocking_task_runner(), - FROM_HERE, - base::Bind(&internal::ResourceMetadata::AddEntry, - base::Unretained(metadata()), directory, &directory_local_id), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Try to copy a file to the new directory which lacks resource ID. - // This should result in waiting for the directory to sync. - std::string waited_local_id; - FileOperationCallback pending_callback; - delegate()->set_wait_for_sync_complete_handler( - base::Bind(&CopyWaitForSyncCompleteArguments, - &waited_local_id, &pending_callback)); - - FileError copy_error = FILE_ERROR_FAILED; - operation_->Copy(src_path, - dest_path, - true, // Preserve last modified. - google_apis::test_util::CreateCopyResultCallback( - ©_error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(directory_local_id, waited_local_id); - ASSERT_FALSE(pending_callback.is_null()); - - // Add a new directory to the server and store the resource ID locally. - google_apis::DriveApiErrorCode status = google_apis::DRIVE_OTHER_ERROR; - std::unique_ptr<google_apis::FileResource> file_resource; - fake_service()->AddNewDirectory( - directory_parent.resource_id(), directory.title(), - AddNewDirectoryOptions(), - google_apis::test_util::CreateCopyResultCallback(&status, - &file_resource)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(google_apis::HTTP_CREATED, status); - ASSERT_TRUE(file_resource); - - directory.set_local_id(directory_local_id); - directory.set_resource_id(file_resource->file_id()); - base::PostTaskAndReplyWithResult( - blocking_task_runner(), - FROM_HERE, - base::Bind(&internal::ResourceMetadata::RefreshEntry, - base::Unretained(metadata()), directory), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Resume the copy operation. - pending_callback.Run(FILE_ERROR_OK); - content::RunAllTasksUntilIdle(); - - EXPECT_EQ(FILE_ERROR_OK, copy_error); - ResourceEntry entry; - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(dest_path, &entry)); -} - -} // namespace file_system -} // namespace drive
diff --git a/components/drive/file_system/create_directory_operation_unittest.cc b/components/drive/file_system/create_directory_operation_unittest.cc deleted file mode 100644 index 6edc966..0000000 --- a/components/drive/file_system/create_directory_operation_unittest.cc +++ /dev/null
@@ -1,128 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/drive/chromeos/file_system/create_directory_operation.h" - -#include "components/drive/file_system/operation_test_base.h" -#include "content/public/test/test_utils.h" -#include "google_apis/drive/test_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace drive { -namespace file_system { - -class CreateDirectoryOperationTest : public OperationTestBase { - protected: - // Returns FILE_ERROR_OK if a directory is found at |path|. - FileError FindDirectory(const base::FilePath& path) { - ResourceEntry entry; - FileError error = GetLocalResourceEntry(path, &entry); - if (error == FILE_ERROR_OK && !entry.file_info().is_directory()) - error = FILE_ERROR_NOT_A_DIRECTORY; - return error; - } -}; - -TEST_F(CreateDirectoryOperationTest, CreateDirectory) { - CreateDirectoryOperation operation(blocking_task_runner(), - delegate(), - metadata()); - - const base::FilePath kExistingFile( - FILE_PATH_LITERAL("drive/root/File 1.txt")); - const base::FilePath kExistingDirectory( - FILE_PATH_LITERAL("drive/root/Directory 1")); - const base::FilePath kNewDirectory1( - FILE_PATH_LITERAL("drive/root/New Directory")); - const base::FilePath kNewDirectory2 = - kNewDirectory1.AppendASCII("New Directory 2/a/b/c"); - - // Create a new directory, not recursively. - EXPECT_EQ(FILE_ERROR_NOT_FOUND, FindDirectory(kNewDirectory1)); - - FileError error = FILE_ERROR_FAILED; - operation.CreateDirectory( - kNewDirectory1, - true, // is_exclusive - false, // is_recursive - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - EXPECT_EQ(FILE_ERROR_OK, FindDirectory(kNewDirectory1)); - EXPECT_EQ(1U, delegate()->get_changed_files().size()); - EXPECT_EQ( - 1U, - delegate()->get_changed_files().CountDirectory(kNewDirectory1.DirName())); - - ResourceEntry entry; - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kNewDirectory1, &entry)); - EXPECT_EQ(ResourceEntry::DIRTY, entry.metadata_edit_state()); - EXPECT_TRUE(entry.file_info().is_directory()); - EXPECT_FALSE(base::Time::FromInternalValue( - entry.file_info().last_modified()).is_null()); - EXPECT_FALSE( - base::Time::FromInternalValue(entry.last_modified_by_me()).is_null()); - EXPECT_FALSE(base::Time::FromInternalValue( - entry.file_info().last_accessed()).is_null()); - EXPECT_EQ(1U, delegate()->updated_local_ids().size()); - EXPECT_EQ(1U, delegate()->updated_local_ids().count(entry.local_id())); - - // Create a new directory recursively. - EXPECT_EQ(FILE_ERROR_NOT_FOUND, FindDirectory(kNewDirectory2)); - operation.CreateDirectory( - kNewDirectory2, - true, // is_exclusive - false, // is_recursive - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_NOT_FOUND, error); - EXPECT_EQ(FILE_ERROR_NOT_FOUND, FindDirectory(kNewDirectory2)); - - operation.CreateDirectory( - kNewDirectory2, - true, // is_exclusive - true, // is_recursive - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - EXPECT_EQ(FILE_ERROR_OK, FindDirectory(kNewDirectory2)); - - // Try to create an existing directory. - operation.CreateDirectory( - kExistingDirectory, - true, // is_exclusive - false, // is_recursive - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_EXISTS, error); - - operation.CreateDirectory( - kExistingDirectory, - false, // is_exclusive - false, // is_recursive - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Try to create a directory with a path for an existing file. - operation.CreateDirectory( - kExistingFile, - false, // is_exclusive - true, // is_recursive - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_NOT_A_DIRECTORY, error); - - // Try to create a directory under a file. - operation.CreateDirectory( - kExistingFile.AppendASCII("New Directory"), - false, // is_exclusive - true, // is_recursive - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_NOT_A_DIRECTORY, error); -} - -} // namespace file_system -} // namespace drive
diff --git a/components/drive/file_system/create_file_operation_unittest.cc b/components/drive/file_system/create_file_operation_unittest.cc deleted file mode 100644 index 884b79cd..0000000 --- a/components/drive/file_system/create_file_operation_unittest.cc +++ /dev/null
@@ -1,163 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/drive/chromeos/file_system/create_file_operation.h" - -#include "components/drive/file_change.h" -#include "components/drive/file_system/operation_test_base.h" -#include "content/public/test/test_utils.h" -#include "google_apis/drive/test_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace drive { -namespace file_system { - -typedef OperationTestBase CreateFileOperationTest; - -TEST_F(CreateFileOperationTest, CreateFile) { - CreateFileOperation operation(blocking_task_runner(), - delegate(), - metadata()); - - const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/New File.txt")); - FileError error = FILE_ERROR_FAILED; - operation.CreateFile( - kFilePath, - true, // is_exclusive - std::string(), // no predetermined mime type - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - ResourceEntry entry; - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath, &entry)); - EXPECT_EQ(ResourceEntry::DIRTY, entry.metadata_edit_state()); - EXPECT_FALSE(base::Time::FromInternalValue( - entry.file_info().last_modified()).is_null()); - EXPECT_FALSE( - base::Time::FromInternalValue(entry.last_modified_by_me()).is_null()); - EXPECT_FALSE(base::Time::FromInternalValue( - entry.file_info().last_accessed()).is_null()); - - EXPECT_EQ(1u, delegate()->get_changed_files().size()); - EXPECT_EQ(1u, delegate()->get_changed_files().count(kFilePath)); - EXPECT_EQ(1u, delegate()->updated_local_ids().size()); - EXPECT_EQ(1u, delegate()->updated_local_ids().count(entry.local_id())); -} - -TEST_F(CreateFileOperationTest, CreateFileIsExclusive) { - CreateFileOperation operation(blocking_task_runner(), - delegate(), - metadata()); - - const base::FilePath kExistingFile( - FILE_PATH_LITERAL("drive/root/File 1.txt")); - const base::FilePath kExistingDirectory( - FILE_PATH_LITERAL("drive/root/Directory 1")); - const base::FilePath kNonExistingFile( - FILE_PATH_LITERAL("drive/root/Directory 1/not exist.png")); - const base::FilePath kFileInNonExistingDirectory( - FILE_PATH_LITERAL("drive/root/not exist/not exist.png")); - - // Create fails if is_exclusive = true and a file exists. - FileError error = FILE_ERROR_FAILED; - operation.CreateFile( - kExistingFile, - true, // is_exclusive - std::string(), // no predetermined mime type - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_EXISTS, error); - - // Create succeeds if is_exclusive = false and a file exists. - operation.CreateFile( - kExistingFile, - false, // is_exclusive - std::string(), // no predetermined mime type - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Create fails if a directory existed even when is_exclusive = false. - operation.CreateFile( - kExistingDirectory, - false, // is_exclusive - std::string(), // no predetermined mime type - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_EXISTS, error); - - // Create succeeds if no entry exists. - operation.CreateFile( - kNonExistingFile, - true, // is_exclusive - std::string(), // no predetermined mime type - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Create fails if the parent directory does not exist. - operation.CreateFile( - kFileInNonExistingDirectory, - false, // is_exclusive - std::string(), // no predetermined mime type - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_NOT_A_DIRECTORY, error); -} - -TEST_F(CreateFileOperationTest, CreateFileMimeType) { - CreateFileOperation operation(blocking_task_runner(), - delegate(), - metadata()); - - const base::FilePath kPng1(FILE_PATH_LITERAL("drive/root/1.png")); - const base::FilePath kPng2(FILE_PATH_LITERAL("drive/root/2.png")); - const base::FilePath kUnknown(FILE_PATH_LITERAL("drive/root/3.unknown")); - const std::string kSpecialMimeType("application/x-createfile-test"); - - FileError error = FILE_ERROR_FAILED; - operation.CreateFile( - kPng1, - false, // is_exclusive - std::string(), // no predetermined mime type - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // If no mime type is specified, it is guessed from the file name. - ResourceEntry entry; - ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kPng1, &entry)); - EXPECT_EQ("image/png", entry.file_specific_info().content_mime_type()); - - error = FILE_ERROR_FAILED; - operation.CreateFile( - kPng2, - false, // is_exclusive - kSpecialMimeType, - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // If the mime type is explicitly set, respect it. - ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kPng2, &entry)); - EXPECT_EQ(kSpecialMimeType, entry.file_specific_info().content_mime_type()); - - error = FILE_ERROR_FAILED; - operation.CreateFile( - kUnknown, - false, // is_exclusive - std::string(), // no predetermined mime type - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // If the mime type is not set and unknown, default to octet-stream. - ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kUnknown, &entry)); - EXPECT_EQ("application/octet-stream", - entry.file_specific_info().content_mime_type()); -} - -} // namespace file_system -} // namespace drive
diff --git a/components/drive/file_system/download_operation_unittest.cc b/components/drive/file_system/download_operation_unittest.cc deleted file mode 100644 index 58625b8d..0000000 --- a/components/drive/file_system/download_operation_unittest.cc +++ /dev/null
@@ -1,510 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/drive/chromeos/file_system/download_operation.h" - -#include <stddef.h> -#include <stdint.h> - -#include <memory> - -#include "base/bind.h" -#include "base/files/file_util.h" -#include "base/task_runner_util.h" -#include "components/drive/chromeos/fake_free_disk_space_getter.h" -#include "components/drive/chromeos/file_cache.h" -#include "components/drive/file_change.h" -#include "components/drive/file_system/operation_test_base.h" -#include "components/drive/file_system_core_util.h" -#include "components/drive/job_scheduler.h" -#include "components/drive/service/fake_drive_service.h" -#include "content/public/test/test_utils.h" -#include "google_apis/drive/test_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace drive { -namespace file_system { - -class DownloadOperationTest : public OperationTestBase { - protected: - void SetUp() override { - OperationTestBase::SetUp(); - - operation_ = std::make_unique<DownloadOperation>( - blocking_task_runner(), delegate(), scheduler(), metadata(), cache(), - temp_dir()); - } - - std::unique_ptr<DownloadOperation> operation_; -}; - -TEST_F(DownloadOperationTest, - EnsureFileDownloadedByPath_FromServer_EnoughSpace) { - base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt")); - ResourceEntry src_entry; - ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry)); - const int64_t file_size = src_entry.file_info().size(); - - // Pretend we have enough space. - fake_free_disk_space_getter()->set_default_value( - file_size + drive::internal::kMinFreeSpaceInBytes); - - FileError error = FILE_ERROR_FAILED; - base::FilePath file_path; - std::unique_ptr<ResourceEntry> entry; - operation_->EnsureFileDownloadedByPath( - file_in_root, - ClientContext(USER_INITIATED), - GetFileContentInitializedCallback(), - google_apis::GetContentCallback(), - google_apis::test_util::CreateCopyResultCallback( - &error, &file_path, &entry)); - content::RunAllTasksUntilIdle(); - - EXPECT_EQ(FILE_ERROR_OK, error); - ASSERT_TRUE(entry); - EXPECT_FALSE(entry->file_specific_info().is_hosted_document()); - - // The transfered file is cached and the change of "offline available" - // attribute is notified. - EXPECT_EQ(1U, delegate()->get_changed_files().size()); - EXPECT_EQ(1U, delegate()->get_changed_files().count(file_in_root)); -} - -TEST_F(DownloadOperationTest, - EnsureFileDownloadedByPath_FromServer_NoSpaceAtAll) { - base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt")); - - // Pretend we have no space at all. - fake_free_disk_space_getter()->set_default_value(0); - - FileError error = FILE_ERROR_OK; - base::FilePath file_path; - std::unique_ptr<ResourceEntry> entry; - operation_->EnsureFileDownloadedByPath( - file_in_root, - ClientContext(USER_INITIATED), - GetFileContentInitializedCallback(), - google_apis::GetContentCallback(), - google_apis::test_util::CreateCopyResultCallback( - &error, &file_path, &entry)); - content::RunAllTasksUntilIdle(); - - EXPECT_EQ(FILE_ERROR_NO_LOCAL_SPACE, error); -} - -TEST_F(DownloadOperationTest, - EnsureFileDownloadedByPath_FromServer_NoEnoughSpaceButCanFreeUp) { - base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt")); - ResourceEntry src_entry; - ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry)); - const int64_t file_size = src_entry.file_info().size(); - - // Make another file cached. - // This file's cache file will be removed to free up the disk space. - base::FilePath cached_file( - FILE_PATH_LITERAL("drive/root/Duplicate Name.txt")); - FileError error = FILE_ERROR_FAILED; - base::FilePath file_path; - std::unique_ptr<ResourceEntry> entry; - operation_->EnsureFileDownloadedByPath( - cached_file, - ClientContext(USER_INITIATED), - GetFileContentInitializedCallback(), - google_apis::GetContentCallback(), - google_apis::test_util::CreateCopyResultCallback( - &error, &file_path, &entry)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - ASSERT_TRUE(entry); - EXPECT_TRUE(entry->file_specific_info().cache_state().is_present()); - - // Pretend we have no space first (checked before downloading a file), - // but then start reporting we have space. This is to emulate that - // the disk space was freed up by removing temporary files. - fake_free_disk_space_getter()->set_default_value( - file_size + drive::internal::kMinFreeSpaceInBytes); - fake_free_disk_space_getter()->PushFakeValue(0); - fake_free_disk_space_getter()->PushFakeValue(0); - - operation_->EnsureFileDownloadedByPath( - file_in_root, - ClientContext(USER_INITIATED), - GetFileContentInitializedCallback(), - google_apis::GetContentCallback(), - google_apis::test_util::CreateCopyResultCallback( - &error, &file_path, &entry)); - content::RunAllTasksUntilIdle(); - - EXPECT_EQ(FILE_ERROR_OK, error); - ASSERT_TRUE(entry); - EXPECT_FALSE(entry->file_specific_info().is_hosted_document()); - - // The transfered file is cached and the change of "offline available" - // attribute is notified. - EXPECT_EQ(2U, delegate()->get_changed_files().size()); - EXPECT_TRUE(delegate()->get_changed_files().count(file_in_root)); - EXPECT_TRUE(delegate()->get_changed_files().count(cached_file)); - - // The cache for the other file should be removed in order to free up space. - ResourceEntry cached_file_entry; - EXPECT_EQ(FILE_ERROR_OK, - GetLocalResourceEntry(cached_file, &cached_file_entry)); - EXPECT_FALSE( - cached_file_entry.file_specific_info().cache_state().is_present()); -} - -TEST_F(DownloadOperationTest, - EnsureFileDownloadedByPath_FromServer_EnoughSpaceButBecomeFull) { - base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt")); - ResourceEntry src_entry; - ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry)); - const int64_t file_size = src_entry.file_info().size(); - - // Pretend we have enough space first (checked before downloading a file), - // but then start reporting we have not enough space. This is to emulate that - // the disk space becomes full after the file is downloaded for some reason - // (ex. the actual file was larger than the expected size). - fake_free_disk_space_getter()->PushFakeValue( - file_size + drive::internal::kMinFreeSpaceInBytes); - fake_free_disk_space_getter()->set_default_value( - drive::internal::kMinFreeSpaceInBytes - 1); - - FileError error = FILE_ERROR_OK; - base::FilePath file_path; - std::unique_ptr<ResourceEntry> entry; - operation_->EnsureFileDownloadedByPath( - file_in_root, - ClientContext(USER_INITIATED), - GetFileContentInitializedCallback(), - google_apis::GetContentCallback(), - google_apis::test_util::CreateCopyResultCallback( - &error, &file_path, &entry)); - content::RunAllTasksUntilIdle(); - - EXPECT_EQ(FILE_ERROR_NO_LOCAL_SPACE, error); -} - -TEST_F(DownloadOperationTest, EnsureFileDownloadedByPath_FromCache) { - base::FilePath temp_file; - ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir(), &temp_file)); - - base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt")); - ResourceEntry src_entry; - ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry)); - - // Store something as cached version of this file. - FileError error = FILE_ERROR_OK; - base::PostTaskAndReplyWithResult( - blocking_task_runner(), - FROM_HERE, - base::Bind(&internal::FileCache::Store, - base::Unretained(cache()), - GetLocalId(file_in_root), - src_entry.file_specific_info().md5(), - temp_file, - internal::FileCache::FILE_OPERATION_COPY), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - base::FilePath file_path; - std::unique_ptr<ResourceEntry> entry; - operation_->EnsureFileDownloadedByPath( - file_in_root, - ClientContext(USER_INITIATED), - GetFileContentInitializedCallback(), - google_apis::GetContentCallback(), - google_apis::test_util::CreateCopyResultCallback( - &error, &file_path, &entry)); - content::RunAllTasksUntilIdle(); - - EXPECT_EQ(FILE_ERROR_OK, error); - ASSERT_TRUE(entry); - EXPECT_FALSE(entry->file_specific_info().is_hosted_document()); -} - -TEST_F(DownloadOperationTest, EnsureFileDownloadedByPath_HostedDocument) { - base::FilePath file_in_root(FILE_PATH_LITERAL( - "drive/root/Document 1 excludeDir-test.gdoc")); - - FileError error = FILE_ERROR_FAILED; - base::FilePath file_path; - std::unique_ptr<ResourceEntry> entry; - operation_->EnsureFileDownloadedByPath( - file_in_root, - ClientContext(USER_INITIATED), - GetFileContentInitializedCallback(), - google_apis::GetContentCallback(), - google_apis::test_util::CreateCopyResultCallback( - &error, &file_path, &entry)); - content::RunAllTasksUntilIdle(); - - EXPECT_EQ(FILE_ERROR_OK, error); - ASSERT_TRUE(entry); - EXPECT_TRUE(entry->file_specific_info().is_hosted_document()); - EXPECT_FALSE(file_path.empty()); - - EXPECT_EQ(GURL(entry->alternate_url()), util::ReadUrlFromGDocFile(file_path)); - EXPECT_EQ(entry->resource_id(), util::ReadResourceIdFromGDocFile(file_path)); - EXPECT_EQ(FILE_PATH_LITERAL(".gdoc"), file_path.Extension()); -} - -TEST_F(DownloadOperationTest, EnsureFileDownloadedByLocalId) { - base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt")); - ResourceEntry src_entry; - ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry)); - - FileError error = FILE_ERROR_OK; - base::FilePath file_path; - std::unique_ptr<ResourceEntry> entry; - operation_->EnsureFileDownloadedByLocalId( - GetLocalId(file_in_root), - ClientContext(USER_INITIATED), - GetFileContentInitializedCallback(), - google_apis::GetContentCallback(), - google_apis::test_util::CreateCopyResultCallback( - &error, &file_path, &entry)); - content::RunAllTasksUntilIdle(); - - EXPECT_EQ(FILE_ERROR_OK, error); - ASSERT_TRUE(entry); - EXPECT_FALSE(entry->file_specific_info().is_hosted_document()); - - // The transfered file is cached and the change of "offline available" - // attribute is notified. - EXPECT_EQ(1U, delegate()->get_changed_files().size()); - EXPECT_EQ(1U, delegate()->get_changed_files().count(file_in_root)); -} - -TEST_F(DownloadOperationTest, - EnsureFileDownloadedByPath_WithGetContentCallback) { - base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt")); - - { - FileError initialized_error = FILE_ERROR_FAILED; - std::unique_ptr<ResourceEntry> entry, entry_dontcare; - base::FilePath local_path, local_path_dontcare; - google_apis::test_util::TestGetContentCallback get_content_callback; - FileError completion_error = FILE_ERROR_FAILED; - base::Closure cancel_download = operation_->EnsureFileDownloadedByPath( - file_in_root, - ClientContext(USER_INITIATED), - google_apis::test_util::CreateCopyResultCallback( - &initialized_error, &local_path, &entry), - get_content_callback.callback(), - google_apis::test_util::CreateCopyResultCallback( - &completion_error, &local_path_dontcare, &entry_dontcare)); - content::RunAllTasksUntilIdle(); - - // For the first time, file is downloaded from the remote server. - // In this case, |local_path| is empty. - EXPECT_EQ(FILE_ERROR_OK, initialized_error); - ASSERT_TRUE(entry); - ASSERT_TRUE(local_path.empty()); - EXPECT_FALSE(cancel_download.is_null()); - // Content is available through the second callback argument. - EXPECT_EQ(static_cast<size_t>(entry->file_info().size()), - get_content_callback.GetConcatenatedData().size()); - EXPECT_EQ(FILE_ERROR_OK, completion_error); - - // The transfered file is cached and the change of "offline available" - // attribute is notified. - EXPECT_EQ(1U, delegate()->get_changed_files().size()); - EXPECT_EQ(1U, delegate()->get_changed_files().count(file_in_root)); - } - - { - FileError initialized_error = FILE_ERROR_FAILED; - std::unique_ptr<ResourceEntry> entry, entry_dontcare; - base::FilePath local_path, local_path_dontcare; - google_apis::test_util::TestGetContentCallback get_content_callback; - FileError completion_error = FILE_ERROR_FAILED; - base::Closure cancel_download = operation_->EnsureFileDownloadedByPath( - file_in_root, - ClientContext(USER_INITIATED), - google_apis::test_util::CreateCopyResultCallback( - &initialized_error, &local_path, &entry), - get_content_callback.callback(), - google_apis::test_util::CreateCopyResultCallback( - &completion_error, &local_path_dontcare, &entry_dontcare)); - content::RunAllTasksUntilIdle(); - - // Try second download. In this case, the file should be cached, so - // |local_path| should not be empty. - EXPECT_EQ(FILE_ERROR_OK, initialized_error); - ASSERT_TRUE(entry); - ASSERT_TRUE(!local_path.empty()); - EXPECT_FALSE(cancel_download.is_null()); - // The content is available from the cache file. - EXPECT_TRUE(get_content_callback.data().empty()); - int64_t local_file_size = 0; - base::GetFileSize(local_path, &local_file_size); - EXPECT_EQ(entry->file_info().size(), local_file_size); - EXPECT_EQ(FILE_ERROR_OK, completion_error); - } -} - -TEST_F(DownloadOperationTest, EnsureFileDownloadedByLocalId_FromCache) { - base::FilePath temp_file; - ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir(), &temp_file)); - - base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt")); - ResourceEntry src_entry; - ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry)); - - // Store something as cached version of this file. - FileError error = FILE_ERROR_FAILED; - base::PostTaskAndReplyWithResult( - blocking_task_runner(), - FROM_HERE, - base::Bind(&internal::FileCache::Store, - base::Unretained(cache()), - GetLocalId(file_in_root), - src_entry.file_specific_info().md5(), - temp_file, - internal::FileCache::FILE_OPERATION_COPY), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // The file is obtained from the cache. - // Hence the downloading should work even if the drive service is offline. - fake_service()->set_offline(true); - - base::FilePath file_path; - std::unique_ptr<ResourceEntry> entry; - operation_->EnsureFileDownloadedByLocalId( - GetLocalId(file_in_root), - ClientContext(USER_INITIATED), - GetFileContentInitializedCallback(), - google_apis::GetContentCallback(), - google_apis::test_util::CreateCopyResultCallback( - &error, &file_path, &entry)); - content::RunAllTasksUntilIdle(); - - EXPECT_EQ(FILE_ERROR_OK, error); - ASSERT_TRUE(entry); - EXPECT_FALSE(entry->file_specific_info().is_hosted_document()); -} - -TEST_F(DownloadOperationTest, EnsureFileDownloadedByPath_DirtyCache) { - base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt")); - ResourceEntry src_entry; - ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry)); - - // Prepare a dirty file to store to cache that has a different size than - // stored in resource metadata. - base::FilePath dirty_file = temp_dir().AppendASCII("dirty.txt"); - size_t dirty_size = src_entry.file_info().size() + 10; - google_apis::test_util::WriteStringToFile(dirty_file, - std::string(dirty_size, 'x')); - - // Store the file as a cache, marking it to be dirty. - FileError error = FILE_ERROR_FAILED; - base::PostTaskAndReplyWithResult( - blocking_task_runner(), - FROM_HERE, - base::Bind(&internal::FileCache::Store, - base::Unretained(cache()), - GetLocalId(file_in_root), - std::string(), - dirty_file, - internal::FileCache::FILE_OPERATION_COPY), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Record values passed to GetFileContentInitializedCallback(). - FileError init_error; - base::FilePath init_path; - std::unique_ptr<ResourceEntry> init_entry; - base::FilePath file_path; - std::unique_ptr<ResourceEntry> entry; - base::Closure cancel_callback = operation_->EnsureFileDownloadedByPath( - file_in_root, - ClientContext(USER_INITIATED), - google_apis::test_util::CreateCopyResultCallback( - &init_error, &init_path, &init_entry), - google_apis::GetContentCallback(), - google_apis::test_util::CreateCopyResultCallback( - &error, &file_path, &entry)); - content::RunAllTasksUntilIdle(); - - EXPECT_EQ(FILE_ERROR_OK, error); - // Check that the result of local modification is propagated. - EXPECT_EQ(static_cast<int64_t>(dirty_size), init_entry->file_info().size()); - EXPECT_EQ(static_cast<int64_t>(dirty_size), entry->file_info().size()); -} - -TEST_F(DownloadOperationTest, EnsureFileDownloadedByPath_LocallyCreatedFile) { - // Add a new file with an empty resource ID. - base::FilePath file_path(FILE_PATH_LITERAL("drive/root/New File.txt")); - ResourceEntry parent; - ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_path.DirName(), &parent)); - - ResourceEntry new_file; - new_file.set_title("New File.txt"); - new_file.set_parent_local_id(parent.local_id()); - - FileError error = FILE_ERROR_FAILED; - std::string local_id; - base::PostTaskAndReplyWithResult( - blocking_task_runner(), - FROM_HERE, - base::Bind(&internal::ResourceMetadata::AddEntry, - base::Unretained(metadata()), - new_file, - &local_id), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Empty cache file should be returned. - base::FilePath cache_file_path; - std::unique_ptr<ResourceEntry> entry; - operation_->EnsureFileDownloadedByPath( - file_path, - ClientContext(USER_INITIATED), - GetFileContentInitializedCallback(), - google_apis::GetContentCallback(), - google_apis::test_util::CreateCopyResultCallback( - &error, &cache_file_path, &entry)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - int64_t cache_file_size = 0; - EXPECT_TRUE(base::GetFileSize(cache_file_path, &cache_file_size)); - EXPECT_EQ(static_cast<int64_t>(0), cache_file_size); - ASSERT_TRUE(entry); - EXPECT_EQ(cache_file_size, entry->file_info().size()); -} - -TEST_F(DownloadOperationTest, CancelBeforeDownloadStarts) { - base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt")); - ResourceEntry src_entry; - ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry)); - - // Start operation. - FileError error = FILE_ERROR_OK; - base::FilePath file_path; - std::unique_ptr<ResourceEntry> entry; - base::Closure cancel_closure = operation_->EnsureFileDownloadedByLocalId( - GetLocalId(file_in_root), - ClientContext(USER_INITIATED), - GetFileContentInitializedCallback(), - google_apis::GetContentCallback(), - google_apis::test_util::CreateCopyResultCallback( - &error, &file_path, &entry)); - - // Cancel immediately. - ASSERT_FALSE(cancel_closure.is_null()); - cancel_closure.Run(); - content::RunAllTasksUntilIdle(); - - EXPECT_EQ(FILE_ERROR_ABORT, error); -} - -} // namespace file_system -} // namespace drive
diff --git a/components/drive/file_system/get_file_for_saving_operation_unittest.cc b/components/drive/file_system/get_file_for_saving_operation_unittest.cc deleted file mode 100644 index d5118c8..0000000 --- a/components/drive/file_system/get_file_for_saving_operation_unittest.cc +++ /dev/null
@@ -1,158 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/drive/chromeos/file_system/get_file_for_saving_operation.h" - -#include <stdint.h> - -#include <memory> - -#include "base/callback.h" -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/memory/ref_counted.h" -#include "base/run_loop.h" -#include "base/single_thread_task_runner.h" -#include "base/task_runner_util.h" -#include "components/drive/drive.pb.h" -#include "components/drive/file_change.h" -#include "components/drive/file_errors.h" -#include "components/drive/file_system/operation_test_base.h" -#include "components/drive/file_write_watcher.h" -#include "components/drive/job_scheduler.h" -#include "content/public/test/test_utils.h" -#include "google_apis/drive/test_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace drive { -namespace file_system { - -namespace { - -// If OnCacheFileUploadNeededByOperation is called, records the local ID and -// calls |quit_closure|. -class TestDelegate : public OperationDelegate { - public: - void set_quit_closure(const base::Closure& quit_closure) { - quit_closure_ = quit_closure; - } - - const std::string& updated_local_id() const { - return updated_local_id_; - } - - // OperationDelegate overrides. - void OnEntryUpdatedByOperation(const ClientContext& /* context */, - const std::string& local_id) override { - updated_local_id_ = local_id; - if (!quit_closure_.is_null()) - quit_closure_.Run(); - } - - private: - std::string updated_local_id_; - base::Closure quit_closure_; -}; - -} // namespace - -class GetFileForSavingOperationTest : public OperationTestBase { - protected: - // FileWriteWatcher requires TYPE_IO message loop to run. - GetFileForSavingOperationTest() - : OperationTestBase(content::BrowserTaskEnvironment::IO_MAINLOOP) {} - - void SetUp() override { - OperationTestBase::SetUp(); - - operation_ = std::make_unique<GetFileForSavingOperation>( - logger(), blocking_task_runner(), &delegate_, scheduler(), metadata(), - cache(), temp_dir()); - operation_->file_write_watcher_for_testing()->DisableDelayForTesting(); - } - - TestDelegate delegate_; - std::unique_ptr<GetFileForSavingOperation> operation_; -}; - -TEST_F(GetFileForSavingOperationTest, GetFileForSaving_Exist) { - base::FilePath drive_path(FILE_PATH_LITERAL("drive/root/File 1.txt")); - ResourceEntry src_entry; - ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(drive_path, &src_entry)); - - // Run the operation. - FileError error = FILE_ERROR_FAILED; - std::unique_ptr<ResourceEntry> entry; - base::FilePath local_path; - operation_->GetFileForSaving( - drive_path, - google_apis::test_util::CreateCopyResultCallback( - &error, &local_path, &entry)); - content::RunAllTasksUntilIdle(); - - // Checks that the file is retrieved. - EXPECT_EQ(FILE_ERROR_OK, error); - ASSERT_TRUE(entry); - EXPECT_EQ(src_entry.resource_id(), entry->resource_id()); - - // Checks that it presents in cache and marked dirty. - EXPECT_TRUE(entry->file_specific_info().cache_state().is_present()); - EXPECT_TRUE(entry->file_specific_info().cache_state().is_dirty()); - - // Write something to the cache and checks that the event is reported. - { - base::RunLoop run_loop; - delegate_.set_quit_closure(run_loop.QuitClosure()); - google_apis::test_util::WriteStringToFile(local_path, "hello"); - run_loop.Run(); - EXPECT_EQ(GetLocalId(drive_path), delegate_.updated_local_id()); - } -} - -TEST_F(GetFileForSavingOperationTest, GetFileForSaving_NotExist) { - base::FilePath drive_path(FILE_PATH_LITERAL("drive/root/NotExist.txt")); - ResourceEntry src_entry; - ASSERT_EQ(FILE_ERROR_NOT_FOUND, - GetLocalResourceEntry(drive_path, &src_entry)); - - // Run the operation. - FileError error = FILE_ERROR_FAILED; - std::unique_ptr<ResourceEntry> entry; - base::FilePath local_path; - operation_->GetFileForSaving( - drive_path, - google_apis::test_util::CreateCopyResultCallback( - &error, &local_path, &entry)); - content::RunAllTasksUntilIdle(); - - // Checks that the file is created and retrieved. - EXPECT_EQ(FILE_ERROR_OK, error); - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(drive_path, &src_entry)); - int64_t size = -1; - EXPECT_TRUE(base::GetFileSize(local_path, &size)); - EXPECT_EQ(0, size); -} - -TEST_F(GetFileForSavingOperationTest, GetFileForSaving_Directory) { - base::FilePath drive_path(FILE_PATH_LITERAL("drive/root/Directory 1")); - ResourceEntry src_entry; - ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(drive_path, &src_entry)); - ASSERT_TRUE(src_entry.file_info().is_directory()); - - // Run the operation. - FileError error = FILE_ERROR_FAILED; - std::unique_ptr<ResourceEntry> entry; - base::FilePath local_path; - operation_->GetFileForSaving( - drive_path, - google_apis::test_util::CreateCopyResultCallback( - &error, &local_path, &entry)); - content::RunAllTasksUntilIdle(); - - // Checks that an error is returned. - EXPECT_EQ(FILE_ERROR_EXISTS, error); -} - -} // namespace file_system -} // namespace drive
diff --git a/components/drive/file_system/move_operation_unittest.cc b/components/drive/file_system/move_operation_unittest.cc deleted file mode 100644 index 5d605f3..0000000 --- a/components/drive/file_system/move_operation_unittest.cc +++ /dev/null
@@ -1,142 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/drive/chromeos/file_system/move_operation.h" - -#include <memory> - -#include "components/drive/file_change.h" -#include "components/drive/file_system/operation_test_base.h" -#include "content/public/test/test_utils.h" -#include "google_apis/drive/test_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace drive { -namespace file_system { - -class MoveOperationTest : public OperationTestBase { - protected: - void SetUp() override { - OperationTestBase::SetUp(); - operation_ = std::make_unique<MoveOperation>(blocking_task_runner(), - delegate(), metadata()); - } - - std::unique_ptr<MoveOperation> operation_; -}; - -TEST_F(MoveOperationTest, MoveFileInSameDirectory) { - const base::FilePath src_path( - FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt")); - const base::FilePath dest_path( - FILE_PATH_LITERAL("drive/root/Directory 1/Test.log")); - - ResourceEntry src_entry, dest_entry; - ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &src_entry)); - ASSERT_EQ(FILE_ERROR_NOT_FOUND, - GetLocalResourceEntry(dest_path, &dest_entry)); - - FileError error = FILE_ERROR_FAILED; - operation_->Move(src_path, - dest_path, - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(dest_path, &dest_entry)); - EXPECT_EQ(src_entry.local_id(), dest_entry.local_id()); - EXPECT_EQ(ResourceEntry::DIRTY, dest_entry.metadata_edit_state()); - EXPECT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntry(src_path, &src_entry)); - - EXPECT_EQ(2U, delegate()->get_changed_files().size()); - EXPECT_TRUE(delegate()->get_changed_files().count(src_path)); - EXPECT_TRUE(delegate()->get_changed_files().count(dest_path)); - - EXPECT_EQ(1U, delegate()->updated_local_ids().size()); - EXPECT_TRUE(delegate()->updated_local_ids().count(src_entry.local_id())); -} - -TEST_F(MoveOperationTest, MoveFileFromRootToSubDirectory) { - base::FilePath src_path(FILE_PATH_LITERAL("drive/root/File 1.txt")); - base::FilePath dest_path( - FILE_PATH_LITERAL("drive/root/Directory 1/Test.log")); - - ResourceEntry src_entry, dest_entry; - ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &src_entry)); - ASSERT_EQ(FILE_ERROR_NOT_FOUND, - GetLocalResourceEntry(dest_path, &dest_entry)); - - FileError error = FILE_ERROR_FAILED; - operation_->Move(src_path, - dest_path, - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(dest_path, &dest_entry)); - EXPECT_EQ(src_entry.local_id(), dest_entry.local_id()); - EXPECT_EQ(ResourceEntry::DIRTY, dest_entry.metadata_edit_state()); - EXPECT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntry(src_path, &src_entry)); - - EXPECT_EQ(2U, delegate()->get_changed_files().size()); - EXPECT_TRUE(delegate()->get_changed_files().count(src_path)); - EXPECT_TRUE(delegate()->get_changed_files().count(dest_path)); - - EXPECT_EQ(1U, delegate()->updated_local_ids().size()); - EXPECT_TRUE(delegate()->updated_local_ids().count(src_entry.local_id())); -} - -TEST_F(MoveOperationTest, MoveNotExistingFile) { - base::FilePath src_path(FILE_PATH_LITERAL("drive/root/Dummy file.txt")); - base::FilePath dest_path(FILE_PATH_LITERAL("drive/root/Test.log")); - - FileError error = FILE_ERROR_OK; - operation_->Move(src_path, - dest_path, - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_NOT_FOUND, error); - - ResourceEntry entry; - EXPECT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntry(src_path, &entry)); - EXPECT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntry(dest_path, &entry)); -} - -TEST_F(MoveOperationTest, MoveFileToNonExistingDirectory) { - base::FilePath src_path(FILE_PATH_LITERAL("drive/root/File 1.txt")); - base::FilePath dest_path(FILE_PATH_LITERAL("drive/root/Dummy/Test.log")); - - FileError error = FILE_ERROR_OK; - operation_->Move(src_path, - dest_path, - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_NOT_FOUND, error); - - ResourceEntry entry; - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &entry)); - EXPECT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntry(dest_path, &entry)); -} - -// Test the case where the parent of |dest_file_path| is a existing file, -// not a directory. -TEST_F(MoveOperationTest, MoveFileToInvalidPath) { - base::FilePath src_path(FILE_PATH_LITERAL("drive/root/File 1.txt")); - base::FilePath dest_path( - FILE_PATH_LITERAL("drive/root/Duplicate Name.txt/Test.log")); - - FileError error = FILE_ERROR_OK; - operation_->Move(src_path, - dest_path, - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_NOT_A_DIRECTORY, error); - - ResourceEntry entry; - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &entry)); - EXPECT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntry(dest_path, &entry)); -} - -} // namespace file_system -} // namespace drive
diff --git a/components/drive/file_system/open_file_operation_unittest.cc b/components/drive/file_system/open_file_operation_unittest.cc deleted file mode 100644 index ae99c316c..0000000 --- a/components/drive/file_system/open_file_operation_unittest.cc +++ /dev/null
@@ -1,259 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/drive/chromeos/file_system/open_file_operation.h" - -#include <stdint.h> - -#include <map> -#include <memory> - -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/task_runner_util.h" -#include "components/drive/chromeos/file_cache.h" -#include "components/drive/drive.pb.h" -#include "components/drive/file_change.h" -#include "components/drive/file_errors.h" -#include "components/drive/file_system/operation_test_base.h" -#include "content/public/test/test_utils.h" -#include "google_apis/drive/test_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace drive { -namespace file_system { - -class OpenFileOperationTest : public OperationTestBase { - protected: - void SetUp() override { - OperationTestBase::SetUp(); - - operation_ = std::make_unique<OpenFileOperation>( - blocking_task_runner(), delegate(), scheduler(), metadata(), cache(), - temp_dir()); - } - - std::unique_ptr<OpenFileOperation> operation_; -}; - -TEST_F(OpenFileOperationTest, OpenExistingFile) { - const base::FilePath file_in_root( - FILE_PATH_LITERAL("drive/root/File 1.txt")); - ResourceEntry src_entry; - ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry)); - const int64_t file_size = src_entry.file_info().size(); - - FileError error = FILE_ERROR_FAILED; - base::FilePath file_path; - base::Closure close_callback; - operation_->OpenFile( - file_in_root, - OPEN_FILE, - std::string(), // mime_type - google_apis::test_util::CreateCopyResultCallback( - &error, &file_path, &close_callback)); - content::RunAllTasksUntilIdle(); - - EXPECT_EQ(FILE_ERROR_OK, error); - ASSERT_TRUE(base::PathExists(file_path)); - int64_t local_file_size; - ASSERT_TRUE(base::GetFileSize(file_path, &local_file_size)); - EXPECT_EQ(file_size, local_file_size); - - ASSERT_FALSE(close_callback.is_null()); - close_callback.Run(); - EXPECT_EQ(1U, delegate()->updated_local_ids().count(src_entry.local_id())); -} - -TEST_F(OpenFileOperationTest, OpenNonExistingFile) { - const base::FilePath file_in_root( - FILE_PATH_LITERAL("drive/root/not-exist.txt")); - - FileError error = FILE_ERROR_FAILED; - base::FilePath file_path; - base::Closure close_callback; - operation_->OpenFile( - file_in_root, - OPEN_FILE, - std::string(), // mime_type - google_apis::test_util::CreateCopyResultCallback( - &error, &file_path, &close_callback)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_NOT_FOUND, error); - EXPECT_TRUE(close_callback.is_null()); -} - -TEST_F(OpenFileOperationTest, CreateExistingFile) { - const base::FilePath file_in_root( - FILE_PATH_LITERAL("drive/root/File 1.txt")); - ResourceEntry src_entry; - ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry)); - - FileError error = FILE_ERROR_FAILED; - base::FilePath file_path; - base::Closure close_callback; - operation_->OpenFile( - file_in_root, - CREATE_FILE, - std::string(), // mime_type - google_apis::test_util::CreateCopyResultCallback( - &error, &file_path, &close_callback)); - content::RunAllTasksUntilIdle(); - - EXPECT_EQ(FILE_ERROR_EXISTS, error); - EXPECT_TRUE(close_callback.is_null()); -} - -TEST_F(OpenFileOperationTest, CreateNonExistingFile) { - const base::FilePath file_in_root( - FILE_PATH_LITERAL("drive/root/not-exist.txt")); - - FileError error = FILE_ERROR_FAILED; - base::FilePath file_path; - base::Closure close_callback; - operation_->OpenFile( - file_in_root, - CREATE_FILE, - std::string(), // mime_type - google_apis::test_util::CreateCopyResultCallback( - &error, &file_path, &close_callback)); - content::RunAllTasksUntilIdle(); - - EXPECT_EQ(1U, delegate()->get_changed_files().size()); - EXPECT_TRUE(delegate()->get_changed_files().count(file_in_root)); - - EXPECT_EQ(FILE_ERROR_OK, error); - ASSERT_TRUE(base::PathExists(file_path)); - int64_t local_file_size; - ASSERT_TRUE(base::GetFileSize(file_path, &local_file_size)); - EXPECT_EQ(0, local_file_size); // Should be an empty file. - - ASSERT_FALSE(close_callback.is_null()); - close_callback.Run(); - EXPECT_EQ(1U, - delegate()->updated_local_ids().count(GetLocalId(file_in_root))); -} - -TEST_F(OpenFileOperationTest, OpenOrCreateExistingFile) { - const base::FilePath file_in_root( - FILE_PATH_LITERAL("drive/root/File 1.txt")); - ResourceEntry src_entry; - ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry)); - const int64_t file_size = src_entry.file_info().size(); - - FileError error = FILE_ERROR_FAILED; - base::FilePath file_path; - base::Closure close_callback; - operation_->OpenFile( - file_in_root, - OPEN_OR_CREATE_FILE, - std::string(), // mime_type - google_apis::test_util::CreateCopyResultCallback( - &error, &file_path, &close_callback)); - content::RunAllTasksUntilIdle(); - - // Notified because 'available offline' status of the existing file changes. - EXPECT_EQ(1U, delegate()->get_changed_files().size()); - EXPECT_TRUE(delegate()->get_changed_files().count(file_in_root)); - - EXPECT_EQ(FILE_ERROR_OK, error); - ASSERT_TRUE(base::PathExists(file_path)); - int64_t local_file_size; - ASSERT_TRUE(base::GetFileSize(file_path, &local_file_size)); - EXPECT_EQ(file_size, local_file_size); - - ASSERT_FALSE(close_callback.is_null()); - close_callback.Run(); - EXPECT_EQ(1U, delegate()->updated_local_ids().count(src_entry.local_id())); - - ResourceEntry result_entry; - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &result_entry)); - EXPECT_TRUE(result_entry.file_specific_info().cache_state().is_present()); - EXPECT_TRUE(result_entry.file_specific_info().cache_state().is_dirty()); -} - -TEST_F(OpenFileOperationTest, OpenOrCreateNonExistingFile) { - const base::FilePath file_in_root( - FILE_PATH_LITERAL("drive/root/not-exist.txt")); - - FileError error = FILE_ERROR_FAILED; - base::FilePath file_path; - base::Closure close_callback; - operation_->OpenFile( - file_in_root, - OPEN_OR_CREATE_FILE, - std::string(), // mime_type - google_apis::test_util::CreateCopyResultCallback( - &error, &file_path, &close_callback)); - content::RunAllTasksUntilIdle(); - - EXPECT_EQ(FILE_ERROR_OK, error); - ASSERT_TRUE(base::PathExists(file_path)); - int64_t local_file_size; - ASSERT_TRUE(base::GetFileSize(file_path, &local_file_size)); - EXPECT_EQ(0, local_file_size); // Should be an empty file. - - ASSERT_FALSE(close_callback.is_null()); - close_callback.Run(); - EXPECT_EQ(1U, - delegate()->updated_local_ids().count(GetLocalId(file_in_root))); -} - -TEST_F(OpenFileOperationTest, OpenFileTwice) { - const base::FilePath file_in_root( - FILE_PATH_LITERAL("drive/root/File 1.txt")); - ResourceEntry src_entry; - ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry)); - const int64_t file_size = src_entry.file_info().size(); - - FileError error = FILE_ERROR_FAILED; - base::FilePath file_path; - base::Closure close_callback; - operation_->OpenFile( - file_in_root, - OPEN_FILE, - std::string(), // mime_type - google_apis::test_util::CreateCopyResultCallback( - &error, &file_path, &close_callback)); - content::RunAllTasksUntilIdle(); - - EXPECT_EQ(FILE_ERROR_OK, error); - ASSERT_TRUE(base::PathExists(file_path)); - int64_t local_file_size; - ASSERT_TRUE(base::GetFileSize(file_path, &local_file_size)); - EXPECT_EQ(file_size, local_file_size); - - // Open again. - error = FILE_ERROR_FAILED; - base::Closure close_callback2; - operation_->OpenFile( - file_in_root, - OPEN_FILE, - std::string(), // mime_type - google_apis::test_util::CreateCopyResultCallback( - &error, &file_path, &close_callback2)); - content::RunAllTasksUntilIdle(); - - EXPECT_EQ(FILE_ERROR_OK, error); - ASSERT_TRUE(base::PathExists(file_path)); - ASSERT_TRUE(base::GetFileSize(file_path, &local_file_size)); - EXPECT_EQ(file_size, local_file_size); - - ASSERT_FALSE(close_callback.is_null()); - ASSERT_FALSE(close_callback2.is_null()); - - close_callback.Run(); - - // There still remains a client opening the file, so it shouldn't be - // uploaded yet. - EXPECT_TRUE(delegate()->updated_local_ids().empty()); - - close_callback2.Run(); - - // Here, all the clients close the file, so it should be uploaded then. - EXPECT_EQ(1U, delegate()->updated_local_ids().count(src_entry.local_id())); -} - -} // namespace file_system -} // namespace drive
diff --git a/components/drive/file_system/operation_test_base.cc b/components/drive/file_system/operation_test_base.cc deleted file mode 100644 index 23ba905..0000000 --- a/components/drive/file_system/operation_test_base.cc +++ /dev/null
@@ -1,196 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/drive/file_system/operation_test_base.h" - -#include <memory> - -#include "base/bind.h" -#include "base/task/post_task.h" -#include "components/drive/chromeos/about_resource_loader.h" -#include "components/drive/chromeos/about_resource_root_folder_id_loader.h" -#include "components/drive/chromeos/change_list_loader.h" -#include "components/drive/chromeos/fake_free_disk_space_getter.h" -#include "components/drive/chromeos/file_cache.h" -#include "components/drive/chromeos/file_system/operation_delegate.h" -#include "components/drive/chromeos/loader_controller.h" -#include "components/drive/chromeos/resource_metadata.h" -#include "components/drive/chromeos/start_page_token_loader.h" -#include "components/drive/event_logger.h" -#include "components/drive/file_change.h" -#include "components/drive/file_system_core_util.h" -#include "components/drive/job_scheduler.h" -#include "components/drive/service/fake_drive_service.h" -#include "components/drive/service/test_util.h" -#include "components/prefs/testing_pref_service.h" -#include "content/public/test/test_utils.h" -#include "google_apis/drive/test_util.h" -#include "mojo/public/cpp/bindings/pending_remote.h" -#include "services/network/test/test_network_connection_tracker.h" - -namespace drive { -namespace file_system { - -OperationTestBase::LoggingDelegate::LoggingDelegate() = default; - -OperationTestBase::LoggingDelegate::~LoggingDelegate() = default; - -void OperationTestBase::LoggingDelegate::OnFileChangedByOperation( - const FileChange& changed_files) { - changed_files_.Apply(changed_files); -} - -void OperationTestBase::LoggingDelegate::OnEntryUpdatedByOperation( - const ClientContext& /* client_context */, - const std::string& local_id) { - updated_local_ids_.insert(local_id); -} - -void OperationTestBase::LoggingDelegate::OnDriveSyncError( - DriveSyncErrorType type, const std::string& local_id) { - drive_sync_errors_.push_back(type); -} - -bool OperationTestBase::LoggingDelegate::WaitForSyncComplete( - const std::string& local_id, - const FileOperationCallback& callback) { - return wait_for_sync_complete_handler_.is_null() ? - false : wait_for_sync_complete_handler_.Run(local_id, callback); -} - -OperationTestBase::~OperationTestBase() = default; - -void OperationTestBase::SetUp() { - blocking_task_runner_ = - base::CreateSequencedTaskRunner({base::ThreadPool(), base::MayBlock()}); - - pref_service_ = std::make_unique<TestingPrefServiceSimple>(); - test_util::RegisterDrivePrefs(pref_service_->registry()); - - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - - logger_ = std::make_unique<EventLogger>(); - - fake_drive_service_ = std::make_unique<FakeDriveService>(); - ASSERT_TRUE(test_util::SetUpTestEntries(fake_drive_service_.get())); - - network::TestNetworkConnectionTracker::GetInstance()->SetConnectionType( - network::mojom::ConnectionType::CONNECTION_WIFI); - scheduler_ = std::make_unique<JobScheduler>( - pref_service_.get(), logger_.get(), fake_drive_service_.get(), - network::TestNetworkConnectionTracker::GetInstance(), - blocking_task_runner_.get(), mojo::NullRemote()); - - metadata_storage_.reset(new internal::ResourceMetadataStorage( - temp_dir_.GetPath(), blocking_task_runner_.get())); - bool success = false; - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), - FROM_HERE, - base::Bind(&internal::ResourceMetadataStorage::Initialize, - base::Unretained(metadata_storage_.get())), - google_apis::test_util::CreateCopyResultCallback(&success)); - content::RunAllTasksUntilIdle(); - ASSERT_TRUE(success); - - fake_free_disk_space_getter_ = std::make_unique<FakeFreeDiskSpaceGetter>(); - cache_.reset(new internal::FileCache( - metadata_storage_.get(), temp_dir_.GetPath(), blocking_task_runner_.get(), - fake_free_disk_space_getter_.get())); - success = false; - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), - FROM_HERE, - base::Bind(&internal::FileCache::Initialize, - base::Unretained(cache_.get())), - google_apis::test_util::CreateCopyResultCallback(&success)); - content::RunAllTasksUntilIdle(); - ASSERT_TRUE(success); - - metadata_.reset(new internal::ResourceMetadata(metadata_storage_.get(), - cache_.get(), - blocking_task_runner_)); - - FileError error = FILE_ERROR_FAILED; - base::PostTaskAndReplyWithResult( - blocking_task_runner_.get(), - FROM_HERE, - base::Bind(&internal::ResourceMetadata::Initialize, - base::Unretained(metadata_.get())), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - ASSERT_EQ(FILE_ERROR_OK, error); - - // Makes sure the FakeDriveService's content is loaded to the metadata_. - about_resource_loader_ = - std::make_unique<internal::AboutResourceLoader>(scheduler_.get()); - root_folder_id_loader_ = - std::make_unique<internal::AboutResourceRootFolderIdLoader>( - about_resource_loader_.get()); - start_page_token_loader_ = std::make_unique<internal::StartPageTokenLoader>( - drive::util::kTeamDriveIdDefaultCorpus, scheduler_.get()); - loader_controller_ = std::make_unique<internal::LoaderController>(); - change_list_loader_ = std::make_unique<internal::ChangeListLoader>( - logger_.get(), blocking_task_runner_.get(), metadata_.get(), - scheduler_.get(), root_folder_id_loader_.get(), - start_page_token_loader_.get(), loader_controller_.get(), - util::kTeamDriveIdDefaultCorpus, util::GetDriveMyDriveRootPath()); - change_list_loader_->LoadIfNeeded( - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - ASSERT_EQ(FILE_ERROR_OK, error); -} - -FileError OperationTestBase::GetLocalResourceEntry(const base::FilePath& path, - ResourceEntry* entry) { - FileError error = FILE_ERROR_FAILED; - base::PostTaskAndReplyWithResult( - blocking_task_runner(), FROM_HERE, - base::Bind(&internal::ResourceMetadata::GetResourceEntryByPath, - base::Unretained(metadata()), path, entry), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - return error; -} - -FileError OperationTestBase::GetLocalResourceEntryById( - const std::string& local_id, - ResourceEntry* entry) { - FileError error = FILE_ERROR_FAILED; - base::PostTaskAndReplyWithResult( - blocking_task_runner(), FROM_HERE, - base::Bind(&internal::ResourceMetadata::GetResourceEntryById, - base::Unretained(metadata()), local_id, entry), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - return error; -} - -std::string OperationTestBase::GetLocalId(const base::FilePath& path) { - std::string local_id; - FileError error = FILE_ERROR_FAILED; - base::PostTaskAndReplyWithResult( - blocking_task_runner(), FROM_HERE, - base::Bind(&internal::ResourceMetadata::GetIdByPath, - base::Unretained(metadata()), path, &local_id), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error) << path.value(); - return local_id; -} - -FileError OperationTestBase::CheckForUpdates() { - FileError error = FILE_ERROR_FAILED; - change_list_loader_->CheckForUpdates( - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - return error; -} - -OperationTestBase::OperationTestBase( - std::unique_ptr<content::BrowserTaskEnvironment> task_environment) - : task_environment_(std::move(task_environment)) {} - -} // namespace file_system -} // namespace drive
diff --git a/components/drive/file_system/operation_test_base.h b/components/drive/file_system/operation_test_base.h deleted file mode 100644 index 1a6c6676..0000000 --- a/components/drive/file_system/operation_test_base.h +++ /dev/null
@@ -1,180 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_DRIVE_FILE_SYSTEM_OPERATION_TEST_BASE_H_ -#define COMPONENTS_DRIVE_FILE_SYSTEM_OPERATION_TEST_BASE_H_ - -#include <set> - -#include "base/files/scoped_temp_dir.h" -#include "components/drive/chromeos/drive_test_util.h" -#include "components/drive/chromeos/file_system/operation_delegate.h" -#include "components/drive/drive.pb.h" -#include "components/drive/file_change.h" -#include "components/drive/file_errors.h" -#include "content/public/test/browser_task_environment.h" -#include "testing/gtest/include/gtest/gtest.h" - -class TestingPrefServiceSimple; - -namespace base { -class SequencedTaskRunner; -} // namespace base - -namespace drive { -struct ClientContext; -class EventLogger; -class FakeDriveService; -class FakeFreeDiskSpaceGetter; -class JobScheduler; - -namespace internal { -class AboutResourceLoader; -class AboutResourceRootFolderIdLoader; -class ChangeListLoader; -class FileCache; -class LoaderController; -class ResourceMetadata; -class ResourceMetadataStorage; -class StartPageTokenLoader; -} // namespace internal - -namespace file_system { - -// Base fixture class for testing Drive file system operations. It sets up the -// basic set of Drive internal classes (ResourceMetadata, Cache, etc) on top of -// FakeDriveService for testing. -class OperationTestBase : public testing::Test { - protected: - // OperationDelegate that records all the events. - class LoggingDelegate : public OperationDelegate { - public: - typedef base::Callback<bool( - const std::string& local_id, - const FileOperationCallback& callback)> WaitForSyncCompleteHandler; - - LoggingDelegate(); - ~LoggingDelegate(); - - // OperationDelegate overrides. - void OnFileChangedByOperation(const FileChange& changed_files) override; - void OnEntryUpdatedByOperation(const ClientContext& context, - const std::string& local_id) override; - void OnDriveSyncError(DriveSyncErrorType type, - const std::string& local_id) override; - bool WaitForSyncComplete(const std::string& local_id, - const FileOperationCallback& callback) override; - - // Gets the set of changed paths. - const FileChange& get_changed_files() { return changed_files_; } - - // Gets the set of updated local IDs. - const std::set<std::string>& updated_local_ids() const { - return updated_local_ids_; - } - - // Gets the list of drive sync errors. - const std::vector<DriveSyncErrorType>& drive_sync_errors() const { - return drive_sync_errors_; - } - - // Sets the callback used to handle WaitForSyncComplete() method calls. - void set_wait_for_sync_complete_handler( - const WaitForSyncCompleteHandler& wait_for_sync_complete_handler) { - wait_for_sync_complete_handler_ = wait_for_sync_complete_handler; - } - - private: - FileChange changed_files_; - std::set<std::string> updated_local_ids_; - std::vector<DriveSyncErrorType> drive_sync_errors_; - WaitForSyncCompleteHandler wait_for_sync_complete_handler_; - }; - - template <typename... Args> - OperationTestBase(Args... args) - : OperationTestBase( - std::make_unique<content::BrowserTaskEnvironment>(args...)) {} - - ~OperationTestBase() override; - - // testing::Test overrides. - void SetUp() override; - - // Returns the path of the temporary directory for putting test files. - base::FilePath temp_dir() const { return temp_dir_.GetPath(); } - - // Synchronously gets the resource entry corresponding to the path from local - // ResourceMetadta. - FileError GetLocalResourceEntry(const base::FilePath& path, - ResourceEntry* entry); - - // Synchronously gets the resource entry corresponding to the ID from local - // ResourceMetadta. - FileError GetLocalResourceEntryById(const std::string& local_id, - ResourceEntry* entry); - - // Gets the local ID of the entry specified by the path. - std::string GetLocalId(const base::FilePath& path); - - // Synchronously updates |metadata_| by fetching the change feed from the - // |fake_service_|. - FileError CheckForUpdates(); - - // Accessors for the components. - FakeDriveService* fake_service() { - return fake_drive_service_.get(); - } - EventLogger* logger() { return logger_.get(); } - LoggingDelegate* delegate() { return &delegate_; } - JobScheduler* scheduler() { return scheduler_.get(); } - base::SequencedTaskRunner* blocking_task_runner() { - return blocking_task_runner_.get(); - } - FakeFreeDiskSpaceGetter* fake_free_disk_space_getter() { - return fake_free_disk_space_getter_.get(); - } - internal::FileCache* cache() { return cache_.get(); } - internal::ResourceMetadata* metadata() { return metadata_.get(); } - internal::LoaderController* loader_controller() { - return loader_controller_.get(); - } - internal::ChangeListLoader* change_list_loader() { - return change_list_loader_.get(); - } - - private: - // The template constructor has to be in the header but it delegates to this - // constructor to initialize all other members out-of-line. - explicit OperationTestBase( - std::unique_ptr<content::BrowserTaskEnvironment> task_environment); - - std::unique_ptr<content::BrowserTaskEnvironment> task_environment_; - scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; - std::unique_ptr<TestingPrefServiceSimple> pref_service_; - base::ScopedTempDir temp_dir_; - - LoggingDelegate delegate_; - std::unique_ptr<EventLogger> logger_; - std::unique_ptr<FakeDriveService> fake_drive_service_; - std::unique_ptr<JobScheduler> scheduler_; - std::unique_ptr<internal::ResourceMetadataStorage, - test_util::DestroyHelperForTests> - metadata_storage_; - std::unique_ptr<FakeFreeDiskSpaceGetter> fake_free_disk_space_getter_; - std::unique_ptr<internal::FileCache, test_util::DestroyHelperForTests> cache_; - std::unique_ptr<internal::ResourceMetadata, test_util::DestroyHelperForTests> - metadata_; - std::unique_ptr<internal::AboutResourceLoader> about_resource_loader_; - std::unique_ptr<internal::StartPageTokenLoader> start_page_token_loader_; - std::unique_ptr<internal::LoaderController> loader_controller_; - std::unique_ptr<internal::ChangeListLoader> change_list_loader_; - std::unique_ptr<internal::AboutResourceRootFolderIdLoader> - root_folder_id_loader_; -}; - -} // namespace file_system -} // namespace drive - -#endif // COMPONENTS_DRIVE_FILE_SYSTEM_OPERATION_TEST_BASE_H_
diff --git a/components/drive/file_system/remove_operation_unittest.cc b/components/drive/file_system/remove_operation_unittest.cc deleted file mode 100644 index c0802cb..0000000 --- a/components/drive/file_system/remove_operation_unittest.cc +++ /dev/null
@@ -1,132 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/drive/chromeos/file_system/remove_operation.h" - -#include "components/drive/file_change.h" -#include "components/drive/file_system/operation_test_base.h" -#include "components/drive/file_system_core_util.h" -#include "content/public/test/test_utils.h" -#include "google_apis/drive/test_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace drive { -namespace file_system { - -typedef OperationTestBase RemoveOperationTest; - -TEST_F(RemoveOperationTest, RemoveFile) { - RemoveOperation operation(blocking_task_runner(), delegate(), metadata(), - cache()); - - base::FilePath nonexisting_file( - FILE_PATH_LITERAL("drive/root/Dummy file.txt")); - base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt")); - base::FilePath file_in_subdir( - FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt")); - - // Remove a file in root. - ResourceEntry entry; - FileError error = FILE_ERROR_FAILED; - ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &entry)); - operation.Remove(file_in_root, - false, // is_recursive - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - EXPECT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntry(file_in_root, &entry)); - - const std::string id_file_in_root = entry.local_id(); - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntryById(id_file_in_root, &entry)); - EXPECT_EQ(util::kDriveTrashDirLocalId, entry.parent_local_id()); - - // Remove a file in subdirectory. - error = FILE_ERROR_FAILED; - ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_subdir, &entry)); - const std::string resource_id = entry.resource_id(); - - operation.Remove(file_in_subdir, - false, // is_recursive - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - EXPECT_EQ(FILE_ERROR_NOT_FOUND, - GetLocalResourceEntry(file_in_subdir, &entry)); - - const std::string id_file_in_subdir = entry.local_id(); - EXPECT_EQ(FILE_ERROR_OK, - GetLocalResourceEntryById(id_file_in_subdir, &entry)); - EXPECT_EQ(util::kDriveTrashDirLocalId, entry.parent_local_id()); - - // Try removing non-existing file. - error = FILE_ERROR_FAILED; - ASSERT_EQ(FILE_ERROR_NOT_FOUND, - GetLocalResourceEntry(nonexisting_file, &entry)); - operation.Remove(nonexisting_file, - false, // is_recursive - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_NOT_FOUND, error); - - // Verify delegate notifications. - EXPECT_EQ(2U, delegate()->get_changed_files().size()); - EXPECT_TRUE(delegate()->get_changed_files().count(file_in_root)); - EXPECT_TRUE(delegate()->get_changed_files().count(file_in_subdir)); - - EXPECT_EQ(2U, delegate()->updated_local_ids().size()); - EXPECT_TRUE(delegate()->updated_local_ids().count(id_file_in_root)); - EXPECT_TRUE(delegate()->updated_local_ids().count(id_file_in_subdir)); -} - -TEST_F(RemoveOperationTest, RemoveDirectory) { - RemoveOperation operation(blocking_task_runner(), delegate(), metadata(), - cache()); - - base::FilePath empty_dir(FILE_PATH_LITERAL( - "drive/root/Directory 1/Sub Directory Folder/Sub Sub Directory Folder")); - base::FilePath non_empty_dir(FILE_PATH_LITERAL( - "drive/root/Directory 1")); - base::FilePath file_in_non_empty_dir(FILE_PATH_LITERAL( - "drive/root/Directory 1/SubDirectory File 1.txt")); - - // Empty directory can be removed even with is_recursive = false. - FileError error = FILE_ERROR_FAILED; - ResourceEntry entry; - operation.Remove(empty_dir, - false, // is_recursive - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - EXPECT_EQ(FILE_ERROR_NOT_FOUND, - GetLocalResourceEntry(empty_dir, &entry)); - - // Non-empty directory, cannot. - error = FILE_ERROR_FAILED; - ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(non_empty_dir, &entry)); - operation.Remove(non_empty_dir, - false, // is_recursive - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_NOT_EMPTY, error); - EXPECT_EQ(FILE_ERROR_OK, - GetLocalResourceEntry(non_empty_dir, &entry)); - - // With is_recursive = true, it can be deleted, however. Descendant entries - // are removed together. - error = FILE_ERROR_FAILED; - ASSERT_EQ(FILE_ERROR_OK, - GetLocalResourceEntry(file_in_non_empty_dir, &entry)); - operation.Remove(non_empty_dir, - true, // is_recursive - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - EXPECT_EQ(FILE_ERROR_NOT_FOUND, - GetLocalResourceEntry(non_empty_dir, &entry)); - EXPECT_EQ(FILE_ERROR_NOT_FOUND, - GetLocalResourceEntry(file_in_non_empty_dir, &entry)); -} - -} // namespace file_system -} // namespace drive
diff --git a/components/drive/file_system/search_operation_unittest.cc b/components/drive/file_system/search_operation_unittest.cc deleted file mode 100644 index 28c1bb7..0000000 --- a/components/drive/file_system/search_operation_unittest.cc +++ /dev/null
@@ -1,160 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/drive/chromeos/file_system/search_operation.h" - -#include <stddef.h> - -#include "base/callback_helpers.h" -#include "components/drive/chromeos/loader_controller.h" -#include "components/drive/file_system/operation_test_base.h" -#include "components/drive/service/fake_drive_service.h" -#include "content/public/test/test_utils.h" -#include "google_apis/drive/drive_api_parser.h" -#include "google_apis/drive/test_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace drive { -namespace file_system { - -typedef OperationTestBase SearchOperationTest; - -TEST_F(SearchOperationTest, ContentSearch) { - SearchOperation operation(blocking_task_runner(), scheduler(), metadata(), - loader_controller()); - - std::set<std::string> expected_results; - expected_results.insert( - "drive/root/Directory 1/Sub Directory Folder/Sub Sub Directory Folder"); - expected_results.insert("drive/root/Directory 1/Sub Directory Folder"); - expected_results.insert("drive/root/Directory 1/SubDirectory File 1.txt"); - expected_results.insert("drive/root/Directory 1"); - expected_results.insert("drive/root/Directory 2 excludeDir-test"); - - FileError error = FILE_ERROR_FAILED; - GURL next_link; - std::unique_ptr<std::vector<SearchResultInfo>> results; - - operation.Search("Directory", GURL(), - google_apis::test_util::CreateCopyResultCallback( - &error, &next_link, &results)); - content::RunAllTasksUntilIdle(); - - EXPECT_EQ(FILE_ERROR_OK, error); - EXPECT_TRUE(next_link.is_empty()); - EXPECT_EQ(expected_results.size(), results->size()); - for (size_t i = 0; i < results->size(); i++) { - EXPECT_TRUE(expected_results.count(results->at(i).path.AsUTF8Unsafe())) - << results->at(i).path.AsUTF8Unsafe(); - } -} - -TEST_F(SearchOperationTest, ContentSearchWithNewEntry) { - SearchOperation operation(blocking_task_runner(), scheduler(), metadata(), - loader_controller()); - - // Create a new directory in the drive service. - google_apis::DriveApiErrorCode status = google_apis::DRIVE_OTHER_ERROR; - std::unique_ptr<google_apis::FileResource> server_entry; - fake_service()->AddNewDirectory( - fake_service()->GetRootResourceId(), "New Directory 1!", - AddNewDirectoryOptions(), - google_apis::test_util::CreateCopyResultCallback(&status, &server_entry)); - content::RunAllTasksUntilIdle(); - ASSERT_EQ(google_apis::HTTP_CREATED, status); - - // As the result of the first Search(), only entries in the current file - // system snapshot are expected to be returned in the "right" path. New - // entries like "New Directory 1!" is temporarily added to "drive/other". - std::set<std::string> expected_results; - expected_results.insert("drive/root/Directory 1"); - expected_results.insert("drive/other/New Directory 1!"); - - FileError error = FILE_ERROR_FAILED; - GURL next_link; - std::unique_ptr<std::vector<SearchResultInfo>> results; - - operation.Search("\"Directory 1\"", GURL(), - google_apis::test_util::CreateCopyResultCallback( - &error, &next_link, &results)); - content::RunAllTasksUntilIdle(); - - EXPECT_EQ(FILE_ERROR_OK, error); - EXPECT_TRUE(next_link.is_empty()); - ASSERT_EQ(expected_results.size(), results->size()); - for (size_t i = 0; i < results->size(); i++) { - EXPECT_TRUE(expected_results.count(results->at(i).path.AsUTF8Unsafe())) - << results->at(i).path.AsUTF8Unsafe(); - } - - // Load the change from FakeDriveService. - ASSERT_EQ(FILE_ERROR_OK, CheckForUpdates()); - - // Now the new entry must be reported to be in the right directory. - expected_results.clear(); - expected_results.insert("drive/root/Directory 1"); - expected_results.insert("drive/root/New Directory 1!"); - error = FILE_ERROR_FAILED; - operation.Search("\"Directory 1\"", GURL(), - google_apis::test_util::CreateCopyResultCallback( - &error, &next_link, &results)); - content::RunAllTasksUntilIdle(); - - EXPECT_EQ(FILE_ERROR_OK, error); - EXPECT_TRUE(next_link.is_empty()); - ASSERT_EQ(expected_results.size(), results->size()); - for (size_t i = 0; i < results->size(); i++) { - EXPECT_TRUE(expected_results.count(results->at(i).path.AsUTF8Unsafe())) - << results->at(i).path.AsUTF8Unsafe(); - } -} - -TEST_F(SearchOperationTest, ContentSearchEmptyResult) { - SearchOperation operation(blocking_task_runner(), scheduler(), metadata(), - loader_controller()); - - FileError error = FILE_ERROR_FAILED; - GURL next_link; - std::unique_ptr<std::vector<SearchResultInfo>> results; - - operation.Search("\"no-match query\"", GURL(), - google_apis::test_util::CreateCopyResultCallback( - &error, &next_link, &results)); - content::RunAllTasksUntilIdle(); - - EXPECT_EQ(FILE_ERROR_OK, error); - EXPECT_TRUE(next_link.is_empty()); - EXPECT_EQ(0U, results->size()); -} - -TEST_F(SearchOperationTest, Lock) { - SearchOperation operation(blocking_task_runner(), scheduler(), metadata(), - loader_controller()); - - // Lock. - std::unique_ptr<base::ScopedClosureRunner> lock = - loader_controller()->GetLock(); - - // Search does not return the result as long as lock is alive. - FileError error = FILE_ERROR_FAILED; - GURL next_link; - std::unique_ptr<std::vector<SearchResultInfo>> results; - - operation.Search("\"Directory 1\"", GURL(), - google_apis::test_util::CreateCopyResultCallback( - &error, &next_link, &results)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_FAILED, error); - EXPECT_FALSE(results); - - // Unlock, this should resume the pending search. - lock.reset(); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - ASSERT_TRUE(results); - EXPECT_EQ(1u, results->size()); -} - -} // namespace file_system -} // namespace drive
diff --git a/components/drive/file_system/set_property_operation_unittest.cc b/components/drive/file_system/set_property_operation_unittest.cc deleted file mode 100644 index d597d58..0000000 --- a/components/drive/file_system/set_property_operation_unittest.cc +++ /dev/null
@@ -1,153 +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 "components/drive/chromeos/file_system/set_property_operation.h" - -#include "base/files/file_path.h" -#include "components/drive/drive.pb.h" -#include "components/drive/file_errors.h" -#include "components/drive/file_system/operation_test_base.h" -#include "content/public/test/test_utils.h" -#include "google_apis/drive/drive_api_requests.h" -#include "google_apis/drive/test_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace drive { -namespace file_system { -namespace { - -const base::FilePath::CharType kTestPath[] = - FILE_PATH_LITERAL("drive/root/File 1.txt"); -const char kTestKey[] = "key"; -const char kTestValue[] = "value"; -const char kTestAnotherValue[] = "another-value"; - -} // namespace - -typedef OperationTestBase SetPropertyOperationTest; - -TEST_F(SetPropertyOperationTest, SetProperty) { - SetPropertyOperation operation(blocking_task_runner(), delegate(), - metadata()); - - const base::FilePath test_path(kTestPath); - FileError result = FILE_ERROR_FAILED; - operation.SetProperty( - test_path, google_apis::drive::Property::Visibility::VISIBILITY_PRIVATE, - kTestKey, kTestValue, - google_apis::test_util::CreateCopyResultCallback(&result)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, result); - - ResourceEntry entry; - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(test_path, &entry)); - EXPECT_EQ(ResourceEntry::DIRTY, entry.metadata_edit_state()); - ASSERT_EQ(1, entry.new_properties().size()); - const drive::Property property = entry.new_properties().Get(0); - EXPECT_EQ(Property_Visibility_PRIVATE, property.visibility()); - EXPECT_EQ(kTestKey, property.key()); - EXPECT_EQ(kTestValue, property.value()); - - EXPECT_EQ(0u, delegate()->get_changed_files().size()); - EXPECT_FALSE(delegate()->get_changed_files().count(test_path)); - - EXPECT_EQ(1u, delegate()->updated_local_ids().size()); - EXPECT_TRUE(delegate()->updated_local_ids().count(entry.local_id())); -} - -TEST_F(SetPropertyOperationTest, SetProperty_Duplicate) { - SetPropertyOperation operation(blocking_task_runner(), delegate(), - metadata()); - - const base::FilePath test_path(kTestPath); - FileError result = FILE_ERROR_FAILED; - operation.SetProperty( - test_path, google_apis::drive::Property::Visibility::VISIBILITY_PRIVATE, - kTestKey, kTestValue, - google_apis::test_util::CreateCopyResultCallback(&result)); - operation.SetProperty( - test_path, google_apis::drive::Property::Visibility::VISIBILITY_PRIVATE, - kTestKey, kTestValue, - google_apis::test_util::CreateCopyResultCallback(&result)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, result); - - ResourceEntry entry; - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(test_path, &entry)); - EXPECT_EQ(1, entry.new_properties().size()); -} - -TEST_F(SetPropertyOperationTest, SetProperty_Overwrite) { - SetPropertyOperation operation(blocking_task_runner(), delegate(), - metadata()); - - const base::FilePath test_path(kTestPath); - FileError result = FILE_ERROR_FAILED; - operation.SetProperty( - test_path, google_apis::drive::Property::Visibility::VISIBILITY_PUBLIC, - kTestKey, kTestValue, - google_apis::test_util::CreateCopyResultCallback(&result)); - operation.SetProperty( - test_path, google_apis::drive::Property::Visibility::VISIBILITY_PUBLIC, - kTestKey, kTestAnotherValue, - google_apis::test_util::CreateCopyResultCallback(&result)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, result); - - ResourceEntry entry; - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(test_path, &entry)); - ASSERT_EQ(1, entry.new_properties().size()); - const drive::Property property = entry.new_properties().Get(0); - EXPECT_EQ(Property_Visibility_PUBLIC, property.visibility()); - EXPECT_EQ(kTestKey, property.key()); - EXPECT_EQ(kTestAnotherValue, property.value()); -} - -TEST_F(SetPropertyOperationTest, SetProperty_DifferentVisibilities) { - SetPropertyOperation operation(blocking_task_runner(), delegate(), - metadata()); - - { - const base::FilePath test_path(kTestPath); - FileError result = FILE_ERROR_FAILED; - operation.SetProperty( - test_path, google_apis::drive::Property::Visibility::VISIBILITY_PRIVATE, - kTestKey, kTestValue, - google_apis::test_util::CreateCopyResultCallback(&result)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, result); - - ResourceEntry entry; - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(test_path, &entry)); - ASSERT_EQ(1, entry.new_properties().size()); - const drive::Property property = entry.new_properties().Get(0); - EXPECT_EQ(Property_Visibility_PRIVATE, property.visibility()); - EXPECT_EQ(kTestKey, property.key()); - EXPECT_EQ(kTestValue, property.value()); - } - - // Insert another property with the same key, same value but different - // visibility. - { - const base::FilePath test_path(kTestPath); - FileError result = FILE_ERROR_FAILED; - operation.SetProperty( - test_path, google_apis::drive::Property::Visibility::VISIBILITY_PUBLIC, - kTestKey, kTestAnotherValue, - google_apis::test_util::CreateCopyResultCallback(&result)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, result); - - ResourceEntry entry; - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(test_path, &entry)); - ASSERT_EQ(2, entry.new_properties().size()); - const drive::Property property = entry.new_properties().Get(1); - EXPECT_EQ(Property_Visibility_PUBLIC, property.visibility()); - EXPECT_EQ(kTestKey, property.key()); - EXPECT_EQ(kTestAnotherValue, property.value()); - } -} - -} // namespace file_system -} // namespace drive
diff --git a/components/drive/file_system/touch_operation_unittest.cc b/components/drive/file_system/touch_operation_unittest.cc deleted file mode 100644 index 3bb5bd83..0000000 --- a/components/drive/file_system/touch_operation_unittest.cc +++ /dev/null
@@ -1,64 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/drive/chromeos/file_system/touch_operation.h" - -#include "base/files/file_path.h" -#include "base/time/time.h" -#include "components/drive/chromeos/resource_metadata.h" -#include "components/drive/drive.pb.h" -#include "components/drive/file_errors.h" -#include "components/drive/file_system/operation_test_base.h" -#include "google_apis/drive/test_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace drive { -namespace file_system { - -typedef OperationTestBase TouchOperationTest; - -TEST_F(TouchOperationTest, TouchFile) { - TouchOperation operation(blocking_task_runner(), - delegate(), - metadata()); - - const base::FilePath kTestPath(FILE_PATH_LITERAL("drive/root/File 1.txt")); - const base::Time::Exploded kLastAccessTime = { - 2012, 7, 0, 19, 15, 59, 13, 123 - }; - const base::Time::Exploded kLastModifiedTime = { - 2013, 7, 0, 19, 15, 59, 13, 123 - }; - - FileError error = FILE_ERROR_FAILED; - base::Time last_access_time_utc; - base::Time last_modified_time_utc; - EXPECT_TRUE( - base::Time::FromUTCExploded(kLastAccessTime, &last_access_time_utc)); - EXPECT_TRUE( - base::Time::FromUTCExploded(kLastModifiedTime, &last_modified_time_utc)); - operation.TouchFile(kTestPath, last_access_time_utc, last_modified_time_utc, - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - ResourceEntry entry; - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kTestPath, &entry)); - EXPECT_EQ(last_access_time_utc, - base::Time::FromInternalValue(entry.file_info().last_accessed())); - EXPECT_EQ(last_modified_time_utc, - base::Time::FromInternalValue(entry.file_info().last_modified())); - EXPECT_EQ(last_modified_time_utc, - base::Time::FromInternalValue(entry.last_modified_by_me())); - EXPECT_EQ(ResourceEntry::DIRTY, entry.metadata_edit_state()); - - EXPECT_EQ(1U, delegate()->get_changed_files().size()); - EXPECT_TRUE(delegate()->get_changed_files().count(kTestPath)); - - EXPECT_EQ(1U, delegate()->updated_local_ids().size()); - EXPECT_TRUE(delegate()->updated_local_ids().count(entry.local_id())); -} - -} // namespace file_system -} // namespace drive
diff --git a/components/drive/file_system/truncate_operation_unittest.cc b/components/drive/file_system/truncate_operation_unittest.cc deleted file mode 100644 index b5a77e3..0000000 --- a/components/drive/file_system/truncate_operation_unittest.cc +++ /dev/null
@@ -1,139 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/drive/chromeos/file_system/truncate_operation.h" - -#include <stdint.h> - -#include <memory> - -#include "base/bind.h" -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/task_runner_util.h" -#include "components/drive/chromeos/fake_free_disk_space_getter.h" -#include "components/drive/drive.pb.h" -#include "components/drive/file_system/operation_test_base.h" -#include "content/public/test/test_utils.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace drive { -namespace file_system { - -class TruncateOperationTest : public OperationTestBase { - protected: - void SetUp() override { - OperationTestBase::SetUp(); - - operation_ = std::make_unique<TruncateOperation>( - blocking_task_runner(), delegate(), scheduler(), metadata(), cache(), - temp_dir()); - } - - std::unique_ptr<TruncateOperation> operation_; -}; - -TEST_F(TruncateOperationTest, Truncate) { - base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt")); - ResourceEntry src_entry; - ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry)); - const int64_t file_size = src_entry.file_info().size(); - - // Make sure the file has at least 2 bytes. - ASSERT_GE(file_size, 2); - - FileError error = FILE_ERROR_FAILED; - operation_->Truncate( - file_in_root, - 1, // Truncate to 1 byte. - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - base::FilePath local_path; - error = FILE_ERROR_FAILED; - base::PostTaskAndReplyWithResult( - blocking_task_runner(), - FROM_HERE, - base::Bind(&internal::FileCache::GetFile, - base::Unretained(cache()), - GetLocalId(file_in_root), &local_path), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - ASSERT_EQ(FILE_ERROR_OK, error); - - // The local file should be truncated. - int64_t local_file_size = 0; - base::GetFileSize(local_path, &local_file_size); - EXPECT_EQ(1, local_file_size); -} - -TEST_F(TruncateOperationTest, NegativeSize) { - base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt")); - ResourceEntry src_entry; - ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry)); - const int64_t file_size = src_entry.file_info().size(); - - // Make sure the file has at least 2 bytes. - ASSERT_GE(file_size, 2); - - FileError error = FILE_ERROR_FAILED; - operation_->Truncate( - file_in_root, - -1, // Truncate to "-1" byte. - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_INVALID_OPERATION, error); -} - -TEST_F(TruncateOperationTest, HostedDocument) { - base::FilePath file_in_root(FILE_PATH_LITERAL( - "drive/root/Document 1 excludeDir-test.gdoc")); - - FileError error = FILE_ERROR_FAILED; - operation_->Truncate( - file_in_root, - 1, // Truncate to 1 byte. - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_INVALID_OPERATION, error); -} - -TEST_F(TruncateOperationTest, Extend) { - base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt")); - ResourceEntry src_entry; - ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry)); - const int64_t file_size = src_entry.file_info().size(); - - FileError error = FILE_ERROR_FAILED; - operation_->Truncate( - file_in_root, - file_size + 10, // Extend to 10 bytes. - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - base::FilePath local_path; - error = FILE_ERROR_FAILED; - base::PostTaskAndReplyWithResult( - blocking_task_runner(), - FROM_HERE, - base::Bind(&internal::FileCache::GetFile, - base::Unretained(cache()), - GetLocalId(file_in_root), &local_path), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - ASSERT_EQ(FILE_ERROR_OK, error); - - // The local file should be truncated. - std::string content; - ASSERT_TRUE(base::ReadFileToString(local_path, &content)); - - EXPECT_EQ(file_size + 10, static_cast<int64_t>(content.size())); - // All trailing 10 bytes should be '\0'. - EXPECT_EQ(std::string(10, '\0'), content.substr(file_size)); -} - -} // namespace file_system -} // namespace drive
diff --git a/components/drive/file_system_unittest.cc b/components/drive/file_system_unittest.cc deleted file mode 100644 index c30be21..0000000 --- a/components/drive/file_system_unittest.cc +++ /dev/null
@@ -1,1549 +0,0 @@ -// Copyright (c) 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. - -#include "components/drive/chromeos/file_system.h" - -#include <stddef.h> -#include <stdint.h> - -#include <memory> -#include <string> -#include <vector> - -#include "base/bind.h" -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/files/scoped_temp_dir.h" -#include "base/macros.h" -#include "base/test/test_mock_time_task_runner.h" -#include "components/drive/chromeos/drive_change_list_loader.h" -#include "components/drive/chromeos/drive_test_util.h" -#include "components/drive/chromeos/fake_free_disk_space_getter.h" -#include "components/drive/chromeos/file_system_observer.h" -#include "components/drive/chromeos/sync_client.h" -#include "components/drive/drive.pb.h" -#include "components/drive/drive_api_util.h" -#include "components/drive/event_logger.h" -#include "components/drive/file_change.h" -#include "components/drive/file_system_core_util.h" -#include "components/drive/job_scheduler.h" -#include "components/drive/service/fake_drive_service.h" -#include "components/drive/service/test_util.h" -#include "components/prefs/testing_pref_service.h" -#include "content/public/test/browser_task_environment.h" -#include "google_apis/drive/drive_api_parser.h" -#include "google_apis/drive/test_util.h" -#include "mojo/public/cpp/bindings/pending_remote.h" -#include "services/network/test/test_network_connection_tracker.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace drive { -namespace { - -// Counts the number of invocation, and if it increased up to |expected_counter| -// quits the current message loop by calling |quit|. -void AsyncInitializationCallback(int* counter, - int expected_counter, - const base::Closure& quit, - FileError error, - std::unique_ptr<ResourceEntry> entry) { - if (error != FILE_ERROR_OK || !entry) { - // If we hit an error case, quit the message loop immediately. - // Then the expectation in the test case can find it because the actual - // value of |counter| is different from the expected one. - quit.Run(); - return; - } - - (*counter)++; - if (*counter >= expected_counter) - quit.Run(); -} - -bool CompareHashAndFilePath(const HashAndFilePath& a, - const HashAndFilePath& b) { - const int result = a.hash.compare(b.hash); - if (result < 0) - return true; - if (result > 0) - return false; - return a.path.AsUTF8Unsafe().compare(b.path.AsUTF8Unsafe()) < 0; -} - -// This class is used to record directory changes and examine them later. -class MockDirectoryChangeObserver : public FileSystemObserver { - public: - MockDirectoryChangeObserver() = default; - ~MockDirectoryChangeObserver() override = default; - - // FileSystemObserver overrides. - void OnDirectoryChanged(const base::FilePath& directory_path) override { - changed_directories_.push_back(directory_path); - } - - void OnFileChanged(const FileChange& new_file_change) override { - changed_files_.Apply(new_file_change); - } - - void OnTeamDrivesUpdated( - const std::set<std::string>& added_team_drive_ids, - const std::set<std::string>& removed_team_drive_ids) override { - added_team_drive_ids_ = added_team_drive_ids; - removed_team_drive_ids_ = removed_team_drive_ids; - } - - const std::vector<base::FilePath>& changed_directories() const { - return changed_directories_; - } - - const FileChange& changed_files() const { return changed_files_; } - - const std::set<std::string>& added_team_drive_ids() const { - return added_team_drive_ids_; - } - - const std::set<std::string>& removed_team_drive_ids() const { - return removed_team_drive_ids_; - } - - private: - std::vector<base::FilePath> changed_directories_; - FileChange changed_files_; - std::set<std::string> added_team_drive_ids_; - std::set<std::string> removed_team_drive_ids_; - - DISALLOW_COPY_AND_ASSIGN(MockDirectoryChangeObserver); -}; - -struct DestroyHelper { - // FileSystemTest needs to be default constructible, so we provide a default - // constructor here. - DestroyHelper() = default; - - explicit DestroyHelper( - scoped_refptr<base::TestMockTimeTaskRunner> task_runner) - : task_runner_(task_runner) {} - - template <typename T> - void operator()(T* object) const { - DCHECK(task_runner_); - if (object) { - object->Destroy(); - task_runner_->RunUntilIdle(); - } - } - - scoped_refptr<base::TestMockTimeTaskRunner> task_runner_; -}; - -} // namespace - -class FileSystemTest : public testing::Test { - protected: - void SetUp() override { - task_runner_ = base::MakeRefCounted<base::TestMockTimeTaskRunner>( - base::TestMockTimeTaskRunner::Type::kBoundToThread); - - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - pref_service_ = std::make_unique<TestingPrefServiceSimple>(); - test_util::RegisterDrivePrefs(pref_service_->registry()); - - logger_ = std::make_unique<EventLogger>(); - fake_drive_service_ = std::make_unique<FakeDriveService>(); - test_util::SetUpTestEntries(fake_drive_service_.get()); - - fake_free_disk_space_getter_ = std::make_unique<FakeFreeDiskSpaceGetter>(); - - network::TestNetworkConnectionTracker::GetInstance()->SetConnectionType( - network::mojom::ConnectionType::CONNECTION_WIFI); - scheduler_ = std::make_unique<JobScheduler>( - pref_service_.get(), logger_.get(), fake_drive_service_.get(), - network::TestNetworkConnectionTracker::GetInstance(), - task_runner_.get(), mojo::NullRemote()); - - mock_directory_observer_ = std::make_unique<MockDirectoryChangeObserver>(); - - SetUpResourceMetadataAndFileSystem(); - } - - void SetUpResourceMetadataAndFileSystem() { - const base::FilePath metadata_dir = temp_dir_.GetPath().AppendASCII("meta"); - ASSERT_TRUE(base::CreateDirectory(metadata_dir)); - metadata_storage_ = - std::unique_ptr<internal::ResourceMetadataStorage, DestroyHelper>( - new internal::ResourceMetadataStorage(metadata_dir, - task_runner_.get()), - DestroyHelper(task_runner_.get())); - ASSERT_TRUE(metadata_storage_->Initialize()); - - const base::FilePath cache_dir = temp_dir_.GetPath().AppendASCII("files"); - ASSERT_TRUE(base::CreateDirectory(cache_dir)); - cache_ = std::unique_ptr<internal::FileCache, DestroyHelper>( - new internal::FileCache(metadata_storage_.get(), cache_dir, - task_runner_.get(), - fake_free_disk_space_getter_.get()), - DestroyHelper(task_runner_.get())); - ASSERT_TRUE(cache_->Initialize()); - - resource_metadata_ = - std::unique_ptr<internal::ResourceMetadata, DestroyHelper>( - new internal::ResourceMetadata(metadata_storage_.get(), - cache_.get(), task_runner_.get()), - DestroyHelper(task_runner_.get())); - ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->Initialize()); - - const base::FilePath temp_file_dir = temp_dir_.GetPath().AppendASCII("tmp"); - ASSERT_TRUE(base::CreateDirectory(temp_file_dir)); - file_system_ = std::make_unique<FileSystem>( - logger_.get(), cache_.get(), scheduler_.get(), resource_metadata_.get(), - task_runner_.get(), temp_file_dir, task_runner_->GetMockClock()); - file_system_->AddObserver(mock_directory_observer_.get()); - - // Disable delaying so that the sync starts immediately. - file_system_->sync_client_for_testing()->set_delay_for_testing( - base::TimeDelta::FromSeconds(0)); - - file_system_->team_drive_operation_queue_for_testing() - ->DisableQueueForTesting(); - } - - // Loads the full resource list via FakeDriveService. - bool LoadFullResourceList() { - FileError error = FILE_ERROR_FAILED; - file_system_->change_list_loader_for_testing()->LoadIfNeeded( - google_apis::test_util::CreateCopyResultCallback(&error)); - task_runner_->RunUntilIdle(); - return error == FILE_ERROR_OK; - } - - // Gets resource entry by path synchronously. - std::unique_ptr<ResourceEntry> GetResourceEntrySync( - const base::FilePath& file_path) { - FileError error = FILE_ERROR_FAILED; - std::unique_ptr<ResourceEntry> entry; - file_system_->GetResourceEntry( - file_path, - google_apis::test_util::CreateCopyResultCallback(&error, &entry)); - task_runner_->RunUntilIdle(); - - return entry; - } - - // Gets directory info by path synchronously. - std::unique_ptr<ResourceEntryVector> ReadDirectorySync( - const base::FilePath& file_path) { - FileError error = FILE_ERROR_FAILED; - std::unique_ptr<ResourceEntryVector> entries(new ResourceEntryVector); - file_system_->ReadDirectory( - file_path, - base::Bind(&AccumulateReadDirectoryResult, entries.get()), - google_apis::test_util::CreateCopyResultCallback(&error)); - task_runner_->RunUntilIdle(); - if (error != FILE_ERROR_OK) - entries.reset(); - return entries; - } - - // Used to implement ReadDirectorySync(). - static void AccumulateReadDirectoryResult( - ResourceEntryVector* out_entries, - std::unique_ptr<ResourceEntryVector> entries) { - ASSERT_TRUE(entries); - out_entries->insert(out_entries->end(), entries->begin(), entries->end()); - } - - // Returns true if an entry exists at |file_path|. - bool EntryExists(const base::FilePath& file_path) { - return GetResourceEntrySync(file_path) != nullptr; - } - - // Flag for specifying the timestamp of the test filesystem cache. - enum SetUpTestFileSystemParam { - USE_OLD_TIMESTAMP, - USE_SERVER_TIMESTAMP, - }; - - // Sets up a filesystem with directories: drive/root, drive/root/Dir1, - // drive/root/Dir1/SubDir2 and files drive/root/File1, drive/root/Dir1/File2, - // drive/root/Dir1/SubDir2/File3. If |use_up_to_date_timestamp| is true, sets - // the start_page_token to that of FakeDriveService, indicating the cache is - // holding the latest file system info. - void SetUpTestFileSystem(SetUpTestFileSystemParam param) { - // Destroy the existing resource metadata to close DB. - resource_metadata_.reset(); - - const base::FilePath metadata_dir = temp_dir_.GetPath().AppendASCII("meta"); - ASSERT_TRUE(base::CreateDirectory(metadata_dir)); - std::unique_ptr<internal::ResourceMetadataStorage, DestroyHelper> - metadata_storage(new internal::ResourceMetadataStorage( - metadata_dir, task_runner_.get()), - DestroyHelper(task_runner_.get())); - - const base::FilePath cache_dir = temp_dir_.GetPath().AppendASCII("files"); - std::unique_ptr<internal::FileCache, DestroyHelper> cache( - new internal::FileCache(metadata_storage.get(), cache_dir, - task_runner_.get(), - fake_free_disk_space_getter_.get()), - DestroyHelper(task_runner_.get())); - - std::unique_ptr<internal::ResourceMetadata, DestroyHelper> - resource_metadata( - new internal::ResourceMetadata(metadata_storage_.get(), cache.get(), - task_runner_.get()), - DestroyHelper(task_runner_.get())); - - ASSERT_EQ(FILE_ERROR_OK, resource_metadata->Initialize()); - - const std::string start_page_token = - param == USE_SERVER_TIMESTAMP - ? fake_drive_service_->start_page_token().start_page_token() - : "2"; - ASSERT_EQ(FILE_ERROR_OK, - resource_metadata->SetStartPageToken(start_page_token)); - - // drive/root - ResourceEntry root; - ASSERT_EQ(FILE_ERROR_OK, resource_metadata->GetResourceEntryByPath( - util::GetDriveMyDriveRootPath(), &root)); - root.set_resource_id(fake_drive_service_->GetRootResourceId()); - ASSERT_EQ(FILE_ERROR_OK, resource_metadata->RefreshEntry(root)); - - std::string local_id; - - // drive/root/File1 - ResourceEntry file1; - file1.set_title("File1"); - file1.set_resource_id("resource_id:File1"); - file1.set_parent_local_id(root.local_id()); - file1.mutable_file_specific_info()->set_md5("md5#1"); - file1.mutable_file_info()->set_is_directory(false); - file1.mutable_file_info()->set_size(1048576); - ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(file1, &local_id)); - - // drive/root/Dir1 - ResourceEntry dir1; - dir1.set_title("Dir1"); - dir1.set_resource_id("resource_id:Dir1"); - dir1.set_parent_local_id(root.local_id()); - dir1.mutable_file_info()->set_is_directory(true); - ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(dir1, &local_id)); - const std::string dir1_local_id = local_id; - - // drive/root/Dir1/File2 - ResourceEntry file2; - file2.set_title("File2"); - file2.set_resource_id("resource_id:File2"); - file2.set_parent_local_id(dir1_local_id); - file2.mutable_file_specific_info()->set_md5("md5#2"); - file2.mutable_file_info()->set_is_directory(false); - file2.mutable_file_info()->set_size(555); - ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(file2, &local_id)); - - // drive/root/Dir1/SubDir2 - ResourceEntry dir2; - dir2.set_title("SubDir2"); - dir2.set_resource_id("resource_id:SubDir2"); - dir2.set_parent_local_id(dir1_local_id); - dir2.mutable_file_info()->set_is_directory(true); - ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(dir2, &local_id)); - const std::string dir2_local_id = local_id; - - // drive/root/Dir1/SubDir2/File3 - ResourceEntry file3; - file3.set_title("File3"); - file3.set_resource_id("resource_id:File3"); - file3.set_parent_local_id(dir2_local_id); - file3.mutable_file_specific_info()->set_md5("md5#2"); - file3.mutable_file_info()->set_is_directory(false); - file3.mutable_file_info()->set_size(12345); - ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(file3, &local_id)); - - // drive/team_drive - ResourceEntry team_drive_root; - ASSERT_EQ(FILE_ERROR_OK, - resource_metadata->GetResourceEntryByPath( - util::GetDriveTeamDrivesRootPath(), &team_drive_root)); - - // drive/team_drive/team_drive_1 - ResourceEntry td_dir; - td_dir.set_title("team_drive_1"); - td_dir.set_resource_id("td_id_1"); - td_dir.set_parent_local_id(team_drive_root.local_id()); - td_dir.mutable_file_info()->set_is_directory(true); - ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(td_dir, &local_id)); - - // Recreate resource metadata. - SetUpResourceMetadataAndFileSystem(); - } - - // Sets up two team drives, team_drive_a and team_drive_b and creates the - // following: - // - Directories: - // -- team_drive_a/dir1 - // -- team_drive_a/dir1/nested_1 - // -- team_drive_b/dir2 - // - // - Files: - // -- team_drive_a/dir1/file1 - // -- team_drive_a/dir1/nested_1/file1 - // -- team_drive_b/dir2/file2 - bool SetupTeamDrives() { - fake_drive_service_->AddTeamDrive("td_id_1", "team_drive_1", ""); - fake_drive_service_->AddTeamDrive("td_id_2", "team_drive_2", ""); - fake_drive_service_->AddTeamDrive("td_id_2_2", "team_drive_2", ""); - - google_apis::DriveApiErrorCode error = google_apis::DRIVE_OTHER_ERROR; - std::unique_ptr<google_apis::FileResource> entry; - - fake_drive_service_->AddNewFileWithResourceId( - "td_1_dir_1_resource_id", util::kDriveFolderMimeType, std::string(), - "td_id_1", "dir1", - false, // shared_with_me - google_apis::test_util::CreateCopyResultCallback(&error, &entry)); - base::RunLoop().RunUntilIdle(); - if (error != google_apis::HTTP_CREATED) - return false; - - fake_drive_service_->AddNewFileWithResourceId( - "td_1_dir_nested_1_resource_id", util::kDriveFolderMimeType, - std::string(), "td_1_dir_1_resource_id", "nested_1", - false, // shared_with_me - google_apis::test_util::CreateCopyResultCallback(&error, &entry)); - base::RunLoop().RunUntilIdle(); - if (error != google_apis::HTTP_CREATED) - return false; - - fake_drive_service_->AddNewFileWithResourceId( - "td_2_dir_2_resource_id", util::kDriveFolderMimeType, std::string(), - "td_id_2", "dir2", - false, // shared_with_me - google_apis::test_util::CreateCopyResultCallback(&error, &entry)); - base::RunLoop().RunUntilIdle(); - if (error != google_apis::HTTP_CREATED) - return false; - - fake_drive_service_->AddNewFileWithResourceId( - "dir1_file_1_resource_id", "audio/mpeg", "dir 1 file 1 content.", - "td_1_dir_1_resource_id", "File 1.txt", - false, // shared_with_me - google_apis::test_util::CreateCopyResultCallback(&error, &entry)); - base::RunLoop().RunUntilIdle(); - if (error != google_apis::HTTP_CREATED) - return false; - - fake_drive_service_->AddNewFileWithResourceId( - "nested_1_file_1_resource_id", "audio/mpeg", "nested 1 file 1 content.", - "td_1_dir_nested_1_resource_id", "Nested File 1.txt", - false, // shared_with_me - google_apis::test_util::CreateCopyResultCallback(&error, &entry)); - base::RunLoop().RunUntilIdle(); - if (error != google_apis::HTTP_CREATED) - return false; - - fake_drive_service_->AddNewFileWithResourceId( - "dir_2_file_1_resource_id", "audio/mpeg", "dir2 file1 content.", - "td_2_dir_2_resource_id", "File 2.txt", - false, // shared_with_me - google_apis::test_util::CreateCopyResultCallback(&error, &entry)); - base::RunLoop().RunUntilIdle(); - if (error != google_apis::HTTP_CREATED) - return false; - - fake_drive_service_->AddNewFileWithResourceId( - "td_2_2_dir_1_resource_id", util::kDriveFolderMimeType, std::string(), - "td_id_2_2", "dir1", - false, // shared_with_me - google_apis::test_util::CreateCopyResultCallback(&error, &entry)); - base::RunLoop().RunUntilIdle(); - if (error != google_apis::HTTP_CREATED) - return false; - - return true; - } - - scoped_refptr<base::TestMockTimeTaskRunner> task_runner_; - base::ScopedTempDir temp_dir_; - // We don't use TestingProfile::GetPrefs() in favor of having less - // dependencies to Profile in general. - std::unique_ptr<TestingPrefServiceSimple> pref_service_; - - std::unique_ptr<EventLogger> logger_; - std::unique_ptr<FakeDriveService> fake_drive_service_; - std::unique_ptr<FakeFreeDiskSpaceGetter> fake_free_disk_space_getter_; - std::unique_ptr<JobScheduler> scheduler_; - std::unique_ptr<MockDirectoryChangeObserver> mock_directory_observer_; - - std::unique_ptr<internal::ResourceMetadataStorage, DestroyHelper> - metadata_storage_; - std::unique_ptr<internal::FileCache, DestroyHelper> cache_; - std::unique_ptr<internal::ResourceMetadata, DestroyHelper> resource_metadata_; - std::unique_ptr<FileSystem> file_system_; -}; - -TEST_F(FileSystemTest, SearchByHashes) { - ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_SERVER_TIMESTAMP)); - - std::set<std::string> hashes; - FileError error; - std::vector<HashAndFilePath> results; - - hashes.insert("md5#1"); - file_system_->SearchByHashes( - hashes, - google_apis::test_util::CreateCopyResultCallback(&error, &results)); - task_runner_->RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - ASSERT_EQ(1u, results.size()); - EXPECT_EQ(FILE_PATH_LITERAL("drive/root/File1"), results[0].path.value()); - - hashes.clear(); - hashes.insert("md5#2"); - file_system_->SearchByHashes( - hashes, - google_apis::test_util::CreateCopyResultCallback(&error, &results)); - task_runner_->RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - ASSERT_EQ(2u, results.size()); - std::sort(results.begin(), results.end(), &CompareHashAndFilePath); - EXPECT_EQ(FILE_PATH_LITERAL("drive/root/Dir1/File2"), - results[0].path.value()); - EXPECT_EQ(FILE_PATH_LITERAL("drive/root/Dir1/SubDir2/File3"), - results[1].path.value()); - - hashes.clear(); - hashes.insert("md5#1"); - hashes.insert("md5#2"); - file_system_->SearchByHashes( - hashes, - google_apis::test_util::CreateCopyResultCallback(&error, &results)); - task_runner_->RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - ASSERT_EQ(3u, results.size()); - std::sort(results.begin(), results.end(), &CompareHashAndFilePath); - EXPECT_EQ(FILE_PATH_LITERAL("drive/root/File1"), results[0].path.value()); - EXPECT_EQ(FILE_PATH_LITERAL("drive/root/Dir1/File2"), - results[1].path.value()); - EXPECT_EQ(FILE_PATH_LITERAL("drive/root/Dir1/SubDir2/File3"), - results[2].path.value()); -} - -TEST_F(FileSystemTest, Copy) { - base::FilePath src_file_path(FILE_PATH_LITERAL("drive/root/File 1.txt")); - base::FilePath dest_file_path(FILE_PATH_LITERAL("drive/root/Copied.txt")); - EXPECT_TRUE(GetResourceEntrySync(src_file_path)); - EXPECT_FALSE(GetResourceEntrySync(dest_file_path)); - - FileError error = FILE_ERROR_FAILED; - file_system_->Copy(src_file_path, - dest_file_path, - false, // preserve_last_modified, - google_apis::test_util::CreateCopyResultCallback(&error)); - task_runner_->RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Entry is added on the server. - std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(dest_file_path); - ASSERT_TRUE(entry); - - google_apis::DriveApiErrorCode status = google_apis::DRIVE_OTHER_ERROR; - std::unique_ptr<google_apis::FileResource> server_entry; - fake_drive_service_->GetFileResource( - entry->resource_id(), - google_apis::test_util::CreateCopyResultCallback(&status, &server_entry)); - task_runner_->RunUntilIdle(); - EXPECT_EQ(google_apis::HTTP_SUCCESS, status); - ASSERT_TRUE(server_entry); - EXPECT_EQ(entry->title(), server_entry->title()); - EXPECT_FALSE(server_entry->IsDirectory()); -} - -TEST_F(FileSystemTest, Move) { - base::FilePath src_file_path(FILE_PATH_LITERAL("drive/root/File 1.txt")); - base::FilePath dest_file_path( - FILE_PATH_LITERAL("drive/root/Directory 1/Moved.txt")); - EXPECT_TRUE(GetResourceEntrySync(src_file_path)); - EXPECT_FALSE(GetResourceEntrySync(dest_file_path)); - std::unique_ptr<ResourceEntry> parent = - GetResourceEntrySync(dest_file_path.DirName()); - ASSERT_TRUE(parent); - - FileError error = FILE_ERROR_FAILED; - file_system_->Move(src_file_path, - dest_file_path, - google_apis::test_util::CreateCopyResultCallback(&error)); - task_runner_->RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Entry is moved on the server. - std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(dest_file_path); - ASSERT_TRUE(entry); - - google_apis::DriveApiErrorCode status = google_apis::DRIVE_OTHER_ERROR; - std::unique_ptr<google_apis::FileResource> server_entry; - fake_drive_service_->GetFileResource( - entry->resource_id(), - google_apis::test_util::CreateCopyResultCallback(&status, &server_entry)); - task_runner_->RunUntilIdle(); - EXPECT_EQ(google_apis::HTTP_SUCCESS, status); - ASSERT_TRUE(server_entry); - EXPECT_EQ(entry->title(), server_entry->title()); - - ASSERT_FALSE(server_entry->parents().empty()); - EXPECT_EQ(parent->resource_id(), server_entry->parents()[0].file_id()); -} - -TEST_F(FileSystemTest, Remove) { - base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt")); - std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(file_path); - ASSERT_TRUE(entry); - - FileError error = FILE_ERROR_FAILED; - file_system_->Remove( - file_path, - false, // is_resursive - google_apis::test_util::CreateCopyResultCallback(&error)); - task_runner_->RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Entry is removed on the server. - google_apis::DriveApiErrorCode status = google_apis::DRIVE_OTHER_ERROR; - std::unique_ptr<google_apis::FileResource> server_entry; - fake_drive_service_->GetFileResource( - entry->resource_id(), - google_apis::test_util::CreateCopyResultCallback(&status, &server_entry)); - task_runner_->RunUntilIdle(); - EXPECT_EQ(google_apis::HTTP_SUCCESS, status); - ASSERT_TRUE(server_entry); - EXPECT_TRUE(server_entry->labels().is_trashed()); -} - -TEST_F(FileSystemTest, CreateDirectory) { - base::FilePath directory_path(FILE_PATH_LITERAL("drive/root/New Directory")); - EXPECT_FALSE(GetResourceEntrySync(directory_path)); - - FileError error = FILE_ERROR_FAILED; - file_system_->CreateDirectory( - directory_path, - true, // is_exclusive - false, // is_recursive - google_apis::test_util::CreateCopyResultCallback(&error)); - task_runner_->RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Directory is created on the server. - std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(directory_path); - ASSERT_TRUE(entry); - - google_apis::DriveApiErrorCode status = google_apis::DRIVE_OTHER_ERROR; - std::unique_ptr<google_apis::FileResource> server_entry; - fake_drive_service_->GetFileResource( - entry->resource_id(), - google_apis::test_util::CreateCopyResultCallback(&status, &server_entry)); - task_runner_->RunUntilIdle(); - EXPECT_EQ(google_apis::HTTP_SUCCESS, status); - ASSERT_TRUE(server_entry); - EXPECT_EQ(entry->title(), server_entry->title()); - EXPECT_TRUE(server_entry->IsDirectory()); -} - -TEST_F(FileSystemTest, CreateFile) { - base::FilePath file_path(FILE_PATH_LITERAL("drive/root/New File.txt")); - EXPECT_FALSE(GetResourceEntrySync(file_path)); - - FileError error = FILE_ERROR_FAILED; - file_system_->CreateFile( - file_path, - true, // is_exclusive - "text/plain", - google_apis::test_util::CreateCopyResultCallback(&error)); - task_runner_->RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // File is created on the server. - std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(file_path); - ASSERT_TRUE(entry); - - google_apis::DriveApiErrorCode status = google_apis::DRIVE_OTHER_ERROR; - std::unique_ptr<google_apis::FileResource> server_entry; - fake_drive_service_->GetFileResource( - entry->resource_id(), - google_apis::test_util::CreateCopyResultCallback(&status, &server_entry)); - task_runner_->RunUntilIdle(); - EXPECT_EQ(google_apis::HTTP_SUCCESS, status); - ASSERT_TRUE(server_entry); - EXPECT_EQ(entry->title(), server_entry->title()); - EXPECT_FALSE(server_entry->IsDirectory()); -} - -TEST_F(FileSystemTest, TouchFile) { - base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt")); - std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(file_path); - ASSERT_TRUE(entry); - - base::Time last_accessed = - base::Time::FromInternalValue(entry->file_info().last_accessed()) + - base::TimeDelta::FromSeconds(1); - base::Time last_modified = - base::Time::FromInternalValue(entry->file_info().last_modified()) + - base::TimeDelta::FromSeconds(1); - - FileError error = FILE_ERROR_FAILED; - file_system_->TouchFile( - file_path, - last_accessed, - last_modified, - google_apis::test_util::CreateCopyResultCallback(&error)); - task_runner_->RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // File is touched on the server. - google_apis::DriveApiErrorCode status = google_apis::DRIVE_OTHER_ERROR; - std::unique_ptr<google_apis::FileResource> server_entry; - fake_drive_service_->GetFileResource( - entry->resource_id(), - google_apis::test_util::CreateCopyResultCallback(&status, &server_entry)); - task_runner_->RunUntilIdle(); - EXPECT_EQ(google_apis::HTTP_SUCCESS, status); - ASSERT_TRUE(server_entry); - EXPECT_EQ(last_accessed, server_entry->last_viewed_by_me_date()); - EXPECT_EQ(last_modified, server_entry->modified_date()); - EXPECT_EQ(last_modified, server_entry->modified_by_me_date()); -} - -TEST_F(FileSystemTest, TruncateFile) { - base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt")); - std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(file_path); - ASSERT_TRUE(entry); - - const int64_t kLength = entry->file_info().size() + 100; - - FileError error = FILE_ERROR_FAILED; - file_system_->TruncateFile( - file_path, - kLength, - google_apis::test_util::CreateCopyResultCallback(&error)); - task_runner_->RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // File is touched on the server. - google_apis::DriveApiErrorCode status = google_apis::DRIVE_OTHER_ERROR; - std::unique_ptr<google_apis::FileResource> server_entry; - fake_drive_service_->GetFileResource( - entry->resource_id(), - google_apis::test_util::CreateCopyResultCallback(&status, &server_entry)); - task_runner_->RunUntilIdle(); - EXPECT_EQ(google_apis::HTTP_SUCCESS, status); - ASSERT_TRUE(server_entry); - EXPECT_EQ(kLength, server_entry->file_size()); -} - -TEST_F(FileSystemTest, DuplicatedAsyncInitialization) { - base::RunLoop loop; - - int counter = 0; - - file_system_->GetResourceEntry( - base::FilePath(FILE_PATH_LITERAL("drive/root")), - base::BindOnce(&AsyncInitializationCallback, &counter, 2, - loop.QuitClosure())); - file_system_->GetResourceEntry( - base::FilePath(FILE_PATH_LITERAL("drive/root")), - base::BindOnce(&AsyncInitializationCallback, &counter, 2, - loop.QuitClosure())); - loop.Run(); // Wait to get our result - EXPECT_EQ(2, counter); - - EXPECT_EQ(1, fake_drive_service_->file_list_load_count()); -} - -TEST_F(FileSystemTest, GetGrandRootEntry) { - const base::FilePath kFilePath(FILE_PATH_LITERAL("drive")); - std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath); - ASSERT_TRUE(entry); - EXPECT_EQ(util::kDriveGrandRootLocalId, entry->local_id()); -} - -TEST_F(FileSystemTest, GetOtherDirEntry) { - const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/other")); - std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath); - ASSERT_TRUE(entry); - EXPECT_EQ(util::kDriveOtherDirLocalId, entry->local_id()); -} - -TEST_F(FileSystemTest, GetMyDriveRoot) { - const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root")); - std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath); - ASSERT_TRUE(entry); - EXPECT_EQ(fake_drive_service_->GetRootResourceId(), entry->resource_id()); - - // After "fast fetch" is done, full resource list is fetched. - EXPECT_EQ(1, fake_drive_service_->file_list_load_count()); -} - -TEST_F(FileSystemTest, GetTeamDriveRoot) { - const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/team_drives")); - std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath); - ASSERT_TRUE(entry); - EXPECT_EQ(util::kDriveTeamDrivesDirLocalId, entry->local_id()); - - // After "fast fetch" is done, full resource list is fetched. - EXPECT_EQ(1, fake_drive_service_->file_list_load_count()); -} - -TEST_F(FileSystemTest, GetExistingFile) { - // Simulate the situation that full feed fetching takes very long time, - // to test the recursive "fast fetch" feature is properly working. - fake_drive_service_->set_never_return_all_file_list(true); - - const base::FilePath kFilePath( - FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt")); - std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath); - ASSERT_TRUE(entry); - EXPECT_EQ("subdirectory_file_1_id", entry->resource_id()); - - EXPECT_EQ(1, fake_drive_service_->about_resource_load_count()); - EXPECT_EQ(2, fake_drive_service_->directory_load_count()); - EXPECT_EQ(1, fake_drive_service_->blocked_file_list_load_count()); -} - -TEST_F(FileSystemTest, GetExistingDocument) { - const base::FilePath kFilePath( - FILE_PATH_LITERAL("drive/root/Document 1 excludeDir-test.gdoc")); - std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath); - ASSERT_TRUE(entry); - EXPECT_EQ("5_document_resource_id", entry->resource_id()); -} - -TEST_F(FileSystemTest, GetNonExistingFile) { - const base::FilePath kFilePath( - FILE_PATH_LITERAL("drive/root/nonexisting.file")); - std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath); - EXPECT_FALSE(entry); -} - -TEST_F(FileSystemTest, GetInSubSubdir) { - const base::FilePath kFilePath( - FILE_PATH_LITERAL("drive/root/Directory 1/Sub Directory Folder/" - "Sub Sub Directory Folder")); - std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath); - ASSERT_TRUE(entry); - ASSERT_EQ("sub_sub_directory_folder_id", entry->resource_id()); -} - -TEST_F(FileSystemTest, GetOrphanFile) { - ASSERT_TRUE(LoadFullResourceList()); - - // Entry without parents are placed under "drive/other". - const base::FilePath kFilePath( - FILE_PATH_LITERAL("drive/other/Orphan File 1.txt")); - std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath); - ASSERT_TRUE(entry); - EXPECT_EQ("1_orphanfile_resource_id", entry->resource_id()); -} - -TEST_F(FileSystemTest, ReadDirectory_Root) { - // ReadDirectory() should kick off the resource list loading. - std::unique_ptr<ResourceEntryVector> entries( - ReadDirectorySync(base::FilePath::FromUTF8Unsafe("drive"))); - // The root directory should be read correctly. - ASSERT_TRUE(entries); - ASSERT_EQ(5U, entries->size()); - - // The found three directories should be /drive/root, /drive/other, - // /drive/trash and /drive/team_drives. - std::set<base::FilePath> found; - for (size_t i = 0; i < entries->size(); ++i) - found.insert(base::FilePath::FromUTF8Unsafe((*entries)[i].title())); - EXPECT_EQ(5U, found.size()); - EXPECT_EQ(1U, found.count(base::FilePath::FromUTF8Unsafe( - util::kDriveMyDriveRootDirName))); - EXPECT_EQ(1U, found.count( - base::FilePath::FromUTF8Unsafe(util::kDriveOtherDirName))); - EXPECT_EQ(1U, found.count( - base::FilePath::FromUTF8Unsafe(util::kDriveTrashDirName))); - EXPECT_EQ(1U, found.count(base::FilePath::FromUTF8Unsafe( - util::kDriveTeamDrivesDirName))); - EXPECT_EQ(1U, found.count(base::FilePath::FromUTF8Unsafe( - util::kDriveComputersDirName))); -} - -TEST_F(FileSystemTest, ReadDirectory_TeamDrivesRoot) { - ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_SERVER_TIMESTAMP)); - ASSERT_TRUE(SetupTeamDrives()); - - // The first load trigger the loading of team drives. - ReadDirectorySync(base::FilePath::FromUTF8Unsafe(".")); - - // After the first load team drive data should be available for reading. - std::unique_ptr<ResourceEntryVector> entries( - ReadDirectorySync(base::FilePath::FromUTF8Unsafe("drive/team_drives"))); - // The root directory should be read correctly. - ASSERT_TRUE(entries); - ASSERT_EQ(3U, entries->size()); - - std::multiset<base::FilePath> found; - for (size_t i = 0; i < entries->size(); ++i) { - found.insert(base::FilePath::FromUTF8Unsafe((*entries)[i].title())); - } - EXPECT_EQ(3U, found.size()); - EXPECT_EQ(1U, found.count(base::FilePath::FromUTF8Unsafe("team_drive_1"))); - EXPECT_EQ(2U, found.count(base::FilePath::FromUTF8Unsafe("team_drive_2"))); - EXPECT_EQ(1, fake_drive_service_->team_drive_list_load_count()); - EXPECT_EQ(3, fake_drive_service_->file_list_load_count()); - - // We should be able to read from drive/team_drives/team_drive_1 - std::unique_ptr<ResourceEntryVector> team_drive_1_entries(ReadDirectorySync( - base::FilePath::FromUTF8Unsafe("drive/team_drives/team_drive_1"))); - - ASSERT_TRUE(team_drive_1_entries); - ASSERT_EQ(1U, team_drive_1_entries->size()); - std::set<base::FilePath> team_drive_1_found; - for (size_t i = 0; i < team_drive_1_entries->size(); ++i) { - team_drive_1_found.insert( - base::FilePath::FromUTF8Unsafe((*team_drive_1_entries)[i].title())); - } - EXPECT_EQ(1U, team_drive_1_found.size()); - EXPECT_EQ(1U, - team_drive_1_found.count(base::FilePath::FromUTF8Unsafe("dir1"))); -} - -TEST_F(FileSystemTest, ReadDirectory_TeamDriveFolder) { - ASSERT_TRUE(SetupTeamDrives()); - - // The first load trigger the loading of team drives. - ReadDirectorySync(base::FilePath::FromUTF8Unsafe(".")); - - // Add a new entry to drive/team_drives/team_drive_1 - // Create a file in the test directory. - std::unique_ptr<google_apis::FileResource> entry; - { - google_apis::DriveApiErrorCode error = google_apis::DRIVE_OTHER_ERROR; - fake_drive_service_->AddNewFile( - "text/plain", "(dummy data)", "td_id_1", "TestFile", - false, // shared_with_me - google_apis::test_util::CreateCopyResultCallback(&error, &entry)); - base::RunLoop().RunUntilIdle(); - ASSERT_EQ(google_apis::HTTP_CREATED, error); - } - - // Notify the update to the file system. - file_system_->CheckForUpdates(); - base::RunLoop().RunUntilIdle(); - - std::unique_ptr<ResourceEntryVector> entries(ReadDirectorySync( - base::FilePath::FromUTF8Unsafe("drive/team_drives/team_drive_1"))); - // The root directory should be read correctly. - ASSERT_TRUE(entries); - - std::set<base::FilePath> found; - for (size_t i = 0; i < entries->size(); ++i) { - found.insert(base::FilePath::FromUTF8Unsafe((*entries)[i].title())); - } - EXPECT_EQ(2U, found.size()); - EXPECT_EQ(1U, found.count(base::FilePath::FromUTF8Unsafe("dir1"))); - EXPECT_EQ(1U, found.count(base::FilePath::FromUTF8Unsafe("TestFile"))); -} - -TEST_F(FileSystemTest, AddTeamDriveInChangeList) { - ASSERT_TRUE(SetupTeamDrives()); - - // The first load trigger the loading of team drives. - ReadDirectorySync(base::FilePath::FromUTF8Unsafe(".")); - - // Add a new team drive to the fake file system. - { - fake_drive_service_->AddTeamDrive("td_id_3", "team_drive_3"); - base::RunLoop().RunUntilIdle(); - } - - // Notify the update to the file system, which will add the team drive - file_system_->CheckForUpdates(); - base::RunLoop().RunUntilIdle(); - - std::unique_ptr<ResourceEntryVector> entries( - ReadDirectorySync(base::FilePath::FromUTF8Unsafe("drive/team_drives/"))); - // The root directory should be read correctly. - ASSERT_TRUE(entries); - std::multiset<base::FilePath> found; - for (size_t i = 0; i < entries->size(); ++i) { - found.insert(base::FilePath::FromUTF8Unsafe((*entries)[i].title())); - } - EXPECT_EQ(4U, found.size()); - EXPECT_EQ(1U, found.count(base::FilePath::FromUTF8Unsafe("team_drive_3"))); - - // Add a new entry to drive/team_drives/team_drive_3 - // Create a file in the test directory. - std::unique_ptr<google_apis::FileResource> entry; - { - google_apis::DriveApiErrorCode error = google_apis::DRIVE_OTHER_ERROR; - fake_drive_service_->AddNewFile( - "text/plain", "(dummy data)", "td_id_3", "TestFile", - false, // shared_with_me - google_apis::test_util::CreateCopyResultCallback(&error, &entry)); - base::RunLoop().RunUntilIdle(); - ASSERT_EQ(google_apis::HTTP_CREATED, error); - } - - // Notify the update to the file system. - file_system_->CheckForUpdates(); - base::RunLoop().RunUntilIdle(); - - entries = ReadDirectorySync( - base::FilePath::FromUTF8Unsafe("drive/team_drives/team_drive_3")); - // The root directory should be read correctly. - ASSERT_TRUE(entries); - - found.clear(); - for (size_t i = 0; i < entries->size(); ++i) { - found.insert(base::FilePath::FromUTF8Unsafe((*entries)[i].title())); - } - EXPECT_EQ(1U, found.size()); - EXPECT_EQ(1U, found.count(base::FilePath::FromUTF8Unsafe("TestFile"))); -} - -TEST_F(FileSystemTest, ReadDirectory_NonRootDirectory) { - // ReadDirectory() should kick off the resource list loading. - std::unique_ptr<ResourceEntryVector> entries(ReadDirectorySync( - base::FilePath::FromUTF8Unsafe("drive/root/Directory 1"))); - // The non root directory should also be read correctly. - // There was a bug (crbug.com/181487), which broke this behavior. - // Make sure this is fixed. - ASSERT_TRUE(entries); - EXPECT_EQ(3U, entries->size()); -} - -TEST_F(FileSystemTest, LoadFileSystemFromUpToDateCache) { - ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_SERVER_TIMESTAMP)); - - // Kicks loading of cached file system and query for server update. - EXPECT_TRUE(ReadDirectorySync(util::GetDriveMyDriveRootPath())); - - // SetUpTestFileSystem and FakeDriveService have the same - // start_page_token (i.e. the local metadata is up to date), so no request for - // new resource list (i.e., call to GetResourceList) should happen. - EXPECT_EQ(0, fake_drive_service_->file_list_load_count()); - - // Since the file system has verified that it holds the latest snapshot, - // it should change its state to "loaded", which admits periodic refresh. - // To test it, call CheckForUpdates and verify it does try to check updates. - const int start_page_toke_load_count_before = - fake_drive_service_->start_page_token_load_count(); - file_system_->CheckForUpdates(); - task_runner_->RunUntilIdle(); - EXPECT_LT(start_page_toke_load_count_before, - fake_drive_service_->start_page_token_load_count()); -} - -TEST_F(FileSystemTest, LoadFileSystemFromCacheWhileOffline) { - ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_OLD_TIMESTAMP)); - - // Make GetResourceList fail for simulating offline situation. This will - // leave the file system "loaded from cache, but not synced with server" - // state. - fake_drive_service_->set_offline(true); - - // Load the root. - EXPECT_TRUE(ReadDirectorySync(util::GetDriveGrandRootPath())); - // Loading of start page token should not happen as it's offline. - EXPECT_EQ(0, fake_drive_service_->start_page_token_load_count()); - - // Load "My Drive". - EXPECT_TRUE(ReadDirectorySync(util::GetDriveMyDriveRootPath())); - EXPECT_EQ(0, fake_drive_service_->start_page_token_load_count()); - - // Tests that cached data can be loaded even if the server is not reachable. - EXPECT_TRUE(EntryExists(base::FilePath( - FILE_PATH_LITERAL("drive/root/File1")))); - EXPECT_TRUE(EntryExists(base::FilePath( - FILE_PATH_LITERAL("drive/root/Dir1")))); - EXPECT_TRUE(EntryExists(base::FilePath( - FILE_PATH_LITERAL("drive/root/Dir1/File2")))); - EXPECT_TRUE(EntryExists(base::FilePath( - FILE_PATH_LITERAL("drive/root/Dir1/SubDir2")))); - EXPECT_TRUE(EntryExists(base::FilePath( - FILE_PATH_LITERAL("drive/root/Dir1/SubDir2/File3")))); - - // Since the file system has at least succeeded to load cached snapshot, - // the file system should be able to start periodic refresh. - // To test it, call CheckForUpdates and verify it does try to check - // updates, which will cause directory changes. - fake_drive_service_->set_offline(false); - - file_system_->CheckForUpdates(); - - task_runner_->RunUntilIdle(); - EXPECT_EQ(1, fake_drive_service_->start_page_token_load_count()); - EXPECT_EQ(1, fake_drive_service_->change_list_load_count()); - - ASSERT_LE(0u, mock_directory_observer_->changed_directories().size()); - ASSERT_LE(1u, mock_directory_observer_->changed_files().size()); -} - -TEST_F(FileSystemTest, ReadDirectoryWhileRefreshing) { - // Use old timestamp so the fast fetch will be performed. - ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_OLD_TIMESTAMP)); - - // The list of resources in "drive/root/Dir1" should be fetched. - EXPECT_TRUE(ReadDirectorySync(base::FilePath( - FILE_PATH_LITERAL("drive/root/Dir1")))); - EXPECT_EQ(1, fake_drive_service_->directory_load_count()); - - ASSERT_LE(1u, mock_directory_observer_->changed_directories().size()); -} - -TEST_F(FileSystemTest, GetResourceEntryNonExistentWhileRefreshing) { - // Use old timestamp so the fast fetch will be performed. - ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_OLD_TIMESTAMP)); - - // If an entry is not found, parent directory's resource list is fetched. - EXPECT_FALSE(GetResourceEntrySync(base::FilePath( - FILE_PATH_LITERAL("drive/root/Dir1/NonExistentFile")))); - EXPECT_EQ(1, fake_drive_service_->directory_load_count()); - - ASSERT_LE(1u, mock_directory_observer_->changed_directories().size()); -} - -TEST_F(FileSystemTest, CreateDirectoryByImplicitLoad) { - // Intentionally *not* calling LoadFullResourceList(), for testing that - // CreateDirectory ensures the resource list is loaded before it runs. - - base::FilePath existing_directory( - FILE_PATH_LITERAL("drive/root/Directory 1")); - FileError error = FILE_ERROR_FAILED; - file_system_->CreateDirectory( - existing_directory, - true, // is_exclusive - false, // is_recursive - google_apis::test_util::CreateCopyResultCallback(&error)); - task_runner_->RunUntilIdle(); - - // It should fail because is_exclusive is set to true. - EXPECT_EQ(FILE_ERROR_EXISTS, error); -} - -TEST_F(FileSystemTest, CreateDirectoryRecursively) { - // Intentionally *not* calling LoadFullResourceList(), for testing that - // CreateDirectory ensures the resource list is loaded before it runs. - - base::FilePath new_directory( - FILE_PATH_LITERAL("drive/root/Directory 1/a/b/c/d")); - FileError error = FILE_ERROR_FAILED; - file_system_->CreateDirectory( - new_directory, - true, // is_exclusive - true, // is_recursive - google_apis::test_util::CreateCopyResultCallback(&error)); - task_runner_->RunUntilIdle(); - - EXPECT_EQ(FILE_ERROR_OK, error); - - std::unique_ptr<ResourceEntry> entry(GetResourceEntrySync(new_directory)); - ASSERT_TRUE(entry); - EXPECT_TRUE(entry->file_info().is_directory()); -} - -TEST_F(FileSystemTest, ReadDirectoryAfterUpdateWhileLoading) { - // Simulate the situation that full feed fetching takes very long time, - // to test the recursive "fast fetch" feature is properly working. - fake_drive_service_->set_never_return_all_file_list(true); - - // On the fake server, create the test directory. - std::unique_ptr<google_apis::FileResource> parent; - { - google_apis::DriveApiErrorCode error = google_apis::DRIVE_OTHER_ERROR; - fake_drive_service_->AddNewDirectory( - fake_drive_service_->GetRootResourceId(), "UpdateWhileLoadingTestDir", - AddNewDirectoryOptions(), - google_apis::test_util::CreateCopyResultCallback(&error, &parent)); - base::RunLoop().RunUntilIdle(); - ASSERT_EQ(google_apis::HTTP_CREATED, error); - } - - // Fetch the directory. Currently it is empty. - std::unique_ptr<ResourceEntryVector> before = - ReadDirectorySync(base::FilePath( - FILE_PATH_LITERAL("drive/root/UpdateWhileLoadingTestDir"))); - ASSERT_TRUE(before); - EXPECT_EQ(0u, before->size()); - - // Create a file in the test directory. - std::unique_ptr<google_apis::FileResource> entry; - { - google_apis::DriveApiErrorCode error = google_apis::DRIVE_OTHER_ERROR; - fake_drive_service_->AddNewFile( - "text/plain", - "(dummy data)", - parent->file_id(), - "TestFile", - false, // shared_with_me - google_apis::test_util::CreateCopyResultCallback(&error, &entry)); - base::RunLoop().RunUntilIdle(); - ASSERT_EQ(google_apis::HTTP_CREATED, error); - } - - // Notify the update to the file system. - file_system_->CheckForUpdates(); - - // Fast forward the clock, so that a new read of the directory is started. - task_runner_->FastForwardBy(base::TimeDelta::FromMinutes(1)); - - // Read the directory once again. Although the full feed fetching is not yet - // finished, the "fast fetch" of the directory works and the refreshed content - // is returned. - std::unique_ptr<ResourceEntryVector> after = ReadDirectorySync(base::FilePath( - FILE_PATH_LITERAL("drive/root/UpdateWhileLoadingTestDir"))); - ASSERT_TRUE(after); - EXPECT_EQ(1u, after->size()); -} - -TEST_F(FileSystemTest, PinAndUnpin) { - ASSERT_TRUE(LoadFullResourceList()); - - base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt")); - - // Get the file info. - std::unique_ptr<ResourceEntry> entry(GetResourceEntrySync(file_path)); - ASSERT_TRUE(entry); - - // Pin the file. - FileError error = FILE_ERROR_FAILED; - file_system_->Pin(file_path, - google_apis::test_util::CreateCopyResultCallback(&error)); - task_runner_->RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - entry = GetResourceEntrySync(file_path); - ASSERT_TRUE(entry); - EXPECT_TRUE(entry->file_specific_info().cache_state().is_pinned()); - EXPECT_TRUE(entry->file_specific_info().cache_state().is_present()); - - // Unpin the file. - error = FILE_ERROR_FAILED; - file_system_->Unpin(file_path, - google_apis::test_util::CreateCopyResultCallback(&error)); - task_runner_->RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - entry = GetResourceEntrySync(file_path); - ASSERT_TRUE(entry); - EXPECT_FALSE(entry->file_specific_info().cache_state().is_pinned()); - - // Pinned file gets synced and it results in entry state changes. - ASSERT_EQ(0u, mock_directory_observer_->changed_directories().size()); - ASSERT_EQ(1u, mock_directory_observer_->changed_files().size()); - EXPECT_EQ(1u, - mock_directory_observer_->changed_files().CountDirectory( - base::FilePath(FILE_PATH_LITERAL("drive/root")))); -} - -TEST_F(FileSystemTest, PinAndUnpin_NotSynced) { - ASSERT_TRUE(LoadFullResourceList()); - - base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt")); - - // Get the file info. - std::unique_ptr<ResourceEntry> entry(GetResourceEntrySync(file_path)); - ASSERT_TRUE(entry); - - // Unpin the file just after pinning. File fetch should be cancelled. - FileError error_pin = FILE_ERROR_FAILED; - file_system_->Pin( - file_path, - google_apis::test_util::CreateCopyResultCallback(&error_pin)); - - FileError error_unpin = FILE_ERROR_FAILED; - file_system_->Unpin( - file_path, - google_apis::test_util::CreateCopyResultCallback(&error_unpin)); - - task_runner_->RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error_pin); - EXPECT_EQ(FILE_ERROR_OK, error_unpin); - - // No cache file available because the sync was cancelled by Unpin(). - entry = GetResourceEntrySync(file_path); - ASSERT_TRUE(entry); - EXPECT_FALSE(entry->file_specific_info().cache_state().is_present()); -} - -TEST_F(FileSystemTest, GetAvailableSpace) { - FileError error = FILE_ERROR_OK; - int64_t bytes_total; - int64_t bytes_used; - file_system_->GetAvailableSpace( - google_apis::test_util::CreateCopyResultCallback( - &error, &bytes_total, &bytes_used)); - task_runner_->RunUntilIdle(); - EXPECT_EQ(6789012345LL, bytes_used); - EXPECT_EQ(9876543210LL, bytes_total); -} - -TEST_F(FileSystemTest, MarkCacheFileAsMountedAndUnmounted) { - ASSERT_TRUE(LoadFullResourceList()); - - base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt")); - - // Make the file cached. - FileError error = FILE_ERROR_FAILED; - base::FilePath file_path; - std::unique_ptr<ResourceEntry> entry; - file_system_->GetFile( - file_in_root, - google_apis::test_util::CreateCopyResultCallback( - &error, &file_path, &entry)); - task_runner_->RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Test for mounting. - error = FILE_ERROR_FAILED; - file_path.clear(); - file_system_->MarkCacheFileAsMounted( - file_in_root, - google_apis::test_util::CreateCopyResultCallback(&error, &file_path)); - task_runner_->RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - error = FILE_ERROR_FAILED; - bool is_marked_as_mounted = false; - file_system_->IsCacheFileMarkedAsMounted( - file_in_root, google_apis::test_util::CreateCopyResultCallback( - &error, &is_marked_as_mounted)); - task_runner_->RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - EXPECT_TRUE(is_marked_as_mounted); - - // Cannot remove a cache entry while it's being mounted. - EXPECT_EQ(FILE_ERROR_IN_USE, cache_->Remove(entry->local_id())); - - // Test for unmounting. - error = FILE_ERROR_FAILED; - file_system_->MarkCacheFileAsUnmounted( - file_path, - google_apis::test_util::CreateCopyResultCallback(&error)); - task_runner_->RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - error = FILE_ERROR_FAILED; - is_marked_as_mounted = true; - file_system_->IsCacheFileMarkedAsMounted( - file_in_root, google_apis::test_util::CreateCopyResultCallback( - &error, &is_marked_as_mounted)); - task_runner_->RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - EXPECT_FALSE(is_marked_as_mounted); - - // Now able to remove the cache entry. - EXPECT_EQ(FILE_ERROR_OK, cache_->Remove(entry->local_id())); -} - -TEST_F(FileSystemTest, FreeDiskSpaceIfNeededFor) { - ASSERT_TRUE(LoadFullResourceList()); - - base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt")); - - // Make the file cached. - FileError error = FILE_ERROR_FAILED; - base::FilePath file_path; - std::unique_ptr<ResourceEntry> entry; - file_system_->GetFile(file_in_root, - google_apis::test_util::CreateCopyResultCallback( - &error, &file_path, &entry)); - task_runner_->RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - ASSERT_TRUE(entry); - EXPECT_TRUE(entry->file_specific_info().cache_state().is_present()); - - bool available; - file_system_->FreeDiskSpaceIfNeededFor( - 512LL << 40, - google_apis::test_util::CreateCopyResultCallback(&available)); - task_runner_->RunUntilIdle(); - ASSERT_FALSE(available); - - entry = GetResourceEntrySync(file_in_root); - ASSERT_TRUE(entry); - EXPECT_FALSE(entry->file_specific_info().cache_state().is_present()); -} - -TEST_F(FileSystemTest, DebugMetadata) { - ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_SERVER_TIMESTAMP)); - ASSERT_TRUE(SetupTeamDrives()); - - // The first load will trigger the loading of team drives. - ReadDirectorySync(base::FilePath::FromUTF8Unsafe(".")); - - base::Time now = base::Time::Now(); - - file_system_->CheckForUpdates(); - base::RunLoop().RunUntilIdle(); - - FileSystemMetadata default_corpus_metadata; - std::map<std::string, FileSystemMetadata> team_drive_metadata; - - file_system_->GetMetadata(google_apis::test_util::CreateCopyResultCallback( - &default_corpus_metadata, &team_drive_metadata)); - base::RunLoop().RunUntilIdle(); - - EXPECT_LE(now, default_corpus_metadata.last_update_check_time); - EXPECT_FALSE(default_corpus_metadata.refreshing); - EXPECT_EQ(FILE_ERROR_OK, default_corpus_metadata.last_update_check_error); - EXPECT_EQ("654340", default_corpus_metadata.start_page_token); - - EXPECT_EQ(3UL, team_drive_metadata.size()); - EXPECT_FALSE(team_drive_metadata["td_id_1"].refreshing); - EXPECT_EQ(util::GetDriveTeamDrivesRootPath().Append("team_drive_1").value(), - team_drive_metadata["td_id_1"].path); - EXPECT_LE(now, team_drive_metadata["td_id_1"].last_update_check_time); - EXPECT_EQ("654345", team_drive_metadata["td_id_1"].start_page_token); - EXPECT_EQ(FILE_ERROR_OK, - team_drive_metadata["td_id_1"].last_update_check_error); - - EXPECT_FALSE(team_drive_metadata["td_id_2"].refreshing); - EXPECT_EQ(util::GetDriveTeamDrivesRootPath().Append("team_drive_2").value(), - team_drive_metadata["td_id_2"].path); - EXPECT_LE(now, team_drive_metadata["td_id_2"].last_update_check_time); - EXPECT_EQ("654346", team_drive_metadata["td_id_2"].start_page_token); - EXPECT_EQ(FILE_ERROR_OK, - team_drive_metadata["td_id_2"].last_update_check_error); - - EXPECT_FALSE(team_drive_metadata["td_id_2_2"].refreshing); - EXPECT_EQ(util::GetDriveTeamDrivesRootPath().Append("team_drive_2").value(), - team_drive_metadata["td_id_2_2"].path); - EXPECT_LE(now, team_drive_metadata["td_id_2_2"].last_update_check_time); - EXPECT_EQ("654347", team_drive_metadata["td_id_2_2"].start_page_token); - EXPECT_EQ(FILE_ERROR_OK, - team_drive_metadata["td_id_2_2"].last_update_check_error); -} - -TEST_F(FileSystemTest, TeamDrivesChangesObserved) { - ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_SERVER_TIMESTAMP)); - ASSERT_TRUE(SetupTeamDrives()); - - // The first load will trigger the loading of team drives. - ReadDirectorySync(base::FilePath::FromUTF8Unsafe(".")); - - // This is the initial set of team drives. - EXPECT_EQ(3UL, mock_directory_observer_->added_team_drive_ids().size()); - EXPECT_TRUE(mock_directory_observer_->removed_team_drive_ids().empty()); - - fake_drive_service_->AddTeamDrive("td_id_3", "team_drive_3"); - // TODO(slangley): Add support for removing a team drive in fake file service. - base::RunLoop().RunUntilIdle(); - - // Notify the update to the file system, which will add the team drive - file_system_->CheckForUpdates(); - base::RunLoop().RunUntilIdle(); - - EXPECT_EQ(1UL, mock_directory_observer_->added_team_drive_ids().size()); - EXPECT_EQ(1UL, - mock_directory_observer_->added_team_drive_ids().count("td_id_3")); - EXPECT_TRUE(mock_directory_observer_->removed_team_drive_ids().empty()); -} - -TEST_F(FileSystemTest, CheckUpdatesWithIds) { - ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_SERVER_TIMESTAMP)); - ASSERT_TRUE(SetupTeamDrives()); - - // The first load will trigger the loading of team drives. - ReadDirectorySync(base::FilePath::FromUTF8Unsafe(".")); - - // Check a non existent team drive id, no other sources should be updated. - file_system_->CheckForUpdates({"non_existant_team_drive_id"}); - base::RunLoop().RunUntilIdle(); - - FileSystemMetadata default_corpus_metadata; - std::map<std::string, FileSystemMetadata> team_drive_metadata; - - file_system_->GetMetadata(google_apis::test_util::CreateCopyResultCallback( - &default_corpus_metadata, &team_drive_metadata)); - base::RunLoop().RunUntilIdle(); - - const base::Time default_time; - EXPECT_EQ(default_time, default_corpus_metadata.last_update_check_time); - EXPECT_EQ(default_time, - team_drive_metadata["td_id_1"].last_update_check_time); - EXPECT_EQ(default_time, - team_drive_metadata["td_id_2"].last_update_check_time); - EXPECT_EQ(default_time, - team_drive_metadata["td_id_2_2"].last_update_check_time); - - base::Time now = base::Time::Now(); - - // Update just the default corpus. - file_system_->CheckForUpdates({""}); - base::RunLoop().RunUntilIdle(); - - file_system_->GetMetadata(google_apis::test_util::CreateCopyResultCallback( - &default_corpus_metadata, &team_drive_metadata)); - base::RunLoop().RunUntilIdle(); - - EXPECT_LE(now, default_corpus_metadata.last_update_check_time); - EXPECT_EQ(default_time, - team_drive_metadata["td_id_1"].last_update_check_time); - EXPECT_EQ(default_time, - team_drive_metadata["td_id_2"].last_update_check_time); - EXPECT_EQ(default_time, - team_drive_metadata["td_id_2_2"].last_update_check_time); - - // Update two team drives. - now = base::Time::Now(); - file_system_->CheckForUpdates({"td_id_1", "td_id_2"}); - base::RunLoop().RunUntilIdle(); - - file_system_->GetMetadata(google_apis::test_util::CreateCopyResultCallback( - &default_corpus_metadata, &team_drive_metadata)); - base::RunLoop().RunUntilIdle(); - - EXPECT_GE(now, default_corpus_metadata.last_update_check_time); - EXPECT_LE(now, team_drive_metadata["td_id_1"].last_update_check_time); - EXPECT_LE(now, team_drive_metadata["td_id_2"].last_update_check_time); - EXPECT_EQ(default_time, - team_drive_metadata["td_id_2_2"].last_update_check_time); - - // Update everything. - now = base::Time::Now(); - file_system_->CheckForUpdates({"", "td_id_1", "td_id_2", "td_id_2_2"}); - base::RunLoop().RunUntilIdle(); - - file_system_->GetMetadata(google_apis::test_util::CreateCopyResultCallback( - &default_corpus_metadata, &team_drive_metadata)); - base::RunLoop().RunUntilIdle(); - - EXPECT_LE(now, default_corpus_metadata.last_update_check_time); - EXPECT_LE(now, team_drive_metadata["td_id_1"].last_update_check_time); - EXPECT_LE(now, team_drive_metadata["td_id_2"].last_update_check_time); - EXPECT_LE(now, team_drive_metadata["td_id_2_2"].last_update_check_time); -} - -TEST_F(FileSystemTest, RemoveNonExistingTeamDrive) { - ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_SERVER_TIMESTAMP)); - ASSERT_TRUE(SetupTeamDrives()); - - // The first load will trigger the loading of team drives. - ReadDirectorySync(base::FilePath::FromUTF8Unsafe(".")); - - // Create a file change with a delete team drive, ensure file_system_ does not - // crash. - const base::FilePath path = - util::GetDriveTeamDrivesRootPath().Append("team_drive_2"); - std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(path); - ASSERT_TRUE(entry); - - drive::FileChange change; - change.Update(path, *entry, FileChange::CHANGE_TYPE_DELETE); - - // First time should be removed. - file_system_->OnTeamDrivesChanged(change); - std::set<std::string> expected_changes = {"td_id_2"}; - EXPECT_EQ(expected_changes, - mock_directory_observer_->removed_team_drive_ids()); - - // Second time should be no changes, and no crash. - file_system_->OnTeamDrivesChanged(change); - expected_changes = {}; - EXPECT_EQ(expected_changes, - mock_directory_observer_->removed_team_drive_ids()); -} - -} // namespace drive
diff --git a/components/drive/start_page_token_loader_unittest.cc b/components/drive/start_page_token_loader_unittest.cc deleted file mode 100644 index 02fab1c..0000000 --- a/components/drive/start_page_token_loader_unittest.cc +++ /dev/null
@@ -1,165 +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 "components/drive/chromeos/start_page_token_loader.h" - -#include <memory> - -#include "base/command_line.h" -#include "base/files/scoped_temp_dir.h" -#include "base/threading/thread_task_runner_handle.h" -#include "components/drive/chromeos/drive_test_util.h" -#include "components/drive/chromeos/file_cache.h" -#include "components/drive/chromeos/resource_metadata.h" -#include "components/drive/event_logger.h" -#include "components/drive/job_scheduler.h" -#include "components/drive/resource_metadata_storage.h" -#include "components/drive/service/fake_drive_service.h" -#include "components/drive/service/test_util.h" -#include "components/prefs/testing_pref_service.h" -#include "content/public/test/browser_task_environment.h" -#include "mojo/public/cpp/bindings/pending_remote.h" -#include "services/network/test/test_network_connection_tracker.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace drive { -namespace internal { - -class StartPageTokenLoaderTest : public testing::Test { - protected: - void SetUp() override { - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - - pref_service_ = std::make_unique<TestingPrefServiceSimple>(); - test_util::RegisterDrivePrefs(pref_service_->registry()); - - logger_ = std::make_unique<EventLogger>(); - - drive_service_ = std::make_unique<FakeDriveService>(); - ASSERT_TRUE(test_util::SetUpTestEntries(drive_service_.get())); - - network::TestNetworkConnectionTracker::GetInstance()->SetConnectionType( - network::mojom::ConnectionType::CONNECTION_WIFI); - scheduler_ = std::make_unique<JobScheduler>( - pref_service_.get(), logger_.get(), drive_service_.get(), - network::TestNetworkConnectionTracker::GetInstance(), - base::ThreadTaskRunnerHandle::Get().get(), mojo::NullRemote()); - metadata_storage_.reset(new ResourceMetadataStorage( - temp_dir_.GetPath(), base::ThreadTaskRunnerHandle::Get().get())); - ASSERT_TRUE(metadata_storage_->Initialize()); - - cache_.reset(new FileCache(metadata_storage_.get(), temp_dir_.GetPath(), - base::ThreadTaskRunnerHandle::Get().get(), - nullptr /* free_disk_space_getter */)); - ASSERT_TRUE(cache_->Initialize()); - - metadata_.reset( - new ResourceMetadata(metadata_storage_.get(), cache_.get(), - base::ThreadTaskRunnerHandle::Get().get())); - ASSERT_EQ(FILE_ERROR_OK, metadata_->Initialize()); - - start_page_token_loader_ = std::make_unique<StartPageTokenLoader>( - empty_team_drive_id_, scheduler_.get()); - } - - // Adds a new file to the root directory of the service. - std::unique_ptr<google_apis::FileResource> AddNewFile( - const std::string& title) { - google_apis::DriveApiErrorCode error = google_apis::DRIVE_FILE_ERROR; - std::unique_ptr<google_apis::FileResource> entry; - drive_service_->AddNewFile( - "text/plain", "content text", drive_service_->GetRootResourceId(), - title, - false, // shared_with_me - google_apis::test_util::CreateCopyResultCallback(&error, &entry)); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(google_apis::HTTP_CREATED, error); - return entry; - } - - // Empty team drive id equates to the users default corpus. - const std::string empty_team_drive_id_; - content::BrowserTaskEnvironment task_environment_; - base::ScopedTempDir temp_dir_; - std::unique_ptr<TestingPrefServiceSimple> pref_service_; - std::unique_ptr<EventLogger> logger_; - std::unique_ptr<FakeDriveService> drive_service_; - std::unique_ptr<JobScheduler> scheduler_; - std::unique_ptr<ResourceMetadataStorage, test_util::DestroyHelperForTests> - metadata_storage_; - std::unique_ptr<FileCache, test_util::DestroyHelperForTests> cache_; - std::unique_ptr<ResourceMetadata, test_util::DestroyHelperForTests> metadata_; - std::unique_ptr<StartPageTokenLoader> start_page_token_loader_; -}; - -TEST_F(StartPageTokenLoaderTest, SingleStartPageTokenLoader) { - google_apis::DriveApiErrorCode error[6] = {}; - std::unique_ptr<google_apis::StartPageToken> start_page_token[6]; - - EXPECT_EQ(0, drive_service_->start_page_token_load_count()); - - ASSERT_FALSE(start_page_token_loader_->cached_start_page_token()); - - start_page_token_loader_->GetStartPageToken( - google_apis::test_util::CreateCopyResultCallback(error + 0, - start_page_token + 0)); - start_page_token_loader_->GetStartPageToken( - google_apis::test_util::CreateCopyResultCallback(error + 1, - start_page_token + 1)); - - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(google_apis::HTTP_SUCCESS, error[0]); - EXPECT_EQ(google_apis::HTTP_SUCCESS, error[1]); - const std::string& first_token = start_page_token[0]->start_page_token(); - EXPECT_EQ(first_token, start_page_token[1]->start_page_token()); - ASSERT_TRUE(start_page_token_loader_->cached_start_page_token()); - ASSERT_EQ( - first_token, - start_page_token_loader_->cached_start_page_token()->start_page_token()); - - // Create a new change, which should change the start page token. - AddNewFile("temp"); - - start_page_token_loader_->UpdateStartPageToken( - google_apis::test_util::CreateCopyResultCallback(error + 2, - start_page_token + 2)); - start_page_token_loader_->GetStartPageToken( - google_apis::test_util::CreateCopyResultCallback(error + 3, - start_page_token + 3)); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(google_apis::HTTP_SUCCESS, error[2]); - EXPECT_EQ(google_apis::HTTP_SUCCESS, error[3]); - const std::string& second_token = start_page_token[2]->start_page_token(); - EXPECT_NE(first_token, second_token); - EXPECT_EQ(second_token, start_page_token[3]->start_page_token()); - ASSERT_EQ( - second_token, - start_page_token_loader_->cached_start_page_token()->start_page_token()); - - // Create a new change, which should change the start page token. - AddNewFile("temp2"); - - start_page_token_loader_->GetStartPageToken( - google_apis::test_util::CreateCopyResultCallback(error + 4, - start_page_token + 4)); - start_page_token_loader_->UpdateStartPageToken( - google_apis::test_util::CreateCopyResultCallback(error + 5, - start_page_token + 5)); - - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(google_apis::HTTP_NO_CONTENT, error[4]); - EXPECT_EQ(google_apis::HTTP_SUCCESS, error[5]); - EXPECT_EQ(second_token, start_page_token[4]->start_page_token()); - const std::string& third_token = start_page_token[5]->start_page_token(); - EXPECT_NE(first_token, third_token); - EXPECT_NE(second_token, third_token); - ASSERT_EQ( - third_token, - start_page_token_loader_->cached_start_page_token()->start_page_token()); - - EXPECT_EQ(3, drive_service_->start_page_token_load_count()); -} - -} // namespace internal -} // namespace drive
diff --git a/components/drive/sync/entry_revert_performer_unittest.cc b/components/drive/sync/entry_revert_performer_unittest.cc deleted file mode 100644 index d94d944..0000000 --- a/components/drive/sync/entry_revert_performer_unittest.cc +++ /dev/null
@@ -1,152 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/drive/chromeos/sync/entry_revert_performer.h" - -#include <memory> - -#include "base/bind.h" -#include "base/task_runner_util.h" -#include "components/drive/chromeos/resource_metadata.h" -#include "components/drive/file_change.h" -#include "components/drive/file_system/operation_test_base.h" -#include "components/drive/file_system_core_util.h" -#include "components/drive/job_scheduler.h" -#include "components/drive/service/fake_drive_service.h" -#include "content/public/test/test_utils.h" -#include "google_apis/drive/test_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace drive { -namespace internal { - -class EntryRevertPerformerTest : public file_system::OperationTestBase { - protected: - void SetUp() override { - OperationTestBase::SetUp(); - performer_ = std::make_unique<EntryRevertPerformer>( - blocking_task_runner(), delegate(), scheduler(), metadata()); - } - - std::unique_ptr<EntryRevertPerformer> performer_; -}; - -TEST_F(EntryRevertPerformerTest, RevertEntry) { - base::FilePath path( - FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt")); - base::FilePath updated_path(FILE_PATH_LITERAL( - "drive/root/Directory 1/UpdatedSubDirectory File 1.txt")); - - ResourceEntry src_entry; - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(path, &src_entry)); - - // Update local entry. - ResourceEntry updated_entry = src_entry; - updated_entry.set_title("Updated" + src_entry.title()); - updated_entry.set_metadata_edit_state(ResourceEntry::DIRTY); - - FileError error = FILE_ERROR_FAILED; - base::PostTaskAndReplyWithResult( - blocking_task_runner(), - FROM_HERE, - base::Bind(&ResourceMetadata::RefreshEntry, - base::Unretained(metadata()), updated_entry), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Revert local change. - error = FILE_ERROR_FAILED; - performer_->RevertEntry( - src_entry.local_id(), - ClientContext(USER_INITIATED), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Verify local change is reverted. - ResourceEntry result_entry; - EXPECT_EQ(FILE_ERROR_OK, - GetLocalResourceEntryById(src_entry.local_id(), &result_entry)); - EXPECT_EQ(src_entry.title(), result_entry.title()); - EXPECT_EQ(ResourceEntry::CLEAN, result_entry.metadata_edit_state()); - - EXPECT_EQ(2U, delegate()->get_changed_files().size()); - EXPECT_TRUE(delegate()->get_changed_files().count(path)); - EXPECT_TRUE(delegate()->get_changed_files().count(updated_path)); -} - -TEST_F(EntryRevertPerformerTest, RevertEntry_NotFoundOnServer) { - ResourceEntry my_drive; - EXPECT_EQ(FILE_ERROR_OK, - GetLocalResourceEntry(util::GetDriveMyDriveRootPath(), &my_drive)); - - // Add a new entry with a nonexistent resource ID. - ResourceEntry entry; - entry.set_title("New File.txt"); - entry.set_resource_id("non-existent-resource-id"); - entry.set_parent_local_id(my_drive.local_id()); - - FileError error = FILE_ERROR_FAILED; - std::string local_id; - base::PostTaskAndReplyWithResult( - blocking_task_runner(), - FROM_HERE, - base::Bind(&ResourceMetadata::AddEntry, - base::Unretained(metadata()), entry, &local_id), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Revert local change. The added entry should be removed. - error = FILE_ERROR_FAILED; - performer_->RevertEntry( - local_id, - ClientContext(USER_INITIATED), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Verify the entry was deleted locally. - EXPECT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntryById(local_id, &entry)); - - EXPECT_EQ(1U, delegate()->get_changed_files().size()); - EXPECT_TRUE(delegate()->get_changed_files().CountDirectory( - util::GetDriveMyDriveRootPath())); -} - -TEST_F(EntryRevertPerformerTest, RevertEntry_TrashedOnServer) { - base::FilePath path( - FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt")); - - ResourceEntry entry; - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(path, &entry)); - - // Trash the entry on the server. - google_apis::DriveApiErrorCode gdata_error = google_apis::DRIVE_OTHER_ERROR; - fake_service()->TrashResource( - entry.resource_id(), - google_apis::test_util::CreateCopyResultCallback(&gdata_error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(google_apis::HTTP_SUCCESS, gdata_error); - - // Revert local change. The entry should be removed. - FileError error = FILE_ERROR_FAILED; - performer_->RevertEntry( - entry.local_id(), - ClientContext(USER_INITIATED), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Verify the entry was deleted locally. - EXPECT_EQ(FILE_ERROR_NOT_FOUND, - GetLocalResourceEntryById(entry.local_id(), &entry)); - - EXPECT_EQ(1U, delegate()->get_changed_files().size()); - EXPECT_TRUE(delegate()->get_changed_files().count(path)); -} - -} // namespace internal -} // namespace drive
diff --git a/components/drive/sync/entry_update_performer_unittest.cc b/components/drive/sync/entry_update_performer_unittest.cc deleted file mode 100644 index c79fc9c..0000000 --- a/components/drive/sync/entry_update_performer_unittest.cc +++ /dev/null
@@ -1,660 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/drive/chromeos/sync/entry_update_performer.h" - -#include <stdint.h> - -#include <memory> - -#include "base/bind.h" -#include "base/callback_helpers.h" -#include "base/files/file_util.h" -#include "base/task_runner_util.h" -#include "components/drive/chromeos/file_cache.h" -#include "components/drive/chromeos/file_system/download_operation.h" -#include "components/drive/chromeos/resource_metadata.h" -#include "components/drive/drive_api_util.h" -#include "components/drive/file_system/operation_test_base.h" -#include "components/drive/job_scheduler.h" -#include "components/drive/service/fake_drive_service.h" -#include "content/public/test/test_utils.h" -#include "google_apis/drive/drive_api_parser.h" -#include "google_apis/drive/test_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace drive { -namespace internal { - -class EntryUpdatePerformerTest : public file_system::OperationTestBase { - protected: - void SetUp() override { - OperationTestBase::SetUp(); - performer_ = std::make_unique<EntryUpdatePerformer>( - blocking_task_runner(), delegate(), scheduler(), metadata(), cache(), - loader_controller()); - } - - // Stores |content| to the cache and mark it as dirty. - FileError StoreAndMarkDirty(const std::string& local_id, - const std::string& content) { - base::FilePath path; - if (!base::CreateTemporaryFileInDir(temp_dir(), &path) || - !google_apis::test_util::WriteStringToFile(path, content)) - return FILE_ERROR_FAILED; - - // Store the file to cache. - FileError error = FILE_ERROR_FAILED; - base::PostTaskAndReplyWithResult( - blocking_task_runner(), - FROM_HERE, - base::Bind(&FileCache::Store, - base::Unretained(cache()), - local_id, std::string(), path, - FileCache::FILE_OPERATION_COPY), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - return error; - } - - std::unique_ptr<EntryUpdatePerformer> performer_; -}; - -TEST_F(EntryUpdatePerformerTest, UpdateEntry) { - base::FilePath src_path( - FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt")); - base::FilePath dest_path( - FILE_PATH_LITERAL("drive/root/Directory 1/Sub Directory Folder")); - - ResourceEntry src_entry, dest_entry; - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &src_entry)); - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(dest_path, &dest_entry)); - - // Update local entry. - base::Time new_last_modified = base::Time::FromInternalValue( - src_entry.file_info().last_modified()) + base::TimeDelta::FromSeconds(1); - base::Time new_last_accessed = base::Time::FromInternalValue( - src_entry.file_info().last_accessed()) + base::TimeDelta::FromSeconds(2); - - src_entry.set_parent_local_id(dest_entry.local_id()); - src_entry.set_title("Moved" + src_entry.title()); - src_entry.mutable_file_info()->set_last_modified( - new_last_modified.ToInternalValue()); - src_entry.mutable_file_info()->set_last_accessed( - new_last_accessed.ToInternalValue()); - src_entry.set_metadata_edit_state(ResourceEntry::DIRTY); - - FileError error = FILE_ERROR_FAILED; - base::PostTaskAndReplyWithResult( - blocking_task_runner(), - FROM_HERE, - base::Bind(&ResourceMetadata::RefreshEntry, - base::Unretained(metadata()), - src_entry), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Perform server side update. - error = FILE_ERROR_FAILED; - performer_->UpdateEntry( - src_entry.local_id(), - ClientContext(USER_INITIATED), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Verify the file is updated on the server. - google_apis::DriveApiErrorCode gdata_error = google_apis::DRIVE_OTHER_ERROR; - std::unique_ptr<google_apis::FileResource> gdata_entry; - fake_service()->GetFileResource( - src_entry.resource_id(), - google_apis::test_util::CreateCopyResultCallback(&gdata_error, - &gdata_entry)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(google_apis::HTTP_SUCCESS, gdata_error); - ASSERT_TRUE(gdata_entry); - - EXPECT_EQ(src_entry.title(), gdata_entry->title()); - EXPECT_EQ(new_last_modified, gdata_entry->modified_date()); - EXPECT_EQ(new_last_accessed, gdata_entry->last_viewed_by_me_date()); - - ASSERT_FALSE(gdata_entry->parents().empty()); - EXPECT_EQ(dest_entry.resource_id(), gdata_entry->parents()[0].file_id()); -} - -TEST_F(EntryUpdatePerformerTest, UpdateEntry_SetProperties) { - base::FilePath entry_path( - FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt")); - - ResourceEntry entry; - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(entry_path, &entry)); - - Property* const first_property = entry.mutable_new_properties()->Add(); - first_property->set_key("hello"); - first_property->set_value("world"); - first_property->set_visibility(Property_Visibility_PUBLIC); - - Property* const second_property = entry.mutable_new_properties()->Add(); - second_property->set_key("this"); - second_property->set_value("will-change"); - second_property->set_visibility(Property_Visibility_PUBLIC); - entry.set_metadata_edit_state(ResourceEntry::DIRTY); - - FileError error = FILE_ERROR_FAILED; - base::PostTaskAndReplyWithResult( - blocking_task_runner(), FROM_HERE, - base::Bind(&ResourceMetadata::RefreshEntry, base::Unretained(metadata()), - entry), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Perform server side update. - error = FILE_ERROR_FAILED; - performer_->UpdateEntry( - entry.local_id(), ClientContext(USER_INITIATED), - google_apis::test_util::CreateCopyResultCallback(&error)); - - // Add a new property during an update. - Property* const property = entry.mutable_new_properties()->Add(); - property->set_key("tokyo"); - property->set_value("kyoto"); - property->set_visibility(Property_Visibility_PUBLIC); - - // Modify an existing property during an update. - second_property->set_value("changed"); - - // Change the resource entry during an update. - base::PostTaskAndReplyWithResult( - blocking_task_runner(), FROM_HERE, - base::Bind(&ResourceMetadata::RefreshEntry, base::Unretained(metadata()), - entry), - google_apis::test_util::CreateCopyResultCallback(&error)); - - // Wait until the update is fully completed. - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // List of synced properties should be removed from the proto. - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(entry_path, &entry)); - ASSERT_EQ(2, entry.new_properties().size()); - EXPECT_EQ("changed", entry.new_properties().Get(0).value()); - EXPECT_EQ("tokyo", entry.new_properties().Get(1).key()); -} - -// Tests updating metadata of a file with a non-dirty cache file. -TEST_F(EntryUpdatePerformerTest, UpdateEntry_WithNonDirtyCache) { - base::FilePath src_path( - FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt")); - - // Download the file content to prepare a non-dirty cache file. - file_system::DownloadOperation download_operation( - blocking_task_runner(), delegate(), scheduler(), metadata(), cache(), - temp_dir()); - FileError error = FILE_ERROR_FAILED; - base::FilePath cache_file_path; - std::unique_ptr<ResourceEntry> src_entry; - download_operation.EnsureFileDownloadedByPath( - src_path, - ClientContext(USER_INITIATED), - GetFileContentInitializedCallback(), - google_apis::GetContentCallback(), - google_apis::test_util::CreateCopyResultCallback( - &error, &cache_file_path, &src_entry)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - ASSERT_TRUE(src_entry); - - // Update the entry locally. - src_entry->set_title("Updated" + src_entry->title()); - src_entry->set_metadata_edit_state(ResourceEntry::DIRTY); - - error = FILE_ERROR_FAILED; - base::PostTaskAndReplyWithResult( - blocking_task_runner(), - FROM_HERE, - base::Bind(&ResourceMetadata::RefreshEntry, - base::Unretained(metadata()), - *src_entry), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Perform server side update. This shouldn't fail. (crbug.com/358590) - error = FILE_ERROR_FAILED; - performer_->UpdateEntry( - src_entry->local_id(), - ClientContext(USER_INITIATED), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Verify the file is updated on the server. - google_apis::DriveApiErrorCode gdata_error = google_apis::DRIVE_OTHER_ERROR; - std::unique_ptr<google_apis::FileResource> gdata_entry; - fake_service()->GetFileResource( - src_entry->resource_id(), - google_apis::test_util::CreateCopyResultCallback(&gdata_error, - &gdata_entry)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(google_apis::HTTP_SUCCESS, gdata_error); - ASSERT_TRUE(gdata_entry); - EXPECT_EQ(src_entry->title(), gdata_entry->title()); -} - -TEST_F(EntryUpdatePerformerTest, UpdateEntry_NotFound) { - const std::string id = "this ID should result in NOT_FOUND"; - FileError error = FILE_ERROR_FAILED; - performer_->UpdateEntry( - id, ClientContext(USER_INITIATED), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_NOT_FOUND, error); -} - -TEST_F(EntryUpdatePerformerTest, UpdateEntry_ContentUpdate) { - const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/File 1.txt")); - const std::string kResourceId("2_file_resource_id"); - - const std::string local_id = GetLocalId(kFilePath); - EXPECT_FALSE(local_id.empty()); - - const std::string kTestFileContent = "I'm being uploaded! Yay!"; - EXPECT_EQ(FILE_ERROR_OK, StoreAndMarkDirty(local_id, kTestFileContent)); - - const std::string original_start_page_token = - fake_service()->start_page_token().start_page_token(); - - // The callback will be called upon completion of UpdateEntry(). - FileError error = FILE_ERROR_FAILED; - performer_->UpdateEntry( - local_id, - ClientContext(USER_INITIATED), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Check that the server has received an update. - EXPECT_NE(original_start_page_token, - fake_service()->start_page_token().start_page_token()); - - // Check that the file size is updated to that of the updated content. - google_apis::DriveApiErrorCode gdata_error = google_apis::DRIVE_OTHER_ERROR; - std::unique_ptr<google_apis::FileResource> server_entry; - fake_service()->GetFileResource( - kResourceId, - google_apis::test_util::CreateCopyResultCallback(&gdata_error, - &server_entry)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(google_apis::HTTP_SUCCESS, gdata_error); - EXPECT_EQ(static_cast<int64_t>(kTestFileContent.size()), - server_entry->file_size()); - - // Make sure that the cache is no longer dirty. - ResourceEntry entry; - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath, &entry)); - EXPECT_FALSE(entry.file_specific_info().cache_state().is_dirty()); -} - -TEST_F(EntryUpdatePerformerTest, UpdateEntry_ContentUpdateMd5Check) { - const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/File 1.txt")); - const std::string kResourceId("2_file_resource_id"); - - const std::string local_id = GetLocalId(kFilePath); - EXPECT_FALSE(local_id.empty()); - - const std::string kTestFileContent = "I'm being uploaded! Yay!"; - EXPECT_EQ(FILE_ERROR_OK, StoreAndMarkDirty(local_id, kTestFileContent)); - - std::string original_start_page_token = - fake_service()->start_page_token().start_page_token(); - - // The callback will be called upon completion of UpdateEntry(). - FileError error = FILE_ERROR_FAILED; - performer_->UpdateEntry( - local_id, - ClientContext(USER_INITIATED), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Check that the server has received an update. - EXPECT_NE(original_start_page_token, - fake_service()->start_page_token().start_page_token()); - - // Check that the file size is updated to that of the updated content. - google_apis::DriveApiErrorCode gdata_error = google_apis::DRIVE_OTHER_ERROR; - std::unique_ptr<google_apis::FileResource> server_entry; - fake_service()->GetFileResource( - kResourceId, - google_apis::test_util::CreateCopyResultCallback(&gdata_error, - &server_entry)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(google_apis::HTTP_SUCCESS, gdata_error); - EXPECT_EQ(static_cast<int64_t>(kTestFileContent.size()), - server_entry->file_size()); - - // Make sure that the cache is no longer dirty. - ResourceEntry entry; - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath, &entry)); - EXPECT_FALSE(entry.file_specific_info().cache_state().is_dirty()); - - // Again mark the cache file dirty. - std::unique_ptr<base::ScopedClosureRunner> file_closer; - error = FILE_ERROR_FAILED; - base::PostTaskAndReplyWithResult( - blocking_task_runner(), - FROM_HERE, - base::Bind(&FileCache::OpenForWrite, - base::Unretained(cache()), - local_id, - &file_closer), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - file_closer.reset(); - - // And call UpdateEntry again. - // In this case, although the file is marked as dirty, but the content - // hasn't been changed. Thus, the actual uploading should be skipped. - original_start_page_token = - fake_service()->start_page_token().start_page_token(); - error = FILE_ERROR_FAILED; - performer_->UpdateEntry( - local_id, - ClientContext(USER_INITIATED), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - EXPECT_EQ(original_start_page_token, - fake_service()->start_page_token().start_page_token()); - - // Make sure that the cache is no longer dirty. - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath, &entry)); - EXPECT_FALSE(entry.file_specific_info().cache_state().is_dirty()); -} - -TEST_F(EntryUpdatePerformerTest, UpdateEntry_OpenedForWrite) { - const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/File 1.txt")); - const std::string kResourceId("2_file_resource_id"); - - const std::string local_id = GetLocalId(kFilePath); - EXPECT_FALSE(local_id.empty()); - - const std::string kTestFileContent = "I'm being uploaded! Yay!"; - EXPECT_EQ(FILE_ERROR_OK, StoreAndMarkDirty(local_id, kTestFileContent)); - - // Emulate a situation where someone is writing to the file. - std::unique_ptr<base::ScopedClosureRunner> file_closer; - FileError error = FILE_ERROR_FAILED; - base::PostTaskAndReplyWithResult( - blocking_task_runner(), - FROM_HERE, - base::Bind(&FileCache::OpenForWrite, - base::Unretained(cache()), - local_id, - &file_closer), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Update. This should not clear the dirty bit. - error = FILE_ERROR_FAILED; - performer_->UpdateEntry( - local_id, - ClientContext(USER_INITIATED), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Make sure that the cache is still dirty. - ResourceEntry entry; - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath, &entry)); - EXPECT_TRUE(entry.file_specific_info().cache_state().is_dirty()); - - // Close the file. - file_closer.reset(); - - // Update. This should clear the dirty bit. - error = FILE_ERROR_FAILED; - performer_->UpdateEntry( - local_id, - ClientContext(USER_INITIATED), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Make sure that the cache is no longer dirty. - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath, &entry)); - EXPECT_FALSE(entry.file_specific_info().cache_state().is_dirty()); -} - -TEST_F(EntryUpdatePerformerTest, UpdateEntry_UploadNewFile) { - // Create a new file locally. - const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/New File.txt")); - - ResourceEntry parent; - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath.DirName(), &parent)); - - ResourceEntry entry; - entry.set_parent_local_id(parent.local_id()); - entry.set_title(kFilePath.BaseName().AsUTF8Unsafe()); - entry.mutable_file_specific_info()->set_content_mime_type("text/plain"); - entry.set_metadata_edit_state(ResourceEntry::DIRTY); - - FileError error = FILE_ERROR_FAILED; - std::string local_id; - base::PostTaskAndReplyWithResult( - blocking_task_runner(), - FROM_HERE, - base::Bind(&internal::ResourceMetadata::AddEntry, - base::Unretained(metadata()), - entry, - &local_id), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Update. This should result in creating a new file on the server. - error = FILE_ERROR_FAILED; - performer_->UpdateEntry( - local_id, - ClientContext(USER_INITIATED), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // The entry got a resource ID. - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath, &entry)); - EXPECT_FALSE(entry.resource_id().empty()); - EXPECT_EQ(ResourceEntry::CLEAN, entry.metadata_edit_state()); - - // Make sure that the cache is no longer dirty. - EXPECT_FALSE(entry.file_specific_info().cache_state().is_dirty()); - - // Make sure that we really created a file. - google_apis::DriveApiErrorCode status = google_apis::DRIVE_OTHER_ERROR; - std::unique_ptr<google_apis::FileResource> server_entry; - fake_service()->GetFileResource( - entry.resource_id(), - google_apis::test_util::CreateCopyResultCallback(&status, &server_entry)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(google_apis::HTTP_SUCCESS, status); - ASSERT_TRUE(server_entry); - EXPECT_FALSE(server_entry->IsDirectory()); -} - -TEST_F(EntryUpdatePerformerTest, UpdateEntry_NewFileOpendForWrite) { - // Create a new file locally. - const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/New File.txt")); - - ResourceEntry parent; - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath.DirName(), &parent)); - - ResourceEntry entry; - entry.set_parent_local_id(parent.local_id()); - entry.set_title(kFilePath.BaseName().AsUTF8Unsafe()); - entry.mutable_file_specific_info()->set_content_mime_type("text/plain"); - entry.set_metadata_edit_state(ResourceEntry::DIRTY); - - FileError error = FILE_ERROR_FAILED; - std::string local_id; - base::PostTaskAndReplyWithResult( - blocking_task_runner(), - FROM_HERE, - base::Bind(&internal::ResourceMetadata::AddEntry, - base::Unretained(metadata()), - entry, - &local_id), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - const std::string kTestFileContent = "This is a new file."; - EXPECT_EQ(FILE_ERROR_OK, StoreAndMarkDirty(local_id, kTestFileContent)); - - // Emulate a situation where someone is writing to the file. - std::unique_ptr<base::ScopedClosureRunner> file_closer; - error = FILE_ERROR_FAILED; - base::PostTaskAndReplyWithResult( - blocking_task_runner(), - FROM_HERE, - base::Bind(&FileCache::OpenForWrite, - base::Unretained(cache()), - local_id, - &file_closer), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Update, but no update is performed because the file is opened. - error = FILE_ERROR_FAILED; - performer_->UpdateEntry( - local_id, - ClientContext(USER_INITIATED), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // The entry hasn't got a resource ID yet. - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath, &entry)); - EXPECT_TRUE(entry.resource_id().empty()); - - // Close the file. - file_closer.reset(); - - // Update. This should result in creating a new file on the server. - error = FILE_ERROR_FAILED; - performer_->UpdateEntry( - local_id, - ClientContext(USER_INITIATED), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // The entry got a resource ID. - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath, &entry)); - EXPECT_FALSE(entry.resource_id().empty()); - EXPECT_EQ(ResourceEntry::CLEAN, entry.metadata_edit_state()); -} - -TEST_F(EntryUpdatePerformerTest, UpdateEntry_CreateDirectory) { - // Create a new directory locally. - const base::FilePath kPath(FILE_PATH_LITERAL("drive/root/New Directory")); - - ResourceEntry parent; - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kPath.DirName(), &parent)); - - ResourceEntry entry; - entry.set_parent_local_id(parent.local_id()); - entry.set_title(kPath.BaseName().AsUTF8Unsafe()); - entry.mutable_file_info()->set_is_directory(true); - entry.set_metadata_edit_state(ResourceEntry::DIRTY); - - FileError error = FILE_ERROR_FAILED; - std::string local_id; - base::PostTaskAndReplyWithResult( - blocking_task_runner(), - FROM_HERE, - base::Bind(&internal::ResourceMetadata::AddEntry, - base::Unretained(metadata()), - entry, - &local_id), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Update. This should result in creating a new directory on the server. - error = FILE_ERROR_FAILED; - performer_->UpdateEntry( - local_id, - ClientContext(USER_INITIATED), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // The entry got a resource ID. - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kPath, &entry)); - EXPECT_FALSE(entry.resource_id().empty()); - EXPECT_EQ(ResourceEntry::CLEAN, entry.metadata_edit_state()); - - // Make sure that we really created a directory. - google_apis::DriveApiErrorCode status = google_apis::DRIVE_OTHER_ERROR; - std::unique_ptr<google_apis::FileResource> server_entry; - fake_service()->GetFileResource( - entry.resource_id(), - google_apis::test_util::CreateCopyResultCallback(&status, &server_entry)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(google_apis::HTTP_SUCCESS, status); - ASSERT_TRUE(server_entry); - EXPECT_TRUE(server_entry->IsDirectory()); -} - -TEST_F(EntryUpdatePerformerTest, UpdateEntry_InsufficientPermission) { - base::FilePath src_path( - FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt")); - - ResourceEntry src_entry; - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &src_entry)); - - // Update local entry. - ResourceEntry updated_entry(src_entry); - updated_entry.set_title("Moved" + src_entry.title()); - updated_entry.set_metadata_edit_state(ResourceEntry::DIRTY); - - FileError error = FILE_ERROR_FAILED; - base::PostTaskAndReplyWithResult( - blocking_task_runner(), - FROM_HERE, - base::Bind(&ResourceMetadata::RefreshEntry, - base::Unretained(metadata()), - updated_entry), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Set user permission to forbid server side update. - EXPECT_EQ(google_apis::HTTP_SUCCESS, fake_service()->SetUserPermission( - src_entry.resource_id(), google_apis::drive::PERMISSION_ROLE_READER)); - - // Try to perform update. - error = FILE_ERROR_FAILED; - performer_->UpdateEntry( - src_entry.local_id(), - ClientContext(USER_INITIATED), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // This should result in reverting the local change. - ResourceEntry result_entry; - EXPECT_EQ(FILE_ERROR_OK, - GetLocalResourceEntryById(src_entry.local_id(), &result_entry)); - EXPECT_EQ(src_entry.title(), result_entry.title()); -} - -} // namespace internal -} // namespace drive
diff --git a/components/drive/sync/remove_performer_unittest.cc b/components/drive/sync/remove_performer_unittest.cc deleted file mode 100644 index 28f99c6d..0000000 --- a/components/drive/sync/remove_performer_unittest.cc +++ /dev/null
@@ -1,200 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/drive/chromeos/sync/remove_performer.h" - -#include "base/bind.h" -#include "base/task_runner_util.h" -#include "components/drive/chromeos/resource_metadata.h" -#include "components/drive/file_system/operation_test_base.h" -#include "components/drive/file_system_core_util.h" -#include "components/drive/job_scheduler.h" -#include "components/drive/service/fake_drive_service.h" -#include "content/public/test/test_utils.h" -#include "google_apis/drive/drive_api_parser.h" -#include "google_apis/drive/test_util.h" - -namespace drive { -namespace internal { - -typedef file_system::OperationTestBase RemovePerformerTest; - -TEST_F(RemovePerformerTest, RemoveFile) { - RemovePerformer performer(blocking_task_runner(), delegate(), scheduler(), - metadata()); - - base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt")); - base::FilePath file_in_subdir( - FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt")); - - // Remove a file in root. - ResourceEntry entry; - FileError error = FILE_ERROR_FAILED; - ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &entry)); - performer.Remove(entry.local_id(), - ClientContext(USER_INITIATED), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Remove a file in subdirectory. - error = FILE_ERROR_FAILED; - ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_subdir, &entry)); - const std::string resource_id = entry.resource_id(); - - performer.Remove(entry.local_id(), - ClientContext(USER_INITIATED), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Verify the file is indeed removed in the server. - google_apis::DriveApiErrorCode gdata_error = google_apis::DRIVE_OTHER_ERROR; - std::unique_ptr<google_apis::FileResource> gdata_entry; - fake_service()->GetFileResource( - resource_id, - google_apis::test_util::CreateCopyResultCallback(&gdata_error, - &gdata_entry)); - content::RunAllTasksUntilIdle(); - ASSERT_EQ(google_apis::HTTP_SUCCESS, gdata_error); - EXPECT_TRUE(gdata_entry->labels().is_trashed()); - - // Try removing non-existing file. - error = FILE_ERROR_FAILED; - performer.Remove("non-existing-id", - ClientContext(USER_INITIATED), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_NOT_FOUND, error); -} - -TEST_F(RemovePerformerTest, RemoveShared) { - RemovePerformer performer(blocking_task_runner(), delegate(), scheduler(), - metadata()); - - const base::FilePath kPathInMyDrive(FILE_PATH_LITERAL( - "drive/root/shared.txt")); - const base::FilePath kPathInOther(FILE_PATH_LITERAL( - "drive/other/shared.txt")); - - // Prepare a shared file to the root folder. - google_apis::DriveApiErrorCode gdata_error = google_apis::DRIVE_OTHER_ERROR; - std::unique_ptr<google_apis::FileResource> gdata_entry; - fake_service()->AddNewFile( - "text/plain", - "dummy content", - fake_service()->GetRootResourceId(), - kPathInMyDrive.BaseName().AsUTF8Unsafe(), - true, // shared_with_me, - google_apis::test_util::CreateCopyResultCallback(&gdata_error, - &gdata_entry)); - content::RunAllTasksUntilIdle(); - ASSERT_EQ(google_apis::HTTP_CREATED, gdata_error); - CheckForUpdates(); - - // Remove it. Locally, the file should be moved to drive/other. - ResourceEntry entry; - ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kPathInMyDrive, &entry)); - FileError error = FILE_ERROR_FAILED; - performer.Remove(entry.local_id(), - ClientContext(USER_INITIATED), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - EXPECT_EQ(FILE_ERROR_NOT_FOUND, - GetLocalResourceEntry(kPathInMyDrive, &entry)); - EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kPathInOther, &entry)); - - // Remotely, the entry should have lost its parent. - gdata_error = google_apis::DRIVE_OTHER_ERROR; - const std::string resource_id = gdata_entry->file_id(); - fake_service()->GetFileResource( - resource_id, - google_apis::test_util::CreateCopyResultCallback(&gdata_error, - &gdata_entry)); - content::RunAllTasksUntilIdle(); - ASSERT_EQ(google_apis::HTTP_SUCCESS, gdata_error); - EXPECT_FALSE(gdata_entry->labels().is_trashed()); // It's not deleted. - EXPECT_TRUE(gdata_entry->parents().empty()); -} - -TEST_F(RemovePerformerTest, RemoveLocallyCreatedFile) { - RemovePerformer performer(blocking_task_runner(), delegate(), scheduler(), - metadata()); - - // Add an entry without resource ID. - ResourceEntry entry; - entry.set_title("New File.txt"); - entry.set_parent_local_id(util::kDriveTrashDirLocalId); - - FileError error = FILE_ERROR_FAILED; - std::string local_id; - base::PostTaskAndReplyWithResult( - blocking_task_runner(), - FROM_HERE, - base::Bind(&ResourceMetadata::AddEntry, - base::Unretained(metadata()), - entry, - &local_id), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Remove the entry. - performer.Remove(local_id, ClientContext(USER_INITIATED), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - EXPECT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntryById(local_id, &entry)); -} - -TEST_F(RemovePerformerTest, Remove_InsufficientPermission) { - RemovePerformer performer(blocking_task_runner(), delegate(), scheduler(), - metadata()); - - base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt")); - - ResourceEntry src_entry; - ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry)); - - // Remove locally. - ResourceEntry updated_entry(src_entry); - updated_entry.set_parent_local_id(util::kDriveTrashDirLocalId); - - FileError error = FILE_ERROR_FAILED; - base::PostTaskAndReplyWithResult( - blocking_task_runner(), - FROM_HERE, - base::Bind(&ResourceMetadata::RefreshEntry, - base::Unretained(metadata()), - updated_entry), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Set user permission to forbid server side update. - EXPECT_EQ(google_apis::HTTP_SUCCESS, fake_service()->SetUserPermission( - src_entry.resource_id(), google_apis::drive::PERMISSION_ROLE_READER)); - - // Try to perform remove. - error = FILE_ERROR_FAILED; - performer.Remove(src_entry.local_id(), - ClientContext(USER_INITIATED), - google_apis::test_util::CreateCopyResultCallback(&error)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // This should result in reverting the local change. - ResourceEntry result_entry; - EXPECT_EQ(FILE_ERROR_OK, - GetLocalResourceEntryById(src_entry.local_id(), &result_entry)); - EXPECT_EQ(src_entry.parent_local_id(), result_entry.parent_local_id()); - - ASSERT_EQ(1U, delegate()->drive_sync_errors().size()); - EXPECT_EQ(file_system::DRIVE_SYNC_ERROR_DELETE_WITHOUT_PERMISSION, - delegate()->drive_sync_errors()[0]); -} - -} // namespace internal -} // namespace drive
diff --git a/components/drive/sync_client_unittest.cc b/components/drive/sync_client_unittest.cc deleted file mode 100644 index 111378bf..0000000 --- a/components/drive/sync_client_unittest.cc +++ /dev/null
@@ -1,530 +0,0 @@ -// Copyright (c) 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. - -#include "components/drive/chromeos/sync_client.h" - -#include <memory> - -#include "base/bind.h" -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/files/scoped_temp_dir.h" -#include "base/run_loop.h" -#include "base/single_thread_task_runner.h" -#include "base/test/test_timeouts.h" -#include "base/threading/thread_task_runner_handle.h" -#include "components/drive/chromeos/about_resource_loader.h" -#include "components/drive/chromeos/about_resource_root_folder_id_loader.h" -#include "components/drive/chromeos/change_list_loader.h" -#include "components/drive/chromeos/drive_test_util.h" -#include "components/drive/chromeos/fake_free_disk_space_getter.h" -#include "components/drive/chromeos/file_cache.h" -#include "components/drive/chromeos/file_system/move_operation.h" -#include "components/drive/chromeos/file_system/operation_delegate.h" -#include "components/drive/chromeos/file_system/remove_operation.h" -#include "components/drive/chromeos/loader_controller.h" -#include "components/drive/chromeos/resource_metadata.h" -#include "components/drive/chromeos/start_page_token_loader.h" -#include "components/drive/drive.pb.h" -#include "components/drive/event_logger.h" -#include "components/drive/file_change.h" -#include "components/drive/file_system_core_util.h" -#include "components/drive/job_scheduler.h" -#include "components/drive/resource_entry_conversion.h" -#include "components/drive/service/fake_drive_service.h" -#include "components/prefs/testing_pref_service.h" -#include "content/public/test/browser_task_environment.h" -#include "google_apis/drive/drive_api_parser.h" -#include "google_apis/drive/test_util.h" -#include "mojo/public/cpp/bindings/pending_remote.h" -#include "services/network/test/test_network_connection_tracker.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace drive { -namespace internal { - -namespace { - -// The content of files initially stored in the cache. -const char kLocalContent[] = "Hello!"; - -// The content of files stored in the service. -const char kRemoteContent[] = "World!"; - -// SyncClientTestDriveService will return DRIVE_CANCELLED when a request is -// made with the specified resource ID. -class SyncClientTestDriveService : public ::drive::FakeDriveService { - public: - SyncClientTestDriveService() : download_file_count_(0) {} - - // FakeDriveService override: - google_apis::CancelCallback DownloadFile( - const base::FilePath& local_cache_path, - const std::string& resource_id, - const google_apis::DownloadActionCallback& download_action_callback, - const google_apis::GetContentCallback& get_content_callback, - const google_apis::ProgressCallback& progress_callback) override { - ++download_file_count_; - if (resource_id == resource_id_to_be_cancelled_) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::BindOnce(download_action_callback, google_apis::DRIVE_CANCELLED, - base::FilePath())); - return google_apis::CancelCallback(); - } - if (resource_id == resource_id_to_be_paused_) { - paused_action_ = base::Bind(download_action_callback, - google_apis::DRIVE_OTHER_ERROR, - base::FilePath()); - return google_apis::CancelCallback(); - } - return FakeDriveService::DownloadFile(local_cache_path, - resource_id, - download_action_callback, - get_content_callback, - progress_callback); - } - - int download_file_count() const { return download_file_count_; } - - void set_resource_id_to_be_cancelled(const std::string& resource_id) { - resource_id_to_be_cancelled_ = resource_id; - } - - void set_resource_id_to_be_paused(const std::string& resource_id) { - resource_id_to_be_paused_ = resource_id; - } - - const base::Closure& paused_action() const { return paused_action_; } - - private: - int download_file_count_; - std::string resource_id_to_be_cancelled_; - std::string resource_id_to_be_paused_; - base::Closure paused_action_; -}; - -} // namespace - -class SyncClientTest : public testing::Test { - public: - void SetUp() override { - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - - pref_service_ = std::make_unique<TestingPrefServiceSimple>(); - test_util::RegisterDrivePrefs(pref_service_->registry()); - - logger_ = std::make_unique<EventLogger>(); - - drive_service_ = std::make_unique<SyncClientTestDriveService>(); - - network::TestNetworkConnectionTracker::GetInstance()->SetConnectionType( - network::mojom::ConnectionType::CONNECTION_WIFI); - scheduler_ = std::make_unique<JobScheduler>( - pref_service_.get(), logger_.get(), drive_service_.get(), - network::TestNetworkConnectionTracker::GetInstance(), - base::ThreadTaskRunnerHandle::Get().get(), mojo::NullRemote()); - - metadata_storage_.reset(new ResourceMetadataStorage( - temp_dir_.GetPath(), base::ThreadTaskRunnerHandle::Get().get())); - ASSERT_TRUE(metadata_storage_->Initialize()); - - cache_.reset(new FileCache(metadata_storage_.get(), temp_dir_.GetPath(), - base::ThreadTaskRunnerHandle::Get().get(), - nullptr /* free_disk_space_getter */)); - ASSERT_TRUE(cache_->Initialize()); - - metadata_.reset(new internal::ResourceMetadata( - metadata_storage_.get(), cache_.get(), - base::ThreadTaskRunnerHandle::Get())); - ASSERT_EQ(FILE_ERROR_OK, metadata_->Initialize()); - - about_resource_loader_ = - std::make_unique<AboutResourceLoader>(scheduler_.get()); - root_folder_id_loader_ = std::make_unique<AboutResourceRootFolderIdLoader>( - about_resource_loader_.get()); - - start_page_token_loader_ = std::make_unique<StartPageTokenLoader>( - drive::util::kTeamDriveIdDefaultCorpus, scheduler_.get()); - loader_controller_ = std::make_unique<LoaderController>(); - change_list_loader_ = std::make_unique<ChangeListLoader>( - logger_.get(), base::ThreadTaskRunnerHandle::Get().get(), - metadata_.get(), scheduler_.get(), root_folder_id_loader_.get(), - start_page_token_loader_.get(), loader_controller_.get(), - util::kTeamDriveIdDefaultCorpus, util::GetDriveMyDriveRootPath()); - ASSERT_NO_FATAL_FAILURE(SetUpTestData()); - - sync_client_ = std::make_unique<SyncClient>( - base::ThreadTaskRunnerHandle::Get().get(), &delegate_, scheduler_.get(), - metadata_.get(), cache_.get(), loader_controller_.get(), - temp_dir_.GetPath()); - - // Disable delaying so that DoSyncLoop() starts immediately. - sync_client_->set_delay_for_testing(base::TimeDelta::FromSeconds(0)); - } - - // Adds a file to the service root and |resource_ids_|. - void AddFileEntry(const std::string& title) { - google_apis::DriveApiErrorCode error = google_apis::DRIVE_FILE_ERROR; - std::unique_ptr<google_apis::FileResource> entry; - drive_service_->AddNewFile( - "text/plain", - kRemoteContent, - drive_service_->GetRootResourceId(), - title, - false, // shared_with_me - google_apis::test_util::CreateCopyResultCallback(&error, &entry)); - base::RunLoop().RunUntilIdle(); - ASSERT_EQ(google_apis::HTTP_CREATED, error); - ASSERT_TRUE(entry); - resource_ids_[title] = entry->file_id(); - } - - // Sets up data for tests. - void SetUpTestData() { - // Prepare a temp file. - base::FilePath temp_file; - EXPECT_TRUE( - base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &temp_file)); - ASSERT_TRUE(google_apis::test_util::WriteStringToFile(temp_file, - kLocalContent)); - - // Add file entries to the service. - ASSERT_NO_FATAL_FAILURE(AddFileEntry("foo")); - ASSERT_NO_FATAL_FAILURE(AddFileEntry("bar")); - ASSERT_NO_FATAL_FAILURE(AddFileEntry("baz")); - ASSERT_NO_FATAL_FAILURE(AddFileEntry("fetched")); - ASSERT_NO_FATAL_FAILURE(AddFileEntry("dirty")); - ASSERT_NO_FATAL_FAILURE(AddFileEntry("removed")); - ASSERT_NO_FATAL_FAILURE(AddFileEntry("moved")); - - // Load data from the service to the metadata. - FileError error = FILE_ERROR_FAILED; - change_list_loader_->LoadIfNeeded( - google_apis::test_util::CreateCopyResultCallback(&error)); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Prepare 3 pinned-but-not-present files. - EXPECT_EQ(FILE_ERROR_OK, cache_->Pin(GetLocalId("foo"))); - EXPECT_EQ(FILE_ERROR_OK, cache_->Pin(GetLocalId("bar"))); - EXPECT_EQ(FILE_ERROR_OK, cache_->Pin(GetLocalId("baz"))); - - // Prepare a pinned-and-fetched file. - const std::string md5_fetched = "md5"; - EXPECT_EQ(FILE_ERROR_OK, - cache_->Store(GetLocalId("fetched"), md5_fetched, - temp_file, FileCache::FILE_OPERATION_COPY)); - EXPECT_EQ(FILE_ERROR_OK, cache_->Pin(GetLocalId("fetched"))); - - // Prepare a pinned-and-fetched-and-dirty file. - EXPECT_EQ(FILE_ERROR_OK, - cache_->Store(GetLocalId("dirty"), std::string(), - temp_file, FileCache::FILE_OPERATION_COPY)); - EXPECT_EQ(FILE_ERROR_OK, cache_->Pin(GetLocalId("dirty"))); - - // Prepare a removed file. - file_system::RemoveOperation remove_operation( - base::ThreadTaskRunnerHandle::Get().get(), &delegate_, metadata_.get(), - cache_.get()); - remove_operation.Remove( - util::GetDriveMyDriveRootPath().AppendASCII("removed"), - false, // is_recursive - google_apis::test_util::CreateCopyResultCallback(&error)); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - // Prepare a moved file. - file_system::MoveOperation move_operation( - base::ThreadTaskRunnerHandle::Get().get(), &delegate_, metadata_.get()); - move_operation.Move( - util::GetDriveMyDriveRootPath().AppendASCII("moved"), - util::GetDriveMyDriveRootPath().AppendASCII("moved_new_title"), - google_apis::test_util::CreateCopyResultCallback(&error)); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - } - - protected: - std::string GetLocalId(const std::string& title) { - EXPECT_EQ(1U, resource_ids_.count(title)); - std::string local_id; - EXPECT_EQ(FILE_ERROR_OK, - metadata_->GetIdByResourceId(resource_ids_[title], &local_id)); - return local_id; - } - - content::BrowserTaskEnvironment task_environment_; - base::ScopedTempDir temp_dir_; - std::unique_ptr<TestingPrefServiceSimple> pref_service_; - std::unique_ptr<EventLogger> logger_; - std::unique_ptr<SyncClientTestDriveService> drive_service_; - file_system::OperationDelegate delegate_; - std::unique_ptr<JobScheduler> scheduler_; - std::unique_ptr<ResourceMetadataStorage, test_util::DestroyHelperForTests> - metadata_storage_; - std::unique_ptr<FileCache, test_util::DestroyHelperForTests> cache_; - std::unique_ptr<ResourceMetadata, test_util::DestroyHelperForTests> metadata_; - std::unique_ptr<AboutResourceLoader> about_resource_loader_; - std::unique_ptr<StartPageTokenLoader> start_page_token_loader_; - std::unique_ptr<LoaderController> loader_controller_; - std::unique_ptr<ChangeListLoader> change_list_loader_; - std::unique_ptr<SyncClient> sync_client_; - std::unique_ptr<AboutResourceRootFolderIdLoader> root_folder_id_loader_; - - std::map<std::string, std::string> resource_ids_; // Name-to-id map. -}; - -TEST_F(SyncClientTest, StartProcessingBacklog) { - sync_client_->StartProcessingBacklog(); - base::RunLoop().RunUntilIdle(); - - ResourceEntry entry; - // Pinned files get downloaded. - EXPECT_EQ(FILE_ERROR_OK, - metadata_->GetResourceEntryById(GetLocalId("foo"), &entry)); - EXPECT_TRUE(entry.file_specific_info().cache_state().is_present()); - - EXPECT_EQ(FILE_ERROR_OK, - metadata_->GetResourceEntryById(GetLocalId("bar"), &entry)); - EXPECT_TRUE(entry.file_specific_info().cache_state().is_present()); - - EXPECT_EQ(FILE_ERROR_OK, - metadata_->GetResourceEntryById(GetLocalId("baz"), &entry)); - EXPECT_TRUE(entry.file_specific_info().cache_state().is_present()); - - // Dirty file gets uploaded. - EXPECT_EQ(FILE_ERROR_OK, - metadata_->GetResourceEntryById(GetLocalId("dirty"), &entry)); - EXPECT_FALSE(entry.file_specific_info().cache_state().is_dirty()); - - // Removed entry is not found. - google_apis::DriveApiErrorCode status = google_apis::DRIVE_OTHER_ERROR; - std::unique_ptr<google_apis::FileResource> server_entry; - drive_service_->GetFileResource( - resource_ids_["removed"], - google_apis::test_util::CreateCopyResultCallback(&status, &server_entry)); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(google_apis::HTTP_SUCCESS, status); - ASSERT_TRUE(server_entry); - EXPECT_TRUE(server_entry->labels().is_trashed()); - - // Moved entry was moved. - status = google_apis::DRIVE_OTHER_ERROR; - drive_service_->GetFileResource( - resource_ids_["moved"], - google_apis::test_util::CreateCopyResultCallback(&status, &server_entry)); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(google_apis::HTTP_SUCCESS, status); - ASSERT_TRUE(server_entry); - EXPECT_EQ("moved_new_title", server_entry->title()); -} - -TEST_F(SyncClientTest, AddFetchTask) { - sync_client_->AddFetchTask(GetLocalId("foo")); - base::RunLoop().RunUntilIdle(); - - ResourceEntry entry; - EXPECT_EQ(FILE_ERROR_OK, - metadata_->GetResourceEntryById(GetLocalId("foo"), &entry)); - EXPECT_TRUE(entry.file_specific_info().cache_state().is_present()); -} - -TEST_F(SyncClientTest, AddFetchTaskAndCancelled) { - // Trigger fetching of a file which results in cancellation. - drive_service_->set_resource_id_to_be_cancelled(resource_ids_["foo"]); - sync_client_->AddFetchTask(GetLocalId("foo")); - base::RunLoop().RunUntilIdle(); - - // The file should be unpinned if the user wants the download to be cancelled. - ResourceEntry entry; - EXPECT_EQ(FILE_ERROR_OK, - metadata_->GetResourceEntryById(GetLocalId("foo"), &entry)); - EXPECT_FALSE(entry.file_specific_info().cache_state().is_pinned()); -} - -TEST_F(SyncClientTest, RemoveFetchTask) { - sync_client_->AddFetchTask(GetLocalId("foo")); - sync_client_->AddFetchTask(GetLocalId("bar")); - sync_client_->AddFetchTask(GetLocalId("baz")); - - sync_client_->RemoveFetchTask(GetLocalId("foo")); - sync_client_->RemoveFetchTask(GetLocalId("baz")); - base::RunLoop().RunUntilIdle(); - - // Only "bar" should be fetched. - ResourceEntry entry; - EXPECT_EQ(FILE_ERROR_OK, - metadata_->GetResourceEntryById(GetLocalId("foo"), &entry)); - EXPECT_FALSE(entry.file_specific_info().cache_state().is_present()); - - EXPECT_EQ(FILE_ERROR_OK, - metadata_->GetResourceEntryById(GetLocalId("bar"), &entry)); - EXPECT_TRUE(entry.file_specific_info().cache_state().is_present()); - - EXPECT_EQ(FILE_ERROR_OK, - metadata_->GetResourceEntryById(GetLocalId("baz"), &entry)); - EXPECT_FALSE(entry.file_specific_info().cache_state().is_present()); - -} - -TEST_F(SyncClientTest, ExistingPinnedFiles) { - // Start checking the existing pinned files. This will collect the resource - // IDs of pinned files, with stale local cache files. - sync_client_->StartCheckingExistingPinnedFiles(); - base::RunLoop().RunUntilIdle(); - - // "fetched" and "dirty" are the existing pinned files. - // The non-dirty one should be synced, but the dirty one should not. - base::FilePath cache_file; - std::string content; - EXPECT_EQ(FILE_ERROR_OK, cache_->GetFile(GetLocalId("fetched"), &cache_file)); - EXPECT_TRUE(base::ReadFileToString(cache_file, &content)); - EXPECT_EQ(kRemoteContent, content); - content.clear(); - - EXPECT_EQ(FILE_ERROR_OK, cache_->GetFile(GetLocalId("dirty"), &cache_file)); - EXPECT_TRUE(base::ReadFileToString(cache_file, &content)); - EXPECT_EQ(kLocalContent, content); -} - -TEST_F(SyncClientTest, RetryOnDisconnection) { - // Let the service go down. - drive_service_->set_offline(true); - // Change the network connection state after some delay, to test that - // FILE_ERROR_NO_CONNECTION is handled by SyncClient correctly. - // Without this delay, JobScheduler will keep the jobs unrun and SyncClient - // will receive no error. - base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, - base::BindOnce(&network::TestNetworkConnectionTracker::SetConnectionType, - base::Unretained( - network::TestNetworkConnectionTracker::GetInstance()), - network::mojom::ConnectionType::CONNECTION_NONE), - TestTimeouts::tiny_timeout()); - - // Try fetch and upload. - sync_client_->AddFetchTask(GetLocalId("foo")); - sync_client_->AddUpdateTask(ClientContext(USER_INITIATED), - GetLocalId("dirty")); - base::RunLoop().RunUntilIdle(); - - // Not yet fetched nor uploaded. - ResourceEntry entry; - EXPECT_EQ(FILE_ERROR_OK, - metadata_->GetResourceEntryById(GetLocalId("foo"), &entry)); - EXPECT_FALSE(entry.file_specific_info().cache_state().is_present()); - EXPECT_EQ(FILE_ERROR_OK, - metadata_->GetResourceEntryById(GetLocalId("dirty"), &entry)); - EXPECT_TRUE(entry.file_specific_info().cache_state().is_dirty()); - - // Switch to online. - network::TestNetworkConnectionTracker::GetInstance()->SetConnectionType( - network::mojom::ConnectionType::CONNECTION_WIFI); - drive_service_->set_offline(false); - base::RunLoop().RunUntilIdle(); - - // Fetched and uploaded. - EXPECT_EQ(FILE_ERROR_OK, - metadata_->GetResourceEntryById(GetLocalId("foo"), &entry)); - EXPECT_TRUE(entry.file_specific_info().cache_state().is_present()); - EXPECT_EQ(FILE_ERROR_OK, - metadata_->GetResourceEntryById(GetLocalId("dirty"), &entry)); - EXPECT_FALSE(entry.file_specific_info().cache_state().is_dirty()); -} - -TEST_F(SyncClientTest, ScheduleRerun) { - // Add a fetch task for "foo", this should result in being paused. - drive_service_->set_resource_id_to_be_paused(resource_ids_["foo"]); - sync_client_->AddFetchTask(GetLocalId("foo")); - base::RunLoop().RunUntilIdle(); - - // While the first task is paused, add a task again. - // This results in scheduling rerun of the task. - sync_client_->AddFetchTask(GetLocalId("foo")); - base::RunLoop().RunUntilIdle(); - - // Resume the paused task. - drive_service_->set_resource_id_to_be_paused(std::string()); - ASSERT_FALSE(drive_service_->paused_action().is_null()); - drive_service_->paused_action().Run(); - base::RunLoop().RunUntilIdle(); - - // Task should be run twice. - EXPECT_EQ(2, drive_service_->download_file_count()); -} - -TEST_F(SyncClientTest, Dependencies) { - // Create directories locally. - const base::FilePath kPath1(FILE_PATH_LITERAL("drive/root/dir1")); - const base::FilePath kPath2 = kPath1.AppendASCII("dir2"); - - ResourceEntry parent; - EXPECT_EQ(FILE_ERROR_OK, - metadata_->GetResourceEntryByPath(kPath1.DirName(), &parent)); - - ResourceEntry entry1; - entry1.set_parent_local_id(parent.local_id()); - entry1.set_title(kPath1.BaseName().AsUTF8Unsafe()); - entry1.mutable_file_info()->set_is_directory(true); - entry1.set_metadata_edit_state(ResourceEntry::DIRTY); - std::string local_id1; - EXPECT_EQ(FILE_ERROR_OK, metadata_->AddEntry(entry1, &local_id1)); - - ResourceEntry entry2; - entry2.set_parent_local_id(local_id1); - entry2.set_title(kPath2.BaseName().AsUTF8Unsafe()); - entry2.mutable_file_info()->set_is_directory(true); - entry2.set_metadata_edit_state(ResourceEntry::DIRTY); - std::string local_id2; - EXPECT_EQ(FILE_ERROR_OK, metadata_->AddEntry(entry2, &local_id2)); - - // Start syncing the child first. - sync_client_->AddUpdateTask(ClientContext(USER_INITIATED), local_id2); - // Start syncing the parent later. - sync_client_->AddUpdateTask(ClientContext(USER_INITIATED), local_id1); - base::RunLoop().RunUntilIdle(); - - // Both entries are synced. - EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryById(local_id1, &entry1)); - EXPECT_EQ(ResourceEntry::CLEAN, entry1.metadata_edit_state()); - EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryById(local_id2, &entry2)); - EXPECT_EQ(ResourceEntry::CLEAN, entry2.metadata_edit_state()); -} - -TEST_F(SyncClientTest, WaitForUpdateTaskToComplete) { - // Create a directory locally. - const base::FilePath kPath(FILE_PATH_LITERAL("drive/root/dir1")); - - ResourceEntry parent; - EXPECT_EQ(FILE_ERROR_OK, - metadata_->GetResourceEntryByPath(kPath.DirName(), &parent)); - - ResourceEntry entry; - entry.set_parent_local_id(parent.local_id()); - entry.set_title(kPath.BaseName().AsUTF8Unsafe()); - entry.mutable_file_info()->set_is_directory(true); - entry.set_metadata_edit_state(ResourceEntry::DIRTY); - std::string local_id; - EXPECT_EQ(FILE_ERROR_OK, metadata_->AddEntry(entry, &local_id)); - - // Sync task is not yet avialable. - FileError error = FILE_ERROR_FAILED; - EXPECT_FALSE(sync_client_->WaitForUpdateTaskToComplete( - local_id, google_apis::test_util::CreateCopyResultCallback(&error))); - - // Start syncing the directory and wait for it to complete. - sync_client_->AddUpdateTask(ClientContext(USER_INITIATED), local_id); - - EXPECT_TRUE(sync_client_->WaitForUpdateTaskToComplete( - local_id, google_apis::test_util::CreateCopyResultCallback(&error))); - - base::RunLoop().RunUntilIdle(); - - // The callback is called. - EXPECT_EQ(FILE_ERROR_OK, error); -} - -} // namespace internal -} // namespace drive
diff --git a/components/drive/team_drive_change_list_loader_unittest.cc b/components/drive/team_drive_change_list_loader_unittest.cc deleted file mode 100644 index 09faac9d..0000000 --- a/components/drive/team_drive_change_list_loader_unittest.cc +++ /dev/null
@@ -1,312 +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 <memory> - -#include "base/command_line.h" -#include "base/files/scoped_temp_dir.h" -#include "base/threading/thread_task_runner_handle.h" -#include "components/drive/chromeos/drive_file_util.h" -#include "components/drive/chromeos/drive_test_util.h" -#include "components/drive/chromeos/file_cache.h" -#include "components/drive/chromeos/loader_controller.h" -#include "components/drive/chromeos/resource_metadata.h" -#include "components/drive/chromeos/team_drive_change_list_loader.h" -#include "components/drive/event_logger.h" -#include "components/drive/file_change.h" -#include "components/drive/file_system_core_util.h" -#include "components/drive/job_scheduler.h" -#include "components/drive/resource_metadata_storage.h" -#include "components/drive/service/fake_drive_service.h" -#include "components/drive/service/test_util.h" -#include "components/prefs/testing_pref_service.h" -#include "content/public/test/browser_task_environment.h" -#include "mojo/public/cpp/bindings/pending_remote.h" -#include "services/network/test/test_network_connection_tracker.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace drive { -namespace internal { - -namespace { - -constexpr char kTeamDriveId[] = "team_drive_id"; -constexpr char kTeamDriveName[] = "team_drive_name"; -constexpr char kTestStartPageToken[] = "1"; - -class TestChangeListLoaderObserver : public ChangeListLoaderObserver { - public: - TestChangeListLoaderObserver() - : load_from_server_complete_count_(0), initial_load_complete_count_(0) {} - - ~TestChangeListLoaderObserver() override = default; - - const FileChange& changed_files() const { return changed_files_; } - void clear_changed_files() { changed_files_.ClearForTest(); } - - int load_from_server_complete_count() const { - return load_from_server_complete_count_; - } - int initial_load_complete_count() const { - return initial_load_complete_count_; - } - - // ChageListObserver overrides: - void OnFileChanged(const FileChange& changed_files) override { - changed_files_.Apply(changed_files); - } - void OnLoadFromServerComplete() override { - ++load_from_server_complete_count_; - } - void OnInitialLoadComplete() override { ++initial_load_complete_count_; } - - private: - FileChange changed_files_; - int load_from_server_complete_count_; - int initial_load_complete_count_; - - DISALLOW_COPY_AND_ASSIGN(TestChangeListLoaderObserver); -}; - -} // namespace - -class TeamDriveChangeListLoaderTest : public testing::Test { - protected: - void SetUp() override { - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - - pref_service_ = std::make_unique<TestingPrefServiceSimple>(); - test_util::RegisterDrivePrefs(pref_service_->registry()); - - logger_ = std::make_unique<EventLogger>(); - - drive_service_ = std::make_unique<FakeDriveService>(); - ASSERT_TRUE(test_util::SetUpTeamDriveTestEntries( - drive_service_.get(), kTeamDriveId, kTeamDriveName)); - - network::TestNetworkConnectionTracker::GetInstance()->SetConnectionType( - network::mojom::ConnectionType::CONNECTION_WIFI); - scheduler_ = std::make_unique<JobScheduler>( - pref_service_.get(), logger_.get(), drive_service_.get(), - network::TestNetworkConnectionTracker::GetInstance(), - base::ThreadTaskRunnerHandle::Get().get(), mojo::NullRemote()); - metadata_storage_.reset(new ResourceMetadataStorage( - temp_dir_.GetPath(), base::ThreadTaskRunnerHandle::Get().get())); - ASSERT_TRUE(metadata_storage_->Initialize()); - - cache_.reset(new FileCache(metadata_storage_.get(), temp_dir_.GetPath(), - base::ThreadTaskRunnerHandle::Get().get(), - nullptr /* free_disk_space_getter */)); - ASSERT_TRUE(cache_->Initialize()); - - metadata_.reset( - new ResourceMetadata(metadata_storage_.get(), cache_.get(), - base::ThreadTaskRunnerHandle::Get().get())); - ASSERT_EQ(FILE_ERROR_OK, metadata_->Initialize()); - - loader_controller_ = std::make_unique<LoaderController>(); - base::FilePath root_entry_path = - util::GetDriveTeamDrivesRootPath().Append(kTeamDriveName); - - team_drive_change_list_loader_ = - std::make_unique<TeamDriveChangeListLoader>( - kTeamDriveId, root_entry_path, logger_.get(), - base::ThreadTaskRunnerHandle::Get().get(), metadata_.get(), - scheduler_.get(), loader_controller_.get()); - - change_list_loader_observer_ = - std::make_unique<TestChangeListLoaderObserver>(); - team_drive_change_list_loader_->AddChangeListLoaderObserver( - change_list_loader_observer_.get()); - } - - // Adds a team drive entry to ResourceMetadata - void AddTeamDriveEntry(const std::string& id, - const std::string& name, - const std::string& start_page_token) { - std::string root_local_id; - ASSERT_EQ(FILE_ERROR_OK, - metadata_->GetIdByPath(util::GetDriveTeamDrivesRootPath(), - &root_local_id)); - - std::string local_id; - ASSERT_EQ(FILE_ERROR_OK, metadata_->AddEntry( - CreateDirectoryEntryWithResourceId( - name, id, root_local_id, start_page_token), - &local_id)); - } - - // Creates a ResourceEntry for a directory with explicitly set resource_id. - ResourceEntry CreateDirectoryEntryWithResourceId( - const std::string& title, - const std::string& resource_id, - const std::string& parent_local_id, - const std::string& start_page_token) { - ResourceEntry entry; - entry.set_title(title); - entry.set_resource_id(resource_id); - entry.set_parent_local_id(parent_local_id); - entry.mutable_file_info()->set_is_directory(true); - entry.mutable_directory_specific_info()->set_start_page_token( - start_page_token); - return entry; - } - - // Adds a new file to the root directory of the service. - std::unique_ptr<google_apis::FileResource> AddNewFile( - const std::string& title, - const std::string& parent_resource_id) { - google_apis::DriveApiErrorCode error = google_apis::DRIVE_FILE_ERROR; - std::unique_ptr<google_apis::FileResource> entry; - drive_service_->AddNewFile( - "text/plain", "content text", parent_resource_id, title, - false, // shared_with_me - google_apis::test_util::CreateCopyResultCallback(&error, &entry)); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(google_apis::HTTP_CREATED, error); - return entry; - } - - content::BrowserTaskEnvironment task_environment_; - base::ScopedTempDir temp_dir_; - std::unique_ptr<TestingPrefServiceSimple> pref_service_; - std::unique_ptr<EventLogger> logger_; - std::unique_ptr<FakeDriveService> drive_service_; - std::unique_ptr<JobScheduler> scheduler_; - std::unique_ptr<ResourceMetadataStorage, test_util::DestroyHelperForTests> - metadata_storage_; - std::unique_ptr<FileCache, test_util::DestroyHelperForTests> cache_; - std::unique_ptr<ResourceMetadata, test_util::DestroyHelperForTests> metadata_; - std::unique_ptr<LoaderController> loader_controller_; - std::unique_ptr<TeamDriveChangeListLoader> team_drive_change_list_loader_; - std::unique_ptr<TestChangeListLoaderObserver> change_list_loader_observer_; -}; - -// When loading, if the local resource metadata contains a start page token then -// we do not load from the server, just use local metadata. -TEST_F(TeamDriveChangeListLoaderTest, MetadataRefresh) { - AddTeamDriveEntry(kTeamDriveId, kTeamDriveName, kTestStartPageToken); - EXPECT_FALSE(team_drive_change_list_loader_->IsRefreshing()); - - FileError error = FILE_ERROR_FAILED; - team_drive_change_list_loader_->LoadIfNeeded( - google_apis::test_util::CreateCopyResultCallback(&error)); - EXPECT_TRUE(team_drive_change_list_loader_->IsRefreshing()); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - EXPECT_FALSE(team_drive_change_list_loader_->IsRefreshing()); - EXPECT_EQ(1, drive_service_->start_page_token_load_count()); - EXPECT_EQ(0, drive_service_->change_list_load_count()); -} - -// Trigger a full load, by setting the start page token of the team drive in -// resource metadata to an empty string. -TEST_F(TeamDriveChangeListLoaderTest, FullLoad) { - AddTeamDriveEntry(kTeamDriveId, kTeamDriveName, std::string()); - EXPECT_FALSE(team_drive_change_list_loader_->IsRefreshing()); - - FileError error = FILE_ERROR_FAILED; - team_drive_change_list_loader_->LoadIfNeeded( - google_apis::test_util::CreateCopyResultCallback(&error)); - EXPECT_TRUE(team_drive_change_list_loader_->IsRefreshing()); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - - EXPECT_FALSE(team_drive_change_list_loader_->IsRefreshing()); - EXPECT_EQ(1, drive_service_->start_page_token_load_count()); - EXPECT_EQ(1, drive_service_->file_list_load_count()); - EXPECT_EQ(0, drive_service_->change_list_load_count()); - EXPECT_EQ(1, change_list_loader_observer_->initial_load_complete_count()); - EXPECT_EQ(1, change_list_loader_observer_->load_from_server_complete_count()); - EXPECT_TRUE(change_list_loader_observer_->changed_files().empty()); - - base::FilePath file_path = util::GetDriveTeamDrivesRootPath() - .AppendASCII(kTeamDriveName) - .AppendASCII("File 1.txt"); - ResourceEntry entry; - EXPECT_EQ(FILE_ERROR_OK, - metadata_->GetResourceEntryByPath(file_path, &entry)); -} - -// CheckForUpdates will trigger a full and delta load from the server -TEST_F(TeamDriveChangeListLoaderTest, CheckForUpdates) { - AddTeamDriveEntry(kTeamDriveId, kTeamDriveName, std::string()); - - // CheckForUpdates() results in no-op before load. - FileError error = FILE_ERROR_FAILED; - team_drive_change_list_loader_->CheckForUpdates( - google_apis::test_util::CreateCopyResultCallback(&error)); - EXPECT_FALSE(team_drive_change_list_loader_->IsRefreshing()); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_FAILED, error); - - EXPECT_EQ(0, drive_service_->file_list_load_count()); - EXPECT_EQ(0, drive_service_->start_page_token_load_count()); - - // Start initial load. - FileError load_error = FILE_ERROR_FAILED; - team_drive_change_list_loader_->LoadIfNeeded( - google_apis::test_util::CreateCopyResultCallback(&load_error)); - EXPECT_TRUE(team_drive_change_list_loader_->IsRefreshing()); - base::RunLoop().RunUntilIdle(); - - std::string start_page_token; - EXPECT_FALSE(team_drive_change_list_loader_->IsRefreshing()); - EXPECT_EQ(FILE_ERROR_OK, load_error); - EXPECT_EQ(FILE_ERROR_OK, - internal::GetStartPageToken(metadata_.get(), kTeamDriveId, - &start_page_token)); - EXPECT_FALSE(start_page_token.empty()); - EXPECT_EQ(1, drive_service_->file_list_load_count()); - - std::string previous_start_page_token = start_page_token; - // CheckForUpdates() results in no update. - FileError check_for_updates_error = FILE_ERROR_FAILED; - team_drive_change_list_loader_->CheckForUpdates( - google_apis::test_util::CreateCopyResultCallback( - &check_for_updates_error)); - EXPECT_TRUE(team_drive_change_list_loader_->IsRefreshing()); - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(team_drive_change_list_loader_->IsRefreshing()); - EXPECT_EQ(FILE_ERROR_OK, - internal::GetStartPageToken(metadata_.get(), kTeamDriveId, - &start_page_token)); - EXPECT_EQ(previous_start_page_token, start_page_token); - - // Add a file to the service. - std::unique_ptr<google_apis::FileResource> gdata_entry = - AddNewFile("New File", kTeamDriveId); - ASSERT_TRUE(gdata_entry); - - // CheckForUpdates() results in update. - change_list_loader_observer_->clear_changed_files(); - team_drive_change_list_loader_->CheckForUpdates( - google_apis::test_util::CreateCopyResultCallback( - &check_for_updates_error)); - EXPECT_TRUE(team_drive_change_list_loader_->IsRefreshing()); - base::RunLoop().RunUntilIdle(); - - EXPECT_FALSE(team_drive_change_list_loader_->IsRefreshing()); - EXPECT_EQ(FILE_ERROR_OK, - internal::GetStartPageToken(metadata_.get(), kTeamDriveId, - &start_page_token)); - EXPECT_NE(previous_start_page_token, start_page_token); - EXPECT_EQ(2, change_list_loader_observer_->load_from_server_complete_count()); - - base::FilePath team_drive_path = - util::GetDriveTeamDrivesRootPath().AppendASCII(kTeamDriveName); - EXPECT_TRUE(change_list_loader_observer_->changed_files().CountDirectory( - team_drive_path)); - - // The new file is found in the local metadata. - base::FilePath new_file_path = - team_drive_path.AppendASCII(gdata_entry->title()); - ResourceEntry entry; - EXPECT_EQ(FILE_ERROR_OK, - metadata_->GetResourceEntryByPath(new_file_path, &entry)); -} - -} // namespace internal -} // namespace drive
diff --git a/components/drive/team_drive_list_loader_unittest.cc b/components/drive/team_drive_list_loader_unittest.cc deleted file mode 100644 index f196d8b..0000000 --- a/components/drive/team_drive_list_loader_unittest.cc +++ /dev/null
@@ -1,406 +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 <memory> - -#include "base/files/scoped_temp_dir.h" -#include "components/drive/chromeos/change_list_loader.h" -#include "components/drive/chromeos/drive_test_util.h" -#include "components/drive/chromeos/loader_controller.h" -#include "components/drive/chromeos/resource_metadata.h" -#include "components/drive/chromeos/team_drive_list_loader.h" -#include "components/drive/event_logger.h" -#include "components/drive/file_system_core_util.h" -#include "components/drive/job_scheduler.h" -#include "components/drive/service/fake_drive_service.h" -#include "components/drive/service/test_util.h" -#include "components/prefs/testing_pref_service.h" -#include "content/public/test/browser_task_environment.h" -#include "google_apis/drive/test_util.h" -#include "mojo/public/cpp/bindings/pending_remote.h" -#include "services/network/test/test_network_connection_tracker.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace drive { -namespace internal { - -namespace { - -constexpr char kTestStartPageToken[] = "123456"; - -class TestTeamDriveListObserver : public TeamDriveListObserver { - public: - ~TestTeamDriveListObserver() override = default; - - void OnTeamDriveListLoaded( - const std::vector<TeamDrive>& team_drives_list, - const std::vector<TeamDrive>& added_team_drives, - const std::vector<TeamDrive>& removed_team_drives) override { - team_drives_list_ = team_drives_list; - added_team_drives_ = added_team_drives; - removed_team_drives_ = removed_team_drives; - } - - const std::vector<TeamDrive>& team_drives_list() const { - return team_drives_list_; - } - - const std::vector<TeamDrive>& added_team_drives() const { - return added_team_drives_; - } - - const std::vector<TeamDrive>& removed_team_drives() const { - return removed_team_drives_; - } - - private: - std::vector<TeamDrive> team_drives_list_; - std::vector<TeamDrive> added_team_drives_; - std::vector<TeamDrive> removed_team_drives_; -}; - -} // namespace - -class TeamDriveListLoaderTest : public testing::Test { - protected: - void SetUp() override { - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - - pref_service_ = std::make_unique<TestingPrefServiceSimple>(); - test_util::RegisterDrivePrefs(pref_service_->registry()); - - logger_ = std::make_unique<EventLogger>(); - - drive_service_ = std::make_unique<FakeDriveService>(); - ASSERT_TRUE(test_util::SetUpTestEntries(drive_service_.get())); - drive_service_->set_default_max_results(2); - - network::TestNetworkConnectionTracker::GetInstance()->SetConnectionType( - network::mojom::ConnectionType::CONNECTION_WIFI); - scheduler_ = std::make_unique<JobScheduler>( - pref_service_.get(), logger_.get(), drive_service_.get(), - network::TestNetworkConnectionTracker::GetInstance(), - base::ThreadTaskRunnerHandle::Get().get(), mojo::NullRemote()); - metadata_storage_.reset(new ResourceMetadataStorage( - temp_dir_.GetPath(), base::ThreadTaskRunnerHandle::Get().get())); - ASSERT_TRUE(metadata_storage_->Initialize()); - - cache_.reset(new FileCache(metadata_storage_.get(), temp_dir_.GetPath(), - base::ThreadTaskRunnerHandle::Get().get(), - nullptr /* free_disk_space_getter */)); - ASSERT_TRUE(cache_->Initialize()); - - metadata_.reset( - new ResourceMetadata(metadata_storage_.get(), cache_.get(), - base::ThreadTaskRunnerHandle::Get().get())); - ASSERT_EQ(FILE_ERROR_OK, metadata_->Initialize()); - - loader_controller_ = std::make_unique<LoaderController>(); - team_drive_list_loader_ = std::make_unique<TeamDriveListLoader>( - logger_.get(), base::ThreadTaskRunnerHandle::Get().get(), - metadata_.get(), scheduler_.get(), loader_controller_.get()); - - team_drive_list_observer_ = std::make_unique<TestTeamDriveListObserver>(); - team_drive_list_loader_->AddObserver(team_drive_list_observer_.get()); - } - - // Creates a ResourceEntry for a directory with explicitly set resource_id. - ResourceEntry CreateDirectoryEntryWithResourceId( - const std::string& title, - const std::string& resource_id, - const std::string& parent_local_id) { - ResourceEntry entry; - entry.set_title(title); - entry.set_resource_id(resource_id); - entry.set_parent_local_id(parent_local_id); - entry.mutable_file_info()->set_is_directory(true); - entry.mutable_directory_specific_info()->set_start_page_token( - kTestStartPageToken); - return entry; - } - - content::BrowserTaskEnvironment task_environment_; - base::ScopedTempDir temp_dir_; - std::unique_ptr<TestingPrefServiceSimple> pref_service_; - std::unique_ptr<EventLogger> logger_; - std::unique_ptr<FakeDriveService> drive_service_; - std::unique_ptr<JobScheduler> scheduler_; - std::unique_ptr<ResourceMetadataStorage, test_util::DestroyHelperForTests> - metadata_storage_; - std::unique_ptr<FileCache, test_util::DestroyHelperForTests> cache_; - std::unique_ptr<ResourceMetadata, test_util::DestroyHelperForTests> metadata_; - std::unique_ptr<LoaderController> loader_controller_; - std::unique_ptr<TeamDriveListLoader> team_drive_list_loader_; - std::unique_ptr<TestTeamDriveListObserver> team_drive_list_observer_; -}; - -// Tests that if there are no team drives on the server, we will not add -// and team drives to local metadata. -TEST_F(TeamDriveListLoaderTest, NoTeamDrives) { - // Tests the response if there are no team drives loaded. - FileError error = FILE_ERROR_FAILED; - team_drive_list_loader_->LoadIfNeeded( - google_apis::test_util::CreateCopyResultCallback(&error)); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - EXPECT_EQ(1, drive_service_->team_drive_list_load_count()); - - EXPECT_TRUE(team_drive_list_observer_->team_drives_list().empty()); - EXPECT_TRUE(team_drive_list_observer_->added_team_drives().empty()); - EXPECT_TRUE(team_drive_list_observer_->removed_team_drives().empty()); - - ResourceEntryVector entries; - EXPECT_EQ(FILE_ERROR_OK, metadata_->ReadDirectoryByPath( - util::GetDriveTeamDrivesRootPath(), &entries)); - EXPECT_TRUE(entries.empty()); -} - -// Tests if there is one team drive on the server we will add it to the local -// metadata. -TEST_F(TeamDriveListLoaderTest, OneTeamDrive) { - constexpr char kTeamDriveId1[] = "the1stTeamDriveId"; - constexpr char kTeamDriveName1[] = "The First Team Drive"; - drive_service_->AddTeamDrive(kTeamDriveId1, kTeamDriveName1); - - FileError error = FILE_ERROR_FAILED; - team_drive_list_loader_->CheckForUpdates( - google_apis::test_util::CreateCopyResultCallback(&error)); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - EXPECT_EQ(1, drive_service_->team_drive_list_load_count()); - - EXPECT_EQ(1UL, team_drive_list_observer_->team_drives_list().size()); - EXPECT_EQ(1UL, team_drive_list_observer_->added_team_drives().size()); - EXPECT_TRUE(team_drive_list_observer_->removed_team_drives().empty()); - - ResourceEntryVector entries; - EXPECT_EQ(FILE_ERROR_OK, metadata_->ReadDirectoryByPath( - util::GetDriveTeamDrivesRootPath(), &entries)); - EXPECT_EQ(1UL, entries.size()); - - ResourceEntry entry; - EXPECT_EQ(FILE_ERROR_OK, - metadata_->GetResourceEntryByPath( - util::GetDriveTeamDrivesRootPath().AppendASCII(kTeamDriveName1), - &entry)); - - const base::FilePath& team_drive_path = - team_drive_list_observer_->team_drives_list().front().team_drive_path(); - EXPECT_EQ(team_drive_path, - util::GetDriveTeamDrivesRootPath().AppendASCII(kTeamDriveName1)); -} - -TEST_F(TeamDriveListLoaderTest, NotmalizedTeamDriveName) { - constexpr char kTeamDriveId1[] = "the1stTeamDriveId"; - constexpr char kTeamDriveName1[] = "A / Strange / Team / Drive / Name"; - constexpr char kTeamDriveNormalized1[] = "A _ Strange _ Team _ Drive _ Name"; - drive_service_->AddTeamDrive(kTeamDriveId1, kTeamDriveName1); - - FileError error = FILE_ERROR_FAILED; - team_drive_list_loader_->CheckForUpdates( - google_apis::test_util::CreateCopyResultCallback(&error)); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - EXPECT_EQ(1, drive_service_->team_drive_list_load_count()); - - EXPECT_EQ(1UL, team_drive_list_observer_->team_drives_list().size()); - EXPECT_EQ(1UL, team_drive_list_observer_->added_team_drives().size()); - EXPECT_TRUE(team_drive_list_observer_->removed_team_drives().empty()); - - ResourceEntryVector entries; - EXPECT_EQ(FILE_ERROR_OK, metadata_->ReadDirectoryByPath( - util::GetDriveTeamDrivesRootPath(), &entries)); - EXPECT_EQ(1UL, entries.size()); - - ResourceEntry entry; - EXPECT_EQ( - FILE_ERROR_OK, - metadata_->GetResourceEntryByPath( - util::GetDriveTeamDrivesRootPath().Append(kTeamDriveNormalized1), - &entry)); - - { - const base::FilePath& team_drive_path = - team_drive_list_observer_->team_drives_list().front().team_drive_path(); - EXPECT_EQ(team_drive_path, - util::GetDriveTeamDrivesRootPath().Append(kTeamDriveNormalized1)); - } - { - const base::FilePath& team_drive_path = - team_drive_list_observer_->added_team_drives() - .front() - .team_drive_path(); - EXPECT_EQ(team_drive_path, - util::GetDriveTeamDrivesRootPath().Append(kTeamDriveNormalized1)); - } -} - -// Tests if there are multiple team drives on the server, we will add them all -// to local metadata. -TEST_F(TeamDriveListLoaderTest, MultipleTeamDrive) { - const std::vector<std::pair<std::string, std::string>> team_drives = { - {"the1stTeamDriveId", "The First Team Drive"}, - {"the2ndTeamDriveId", "The Second Team Drive"}, - {"the3rdTeamDriveId", "The Third Team Drive"}, - {"the4thTeamDriveId", "The Forth Team Drive"}, - }; - - for (const auto& drive : team_drives) { - drive_service_->AddTeamDrive(drive.first, drive.second); - } - - FileError error = FILE_ERROR_FAILED; - team_drive_list_loader_->CheckForUpdates( - google_apis::test_util::CreateCopyResultCallback(&error)); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - EXPECT_EQ(1, drive_service_->team_drive_list_load_count()); - - EXPECT_EQ(team_drives.size(), - team_drive_list_observer_->team_drives_list().size()); - EXPECT_EQ(team_drives.size(), - team_drive_list_observer_->added_team_drives().size()); - EXPECT_TRUE(team_drive_list_observer_->removed_team_drives().empty()); - - ResourceEntryVector entries; - EXPECT_EQ(FILE_ERROR_OK, metadata_->ReadDirectoryByPath( - util::GetDriveTeamDrivesRootPath(), &entries)); - EXPECT_EQ(team_drives.size(), entries.size()); - - ResourceEntry entry; - - for (const auto& drive : team_drives) { - EXPECT_EQ(FILE_ERROR_OK, - metadata_->GetResourceEntryByPath( - util::GetDriveTeamDrivesRootPath().AppendASCII(drive.second), - &entry)); - EXPECT_EQ(drive.first, entry.resource_id()); - EXPECT_EQ(drive.second, entry.base_name()); - EXPECT_TRUE(entry.file_info().is_directory()); - EXPECT_EQ("", entry.directory_specific_info().start_page_token()); - } -} - -// Tests that is we have existing team drives in local metadata, and we add -// new team drives from the server, that we retain the pre-existing local -// metadata. -TEST_F(TeamDriveListLoaderTest, RetainExistingMetadata) { - const std::vector<std::pair<std::string, std::string>> new_team_drives = { - {"the3rdTeamDriveId", "The Third Team Drive"}, - {"the4thTeamDriveId", "The Forth Team Drive"}, - }; - - const std::vector<std::pair<std::string, std::string>> old_team_drives = { - {"the1stTeamDriveId", "The First Team Drive"}, - {"the2ndTeamDriveId", "The Second Team Drive"}, - }; - - for (const auto& drive : old_team_drives) { - drive_service_->AddTeamDrive(drive.first, drive.second); - } - - for (const auto& drive : new_team_drives) { - drive_service_->AddTeamDrive(drive.first, drive.second); - } - - std::string root_local_id; - ASSERT_EQ(FILE_ERROR_OK, - metadata_->GetIdByPath(util::GetDriveTeamDrivesRootPath(), - &root_local_id)); - - for (const auto& drive : old_team_drives) { - std::string local_id; - ASSERT_EQ(FILE_ERROR_OK, - metadata_->AddEntry(CreateDirectoryEntryWithResourceId( - drive.second, drive.first, root_local_id), - &local_id)); - } - - FileError error = FILE_ERROR_FAILED; - team_drive_list_loader_->CheckForUpdates( - google_apis::test_util::CreateCopyResultCallback(&error)); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - EXPECT_EQ(1, drive_service_->team_drive_list_load_count()); - - EXPECT_EQ(old_team_drives.size() + new_team_drives.size(), - team_drive_list_observer_->team_drives_list().size()); - EXPECT_EQ(new_team_drives.size(), - team_drive_list_observer_->added_team_drives().size()); - EXPECT_TRUE(team_drive_list_observer_->removed_team_drives().empty()); - - ResourceEntryVector entries; - EXPECT_EQ(FILE_ERROR_OK, metadata_->ReadDirectoryByPath( - util::GetDriveTeamDrivesRootPath(), &entries)); - EXPECT_EQ(new_team_drives.size() + old_team_drives.size(), entries.size()); - - ResourceEntry entry; - for (const auto& drive : new_team_drives) { - EXPECT_EQ(FILE_ERROR_OK, - metadata_->GetResourceEntryByPath( - util::GetDriveTeamDrivesRootPath().AppendASCII(drive.second), - &entry)); - EXPECT_EQ(drive.first, entry.resource_id()); - EXPECT_EQ(drive.second, entry.base_name()); - EXPECT_TRUE(entry.file_info().is_directory()); - EXPECT_EQ("", entry.directory_specific_info().start_page_token()); - } - - for (const auto& drive : old_team_drives) { - EXPECT_EQ(FILE_ERROR_OK, - metadata_->GetResourceEntryByPath( - util::GetDriveTeamDrivesRootPath().AppendASCII(drive.second), - &entry)); - EXPECT_EQ(drive.first, entry.resource_id()); - EXPECT_EQ(drive.second, entry.base_name()); - EXPECT_TRUE(entry.file_info().is_directory()); - EXPECT_EQ(kTestStartPageToken, - entry.directory_specific_info().start_page_token()); - } -} - -// Tests that if we we had team drives stored locally that are no longer on the -// server that we deleted them correctly. -TEST_F(TeamDriveListLoaderTest, RemoveMissingTeamDriveFromMetadata) { - const std::vector<std::pair<std::string, std::string>> old_team_drives = { - {"the1stTeamDriveId", "The First Team Drive"}, - {"the2ndTeamDriveId", "The Second Team Drive"}, - }; - - std::string root_local_id; - ASSERT_EQ(FILE_ERROR_OK, - metadata_->GetIdByPath(util::GetDriveTeamDrivesRootPath(), - &root_local_id)); - - for (const auto& drive : old_team_drives) { - std::string local_id; - ASSERT_EQ(FILE_ERROR_OK, - metadata_->AddEntry(CreateDirectoryEntryWithResourceId( - drive.second, drive.first, root_local_id), - &local_id)); - } - - FileError error = FILE_ERROR_FAILED; - team_drive_list_loader_->CheckForUpdates( - google_apis::test_util::CreateCopyResultCallback(&error)); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(FILE_ERROR_OK, error); - EXPECT_EQ(1, drive_service_->team_drive_list_load_count()); - - EXPECT_TRUE(team_drive_list_observer_->team_drives_list().empty()); - EXPECT_TRUE(team_drive_list_observer_->added_team_drives().empty()); - EXPECT_EQ(old_team_drives.size(), - team_drive_list_observer_->removed_team_drives().size()); - - ResourceEntry entry; - for (const auto& drive : old_team_drives) { - EXPECT_EQ(FILE_ERROR_NOT_FOUND, - metadata_->GetResourceEntryByPath( - util::GetDriveTeamDrivesRootPath().AppendASCII(drive.second), - &entry)); - } -} - -} // namespace internal -} // namespace drive
diff --git a/components/exo/text_input.cc b/components/exo/text_input.cc index 1ff8822..d004a1f 100644 --- a/components/exo/text_input.cc +++ b/components/exo/text_input.cc
@@ -119,7 +119,12 @@ delegate_->SetCompositionText(composition); } -void TextInput::ConfirmCompositionText() { +void TextInput::ConfirmCompositionText(bool keep_selection) { + // TODO(b/134473433) Modify this function so that when keep_selection is + // true, the selection is not changed when text committed + if (keep_selection) { + NOTIMPLEMENTED_LOG_ONCE(); + } delegate_->Commit(composition_.text); }
diff --git a/components/exo/text_input.h b/components/exo/text_input.h index 25ba6e9..cbdc7a2b 100644 --- a/components/exo/text_input.h +++ b/components/exo/text_input.h
@@ -105,7 +105,7 @@ // ui::TextInputClient: void SetCompositionText(const ui::CompositionText& composition) override; - void ConfirmCompositionText() override; + void ConfirmCompositionText(bool keep_selection) override; void ClearCompositionText() override; void InsertText(const base::string16& text) override; void InsertChar(const ui::KeyEvent& event) override;
diff --git a/components/exo/text_input_unittest.cc b/components/exo/text_input_unittest.cc index f357f38..88f3c38 100644 --- a/components/exo/text_input_unittest.cc +++ b/components/exo/text_input_unittest.cc
@@ -250,7 +250,7 @@ SetCompositionText("composition"); EXPECT_CALL(*delegate(), Commit(base::UTF8ToUTF16("composition"))).Times(1); - text_input()->ConfirmCompositionText(); + text_input()->ConfirmCompositionText(/** keep_selection */ false); } TEST_F(TextInputTest, Commit) {
diff --git a/components/omnibox/browser/omnibox_edit_model.cc b/components/omnibox/browser/omnibox_edit_model.cc index 3c965a8..88a12982 100644 --- a/components/omnibox/browser/omnibox_edit_model.cc +++ b/components/omnibox/browser/omnibox_edit_model.cc
@@ -1475,6 +1475,10 @@ const char OmniboxEditModel::kCutOrCopyAllTextHistogram[] = "Omnibox.CutOrCopyAllText"; +void OmniboxEditModel::SetAccessibilityLabel(const AutocompleteMatch& match) { + view_->SetAccessibilityLabel(view_->GetText(), match); +} + bool OmniboxEditModel::PopupIsOpen() const { return popup_model() && popup_model()->IsOpen(); }
diff --git a/components/omnibox/browser/omnibox_edit_model.h b/components/omnibox/browser/omnibox_edit_model.h index b54dc4e..65b5447 100644 --- a/components/omnibox/browser/omnibox_edit_model.h +++ b/components/omnibox/browser/omnibox_edit_model.h
@@ -385,7 +385,8 @@ // Name of the histogram tracking cut or copy omnibox commands. static const char kCutOrCopyAllTextHistogram[]; - OmniboxView* view() { return view_; } + // Just forwards the call to the OmniboxView referred within. + void SetAccessibilityLabel(const AutocompleteMatch& match); private: friend class OmniboxControllerTest;
diff --git a/components/omnibox/browser/omnibox_popup_model.cc b/components/omnibox/browser/omnibox_popup_model.cc index b4ee988..1acef07 100644 --- a/components/omnibox/browser/omnibox_popup_model.cc +++ b/components/omnibox/browser/omnibox_popup_model.cc
@@ -195,8 +195,7 @@ view_->InvalidateLine(selected_line_); if (state == BUTTON_FOCUSED) { - edit_model_->view()->SetAccessibilityLabel(edit_model_->view()->GetText(), - match); + edit_model_->SetAccessibilityLabel(match); view_->ProvideButtonFocusHint(selected_line_); } }
diff --git a/components/optimization_guide/optimization_guide_enums.h b/components/optimization_guide/optimization_guide_enums.h index 89ee8e3..88d1eb73 100644 --- a/components/optimization_guide/optimization_guide_enums.h +++ b/components/optimization_guide/optimization_guide_enums.h
@@ -40,9 +40,13 @@ kNoHintAvailable, // The OptimizationGuideDecider was not initialized yet. kDeciderNotInitialized, + // A fetch to get the hint for the page load from the remote Optimization + // Guide Service was started, but was not available in time to make a + // decision. + kHintFetchStartedButNotAvailableInTime, // Add new values above this line. - kMaxValue = kDeciderNotInitialized, + kMaxValue = kHintFetchStartedButNotAvailableInTime, }; // The types of decisions that can be made for an optimization target.
diff --git a/components/password_manager/core/browser/login_database.cc b/components/password_manager/core/browser/login_database.cc index cada731..26f7f1b 100644 --- a/components/password_manager/core/browser/login_database.cc +++ b/components/password_manager/core/browser/login_database.cc
@@ -144,6 +144,7 @@ MIGRATION_ERROR, COMMIT_TRANSACTION_ERROR, INIT_LEAKED_CREDENTIALS_ERROR, + INIT_FIELD_INFO_ERROR, DATABASE_INIT_ERROR_COUNT, }; @@ -774,6 +775,7 @@ stats_table_.Init(&db_); leaked_credentials_table_.Init(&db_); + field_info_table_.Init(&db_); int current_version = meta_table_.GetVersionNumber(); bool migration_success = FixVersionIfNeeded(&db_, ¤t_version); @@ -820,6 +822,14 @@ return false; } + if (!field_info_table_.CreateTableIfNecessary()) { + LogDatabaseInitError(INIT_FIELD_INFO_ERROR); + LOG(ERROR) << "Unable to create the field info table."; + transaction.Rollback(); + db_.Close(); + return false; + } + if (!transaction.Commit()) { LogDatabaseInitError(COMMIT_TRANSACTION_ERROR); LOG(ERROR) << "Unable to commit a transaction.";
diff --git a/components/password_manager/core/browser/login_database.h b/components/password_manager/core/browser/login_database.h index e2c73b9..5f5065c 100644 --- a/components/password_manager/core/browser/login_database.h +++ b/components/password_manager/core/browser/login_database.h
@@ -17,6 +17,7 @@ #include "base/util/type_safety/strong_alias.h" #include "build/build_config.h" #include "components/password_manager/core/browser/compromised_credentials_table.h" +#include "components/password_manager/core/browser/field_info_table.h" #include "components/password_manager/core/browser/password_store.h" #include "components/password_manager/core/browser/password_store_change.h" #include "components/password_manager/core/browser/password_store_sync.h" @@ -209,6 +210,8 @@ return leaked_credentials_table_; } + FieldInfoTable& field_info_table() { return field_info_table_; } + #if defined(OS_POSIX) && !defined(OS_MACOSX) void enable_encryption() { use_encryption_ = true; } // This instance should not encrypt/decrypt password values using OSCrypt. @@ -323,6 +326,7 @@ sql::MetaTable meta_table_; StatisticsTable stats_table_; LeakedCredentialsTable leaked_credentials_table_; + FieldInfoTable field_info_table_; // These cached strings are used to build SQL statements. std::string add_statement_;
diff --git a/components/password_manager/core/browser/mock_password_store.h b/components/password_manager/core/browser/mock_password_store.h index 7f673f05..1d86ce0 100644 --- a/components/password_manager/core/browser/mock_password_store.h +++ b/components/password_manager/core/browser/mock_password_store.h
@@ -11,6 +11,7 @@ #include "components/autofill/core/common/password_form.h" #include "components/password_manager/core/browser/compromised_credentials_table.h" +#include "components/password_manager/core/browser/field_info_table.h" #include "components/password_manager/core/browser/password_store.h" #include "components/password_manager/core/browser/statistics_table.h" #include "testing/gmock/include/gmock/gmock.h" @@ -80,6 +81,10 @@ void(const base::RepeatingCallback<bool(const GURL&)>&, base::Time, base::Time)); + MOCK_METHOD1(AddFieldInfoImpl, void(const FieldInfo&)); + MOCK_METHOD0(GetAllFieldInfoImpl, std::vector<FieldInfo>()); + MOCK_METHOD2(RemoveFieldInfoByTimeImpl, void(base::Time, base::Time)); + MOCK_CONST_METHOD0(IsAbleToSavePasswords, bool()); #if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
diff --git a/components/password_manager/core/browser/password_form_manager.cc b/components/password_manager/core/browser/password_form_manager.cc index 82ce861..af5f94e 100644 --- a/components/password_manager/core/browser/password_form_manager.cc +++ b/components/password_manager/core/browser/password_form_manager.cc
@@ -941,8 +941,7 @@ is_new_login_ = true; // No stored credentials can be matched to the submitted form. Offer to // save new credentials. - CreatePendingCredentialsForNewCredentials(*parsed_submitted_form_, - password_to_save.second); + CreatePendingCredentialsForNewCredentials(password_to_save.second); // Generate username correction votes. bool username_correction_found = votes_uploader_.FindCorrectedUsernameElement( @@ -989,28 +988,14 @@ } void PasswordFormManager::CreatePendingCredentialsForNewCredentials( - const PasswordForm& submitted_password_form, const base::string16& password_element) { if (IsHttpAuth() || IsCredentialAPISave()) { - pending_credentials_ = submitted_password_form; + pending_credentials_ = *parsed_submitted_form_; return; } - // TODO(https://crbug.com/831123): Replace parsing of the observed form with - // usage of already parsed submitted form. - std::unique_ptr<PasswordForm> parsed_observed_form = - ParseFormAndMakeLogging(observed_form_, FormDataParser::Mode::kFilling); - if (!parsed_observed_form) - return; - pending_credentials_ = *parsed_observed_form; - pending_credentials_.username_element = - submitted_password_form.username_element; - pending_credentials_.username_value = submitted_password_form.username_value; - pending_credentials_.all_possible_usernames = - submitted_password_form.all_possible_usernames; - pending_credentials_.all_possible_passwords = - submitted_password_form.all_possible_passwords; - + pending_credentials_ = *parsed_submitted_form_; + pending_credentials_.form_data = observed_form_; // The password value will be filled in later, remove any garbage for now. pending_credentials_.password_value.clear(); // The password element should be determined earlier in |PasswordToSave|.
diff --git a/components/password_manager/core/browser/password_form_manager.h b/components/password_manager/core/browser/password_form_manager.h index b7a64df..1522780 100644 --- a/components/password_manager/core/browser/password_form_manager.h +++ b/components/password_manager/core/browser/password_form_manager.h
@@ -242,9 +242,8 @@ void ReportTimeBetweenStoreAndServerUMA(); // Create pending credentials from provisionally saved form when this form - // represents credentials that were not previosly saved. + // represents credentials that were not previously saved. void CreatePendingCredentialsForNewCredentials( - const autofill::PasswordForm& submitted_password_form, const base::string16& password_element); void SetPasswordOverridden(bool password_overridden) {
diff --git a/components/password_manager/core/browser/password_store.cc b/components/password_manager/core/browser/password_store.cc index a6cc833..37625a2f 100644 --- a/components/password_manager/core/browser/password_store.cc +++ b/components/password_manager/core/browser/password_store.cc
@@ -25,6 +25,7 @@ #include "components/autofill/core/common/password_form.h" #include "components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h" #include "components/password_manager/core/browser/compromised_credentials_table.h" +#include "components/password_manager/core/browser/field_info_table.h" #include "components/password_manager/core/browser/password_leak_history_consumer.h" #include "components/password_manager/core/browser/password_manager_metrics_util.h" #include "components/password_manager/core/browser/password_manager_util.h" @@ -371,6 +372,32 @@ std::move(url_filter), remove_begin, remove_end, std::move(completion))); } +void PasswordStore::AddFieldInfo(const FieldInfo& field_info) { + DCHECK(main_task_runner_->RunsTasksInCurrentSequence()); + ScheduleTask( + base::BindOnce(&PasswordStore::AddFieldInfoImpl, this, field_info)); +} + +void PasswordStore::GetAllFieldInfo(PasswordStoreConsumer* consumer) { + DCHECK(main_task_runner_->RunsTasksInCurrentSequence()); + auto get_all_field_info_task = + base::BindOnce(&PasswordStore::GetAllFieldInfoImpl, this); + consumer->cancelable_task_tracker()->PostTaskAndReplyWithResult( + background_task_runner_.get(), FROM_HERE, + std::move(get_all_field_info_task), + base::BindOnce(&PasswordStoreConsumer::OnGetAllFieldInfo, + consumer->GetWeakPtr())); +} + +void PasswordStore::RemoveFieldInfoByTime(base::Time remove_begin, + base::Time remove_end, + base::OnceClosure completion) { + DCHECK(main_task_runner_->RunsTasksInCurrentSequence()); + ScheduleTask(base::BindOnce(&PasswordStore::RemoveFieldInfoByTimeInternal, + this, remove_begin, remove_end, + std::move(completion))); +} + void PasswordStore::AddObserver(Observer* observer) { observers_->AddObserver(observer); } @@ -871,6 +898,15 @@ main_task_runner_->PostTask(FROM_HERE, std::move(completion)); } +void PasswordStore::RemoveFieldInfoByTimeInternal( + base::Time remove_begin, + base::Time remove_end, + base::OnceClosure completion) { + RemoveFieldInfoByTimeImpl(remove_begin, remove_end); + if (!completion.is_null()) + main_task_runner_->PostTask(FROM_HERE, std::move(completion)); +} + std::vector<std::unique_ptr<autofill::PasswordForm>> PasswordStore::GetLoginsImpl(const FormDigest& form) { DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
diff --git a/components/password_manager/core/browser/password_store.h b/components/password_manager/core/browser/password_store.h index 3e1a077..639ceb1 100644 --- a/components/password_manager/core/browser/password_store.h +++ b/components/password_manager/core/browser/password_store.h
@@ -58,6 +58,7 @@ class PasswordStoreSigninNotifier; class PasswordSyncableService; class PasswordSyncBridge; +struct FieldInfo; struct InteractionsStats; struct LeakedCredentials; @@ -264,6 +265,21 @@ base::Time remove_end, base::OnceClosure completion); + // Adds information about field. If the record for given form_signature and + // field_signature already exists, the new one will be ignored. + void AddFieldInfo(const FieldInfo& field_info); + + // Retrieves all field info and notifies |consumer| on completion. The request + // will be cancelled if the consumer is destroyed. + void GetAllFieldInfo(PasswordStoreConsumer* consumer); + + // Removes all leaked credentials in the given date range. If |completion| is + // not null, it will be posted to the |main_task_runner_| after deletions have + // been completed. Should be called on the UI thread. + void RemoveFieldInfoByTime(base::Time remove_begin, + base::Time remove_end, + base::OnceClosure completion); + // Adds an observer to be notified when the password store data changes. void AddObserver(Observer* observer); @@ -469,6 +485,13 @@ base::Time remove_begin, base::Time remove_end) = 0; + // Synchronous implementation for manipulating with information about field + // info. + virtual void AddFieldInfoImpl(const FieldInfo& field_info) = 0; + virtual std::vector<FieldInfo> GetAllFieldInfoImpl() = 0; + virtual void RemoveFieldInfoByTimeImpl(base::Time remove_begin, + base::Time remove_end) = 0; + // PasswordStoreSync: PasswordStoreChangeList AddLoginSync(const autofill::PasswordForm& form, AddLoginError* error) override; @@ -613,6 +636,10 @@ base::Time remove_end, base::OnceClosure completion); + void RemoveFieldInfoByTimeInternal(base::Time remove_begin, + base::Time remove_end, + base::OnceClosure completion); + // Finds all PasswordForms with a signon_realm that is equal to, or is a // PSL-match to that of |form|, and takes care of notifying the consumer with // the results when done.
diff --git a/components/password_manager/core/browser/password_store_consumer.cc b/components/password_manager/core/browser/password_store_consumer.cc index 2a9904b..e4e4d4b 100644 --- a/components/password_manager/core/browser/password_store_consumer.cc +++ b/components/password_manager/core/browser/password_store_consumer.cc
@@ -4,18 +4,21 @@ #include "components/password_manager/core/browser/password_store_consumer.h" +#include "components/password_manager/core/browser/field_info_table.h" #include "components/password_manager/core/browser/statistics_table.h" namespace password_manager { -PasswordStoreConsumer::PasswordStoreConsumer() {} +PasswordStoreConsumer::PasswordStoreConsumer() = default; -PasswordStoreConsumer::~PasswordStoreConsumer() { -} +PasswordStoreConsumer::~PasswordStoreConsumer() = default; void PasswordStoreConsumer::OnGetSiteStatistics( std::vector<InteractionsStats> stats) {} +void PasswordStoreConsumer::OnGetAllFieldInfo( + std::vector<FieldInfo> field_info) {} + void PasswordStoreConsumer::CancelAllRequests() { cancelable_task_tracker_.TryCancelAll(); weak_ptr_factory_.InvalidateWeakPtrs();
diff --git a/components/password_manager/core/browser/password_store_consumer.h b/components/password_manager/core/browser/password_store_consumer.h index 14b70dd..5e8e25d 100644 --- a/components/password_manager/core/browser/password_store_consumer.h +++ b/components/password_manager/core/browser/password_store_consumer.h
@@ -16,6 +16,7 @@ namespace password_manager { +struct FieldInfo; struct InteractionsStats; // Reads from the PasswordStore are done asynchronously on a separate @@ -32,10 +33,14 @@ virtual void OnGetPasswordStoreResults( std::vector<std::unique_ptr<autofill::PasswordForm>> results) = 0; - // Called when the GetLogins() request is finished, with the associated site - // statistics. + // Called when the GetSiteStats() request is finished, with the associated + // site statistics. virtual void OnGetSiteStatistics(std::vector<InteractionsStats> stats); + // Called when the GetAllFieldInfo() request is finished, with the associated + // field info. + virtual void OnGetAllFieldInfo(std::vector<FieldInfo> field_info); + // The base::CancelableTaskTracker can be used for cancelling the // tasks associated with the consumer. base::CancelableTaskTracker* cancelable_task_tracker() {
diff --git a/components/password_manager/core/browser/password_store_default.cc b/components/password_manager/core/browser/password_store_default.cc index c37b5cf..369266c 100644 --- a/components/password_manager/core/browser/password_store_default.cc +++ b/components/password_manager/core/browser/password_store_default.cc
@@ -254,6 +254,22 @@ } } +void PasswordStoreDefault::AddFieldInfoImpl(const FieldInfo& field_info) { + if (login_db_) + login_db_->field_info_table().AddRow(field_info); +} + +std::vector<FieldInfo> PasswordStoreDefault::GetAllFieldInfoImpl() { + return login_db_ ? login_db_->field_info_table().GetAllRows() + : std::vector<FieldInfo>(); +} + +void PasswordStoreDefault::RemoveFieldInfoByTimeImpl(base::Time remove_begin, + base::Time remove_end) { + if (login_db_) + login_db_->field_info_table().RemoveRowsByTime(remove_begin, remove_end); +} + bool PasswordStoreDefault::BeginTransaction() { if (login_db_) return login_db_->BeginTransaction();
diff --git a/components/password_manager/core/browser/password_store_default.h b/components/password_manager/core/browser/password_store_default.h index b48f8ee8..ce3b18f 100644 --- a/components/password_manager/core/browser/password_store_default.h +++ b/components/password_manager/core/browser/password_store_default.h
@@ -82,6 +82,11 @@ base::Time remove_begin, base::Time remove_end) override; + void AddFieldInfoImpl(const FieldInfo& field_info) override; + std::vector<FieldInfo> GetAllFieldInfoImpl() override; + void RemoveFieldInfoByTimeImpl(base::Time remove_begin, + base::Time remove_end) override; + // Implements PasswordStoreSync interface. bool BeginTransaction() override; void RollbackTransaction() override;
diff --git a/components/password_manager/core/browser/password_store_unittest.cc b/components/password_manager/core/browser/password_store_unittest.cc index 1326f1a..c23bdf7c 100644 --- a/components/password_manager/core/browser/password_store_unittest.cc +++ b/components/password_manager/core/browser/password_store_unittest.cc
@@ -92,6 +92,7 @@ MOCK_METHOD1(OnGetPasswordStoreResultsConstRef, void(const std::vector<std::unique_ptr<PasswordForm>>&)); + MOCK_METHOD1(OnGetAllFieldInfo, void(const std::vector<FieldInfo>)); // GMock cannot mock methods with move-only args. void OnGetPasswordStoreResults( @@ -1246,6 +1247,7 @@ GaiaPasswordHashChange::NOT_SYNC_PASSWORD_CHANGE, 1); store->ShutdownOnUIThread(); } +#endif TEST_F(PasswordStoreTest, GetAllLeakedCredentials) { LeakedCredentials leaked_credentials(GURL("https://example.com"), @@ -1315,6 +1317,57 @@ store->ShutdownOnUIThread(); } -#endif +TEST_F(PasswordStoreTest, GetAllFieldInfo) { + FieldInfo field_info1{1001 /*form_signature*/, 1 /* field_signature */, + autofill::USERNAME, base::Time::FromTimeT(1)}; + FieldInfo field_info2{1002 /*form_signature*/, 10 /* field_signature */, + autofill::PASSWORD, base::Time::FromTimeT(2)}; + scoped_refptr<PasswordStoreDefault> store = CreatePasswordStore(); + store->Init(syncer::SyncableService::StartSyncFlare(), nullptr); + + store->AddFieldInfo(field_info1); + store->AddFieldInfo(field_info2); + MockPasswordStoreConsumer consumer; + EXPECT_CALL(consumer, OnGetAllFieldInfo( + UnorderedElementsAre(field_info1, field_info2))); + store->GetAllFieldInfo(&consumer); + WaitForPasswordStore(); + + store->ShutdownOnUIThread(); +} + +TEST_F(PasswordStoreTest, RemoveFieldInfo) { + FieldInfo field_info1{1001 /*form_signature*/, 1 /* field_signature */, + autofill::USERNAME, base::Time::FromTimeT(100)}; + FieldInfo field_info2{1002 /*form_signature*/, 10 /* field_signature */, + autofill::PASSWORD, base::Time::FromTimeT(200)}; + + FieldInfo field_info3{1003 /*form_signature*/, 11 /* field_signature */, + autofill::PASSWORD, base::Time::FromTimeT(300)}; + + scoped_refptr<PasswordStoreDefault> store = CreatePasswordStore(); + store->Init(syncer::SyncableService::StartSyncFlare(), nullptr); + + store->AddFieldInfo(field_info1); + store->AddFieldInfo(field_info2); + store->AddFieldInfo(field_info3); + + MockPasswordStoreConsumer consumer; + EXPECT_CALL(consumer, OnGetAllFieldInfo(UnorderedElementsAre( + field_info1, field_info2, field_info3))); + store->GetAllFieldInfo(&consumer); + WaitForPasswordStore(); + testing::Mock::VerifyAndClearExpectations(&consumer); + + store->RemoveFieldInfoByTime(base::Time::FromTimeT(150), + base::Time::FromTimeT(250), base::Closure()); + + EXPECT_CALL(consumer, OnGetAllFieldInfo( + UnorderedElementsAre(field_info1, field_info3))); + store->GetAllFieldInfo(&consumer); + WaitForPasswordStore(); + + store->ShutdownOnUIThread(); +} } // namespace password_manager
diff --git a/components/password_manager/core/browser/test_password_store.cc b/components/password_manager/core/browser/test_password_store.cc index 872c8a8..3ac548e 100644 --- a/components/password_manager/core/browser/test_password_store.cc +++ b/components/password_manager/core/browser/test_password_store.cc
@@ -249,6 +249,19 @@ NOTIMPLEMENTED(); } +void TestPasswordStore::AddFieldInfoImpl(const FieldInfo& field_info) { + NOTIMPLEMENTED(); +} +std::vector<FieldInfo> TestPasswordStore::GetAllFieldInfoImpl() { + NOTIMPLEMENTED(); + return std::vector<FieldInfo>(); +} + +void TestPasswordStore::RemoveFieldInfoByTimeImpl(base::Time remove_begin, + base::Time remove_end) { + NOTIMPLEMENTED(); +} + bool TestPasswordStore::BeginTransaction() { return true; }
diff --git a/components/password_manager/core/browser/test_password_store.h b/components/password_manager/core/browser/test_password_store.h index 53cb38e..2ec2c8c1 100644 --- a/components/password_manager/core/browser/test_password_store.h +++ b/components/password_manager/core/browser/test_password_store.h
@@ -94,6 +94,10 @@ const base::RepeatingCallback<bool(const GURL&)>& url_filter, base::Time remove_begin, base::Time remove_end) override; + void AddFieldInfoImpl(const FieldInfo& field_info) override; + std::vector<FieldInfo> GetAllFieldInfoImpl() override; + void RemoveFieldInfoByTimeImpl(base::Time remove_begin, + base::Time remove_end) override; // PasswordStoreSync interface. bool BeginTransaction() override;
diff --git a/components/signin/internal/identity_manager/ubertoken_fetcher_impl.cc b/components/signin/internal/identity_manager/ubertoken_fetcher_impl.cc index bc5b9f19..3053e34b 100644 --- a/components/signin/internal/identity_manager/ubertoken_fetcher_impl.cc +++ b/components/signin/internal/identity_manager/ubertoken_fetcher_impl.cc
@@ -34,28 +34,24 @@ ProfileOAuth2TokenService* token_service, CompletionCallback ubertoken_callback, gaia::GaiaSource source, - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, - bool is_bound_to_channel_id) + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) : UbertokenFetcherImpl(account_id, /*access_token=*/"", token_service, std::move(ubertoken_callback), base::BindRepeating(CreateGaiaAuthFetcher, source, - url_loader_factory), - is_bound_to_channel_id) {} + url_loader_factory)) {} UbertokenFetcherImpl::UbertokenFetcherImpl( const CoreAccountId& account_id, const std::string& access_token, ProfileOAuth2TokenService* token_service, CompletionCallback ubertoken_callback, - GaiaAuthFetcherFactory factory, - bool is_bound_to_channel_id) + GaiaAuthFetcherFactory factory) : OAuth2AccessTokenManager::Consumer("uber_token_fetcher"), token_service_(token_service), ubertoken_callback_(std::move(ubertoken_callback)), - is_bound_to_channel_id_(is_bound_to_channel_id), gaia_auth_fetcher_factory_(factory), account_id_(account_id), access_token_(access_token), @@ -146,8 +142,7 @@ void UbertokenFetcherImpl::ExchangeTokens() { gaia_auth_fetcher_ = gaia_auth_fetcher_factory_.Run(this); - gaia_auth_fetcher_->StartTokenFetchForUberAuthExchange( - access_token_, is_bound_to_channel_id_); + gaia_auth_fetcher_->StartTokenFetchForUberAuthExchange(access_token_); } } // namespace signin
diff --git a/components/signin/internal/identity_manager/ubertoken_fetcher_impl.h b/components/signin/internal/identity_manager/ubertoken_fetcher_impl.h index 8f38c5d..59247e8 100644 --- a/components/signin/internal/identity_manager/ubertoken_fetcher_impl.h +++ b/components/signin/internal/identity_manager/ubertoken_fetcher_impl.h
@@ -55,16 +55,14 @@ ProfileOAuth2TokenService* token_service, CompletionCallback ubertoken_callback, gaia::GaiaSource source, - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, - bool is_bound_to_channel_id = true); + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory); // Constructs an instance and starts fetching the ubertoken for |account_id|. UbertokenFetcherImpl(const CoreAccountId& account_id, const std::string& access_token, ProfileOAuth2TokenService* token_service, CompletionCallback ubertoken_callback, - GaiaAuthFetcherFactory factory, - bool is_bound_to_channel_id = true); + GaiaAuthFetcherFactory factory); ~UbertokenFetcherImpl() override; // Overridden from GaiaAuthConsumer @@ -87,7 +85,6 @@ ProfileOAuth2TokenService* token_service_; CompletionCallback ubertoken_callback_; - bool is_bound_to_channel_id_; // defaults to true GaiaAuthFetcherFactory gaia_auth_fetcher_factory_; std::unique_ptr<GaiaAuthFetcher> gaia_auth_fetcher_; std::unique_ptr<OAuth2AccessTokenManager::Request> access_token_request_;
diff --git a/components/signin/public/identity_manager/identity_manager.cc b/components/signin/public/identity_manager/identity_manager.cc index 97612ba..8990fc2 100644 --- a/components/signin/public/identity_manager/identity_manager.cc +++ b/components/signin/public/identity_manager/identity_manager.cc
@@ -296,11 +296,10 @@ const CoreAccountId& account_id, UbertokenFetcher::CompletionCallback callback, gaia::GaiaSource source, - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, - bool bount_to_channel_id) { + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) { return std::make_unique<UbertokenFetcherImpl>( account_id, token_service_.get(), std::move(callback), source, - url_loader_factory, bount_to_channel_id); + url_loader_factory); } AccountsInCookieJarInfo IdentityManager::GetAccountsInCookieJar() const {
diff --git a/components/signin/public/identity_manager/identity_manager.h b/components/signin/public/identity_manager/identity_manager.h index 4b30bc8..a3d9272 100644 --- a/components/signin/public/identity_manager/identity_manager.h +++ b/components/signin/public/identity_manager/identity_manager.h
@@ -295,8 +295,7 @@ const CoreAccountId& account_id, UbertokenFetcher::CompletionCallback callback, gaia::GaiaSource source, - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, - bool bound_to_channel_id = true); + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory); // Provides the information of all accounts that are present in the Gaia // cookie in the cookie jar, ordered by their order in the cookie.
diff --git a/components/sync/driver/syncable_service_based_model_type_controller.cc b/components/sync/driver/syncable_service_based_model_type_controller.cc index 4e90a70..324664d 100644 --- a/components/sync/driver/syncable_service_based_model_type_controller.cc +++ b/components/sync/driver/syncable_service_based_model_type_controller.cc
@@ -22,14 +22,13 @@ base::WeakPtr<SyncableService> syncable_service, const base::RepeatingClosure& dump_stack) : type_(type), - store_factory_(std::move(store_factory)), dump_stack_(dump_stack) { - DCHECK(store_factory_); + DCHECK(store_factory); // The |syncable_service| can be null in tests. if (syncable_service) { bridge_ = std::make_unique<SyncableServiceBasedBridge>( - type_, std::move(store_factory_), + type_, std::move(store_factory), std::make_unique<ClientTagBasedModelTypeProcessor>(type_, dump_stack_), syncable_service.get()); @@ -66,7 +65,6 @@ } const ModelType type_; - OnceModelTypeStoreFactory store_factory_; const base::RepeatingClosure dump_stack_; std::unique_ptr<ModelTypeSyncBridge> bridge_;
diff --git a/components/viz/host/host_gpu_memory_buffer_manager_unittest.cc b/components/viz/host/host_gpu_memory_buffer_manager_unittest.cc index e1bd0c6..f1d7ac7 100644 --- a/components/viz/host/host_gpu_memory_buffer_manager_unittest.cc +++ b/components/viz/host/host_gpu_memory_buffer_manager_unittest.cc
@@ -160,7 +160,7 @@ void WakeUpGpu() override {} - void GpuSwitched() override {} + void GpuSwitched(gl::GpuPreference active_gpu_heuristic) override {} void DestroyAllChannels() override {}
diff --git a/components/viz/service/gl/gpu_service_impl.cc b/components/viz/service/gl/gpu_service_impl.cc index 70b11ce..d38dfac5 100644 --- a/components/viz/service/gl/gpu_service_impl.cc +++ b/components/viz/service/gl/gpu_service_impl.cc
@@ -813,10 +813,11 @@ #endif } -void GpuServiceImpl::GpuSwitched() { +void GpuServiceImpl::GpuSwitched(gl::GpuPreference active_gpu_heuristic) { DVLOG(1) << "GPU: GPU has switched"; if (!in_host_process()) - ui::GpuSwitchingManager::GetInstance()->NotifyGpuSwitched(); + ui::GpuSwitchingManager::GetInstance()->NotifyGpuSwitched( + active_gpu_heuristic); } void GpuServiceImpl::DestroyAllChannels() {
diff --git a/components/viz/service/gl/gpu_service_impl.h b/components/viz/service/gl/gpu_service_impl.h index 7989adc..7919309 100644 --- a/components/viz/service/gl/gpu_service_impl.h +++ b/components/viz/service/gl/gpu_service_impl.h
@@ -166,7 +166,7 @@ const std::string& key, const std::string& data) override; void WakeUpGpu() override; - void GpuSwitched() override; + void GpuSwitched(gl::GpuPreference active_gpu_heuristic) override; void DestroyAllChannels() override; void OnBackgroundCleanup() override; void OnBackgrounded() override;
diff --git a/content/browser/accessibility/accessibility_win_browsertest.cc b/content/browser/accessibility/accessibility_win_browsertest.cc index d9cc53c..cd80daa 100644 --- a/content/browser/accessibility/accessibility_win_browsertest.cc +++ b/content/browser/accessibility/accessibility_win_browsertest.cc
@@ -3788,10 +3788,10 @@ BrowserAccessibilityComWin* browser_accessibility_com_win = ToBrowserAccessibilityWin(browser_accessibility)->GetCOM(); - CComPtr<IScrollProvider> scroll_provider; + Microsoft::WRL::ComPtr<IScrollProvider> scroll_provider; EXPECT_HRESULT_SUCCEEDED(browser_accessibility_com_win->GetPatternProvider( - UIA_ScrollPatternId, reinterpret_cast<IUnknown**>(&scroll_provider))); + UIA_ScrollPatternId, &scroll_provider)); if (expected.can_scroll_vertical || expected.can_scroll_horizontal) { ASSERT_NE(nullptr, scroll_provider);
diff --git a/content/browser/accessibility/ax_platform_node_textprovider_win_browsertest.cc b/content/browser/accessibility/ax_platform_node_textprovider_win_browsertest.cc index 2488119..48a76bc 100644 --- a/content/browser/accessibility/ax_platform_node_textprovider_win_browsertest.cc +++ b/content/browser/accessibility/ax_platform_node_textprovider_win_browsertest.cc
@@ -23,19 +23,18 @@ namespace content { -#define ASSERT_UIA_SAFEARRAY_OF_TEXTRANGEPROVIDER(safearray, expected_size) \ - { \ - EXPECT_EQ(sizeof(CComPtr<ITextRangeProvider>), \ - ::SafeArrayGetElemsize(safearray)); \ - ASSERT_EQ(1u, SafeArrayGetDim(safearray)); \ - LONG array_lower_bound; \ - ASSERT_HRESULT_SUCCEEDED( \ - SafeArrayGetLBound(safearray, 1, &array_lower_bound)); \ - LONG array_upper_bound; \ - ASSERT_HRESULT_SUCCEEDED( \ - SafeArrayGetUBound(safearray, 1, &array_upper_bound)); \ - size_t count = array_upper_bound - array_lower_bound + 1; \ - ASSERT_EQ(expected_size, count); \ +#define ASSERT_UIA_SAFEARRAY_OF_TEXTRANGEPROVIDER(safearray, expected_size) \ + { \ + EXPECT_EQ(sizeof(ITextRangeProvider*), ::SafeArrayGetElemsize(safearray)); \ + ASSERT_EQ(1u, SafeArrayGetDim(safearray)); \ + LONG array_lower_bound; \ + ASSERT_HRESULT_SUCCEEDED( \ + SafeArrayGetLBound(safearray, 1, &array_lower_bound)); \ + LONG array_upper_bound; \ + ASSERT_HRESULT_SUCCEEDED( \ + SafeArrayGetUBound(safearray, 1, &array_upper_bound)); \ + size_t count = array_upper_bound - array_lower_bound + 1; \ + ASSERT_EQ(expected_size, count); \ } #define EXPECT_UIA_TEXTRANGE_EQ(provider, expected_content) \ @@ -172,11 +171,11 @@ GetTextProviderFromTextNode(text_provider, node); base::win::ScopedSafearray text_provider_ranges; - CComPtr<ITextRangeProvider>* array_data; EXPECT_HRESULT_SUCCEEDED( text_provider->GetVisibleRanges(text_provider_ranges.Receive())); ASSERT_UIA_SAFEARRAY_OF_TEXTRANGEPROVIDER(text_provider_ranges.Get(), 2U); + ITextRangeProvider** array_data; ASSERT_HRESULT_SUCCEEDED(::SafeArrayAccessData( text_provider_ranges.Get(), reinterpret_cast<void**>(&array_data)));
diff --git a/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc b/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc index 53a2f94..5dccd2f 100644 --- a/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc +++ b/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc
@@ -260,7 +260,7 @@ ToBrowserAccessibilityWin(browser_accessibility_start)->GetCOM(); ASSERT_NE(nullptr, start_browser_accessibility_com_win); - CComPtr<ITextRangeProvider> text_range_provider = + ComPtr<ITextRangeProvider> text_range_provider = ui::AXPlatformNodeTextRangeProviderWin::CreateTextRangeProvider( start_browser_accessibility_com_win, std::move(start), std::move(end));
diff --git a/content/browser/accessibility/ax_platform_node_win_browsertest.cc b/content/browser/accessibility/ax_platform_node_win_browsertest.cc index bb2d610..c3004527f 100644 --- a/content/browser/accessibility/ax_platform_node_win_browsertest.cc +++ b/content/browser/accessibility/ax_platform_node_win_browsertest.cc
@@ -71,14 +71,15 @@ std::vector<std::string> names; for (LONG i = 0; i < size; ++i) { - CComPtr<IUnknown> unknown_element = nullptr; - ASSERT_HRESULT_SUCCEEDED(SafeArrayGetElement( - V_ARRAY(flows_from_variant.ptr()), &i, &unknown_element)); + ComPtr<IUnknown> unknown_element; + ASSERT_HRESULT_SUCCEEDED( + SafeArrayGetElement(V_ARRAY(flows_from_variant.ptr()), &i, + static_cast<void**>(&unknown_element))); ASSERT_NE(nullptr, unknown_element); - CComPtr<IRawElementProviderSimple> raw_element_provider_simple = nullptr; + ComPtr<IRawElementProviderSimple> raw_element_provider_simple = nullptr; ASSERT_HRESULT_SUCCEEDED( - unknown_element->QueryInterface(&raw_element_provider_simple)); + unknown_element.As(&raw_element_provider_simple)); ASSERT_NE(nullptr, raw_element_provider_simple); base::win::ScopedVariant name;
diff --git a/content/browser/appcache/appcache_subresource_url_factory.cc b/content/browser/appcache/appcache_subresource_url_factory.cc index 965f5cc..a62e806 100644 --- a/content/browser/appcache/appcache_subresource_url_factory.cc +++ b/content/browser/appcache/appcache_subresource_url_factory.cc
@@ -64,7 +64,6 @@ options_(options), traffic_annotation_(annotation), network_loader_factory_(std::move(network_loader_factory)), - local_client_binding_(this), host_(appcache_host) { DCHECK_CURRENTLY_ON(BrowserThread::UI); remote_receiver_.set_disconnect_handler(base::BindOnce( @@ -111,11 +110,11 @@ DCHECK(handler); // Disconnect from the network loader first. - local_client_binding_.Close(); + local_client_receiver_.reset(); network_loader_ = nullptr; network::mojom::URLLoaderClientPtr client_ptr; - local_client_binding_.Bind(mojo::MakeRequest(&client_ptr)); + local_client_receiver_.Bind(mojo::MakeRequest(&client_ptr)); std::move(handler).Run(request_, mojo::MakeRequest(&appcache_loader_), std::move(client_ptr)); } @@ -123,7 +122,7 @@ void CreateAndStartNetworkLoader() { DCHECK(!appcache_loader_); network::mojom::URLLoaderClientPtr client_ptr; - local_client_binding_.Bind(mojo::MakeRequest(&client_ptr)); + local_client_receiver_.Bind(mojo::MakeRequest(&client_ptr)); network_loader_factory_->CreateLoaderAndStart( mojo::MakeRequest(&network_loader_), routing_id_, request_id_, options_, request_, std::move(client_ptr), traffic_annotation_); @@ -309,9 +308,9 @@ // Core appcache logic that decides how to handle a request. std::unique_ptr<AppCacheRequestHandler> handler_; - // The local binding to either our network or appcache loader, + // The local receiver to either our network or appcache loader, // we only use one of them at any given time. - mojo::Binding<network::mojom::URLLoaderClient> local_client_binding_; + mojo::Receiver<network::mojom::URLLoaderClient> local_client_receiver_{this}; network::mojom::URLLoaderPtr network_loader_; network::mojom::URLLoaderPtr appcache_loader_;
diff --git a/content/browser/appcache/appcache_update_url_loader_request.cc b/content/browser/appcache/appcache_update_url_loader_request.cc index d4e65fa3..07657d8 100644 --- a/content/browser/appcache/appcache_update_url_loader_request.cc +++ b/content/browser/appcache/appcache_update_url_loader_request.cc
@@ -54,7 +54,7 @@ return; network::mojom::URLLoaderClientPtr client; - client_binding_.Bind(mojo::MakeRequest(&client)); + client_receiver_.Bind(mojo::MakeRequest(&client)); // The partition has shutdown, return without making the request. if (!partition_) @@ -123,7 +123,7 @@ } int AppCacheUpdateJob::UpdateURLLoaderRequest::Cancel() { - client_binding_.Close(); + client_receiver_.reset(); url_loader_ = nullptr; handle_watcher_.Cancel(); handle_.reset(); @@ -208,7 +208,6 @@ URLFetcher* fetcher) : fetcher_(fetcher), partition_(std::move(partition)), - client_binding_(this), buffer_size_(buffer_size), handle_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL,
diff --git a/content/browser/appcache/appcache_update_url_loader_request.h b/content/browser/appcache/appcache_update_url_loader_request.h index bb7fce0..1ed1cf4 100644 --- a/content/browser/appcache/appcache_update_url_loader_request.h +++ b/content/browser/appcache/appcache_update_url_loader_request.h
@@ -12,7 +12,7 @@ #include "base/macros.h" #include "content/browser/appcache/appcache_update_job.h" -#include "mojo/public/cpp/bindings/binding.h" +#include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/system/simple_watcher.h" #include "net/base/io_buffer.h" #include "services/network/public/cpp/net_adapters.h" @@ -122,7 +122,7 @@ // Response details. std::unique_ptr<net::HttpResponseInfo> http_response_info_; // Binds the URLLoaderClient interface to the channel. - mojo::Binding<network::mojom::URLLoaderClient> client_binding_; + mojo::Receiver<network::mojom::URLLoaderClient> client_receiver_{this}; // The network URL loader. network::mojom::URLLoaderPtr url_loader_; // Caller buffer size.
diff --git a/content/browser/back_forward_cache_browsertest.cc b/content/browser/back_forward_cache_browsertest.cc index f87e44f..adecb5d 100644 --- a/content/browser/back_forward_cache_browsertest.cc +++ b/content/browser/back_forward_cache_browsertest.cc
@@ -38,7 +38,10 @@ #include "net/dns/mock_host_resolver.h" #include "net/test/embedded_test_server/controllable_http_response.h" #include "net/test/embedded_test_server/embedded_test_server.h" +#include "services/device/public/cpp/test/fake_sensor_and_provider.h" #include "services/device/public/cpp/test/scoped_geolocation_overrider.h" +#include "services/device/public/mojom/constants.mojom.h" +#include "services/service_manager/public/cpp/service_binding.h" #include "testing/gmock/include/gmock/gmock.h" #include "third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h" @@ -3675,4 +3678,98 @@ EXPECT_EQ(web_contents()->GetThemeColor(), 0xFFFF0000u); } +class SensorBackForwardCacheBrowserTest : public BackForwardCacheBrowserTest { + protected: + SensorBackForwardCacheBrowserTest() { + service_manager::ServiceBinding::OverrideInterfaceBinderForTesting( + device::mojom::kServiceName, + base::BindRepeating( + &SensorBackForwardCacheBrowserTest::BindSensorProvider, + base::Unretained(this))); + } + + ~SensorBackForwardCacheBrowserTest() override { + service_manager::ServiceBinding::ClearInterfaceBinderOverrideForTesting< + device::mojom::SensorProvider>(device::mojom::kServiceName); + } + + void SetUpOnMainThread() override { + provider_ = std::make_unique<device::FakeSensorProvider>(); + provider_->SetAccelerometerData(1.0, 2.0, 3.0); + + BackForwardCacheBrowserTest::SetUpOnMainThread(); + } + + std::unique_ptr<device::FakeSensorProvider> provider_; + + private: + void BindSensorProvider( + mojo::PendingReceiver<device::mojom::SensorProvider> receiver) { + provider_->Bind(std::move(receiver)); + } +}; + +IN_PROC_BROWSER_TEST_F(SensorBackForwardCacheBrowserTest, + AccelerometerNotCached) { + ASSERT_TRUE(embedded_test_server()->Start()); + GURL url_a(embedded_test_server()->GetURL("/title1.html")); + GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html")); + + // 1) Navigate to A. + ASSERT_TRUE(NavigateToURL(shell(), url_a)); + RenderFrameHostImpl* rfh_a = current_frame_host(); + RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a); + + EXPECT_TRUE(ExecJs(rfh_a, R"( + new Promise(resolve => { + const sensor = new Accelerometer(); + sensor.addEventListener('reading', () => { resolve(); }); + sensor.start(); + }) + )")); + + // 2) Navigate to B. + ASSERT_TRUE(NavigateToURL(shell(), url_b)); + + // - Page A should not be in the cache. + delete_observer_rfh_a.WaitUntilDeleted(); + + // 3) Go back. + web_contents()->GetController().GoBack(); + EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); + ExpectNotRestored( + {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures}, + FROM_HERE); +} + +IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, WebMidiNotCached) { + ASSERT_TRUE(embedded_test_server()->Start()); + GURL url_a(embedded_test_server()->GetURL("/title1.html")); + GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html")); + + // 1) Navigate to A. + ASSERT_TRUE(NavigateToURL(shell(), url_a)); + RenderFrameHostImpl* rfh_a = current_frame_host(); + RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a); + + // - Wait until requestMIDIAccess() promise is resolved. + EXPECT_TRUE(ExecJs(rfh_a, "navigator.requestMIDIAccess()")); + + // 2) Navigate to B. + ASSERT_TRUE(NavigateToURL(shell(), url_b)); + + // - Page A should not be in the cache. + EXPECT_TRUE(delete_observer_rfh_a.deleted()); + + // 3) Go back. + web_contents()->GetController().GoBack(); + EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); + ExpectNotRestored( + {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures}, + FROM_HERE); + ExpectBlocklistedFeature( + blink::scheduler::WebSchedulerTrackedFeature::kRequestedMIDIPermission, + FROM_HERE); +} + } // namespace content
diff --git a/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc b/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc index 7238ee2..ba30c78 100644 --- a/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc +++ b/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc
@@ -534,10 +534,9 @@ } auto id = scheduler_->CreateId(); - // TODO: use priority scheduler_->ScheduleOperation( id, CacheStorageSchedulerMode::kShared, CacheStorageSchedulerOp::kMatch, - CacheStorageSchedulerPriority::kNormal, + priority, base::BindOnce( &LegacyCacheStorageCache::MatchImpl, weak_ptr_factory_.GetWeakPtr(), std::move(request), std::move(match_options), trace_id,
diff --git a/content/browser/devtools/devtools_url_loader_interceptor.cc b/content/browser/devtools/devtools_url_loader_interceptor.cc index 319246ad..e3d76f74 100644 --- a/content/browser/devtools/devtools_url_loader_interceptor.cc +++ b/content/browser/devtools/devtools_url_loader_interceptor.cc
@@ -373,7 +373,7 @@ std::unique_ptr<CreateLoaderParameters> create_loader_params_; const bool is_download_; - mojo::Binding<network::mojom::URLLoaderClient> client_binding_; + mojo::Receiver<network::mojom::URLLoaderClient> client_receiver_{this}; mojo::Receiver<network::mojom::URLLoader> loader_receiver_{this}; network::mojom::URLLoaderClientPtr client_; @@ -676,7 +676,6 @@ interceptor_(interceptor), create_loader_params_(std::move(create_loader_params)), is_download_(is_download), - client_binding_(this), client_(std::move(client)), target_factory_(std::move(target_factory)), cookie_manager_(std::move(cookie_manager)), @@ -785,7 +784,7 @@ if (!body_reader_) { body_reader_ = std::make_unique<BodyReader>(base::BindOnce( &InterceptionJob::ResponseBodyComplete, base::Unretained(this))); - client_binding_.ResumeIncomingMethodCallProcessing(); + client_receiver_.Resume(); loader_->ResumeReadingBodyFromNet(); } body_reader_->AddCallback(std::move(callback)); @@ -804,7 +803,7 @@ DCHECK(!!response_metadata_); state_ = State::kResponseTaken; pending_response_body_pipe_callback_ = std::move(callback); - client_binding_.ResumeIncomingMethodCallProcessing(); + client_receiver_.Resume(); loader_->ResumeReadingBodyFromNet(); } @@ -921,7 +920,7 @@ client_->OnReceiveResponse(response_metadata_->head); response_metadata_.reset(); loader_->ResumeReadingBodyFromNet(); - client_binding_.ResumeIncomingMethodCallProcessing(); + client_receiver_.Resume(); return Response::OK(); } @@ -1166,8 +1165,8 @@ state_ = State::kRequestSent; network::mojom::URLLoaderClientPtr loader_client; - client_binding_.Bind(MakeRequest(&loader_client)); - client_binding_.set_connection_error_handler( + client_receiver_.Bind(MakeRequest(&loader_client)); + client_receiver_.set_disconnect_handler( base::BindOnce(&InterceptionJob::Shutdown, base::Unretained(this))); target_factory_->CreateLoaderAndStart( @@ -1183,7 +1182,7 @@ void InterceptionJob::CancelRequest() { if (state_ == State::kNotStarted) return; - client_binding_.Close(); + client_receiver_.reset(); loader_.reset(); if (body_reader_) { body_reader_->CancelWithError( @@ -1348,7 +1347,7 @@ return; } loader_->PauseReadingBodyFromNet(); - client_binding_.PauseIncomingMethodCallProcessing(); + client_receiver_.Pause(); response_metadata_ = std::make_unique<ResponseMetadata>(head); @@ -1429,9 +1428,9 @@ return; } response_metadata_->status = status; - // No need to listen to the channel any more, so just close it, so if the pipe + // No need to listen to the channel any more, so just reset it, so if the pipe // is closed by the other end, |shutdown| isn't run. - client_binding_.Close(); + client_receiver_.reset(); loader_.reset(); }
diff --git a/content/browser/gpu/gpu_data_manager_impl.h b/content/browser/gpu/gpu_data_manager_impl.h index 9c20ae8..042edea 100644 --- a/content/browser/gpu/gpu_data_manager_impl.h +++ b/content/browser/gpu/gpu_data_manager_impl.h
@@ -117,7 +117,7 @@ // Returns a new copy of the ListValue. std::unique_ptr<base::ListValue> GetLogMessages() const; - // Called when switching gpu. + // Called when switching GPUs. void HandleGpuSwitch(); // Maintenance of domains requiring explicit user permission before
diff --git a/content/browser/gpu/gpu_data_manager_impl_private.cc b/content/browser/gpu/gpu_data_manager_impl_private.cc index 6101710..e85bea68 100644 --- a/content/browser/gpu/gpu_data_manager_impl_private.cc +++ b/content/browser/gpu/gpu_data_manager_impl_private.cc
@@ -57,6 +57,7 @@ #include "ui/gl/buildflags.h" #include "ui/gl/gl_implementation.h" #include "ui/gl/gl_switches.h" +#include "ui/gl/gpu_preference.h" #include "ui/gl/gpu_switching_manager.h" #if defined(OS_ANDROID) @@ -807,25 +808,36 @@ void GpuDataManagerImplPrivate::HandleGpuSwitch() { base::AutoUnlock unlock(owner_->lock_); // Notify observers in the browser process. - ui::GpuSwitchingManager::GetInstance()->NotifyGpuSwitched(); + ui::GpuSwitchingManager::GetInstance()->NotifyGpuSwitched( + active_gpu_heuristic_); // Pass the notification to the GPU process to notify observers there. - GpuProcessHost::CallOnIO(GPU_PROCESS_KIND_SANDBOXED, false /* force_create */, - base::BindOnce([](GpuProcessHost* host) { - if (host) - host->gpu_service()->GpuSwitched(); - })); + GpuProcessHost::CallOnIO( + GPU_PROCESS_KIND_SANDBOXED, false /* force_create */, + base::BindOnce( + [](gl::GpuPreference active_gpu, GpuProcessHost* host) { + if (host) + host->gpu_service()->GpuSwitched(active_gpu); + }, + active_gpu_heuristic_)); } bool GpuDataManagerImplPrivate::UpdateActiveGpu(uint32_t vendor_id, uint32_t device_id) { + // Heuristics for dual-GPU detection. + bool is_dual_gpu = gpu_info_.secondary_gpus.size() == 1; + const uint32_t kIntelID = 0x8086; + bool saw_intel_gpu = false; + bool saw_non_intel_gpu = false; + if (gpu_info_.gpu.vendor_id == vendor_id && gpu_info_.gpu.device_id == device_id) { // The primary GPU is active. if (gpu_info_.gpu.active) return false; gpu_info_.gpu.active = true; - for (size_t ii = 0; ii < gpu_info_.secondary_gpus.size(); ++ii) + for (size_t ii = 0; ii < gpu_info_.secondary_gpus.size(); ++ii) { gpu_info_.secondary_gpus[ii].active = false; + } } else { // A secondary GPU is active. for (size_t ii = 0; ii < gpu_info_.secondary_gpus.size(); ++ii) { @@ -840,6 +852,26 @@ } gpu_info_.gpu.active = false; } + active_gpu_heuristic_ = gl::GpuPreference::kDefault; + if (is_dual_gpu) { + if (gpu_info_.gpu.vendor_id == kIntelID) { + saw_intel_gpu = true; + } else { + saw_non_intel_gpu = true; + } + if (gpu_info_.secondary_gpus[0].vendor_id == kIntelID) { + saw_intel_gpu = true; + } else { + saw_non_intel_gpu = true; + } + if (saw_intel_gpu && saw_non_intel_gpu) { + if (vendor_id == kIntelID) { + active_gpu_heuristic_ = gl::GpuPreference::kLowPower; + } else { + active_gpu_heuristic_ = gl::GpuPreference::kHighPerformance; + } + } + } GetContentClient()->SetGpuInfo(gpu_info_); NotifyGpuInfoUpdate(); return true;
diff --git a/content/browser/gpu/gpu_data_manager_impl_private.h b/content/browser/gpu/gpu_data_manager_impl_private.h index 83fa485..3acc216b 100644 --- a/content/browser/gpu/gpu_data_manager_impl_private.h +++ b/content/browser/gpu/gpu_data_manager_impl_private.h
@@ -23,6 +23,7 @@ #include "base/values.h" #include "build/build_config.h" #include "content/browser/gpu/gpu_data_manager_impl.h" +#include "ui/gl/gpu_preference.h" namespace base { class CommandLine; @@ -189,6 +190,7 @@ gpu::GpuFeatureInfo gpu_feature_info_; gpu::GPUInfo gpu_info_; + gl::GpuPreference active_gpu_heuristic_ = gl::GpuPreference::kDefault; #if defined(OS_WIN) bool gpu_info_dx_diag_requested_ = false; bool gpu_info_dx_diag_request_failed_ = false;
diff --git a/content/browser/gpu/gpu_internals_ui.cc b/content/browser/gpu/gpu_internals_ui.cc index 96023f2..9ac4194 100644 --- a/content/browser/gpu/gpu_internals_ui.cc +++ b/content/browser/gpu/gpu_internals_ui.cc
@@ -533,7 +533,7 @@ void OnGpuInfoUpdate() override; // ui::GpuSwitchingObserver implementation. - void OnGpuSwitched() override; + void OnGpuSwitched(gl::GpuPreference) override; // Messages void OnBrowserBridgeInitialized(const base::ListValue* list); @@ -720,7 +720,7 @@ *(gpu_info_val.get())); } -void GpuMessageHandler::OnGpuSwitched() { +void GpuMessageHandler::OnGpuSwitched(gl::GpuPreference active_gpu_heuristic_) { // Currently, about:gpu page does not update GPU info after the GPU switch. // If there is something to be updated, the code should be added here. }
diff --git a/content/browser/gpu/peak_gpu_memory_tracker_impl_browsertest.cc b/content/browser/gpu/peak_gpu_memory_tracker_impl_browsertest.cc index 3e3448e002..9a68b16 100644 --- a/content/browser/gpu/peak_gpu_memory_tracker_impl_browsertest.cc +++ b/content/browser/gpu/peak_gpu_memory_tracker_impl_browsertest.cc
@@ -103,7 +103,7 @@ const std::string& key, const std::string& data) override {} void WakeUpGpu() override {} - void GpuSwitched() override {} + void GpuSwitched(gl::GpuPreference active_gpu_heuristic) override {} void DestroyAllChannels() override {} void OnBackgroundCleanup() override {} void OnBackgrounded() override {}
diff --git a/content/browser/loader/prefetch_url_loader.cc b/content/browser/loader/prefetch_url_loader.cc index e9029db..d65498c 100644 --- a/content/browser/loader/prefetch_url_loader.cc +++ b/content/browser/loader/prefetch_url_loader.cc
@@ -49,7 +49,6 @@ : frame_tree_node_id_(frame_tree_node_id), resource_request_(resource_request), network_loader_factory_(std::move(network_loader_factory)), - client_binding_(this), forwarding_client_(std::move(client)), url_loader_throttles_getter_(url_loader_throttles_getter), signed_exchange_prefetch_metric_recorder_( @@ -79,8 +78,8 @@ } network::mojom::URLLoaderClientPtr network_client; - client_binding_.Bind(mojo::MakeRequest(&network_client)); - client_binding_.set_connection_error_handler(base::BindOnce( + client_receiver_.Bind(mojo::MakeRequest(&network_client)); + client_receiver_.set_disconnect_handler(base::BindOnce( &PrefetchURLLoader::OnNetworkConnectionError, base::Unretained(this))); network_loader_factory_->CreateLoaderAndStart( mojo::MakeRequest(&loader_), routing_id, request_id, options, @@ -112,8 +111,8 @@ RecordPrefetchRedirectHistogram( PrefetchRedirect::kPrefetchRedirectedSXGHandler); - // Rebind |client_binding_| and |loader_|. - client_binding_.Bind(signed_exchange_prefetch_handler_->FollowRedirect( + // Rebind |client_receiver_| and |loader_|. + client_receiver_.Bind(signed_exchange_prefetch_handler_->FollowRedirect( mojo::MakeRequest(&loader_))); return; } @@ -162,7 +161,7 @@ std::make_unique<SignedExchangePrefetchHandler>( frame_tree_node_id_, resource_request_, response, mojo::ScopedDataPipeConsumerHandle(), std::move(loader_), - client_binding_.Unbind(), network_loader_factory_, + client_receiver_.Unbind(), network_loader_factory_, url_loader_throttles_getter_, this, signed_exchange_prefetch_metric_recorder_, accept_langs_); return; @@ -263,7 +262,7 @@ forwarding_client_->OnComplete( network::URLLoaderCompletionStatus(net::ERR_INSUFFICIENT_RESOURCES)); forwarding_client_.reset(); - client_binding_.Close(); + client_receiver_.reset(); return false; } forwarding_client_->OnStartLoadingResponseBody(std::move(consumer));
diff --git a/content/browser/loader/prefetch_url_loader.h b/content/browser/loader/prefetch_url_loader.h index b450e29..42c1f6e 100644 --- a/content/browser/loader/prefetch_url_loader.h +++ b/content/browser/loader/prefetch_url_loader.h
@@ -15,7 +15,7 @@ #include "base/unguessable_token.h" #include "content/browser/web_package/prefetched_signed_exchange_cache.h" #include "content/common/content_export.h" -#include "mojo/public/cpp/bindings/binding.h" +#include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/system/data_pipe_drainer.h" #include "net/traffic_annotation/network_traffic_annotation.h" #include "services/network/public/mojom/url_loader.mojom.h" @@ -132,7 +132,7 @@ // For the actual request. network::mojom::URLLoaderPtr loader_; - mojo::Binding<network::mojom::URLLoaderClient> client_binding_; + mojo::Receiver<network::mojom::URLLoaderClient> client_receiver_{this}; // To be a URLLoader for the client. network::mojom::URLLoaderClientPtr forwarding_client_;
diff --git a/content/browser/navigation_browsertest.cc b/content/browser/navigation_browsertest.cc index 6de95bbf..2eb201dd 100644 --- a/content/browser/navigation_browsertest.cc +++ b/content/browser/navigation_browsertest.cc
@@ -3119,10 +3119,19 @@ NavigationUrlRewriteBrowserTest, ::testing::Bool()); +// TODO(1021779): Figure out why this fails on the kitkat-dbg builder +// and re-enable for all platforms. +#if defined(OS_ANDROID) && !defined(NDEBUG) +#define DISABLE_ON_ANDROID_DEBUG(x) DISABLED_##x +#else +#define DISABLE_ON_ANDROID_DEBUG(x) x +#endif + // Tests navigating to a URL that gets rewritten to a "no access" URL. This // mimics the behavior of navigating to special URLs like chrome://newtab and // chrome://history which get rewritten to "no access" chrome-native:// URLs. -IN_PROC_BROWSER_TEST_P(NavigationUrlRewriteBrowserTest, RewriteToNoAccess) { +IN_PROC_BROWSER_TEST_P(NavigationUrlRewriteBrowserTest, + DISABLE_ON_ANDROID_DEBUG(RewriteToNoAccess)) { // Perform an initial navigation. { TestNavigationObserver observer(shell()->web_contents());
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc index b34aa688..2e4c2b9 100644 --- a/content/browser/renderer_host/render_view_host_impl.cc +++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -1017,7 +1017,7 @@ &RenderViewHostImpl::RenderViewReady, weak_factory_.GetWeakPtr())); } -void RenderViewHostImpl::OnGpuSwitched() { +void RenderViewHostImpl::OnGpuSwitched(gl::GpuPreference active_gpu_heuristic) { OnHardwareConfigurationChanged(); }
diff --git a/content/browser/renderer_host/render_view_host_impl.h b/content/browser/renderer_host/render_view_host_impl.h index 994b6142..4bdfe452 100644 --- a/content/browser/renderer_host/render_view_host_impl.h +++ b/content/browser/renderer_host/render_view_host_impl.h
@@ -35,6 +35,7 @@ #include "third_party/blink/public/web/web_console_message.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/base/window_open_disposition.h" +#include "ui/gl/gpu_preference.h" #include "ui/gl/gpu_switching_observer.h" namespace content { @@ -111,7 +112,7 @@ const ChildProcessTerminationInfo& info) override; // GpuSwitchingObserver implementation. - void OnGpuSwitched() override; + void OnGpuSwitched(gl::GpuPreference active_gpu_heuristic) override; // Set up the RenderView child process. Virtual because it is overridden by // TestRenderViewHost.
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc index 57f2c8f5..73e5257 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -1220,10 +1220,11 @@ has_composition_text_ = !composition.text.empty(); } -void RenderWidgetHostViewAura::ConfirmCompositionText() { +void RenderWidgetHostViewAura::ConfirmCompositionText(bool keep_selection) { if (text_input_manager_ && text_input_manager_->GetActiveWidget() && has_composition_text_) { - text_input_manager_->GetActiveWidget()->ImeFinishComposingText(false); + text_input_manager_->GetActiveWidget()->ImeFinishComposingText( + keep_selection); } has_composition_text_ = false; }
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h index 8e874e2..272be96 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.h +++ b/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -202,7 +202,7 @@ // Overridden from ui::TextInputClient: void SetCompositionText(const ui::CompositionText& composition) override; - void ConfirmCompositionText() override; + void ConfirmCompositionText(bool keep_selection) override; void ClearCompositionText() override; void InsertText(const base::string16& text) override; void InsertChar(const ui::KeyEvent& event) override;
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc index e3de2e7..52c2a120 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -6213,18 +6213,33 @@ // This test is for ui::TextInputClient::ConfirmCompositionText. TEST_F(InputMethodResultAuraTest, ConfirmCompositionText) { - base::Closure ime_call = - base::Bind(&ui::TextInputClient::ConfirmCompositionText, - base::Unretained(text_input_client())); + base::Closure ime_call = base::Bind( + &ui::TextInputClient::ConfirmCompositionText, + base::Unretained(text_input_client()), /** keep_selection */ true); for (auto index : active_view_sequence_) { ActivateViewForTextInputManager(views_[index], ui::TEXT_INPUT_TYPE_TEXT); SetHasCompositionTextToTrue(); + // Due to a webkit bug. See: https://bugs.webkit.org/show_bug.cgi?id=37788 + // RenderWidgetHostViewAura::SetCompositionText() will ignore the + // selection range passed into it. Hence, RWHVA::SetCompositionText() + // cannot be used to set the selection range. + + // RenderWidgetHostViewAura::GetFocusedFrame() does not return a focused + // frame due to (crbug.com/689777). Hence, + // RWHVA::SetEditableSelectionRange(gfx::Range(0, 2)) also cannot be used + // to set the selection range. + + // Hence, there exists no easy way to set the selection range to a specific + // value and test the behaviour of keep_selection. ime_call.Run(); base::RunLoop().RunUntilIdle(); EXPECT_EQ("SetComposition FinishComposingText", GetMessageNames(widget_hosts_[index] ->input_handler() ->GetAndResetDispatchedMessages())); + // TODO(keithlee) - If either of the previous bugs get fixed, amend + // this unittest to check if the TIC::SelectionRange is updated to the + // gfx::Range(0,2) value after the IME call. } }
diff --git a/content/browser/renderer_host/render_widget_host_view_event_handler.cc b/content/browser/renderer_host/render_widget_host_view_event_handler.cc index 7f5763a..d24752156 100644 --- a/content/browser/renderer_host/render_widget_host_view_event_handler.cc +++ b/content/browser/renderer_host/render_widget_host_view_event_handler.cc
@@ -664,7 +664,8 @@ // call to finish composition text should be made through the RWHVA itself // otherwise the following call to cancel composition will lead to an extra // IPC for finishing the ongoing composition (see https://crbug.com/723024). - host_view_->GetTextInputClient()->ConfirmCompositionText(); + host_view_->GetTextInputClient()->ConfirmCompositionText( + /* keep_selection */ false); host_view_->ImeCancelComposition(); }
diff --git a/content/browser/service_worker/service_worker_fetch_dispatcher.cc b/content/browser/service_worker/service_worker_fetch_dispatcher.cc index 1681b0b4..4d0f6cf0 100644 --- a/content/browser/service_worker/service_worker_fetch_dispatcher.cc +++ b/content/browser/service_worker/service_worker_fetch_dispatcher.cc
@@ -88,8 +88,7 @@ using WorkerId = std::pair<int, int>; explicit DelegatingURLLoaderClient(network::mojom::URLLoaderClientPtr client, const network::ResourceRequest& request) - : binding_(this), - client_(std::move(client)), + : client_(std::move(client)), url_(request.url), devtools_enabled_(request.report_raw_headers) { if (!devtools_enabled_) @@ -178,7 +177,7 @@ } void Bind(network::mojom::URLLoaderClientPtr* ptr_info) { - binding_.Bind(mojo::MakeRequest(ptr_info)); + receiver_.Bind(mojo::MakeRequest(ptr_info)); } private: @@ -198,7 +197,7 @@ MaybeRunDevToolsCallbacks(); } - mojo::Binding<network::mojom::URLLoaderClient> binding_; + mojo::Receiver<network::mojom::URLLoaderClient> receiver_{this}; network::mojom::URLLoaderClientPtr client_; bool completed_ = false; const GURL url_;
diff --git a/content/browser/service_worker/service_worker_new_script_loader.cc b/content/browser/service_worker/service_worker_new_script_loader.cc index b831990..bdd5e79e 100644 --- a/content/browser/service_worker/service_worker_new_script_loader.cc +++ b/content/browser/service_worker/service_worker_new_script_loader.cc
@@ -75,7 +75,6 @@ resource_type_(static_cast<ResourceType>(original_request.resource_type)), original_options_(options), version_(version), - network_client_binding_(this), network_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL, base::SequencedTaskRunnerHandle::Get()), @@ -151,7 +150,7 @@ options &= ~network::mojom::kURLLoadOptionSniffMimeType; network::mojom::URLLoaderClientPtr network_client; - network_client_binding_.Bind(mojo::MakeRequest(&network_client)); + network_client_receiver_.Bind(mojo::MakeRequest(&network_client)); loader_factory_->CreateLoaderAndStart( mojo::MakeRequest(&network_loader_), routing_id, request_id, options, resource_request, std::move(network_client), traffic_annotation); @@ -559,7 +558,7 @@ client_producer_.reset(); network_loader_.reset(); - network_client_binding_.Close(); + network_client_receiver_.reset(); network_consumer_.reset(); network_watcher_.Cancel(); cache_writer_.reset();
diff --git a/content/browser/service_worker/service_worker_new_script_loader.h b/content/browser/service_worker/service_worker_new_script_loader.h index f54608d..2be800c 100644 --- a/content/browser/service_worker/service_worker_new_script_loader.h +++ b/content/browser/service_worker/service_worker_new_script_loader.h
@@ -9,7 +9,7 @@ #include "content/browser/service_worker/service_worker_cache_writer.h" #include "content/common/content_export.h" #include "content/public/common/resource_type.h" -#include "mojo/public/cpp/bindings/binding.h" +#include "mojo/public/cpp/bindings/receiver.h" #include "net/traffic_annotation/network_traffic_annotation.h" #include "services/network/public/cpp/net_adapters.h" #include "services/network/public/cpp/resource_request.h" @@ -182,7 +182,8 @@ // sometimes). network::mojom::URLLoaderPtr network_loader_; - mojo::Binding<network::mojom::URLLoaderClient> network_client_binding_; + mojo::Receiver<network::mojom::URLLoaderClient> network_client_receiver_{ + this}; mojo::ScopedDataPipeConsumerHandle network_consumer_; mojo::SimpleWatcher network_watcher_; scoped_refptr<network::SharedURLLoaderFactory> loader_factory_;
diff --git a/content/browser/utility_process_host.cc b/content/browser/utility_process_host.cc index 7fc0e32..5df41d8 100644 --- a/content/browser/utility_process_host.cc +++ b/content/browser/utility_process_host.cc
@@ -390,6 +390,7 @@ network::switches::kNetLogCaptureMode, network::switches::kExplicitlyAllowedPorts, service_manager::switches::kNoSandbox, + service_manager::switches::kEnableAudioServiceSandbox, #if defined(OS_MACOSX) service_manager::switches::kEnableSandboxLogging, os_crypt::switches::kUseMockKeychain,
diff --git a/content/common/content_security_policy/csp_source_list.cc b/content/common/content_security_policy/csp_source_list.cc index 664c2b64..0fe3e5f5 100644 --- a/content/common/content_security_policy/csp_source_list.cc +++ b/content/common/content_security_policy/csp_source_list.cc
@@ -38,25 +38,11 @@ CSPSourceList::CSPSourceList( const network::mojom::CSPSourceList& csp_source_list) - : allow_self(false), allow_star(false), allow_response_redirects(false) { - for (auto& source : csp_source_list.sources) { - // The mojo representation of the source list has 'self' as a source entry, - // mark this source list as accepting 'self'. - if (source->allow_self) { - allow_self = true; - continue; - } - // The mojo representation has a '*' (wildcard) representation as empty - // scheme, host and port with is_host_wildcard set to true. Mark the source - // list as accepting star. - if (source->scheme == "" && source->is_host_wildcard && - source->host == "" && source->port == url::PORT_UNSPECIFIED) { - allow_star = true; - continue; - } - + : allow_self(csp_source_list.allow_self), + allow_star(csp_source_list.allow_star), + allow_response_redirects(false) { + for (auto& source : csp_source_list.sources) sources.push_back(CSPSource(*source)); - } } CSPSourceList::CSPSourceList(const CSPSourceList&) = default;
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc index 93a3a8d..c244b17 100644 --- a/content/public/test/browser_test_utils.cc +++ b/content/public/test/browser_test_utils.cc
@@ -135,7 +135,6 @@ #if defined(OS_WIN) #include <uiautomation.h> #include <wrl/client.h> -#include "base/win/atl.h" #include "base/win/scoped_safearray.h" #include "base/win/scoped_variant.h" #endif @@ -2106,14 +2105,15 @@ std::vector<std::string> names; for (LONG i = 0; i < size; ++i) { - CComPtr<IUnknown> unknown_element = nullptr; - ASSERT_HRESULT_SUCCEEDED(SafeArrayGetElement(V_ARRAY(result_variant.ptr()), - &i, &unknown_element)); + Microsoft::WRL::ComPtr<IUnknown> unknown_element; + ASSERT_HRESULT_SUCCEEDED( + SafeArrayGetElement(V_ARRAY(result_variant.ptr()), &i, + static_cast<void**>(&unknown_element))); ASSERT_NE(nullptr, unknown_element); - CComPtr<IRawElementProviderSimple> raw_element_provider_simple = nullptr; - ASSERT_HRESULT_SUCCEEDED( - unknown_element->QueryInterface(&raw_element_provider_simple)); + Microsoft::WRL::ComPtr<IRawElementProviderSimple> + raw_element_provider_simple; + ASSERT_HRESULT_SUCCEEDED(unknown_element.As(&raw_element_provider_simple)); ASSERT_NE(nullptr, raw_element_provider_simple); base::win::ScopedVariant name;
diff --git a/content/public/test/url_loader_interceptor.cc b/content/public/test/url_loader_interceptor.cc index 1ca1a94..e8f62c5 100644 --- a/content/public/test/url_loader_interceptor.cc +++ b/content/public/test/url_loader_interceptor.cc
@@ -26,6 +26,7 @@ #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/test/mock_render_process_host.h" +#include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/bindings/receiver_set.h" #include "mojo/public/cpp/bindings/remote.h" #include "net/http/http_util.h" @@ -187,11 +188,10 @@ const URLLoaderInterceptor::URLLoaderCompletionStatusCallback& completion_status_callback) : original_client_(std::move(params.client)), - delegating_client_binding_(this), completion_status_callback_(std::move(completion_status_callback)), request_url_(params.url_request.url) { network::mojom::URLLoaderClientPtr delegating_client; - delegating_client_binding_.Bind(mojo::MakeRequest(&delegating_client)); + delegating_client_receiver_.Bind(mojo::MakeRequest(&delegating_client)); factory_getter.Run()->CreateLoaderAndStart( std::move(params.receiver), params.routing_id, params.request_id, params.options, std::move(params.url_request), @@ -235,7 +235,8 @@ private: network::mojom::URLLoaderClientPtr original_client_; - mojo::Binding<network::mojom::URLLoaderClient> delegating_client_binding_; + mojo::Receiver<network::mojom::URLLoaderClient> delegating_client_receiver_{ + this}; URLLoaderInterceptor::URLLoaderCompletionStatusCallback completion_status_callback_; GURL request_url_;
diff --git a/content/renderer/loader/navigation_body_loader.cc b/content/renderer/loader/navigation_body_loader.cc index 09762f76..918f062 100644 --- a/content/renderer/loader/navigation_body_loader.cc +++ b/content/renderer/loader/navigation_body_loader.cc
@@ -97,7 +97,6 @@ endpoints_(std::move(endpoints)), task_runner_(std::move(task_runner)), resource_load_info_(std::move(resource_load_info)), - url_loader_client_binding_(this), handle_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL, task_runner_) {} @@ -220,9 +219,9 @@ void NavigationBodyLoader::BindURLLoaderAndContinue() { url_loader_.Bind(std::move(endpoints_->url_loader), task_runner_); - url_loader_client_binding_.Bind(std::move(endpoints_->url_loader_client), - task_runner_); - url_loader_client_binding_.set_connection_error_handler(base::BindOnce( + url_loader_client_receiver_.Bind(std::move(endpoints_->url_loader_client), + task_runner_); + url_loader_client_receiver_.set_disconnect_handler(base::BindOnce( &NavigationBodyLoader::OnConnectionClosed, base::Unretained(this))); }
diff --git a/content/renderer/loader/navigation_body_loader.h b/content/renderer/loader/navigation_body_loader.h index 8780320..b053a8f8 100644 --- a/content/renderer/loader/navigation_body_loader.h +++ b/content/renderer/loader/navigation_body_loader.h
@@ -18,7 +18,7 @@ #include "content/common/navigation_params.h" #include "content/public/common/resource_load_info.mojom.h" #include "mojo/public/cpp/base/big_buffer.h" -#include "mojo/public/cpp/bindings/binding.h" +#include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/system/data_pipe.h" #include "mojo/public/cpp/system/simple_watcher.h" #include "services/network/public/mojom/url_loader.mojom.h" @@ -145,7 +145,8 @@ // These bindings are live while loading the response. network::mojom::URLLoaderPtr url_loader_; - mojo::Binding<network::mojom::URLLoaderClient> url_loader_client_binding_; + mojo::Receiver<network::mojom::URLLoaderClient> url_loader_client_receiver_{ + this}; WebNavigationBodyLoader::Client* client_ = nullptr; // The handle and watcher are live while loading the body.
diff --git a/content/renderer/loader/url_loader_client_impl.cc b/content/renderer/loader/url_loader_client_impl.cc index 70d6e06..44fe52b2a 100644 --- a/content/renderer/loader/url_loader_client_impl.cc +++ b/content/renderer/loader/url_loader_client_impl.cc
@@ -152,8 +152,7 @@ resource_dispatcher_(resource_dispatcher), task_runner_(std::move(task_runner)), bypass_redirect_checks_(bypass_redirect_checks), - last_loaded_url_(request_url), - url_loader_client_binding_(this) {} + last_loaded_url_(request_url) {} URLLoaderClientImpl::~URLLoaderClientImpl() = default; @@ -230,9 +229,9 @@ void URLLoaderClientImpl::Bind( network::mojom::URLLoaderClientEndpointsPtr endpoints) { url_loader_.Bind(std::move(endpoints->url_loader), task_runner_); - url_loader_client_binding_.Bind(std::move(endpoints->url_loader_client), - task_runner_); - url_loader_client_binding_.set_connection_error_handler(base::BindOnce( + url_loader_client_receiver_.Bind(std::move(endpoints->url_loader_client), + task_runner_); + url_loader_client_receiver_.set_disconnect_handler(base::BindOnce( &URLLoaderClientImpl::OnConnectionClosed, weak_factory_.GetWeakPtr())); }
diff --git a/content/renderer/loader/url_loader_client_impl.h b/content/renderer/loader/url_loader_client_impl.h index a940d61..b0b5ae98 100644 --- a/content/renderer/loader/url_loader_client_impl.h +++ b/content/renderer/loader/url_loader_client_impl.h
@@ -11,7 +11,7 @@ #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "content/common/content_export.h" -#include "mojo/public/cpp/bindings/binding.h" +#include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/system/data_pipe.h" #include "services/network/public/mojom/url_loader.mojom.h" @@ -99,7 +99,8 @@ GURL last_loaded_url_; network::mojom::URLLoaderPtr url_loader_; - mojo::Binding<network::mojom::URLLoaderClient> url_loader_client_binding_; + mojo::Receiver<network::mojom::URLLoaderClient> url_loader_client_receiver_{ + this}; base::WeakPtrFactory<URLLoaderClientImpl> weak_factory_{this}; };
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc index dbe2b9c..f840cfc 100644 --- a/content/renderer/renderer_blink_platform_impl.cc +++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -827,21 +827,17 @@ std::unique_ptr<blink::WebGraphicsContext3DProvider> RendererBlinkPlatformImpl::CreateWebGPUGraphicsContext3DProvider( - const blink::WebURL& top_document_web_url, - blink::Platform::GraphicsInfo* gl_info) { + const blink::WebURL& top_document_web_url) { #if !BUILDFLAG(USE_DAWN) return nullptr; #else scoped_refptr<gpu::GpuChannelHost> gpu_channel_host( RenderThreadImpl::current()->EstablishGpuChannelSync()); if (!gpu_channel_host) { - std::string error_message( - "WebGPUGraphicsContext3DProvider creation failed, GpuChannelHost " - "creation failed"); - gl_info->error_message = WebString::FromUTF8(error_message); + // TODO(crbug.com/973017): Collect GPU info and surface context creation + // error. return nullptr; } - Collect3DContextInformation(gl_info, gpu_channel_host->gpu_info()); gpu::ContextCreationAttribs attributes; // TODO(kainino): It's not clear yet how GPU preferences work for WebGPU.
diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h index d2d54ab..f54e6c3 100644 --- a/content/renderer/renderer_blink_platform_impl.h +++ b/content/renderer/renderer_blink_platform_impl.h
@@ -167,8 +167,7 @@ CreateSharedOffscreenGraphicsContext3DProvider() override; std::unique_ptr<blink::WebGraphicsContext3DProvider> CreateWebGPUGraphicsContext3DProvider( - const blink::WebURL& top_document_web_url, - blink::Platform::GraphicsInfo* gl_info) override; + const blink::WebURL& top_document_web_url) override; gpu::GpuMemoryBufferManager* GetGpuMemoryBufferManager() override; blink::WebString ConvertIDNToUnicode(const blink::WebString& host) override; void SetDisplayThreadPriority(base::PlatformThreadId thread_id) override;
diff --git a/content/test/data/gpu/functional_blank.html b/content/test/data/gpu/functional_blank.html new file mode 100644 index 0000000..246224e --- /dev/null +++ b/content/test/data/gpu/functional_blank.html
@@ -0,0 +1,11 @@ +<head> +<script> +function main() { + if (window.domAutomationController) { + domAutomationController.send("FINISHED"); + } +} +</script> +</head> +<body onload="main()"> +</body>
diff --git a/content/test/data/gpu/functional_files/context.js b/content/test/data/gpu/functional_files/context.js index 9f072aa..3e96f2d 100644 --- a/content/test/data/gpu/functional_files/context.js +++ b/content/test/data/gpu/functional_files/context.js
@@ -6,11 +6,10 @@ var gl_context; var gl_renderer; -initializeWebGL = function(canvas) { +initializeWebGL = function(canvas, opt_attrs) { gl_context = null; // Try to grab the standard context. - gl_context = canvas.getContext("webgl") || - canvas.getContext("experimental-webgl"); + gl_context = canvas.getContext("webgl", opt_attrs); // If we don't have a GL context, give up now. if (!gl_context) { err = "Unable to initialize WebGL. Your browser may not support it."; @@ -22,10 +21,10 @@ } } -startWebGLContext = function() { +startWebGLContext = function(opt_attrs) { var canvas = document.getElementById("glcanvas"); // Initialize the GL context. - initializeWebGL(canvas); + initializeWebGL(canvas, opt_attrs); // Only continue if WebGL is available and working. if (gl_context) {
diff --git a/content/test/data/gpu/functional_webgl_high_performance.html b/content/test/data/gpu/functional_webgl_high_performance.html new file mode 100644 index 0000000..9f599a5 --- /dev/null +++ b/content/test/data/gpu/functional_webgl_high_performance.html
@@ -0,0 +1,8 @@ +<html> +<script type="text/javascript" src="./functional_files/context.js"></script> +<body onload="startWebGLContext({powerPreference: 'high-performance'})"> + <canvas id="glcanvas" width="640" height="480"> + Your browser doesn't appear to support the HTML5 <code><canvas></code> element. + </canvas> +</body> +</html>
diff --git a/content/test/data/gpu/functional_webgl_low_power.html b/content/test/data/gpu/functional_webgl_low_power.html new file mode 100644 index 0000000..38a1ab5 --- /dev/null +++ b/content/test/data/gpu/functional_webgl_low_power.html
@@ -0,0 +1,8 @@ +<html> +<script type="text/javascript" src="./functional_files/context.js"></script> +<body onload="startWebGLContext({powerPreference: 'low-power'})"> + <canvas id="glcanvas" width="640" height="480"> + Your browser doesn't appear to support the HTML5 <code><canvas></code> element. + </canvas> +</body> +</html>
diff --git a/content/test/data/gpu/pixel_webgl_fullscreen_quad.js b/content/test/data/gpu/pixel_webgl_fullscreen_quad.js new file mode 100644 index 0000000..8233144 --- /dev/null +++ b/content/test/data/gpu/pixel_webgl_fullscreen_quad.js
@@ -0,0 +1,127 @@ +// 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. + +const vertexShader = [ + "attribute vec3 pos;", + "void main(void)", + "{", + " gl_Position = vec4(pos, 1.0);", + "}" +].join("\n"); + +const fragmentShader = [ + "precision mediump float;", + "void main(void)", + "{", + " gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);", + "}" +].join("\n"); + +let gl; + +function sendResult(status, detail) { + console.log(detail); + if (window.domAutomationController) { + window.domAutomationController.send(status); + } else { + console.log(status); + } +} + +function initGL(canvas) +{ + try { + gl = canvas.getContext("webgl", { powerPreference: "low-power" }); + } catch (e) {} + return gl; +} + +function setupShader(source, type) { + var shader = gl.createShader(type); + gl.shaderSource(shader, source); + gl.compileShader(shader); + if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) + return null; + return shader; +} + +function setupProgram(vs_id, fs_id) { + var vs = setupShader(vertexShader, gl.VERTEX_SHADER); + var fs = setupShader(fragmentShader, gl.FRAGMENT_SHADER); + if (!vs || !fs) + return null; + var program = gl.createProgram(); + gl.attachShader(program, vs); + gl.attachShader(program, fs); + gl.linkProgram(program); + if (!gl.getProgramParameter(program, gl.LINK_STATUS)) + return null; + gl.useProgram(program); + return program; +} + +function setupBuffer(gl) { + var buffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, buffer); + var vertexData = [ + // Triangle 1 + -1.0, -1.0, 0.0, + 1.0, 1.0, 0.0, + -1.0, 1.0, 0.0, + + // Triangle 2 + -1.0, -1.0, 0.0, + 1.0, -1.0, 0.0, + 1.0, 1.0, 0.0 + ]; + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW); +} + +function setupGL() { + var program = setupProgram("shader-vs", "shader-fs"); + if (!program) + return false; + var posAttr = gl.getAttribLocation(program, "pos"); + gl.enableVertexAttribArray(posAttr); + setupBuffer(gl); + var stride = 3 * Float32Array.BYTES_PER_ELEMENT; + gl.vertexAttribPointer(posAttr, 3, gl.FLOAT, false, stride, 0); + gl.clearColor(0.0, 0.0, 0.0, 0.0); + gl.viewport(0, 0, 300, 300); + gl.disable(gl.DEPTH_TEST); + if (gl.getError() != gl.NO_ERROR) + return false; + return true; +} + +function drawQuad() { + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + gl.drawArrays(gl.TRIANGLES, 0, 6); +} + +function setup() +{ + let canvas = document.getElementById("c"); + initGL(canvas); + if (gl && setupGL(gl)) + return true; + domAutomationController.send("FAILURE"); + return false; +} + +function drawSomeFrames(callback) +{ + let swapsBeforeCallback = 15; + + function drawSomeFramesHelper() { + if (--swapsBeforeCallback == 0) { + callback(); + } else { + drawQuad(); + window.requestAnimationFrame(drawSomeFramesHelper); + } + } + + window.requestAnimationFrame(drawSomeFramesHelper); +}
diff --git a/content/test/data/gpu/pixel_webgl_high_to_low_power.html b/content/test/data/gpu/pixel_webgl_high_to_low_power.html new file mode 100644 index 0000000..aa6f7a0 --- /dev/null +++ b/content/test/data/gpu/pixel_webgl_high_to_low_power.html
@@ -0,0 +1,52 @@ +<!DOCTYPE HTML> + +<html> +<head> +<meta name="viewport" content="initial-scale=1"> +<title>WebGL High to Low Power Transition Test</title> +<style type="text/css"> +.nomargin { + margin: 0px auto; +} +</style> +<script src="pixel_webgl_fullscreen_quad.js"></script> + +<script> +function ready() { + sendResult("READY", "Ready for second tab to be launched"); +} + +function initialize() { + if (setup()) + drawSomeFrames(notifyHarness); +} + +function notifyHarness() { + sendResult("READY", "Ready for second tab to be closed"); +} + +function runToCompletion() { + drawSomeFrames(waitForFinish); +} + +function waitForFinish() +{ + let numFramesBeforeEnd = 15; + + function waitForFinishImpl() { + if (--numFramesBeforeEnd == 0) { + sendResult("SUCCESS", "Test complete"); + } else { + window.requestAnimationFrame(waitForFinishImpl); + } + } + + window.requestAnimationFrame(waitForFinishImpl); +} +</script> +</head> +<body onload="ready()"> +<canvas id="c" width="300" height="300" class="nomargin" style="position:absolute; top:0px; left:0px;"></canvas> +</div> +</body> +</html>
diff --git a/content/test/data/gpu/pixel_webgl_low_to_high_power.html b/content/test/data/gpu/pixel_webgl_low_to_high_power.html new file mode 100644 index 0000000..b97e4cd --- /dev/null +++ b/content/test/data/gpu/pixel_webgl_low_to_high_power.html
@@ -0,0 +1,46 @@ +<!DOCTYPE HTML> + +<html> +<head> +<meta name="viewport" content="initial-scale=1"> +<title>WebGL Low to High Power Transition Test</title> +<style type="text/css"> +.nomargin { + margin: 0px auto; +} +</style> +<script src="pixel_webgl_fullscreen_quad.js"></script> + +<script> +function main() { + if (setup()) + drawSomeFrames(allocateHighPowerContext); +} + +function allocateHighPowerContext() { + c2.getContext("webgl", { powerPreference: "high-performance" }); + setTimeout(() => { drawSomeFrames(waitForFinish) }, 1000); +} + +function waitForFinish() +{ + let numFramesBeforeEnd = 15; + + function waitForFinishImpl() { + if (--numFramesBeforeEnd == 0) { + sendResult("SUCCESS", "Test complete"); + } else { + window.requestAnimationFrame(waitForFinishImpl); + } + } + + window.requestAnimationFrame(waitForFinishImpl); +} +</script> +</head> +<body onload="main()"> +<canvas id="c" width="300" height="300" class="nomargin" style="position:absolute; top:0px; left:0px;"></canvas> +<canvas id="c2" width="1" height="1" class="nomargin"></canvas> +</div> +</body> +</html>
diff --git a/content/test/data/gpu/pixel_webgl_util.js b/content/test/data/gpu/pixel_webgl_util.js index 1f084d8..8f88e2f 100644 --- a/content/test/data/gpu/pixel_webgl_util.js +++ b/content/test/data/gpu/pixel_webgl_util.js
@@ -1,11 +1,6 @@ // Copyright 2016 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// -// READ BEFORE UPDATING: -// If this file is updated, make sure to increment the "revision" value of any -// tests that use this file in content/test/gpu/page_sets/pixel_tests.py. This -// will ensure that the baseline images are regenerated on the next run. var vertexShader = [ "attribute vec3 pos;",
diff --git a/content/test/data/gpu/webgl2-multisampling-high-power-switch-loses-context.html b/content/test/data/gpu/webgl2-multisampling-high-power-switch-loses-context.html new file mode 100644 index 0000000..4b4aa98 --- /dev/null +++ b/content/test/data/gpu/webgl2-multisampling-high-power-switch-loses-context.html
@@ -0,0 +1,62 @@ +<html> +<head> +<script type="text/javascript"> +let canvas; +let gl; +let msrb; +let contextLost = false; + +function send(str) { + if (window.domAutomationController) { + window.domAutomationController.send(str); + } else { + console.log(str); + } +} + +function animate() { + if (!contextLost) { + gl.clearColor(0, 1, 0, 1); + gl.clear(gl.COLOR_BUFFER_BIT); + } + requestAnimationFrame(animate); +} + +function onLoad() { + canvas = document.getElementById("canvas1"); + canvas.addEventListener('webglcontextlost', function(e) { + console.log('Context lost'); + e.preventDefault(); + contextLost = true; + }, false); + canvas.addEventListener('webglcontextrestored', function(e) { + contextLost = false; + send("SUCCESS"); + }, false); + gl = canvas.getContext('webgl2', {powerPreference: "low-power"}); + msrb = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, msrb); + gl.renderbufferStorageMultisample(gl.RENDERBUFFER, 2, gl.RGBA8, 16, 16); + gl.bindRenderbuffer(gl.RENDERBUFFER, null); + let err = gl.getError(); + if (err != 0) { + console.log("Error " + err + " allocating multisampled renderbuffer"); + send("FAILED"); + return; + } + // Must draw to the WebGL canvas in order for the GPU switch to be detected. + requestAnimationFrame(animate); + send("LOADED"); +} + +function runTest() { + let c2 = document.getElementById("canvas2"); + let gl = c2.getContext('webgl2', {powerPreference: "high-performance"}); +} +</script> +</head> +<body onload="onLoad()"> +<canvas id="canvas1" width="16px" height="16px"></canvas> +<canvas id="canvas2" width="16px" height="16px"></canvas> +</body> +</html>
diff --git a/content/test/data/gpu/webgl2-preserve-db-high-power-switch-loses-context.html b/content/test/data/gpu/webgl2-preserve-db-high-power-switch-loses-context.html new file mode 100644 index 0000000..d0d5b6b5 --- /dev/null +++ b/content/test/data/gpu/webgl2-preserve-db-high-power-switch-loses-context.html
@@ -0,0 +1,52 @@ +<html> +<head> +<script type="text/javascript"> +let canvas; +let gl; +let msrb; +let contextLost = false; + +function send(str) { + if (window.domAutomationController) { + window.domAutomationController.send(str); + } else { + console.log(str); + } +} + +function animate() { + if (!contextLost) { + gl.clearColor(0, 1, 0, 1); + gl.clear(gl.COLOR_BUFFER_BIT); + } + requestAnimationFrame(animate); +} + +function onLoad() { + canvas = document.getElementById("canvas1"); + canvas.addEventListener('webglcontextlost', function(e) { + console.log('Context lost'); + e.preventDefault(); + contextLost = true; + }, false); + canvas.addEventListener('webglcontextrestored', function(e) { + contextLost = false; + send("SUCCESS"); + }, false); + gl = canvas.getContext('webgl2', {powerPreference: "low-power", preserveDrawingBuffer:true}); + // Must draw to the WebGL canvas in order for the GPU switch to be detected. + requestAnimationFrame(animate); + send("LOADED"); +} + +function runTest() { + let c2 = document.getElementById("canvas2"); + let gl = c2.getContext('webgl2', {powerPreference: "high-performance"}); +} +</script> +</head> +<body onload="onLoad()"> +<canvas id="canvas1" width="16px" height="16px"></canvas> +<canvas id="canvas2" width="16px" height="16px"></canvas> +</body> +</html>
diff --git a/content/test/gpu/gpu_tests/context_lost_integration_test.py b/content/test/gpu/gpu_tests/context_lost_integration_test.py index 6e3db6d..a30d380 100644 --- a/content/test/gpu/gpu_tests/context_lost_integration_test.py +++ b/content/test/gpu/gpu_tests/context_lost_integration_test.py
@@ -2,6 +2,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import logging import os import sys import time @@ -70,7 +71,13 @@ return [ '--disable-gpu-process-crash-limit', # Required to call crashGpuProcess. - '--enable-gpu-benchmarking'] + browser_args + '--enable-gpu-benchmarking', + # Disable: + # Do you want the application "Chromium Helper.app" to accept incoming + # network connections? + # dialogs on macOS. crbug.com/969559 + '--disable-device-discovery-notifications', + ] + browser_args @classmethod def GenerateGpuTests(cls, options): @@ -96,7 +103,11 @@ ('ContextLost_WorkerRAFAfterGPUCrash_OOPD', 'worker-raf-after-gpu-crash.html'), ('ContextLost_WebGL2Blocked', - 'webgl2-context-blocked.html')) + 'webgl2-context-blocked.html'), + ('ContextLost_MacWebGLMultisamplingHighPowerSwitchLosesContext', + 'webgl2-multisampling-high-power-switch-loses-context.html'), + ('ContextLost_MacWebGLPreserveDBHighPowerSwitchLosesContext', + 'webgl2-preserve-db-high-power-switch-loses-context.html')) for t in tests: yield (t[0], t[1], ('_' + t[0])) @@ -214,7 +225,7 @@ tab = self.tab completed = self._WaitForPageToFinish(tab) if not completed: - self.fail('Test didn\'t complete (no context restored event?)') + self.fail('Test didn\'t complete (no context lost / restored event?)') if not tab.EvaluateJavaScript('window.domAutomationController._succeeded'): self.fail('Test failed (context not restored properly?)') @@ -357,6 +368,47 @@ # blacklisted should not cause the GPU process to crash. self._CheckCrashCount(tab, 0) + def _ContextLost_MacWebGLMultisamplingHighPowerSwitchLosesContext(self, test_path): + # Verifies that switching from the low-power to the high-power GPU + # on a dual-GPU Mac, while the user has allocated multisampled + # renderbuffers via the WebGL 2.0 API, causes the context to be + # lost. + if not self._IsDualGPUMacLaptop(): + logging.info('Skipping test because not running on dual-GPU Mac laptop') + return + # Start with a browser with clean GPU process state. + self.RestartBrowserWithArgs(self._AddDefaultArgs([])) + # Wait a few seconds for the system to dispatch any GPU switched + # notifications. + time.sleep(3) + self._NavigateAndWaitForLoad(test_path) + if not self._IsIntel(self.browser.GetSystemInfo().gpu.devices[0].vendor_id): + self.fail('Test did not start up on low-power GPU') + tab = self.tab + tab.EvaluateJavaScript('runTest()') + self._WaitForTabAndCheckCompletion() + self._CheckCrashCount(tab, 0) + + def _ContextLost_MacWebGLPreserveDBHighPowerSwitchLosesContext(self, test_path): + # Verifies that switching from the low-power to the high-power GPU on a + # dual-GPU Mac, when the user specified preserveDrawingBuffer:true, causes + # the context to be lost. + if not self._IsDualGPUMacLaptop(): + logging.info('Skipping test because not running on dual-GPU Mac laptop') + return + # Start with a browser with clean GPU process state. + self.RestartBrowserWithArgs(self._AddDefaultArgs([])) + # Wait a few seconds for the system to dispatch any GPU switched + # notifications. + time.sleep(3) + self._NavigateAndWaitForLoad(test_path) + if not self._IsIntel(self.browser.GetSystemInfo().gpu.devices[0].vendor_id): + self.fail('Test did not start up on low-power GPU') + tab = self.tab + tab.EvaluateJavaScript('runTest()') + self._WaitForTabAndCheckCompletion() + self._CheckCrashCount(tab, 0) + @classmethod def GetPlatformTags(cls, browser): tags = super(ContextLostIntegrationTest, cls).GetPlatformTags(browser)
diff --git a/content/test/gpu/gpu_tests/gpu_integration_test.py b/content/test/gpu/gpu_tests/gpu_integration_test.py index b6acf57c..38d2910 100644 --- a/content/test/gpu/gpu_tests/gpu_integration_test.py +++ b/content/test/gpu/gpu_tests/gpu_integration_test.py
@@ -4,6 +4,7 @@ import logging import re +import sys from telemetry.core import android_platform from telemetry.testing import serially_executed_browser_test_case @@ -217,6 +218,34 @@ logging.warning( '%s was expected to fail, but passed.\n', test_name) + def _IsIntel(self, vendor_id): + return vendor_id == 0x8086 + + def _IsIntelGPUActive(self): + gpu = self.browser.GetSystemInfo().gpu + # The implementation of GetSystemInfo guarantees that the first entry in the + # GPU devices list is the active GPU. + return self._IsIntel(gpu.devices[0].vendor_id) + + def _IsDualGPUMacLaptop(self): + if sys.platform != 'darwin': + return False + system_info = self.browser.GetSystemInfo() + if not system_info: + self.fail("Browser doesn't support GetSystemInfo") + gpu = system_info.gpu + if not gpu: + self.fail('Target machine must have a GPU') + if len(gpu.devices) != 2: + return False + if (self._IsIntel(gpu.devices[0].vendor_id) and not + self._IsIntel(gpu.devices[1].vendor_id)): + return True + if (not self._IsIntel(gpu.devices[0].vendor_id) and + self._IsIntel(gpu.devices[1].vendor_id)): + return True + return False + @classmethod def GenerateGpuTests(cls, options): """Subclasses must implement this to yield (test_name, url, args)
diff --git a/content/test/gpu/gpu_tests/gpu_process_integration_test.py b/content/test/gpu/gpu_tests/gpu_process_integration_test.py index a7aa064..6168ca3d 100644 --- a/content/test/gpu/gpu_tests/gpu_process_integration_test.py +++ b/content/test/gpu/gpu_tests/gpu_process_integration_test.py
@@ -2,8 +2,10 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import logging import os import sys +import time from gpu_tests import gpu_integration_test from gpu_tests import path_util @@ -56,7 +58,13 @@ # TODO(kbr): figure out why the following option seems to be # needed on Android for robustness. # https://github.com/catapult-project/catapult/issues/3122 - '--no-first-run'] + browser_args + '--no-first-run', + # Disable: + # Do you want the application "Chromium Helper.app" to accept incoming + # network connections? + # dialogs on macOS. crbug.com/969559 + '--disable-device-discovery-notifications', + ] + browser_args @classmethod def GenerateGpuTests(cls, options): @@ -81,14 +89,18 @@ 'gpu/functional_webgl.html'), ('GpuProcess_disable_swiftshader', 'gpu/functional_webgl.html'), ('GpuProcess_disabling_workarounds_works', 'chrome:gpu'), + ('GpuProcess_mac_webgl_backgrounded_high_performance', + 'gpu/functional_blank.html'), + ('GpuProcess_mac_webgl_high_performance', + 'gpu/functional_webgl_high_performance.html'), + ('GpuProcess_mac_webgl_low_power', + 'gpu/functional_webgl_low_power.html'), + ('GpuProcess_mac_webgl_terminated_high_performance', + 'gpu/functional_blank.html'), ('GpuProcess_swiftshader_for_webgl', 'gpu/functional_webgl.html'), ('GpuProcess_webgl_disabled_extension', 'gpu/functional_webgl_disabled_extension.html')) - # The earlier has_transparent_visuals_gpu_process and - # no_transparent_visuals_gpu_process tests became no-ops in - # http://crrev.com/2347383002 and were deleted. - for t in tests: yield (t[0], t[1], ('_' + t[0])) @@ -108,14 +120,16 @@ self.tab.action_runner.Navigate( url, script_to_evaluate_on_commit=test_harness_script) - def _NavigateAndWait(self, test_path): - self._Navigate(test_path) - tab = self.tab + def _WaitForTestCompletion(self, tab): tab.action_runner.WaitForJavaScriptCondition( 'window.domAutomationController._finished', timeout=10) if not tab.EvaluateJavaScript('window.domAutomationController._succeeded'): self.fail('Test reported that it failed') + def _NavigateAndWait(self, test_path): + self._Navigate(test_path) + self._WaitForTestCompletion(self.tab) + def _VerifyGpuProcessPresent(self): tab = self.tab if not tab.EvaluateJavaScript('chrome.gpuBenchmarking.hasGpuChannel()'): @@ -219,28 +233,28 @@ # The actual tests def _GpuProcess_canvas2d(self, test_path): - self.RestartBrowserIfNecessaryWithArgs([]) + self.RestartBrowserIfNecessaryWithArgs(self._AddDefaultArgs([])) self._NavigateAndWait(test_path) self._VerifyGpuProcessPresent() def _GpuProcess_css3d(self, test_path): - self.RestartBrowserIfNecessaryWithArgs([]) + self.RestartBrowserIfNecessaryWithArgs(self._AddDefaultArgs([])) self._NavigateAndWait(test_path) self._VerifyGpuProcessPresent() def _GpuProcess_webgl(self, test_path): - self.RestartBrowserIfNecessaryWithArgs([]) + self.RestartBrowserIfNecessaryWithArgs(self._AddDefaultArgs([])) self._NavigateAndWait(test_path) self._VerifyGpuProcessPresent() def _GpuProcess_video(self, test_path): - self.RestartBrowserIfNecessaryWithArgs([]) + self.RestartBrowserIfNecessaryWithArgs(self._AddDefaultArgs([])) self._NavigateAndWait(test_path) self._VerifyGpuProcessPresent() def _GpuProcess_gpu_info_complete(self, test_path): # Regression test for crbug.com/454906 - self.RestartBrowserIfNecessaryWithArgs([]) + self.RestartBrowserIfNecessaryWithArgs(self._AddDefaultArgs([])) self._NavigateAndWait(test_path) tab = self.tab system_info = tab.browser.GetSystemInfo() @@ -258,16 +272,16 @@ self.fail('Must have a non-empty gl_renderer string') def _GpuProcess_driver_bug_workarounds_in_gpu_process(self, test_path): - self.RestartBrowserIfNecessaryWithArgs([ - '--use_gpu_driver_workaround_for_testing']) + self.RestartBrowserIfNecessaryWithArgs(self._AddDefaultArgs([ + '--use_gpu_driver_workaround_for_testing'])) self._Navigate(test_path) self._ValidateDriverBugWorkarounds( 'use_gpu_driver_workaround_for_testing', None) def _GpuProcess_readback_webgl_gpu_process(self, test_path): # Hit test group 1 with entry 152 from kSoftwareRenderingListEntries. - self.RestartBrowserIfNecessaryWithArgs([ - '--gpu-blacklist-test-group=1']) + self.RestartBrowserIfNecessaryWithArgs(self._AddDefaultArgs([ + '--gpu-blacklist-test-group=1'])) self._Navigate(test_path) feature_status_list = self.tab.EvaluateJavaScript( 'browserBridge.gpuInfo.featureStatus.featureStatus') @@ -286,8 +300,8 @@ if not self._SupportsSwiftShader(): return # Hit test group 2 with entry 153 from kSoftwareRenderingListEntries. - self.RestartBrowserIfNecessaryWithArgs([ - '--gpu-blacklist-test-group=2']) + self.RestartBrowserIfNecessaryWithArgs(self._AddDefaultArgs([ + '--gpu-blacklist-test-group=2'])) self._Navigate(test_path) feature_status_list = self.tab.EvaluateJavaScript( 'browserBridge.gpuInfo.featureStatus.featureStatus') @@ -322,7 +336,7 @@ def _GpuProcess_one_extra_workaround(self, test_path): # Start this test by launching the browser with no command line # arguments. - self.RestartBrowserIfNecessaryWithArgs([]) + self.RestartBrowserIfNecessaryWithArgs(self._AddDefaultArgs([])) self._Navigate(test_path) self._VerifyGpuProcessPresent() recorded_workarounds, recorded_disabled_gl_extensions = ( @@ -334,7 +348,7 @@ recorded_workarounds.append('use_gpu_driver_workaround_for_testing') browser_args.append('--disable-gl-extensions=' + recorded_disabled_gl_extensions) - self.RestartBrowserIfNecessaryWithArgs(browser_args) + self.RestartBrowserIfNecessaryWithArgs(self._AddDefaultArgs(browser_args)) self._Navigate(test_path) self._VerifyGpuProcessPresent() new_workarounds, new_disabled_gl_extensions = ( @@ -364,7 +378,8 @@ # Chrome on Android doesn't support software fallback, skip it. # TODO(zmo): If this test runs on ChromeOS, we also need to skip it. return - self.RestartBrowserIfNecessaryWithArgs(['--disable-gpu']) + self.RestartBrowserIfNecessaryWithArgs(self._AddDefaultArgs( + ['--disable-gpu'])) self._NavigateAndWait(test_path) # On Windows, Linux or MacOS, SwiftShader is enabled, so GPU process # will still launch with SwiftShader. @@ -387,16 +402,17 @@ # The current configuration will always launch a GPU process, skip test. return - self.RestartBrowserIfNecessaryWithArgs([ + self.RestartBrowserIfNecessaryWithArgs(self._AddDefaultArgs([ '--disable-gpu', - '--disable-software-rasterizer']) + '--disable-software-rasterizer'])) self._NavigateAndWait(test_path) if self.tab.EvaluateJavaScript('chrome.gpuBenchmarking.hasGpuProcess()'): self.fail('GPU process detected') def _GpuProcess_disable_swiftshader(self, test_path): # Disable SwiftShader, GPU process should be able to launch. - self.RestartBrowserIfNecessaryWithArgs(['--disable-software-rasterizer']) + self.RestartBrowserIfNecessaryWithArgs(self._AddDefaultArgs( + ['--disable-software-rasterizer'])) self._NavigateAndWait(test_path) if not self.tab.EvaluateJavaScript( 'chrome.gpuBenchmarking.hasGpuProcess()'): @@ -404,9 +420,9 @@ def _GpuProcess_disabling_workarounds_works(self, test_path): # Hit exception from id 215 from kGpuDriverBugListEntries. - self.RestartBrowserIfNecessaryWithArgs([ + self.RestartBrowserIfNecessaryWithArgs(self._AddDefaultArgs([ '--gpu-driver-bug-list-test-group=1', - '--use_gpu_driver_workaround_for_testing=0']) + '--use_gpu_driver_workaround_for_testing=0'])) self._Navigate(test_path) workarounds, _ = ( self._CompareAndCaptureDriverBugWorkarounds()) @@ -425,7 +441,7 @@ # Explicitly disable GPU access. ['--disable-gpu']) for args in args_list: - self.RestartBrowserIfNecessaryWithArgs(args) + self.RestartBrowserIfNecessaryWithArgs(self._AddDefaultArgs(args)) self._NavigateAndWait(test_path) # Validate the WebGL unmasked renderer string. renderer = self.tab.EvaluateJavaScript('gl_renderer') @@ -480,11 +496,124 @@ def _GpuProcess_webgl_disabled_extension(self, test_path): # Hit exception from id 257 from kGpuDriverBugListEntries. - self.RestartBrowserIfNecessaryWithArgs([ + self.RestartBrowserIfNecessaryWithArgs(self._AddDefaultArgs([ '--gpu-driver-bug-list-test-group=2', - ]) + ])) self._NavigateAndWait(test_path) + + def _GpuProcess_mac_webgl_low_power(self, test_path): + # Ensures that low-power WebGL content stays on the low-power GPU. + if not self._IsDualGPUMacLaptop(): + logging.info('Skipping test because not running on dual-GPU Mac laptop') + return + # Start with a clean browser instance to ensure the GPU process is in a + # clean state. + self.RestartBrowserWithArgs(self._AddDefaultArgs([])) + # Wait a few seconds for the system to dispatch any GPU switched + # notifications. + time.sleep(3) + self._NavigateAndWait(test_path) + # Sleep for several seconds to ensure that any GPU switch is detected. + time.sleep(6) + if not self._IsIntelGPUActive(): + self.fail( + 'Low-power WebGL context incorrectly activated the high-performance ' + 'GPU') + + def _GpuProcess_mac_webgl_high_performance(self, test_path): + # Ensures that high-performance WebGL content activates the high-performance + # GPU. + if not self._IsDualGPUMacLaptop(): + logging.info('Skipping test because not running on dual-GPU Mac laptop') + return + # Start with a clean browser instance to ensure the GPU process is in a + # clean state. + self.RestartBrowserWithArgs(self._AddDefaultArgs([])) + # Wait a few seconds for the system to dispatch any GPU switched + # notifications. + time.sleep(3) + self._NavigateAndWait(test_path) + # Sleep for several seconds to ensure that any GPU switch is detected. + time.sleep(6) + if self._IsIntelGPUActive(): + self.fail( + 'High-performance WebGL context did not activate the high-performance ' + 'GPU') + + def _GpuProcess_mac_webgl_backgrounded_high_performance(self, test_path): + # Ensures that high-performance WebGL content in a background tab releases + # the hold on the discrete GPU after 10 seconds. + if not self._IsDualGPUMacLaptop(): + logging.info('Skipping test because not running on dual-GPU Mac laptop') + return + # Start with a clean browser instance to ensure the GPU process is in a + # clean state. + self.RestartBrowserWithArgs(self._AddDefaultArgs([])) + # Wait a few seconds for the system to dispatch any GPU switched + # notifications. + time.sleep(3) + self._NavigateAndWait(test_path) + blank_tab = self.tab + # Create a new tab and navigate it to the high-power WebGL test. + webgl_tab = self.browser.tabs.New() + webgl_tab.Activate() + webgl_url = self.UrlOfStaticFilePath( + 'gpu/functional_webgl_high_performance.html') + webgl_tab.action_runner.Navigate( + webgl_url, script_to_evaluate_on_commit=test_harness_script) + self._WaitForTestCompletion(webgl_tab) + # Verify that the high-performance GPU is active. + if self._IsIntelGPUActive(): + self.fail( + 'High-performance WebGL context did not activate the high-performance ' + 'GPU') + # Now activate the original tab. + blank_tab.Activate() + # Sleep for >10 seconds in order to wait for the hold on the + # high-performance GPU to be released. + time.sleep(15) + if not self._IsIntelGPUActive(): + self.fail( + 'Backgrounded high-performance WebGL context did not release the hold ' + 'on the high-performance GPU') + + def _GpuProcess_mac_webgl_terminated_high_performance(self, test_path): + # Ensures that high-performance WebGL content in a background tab releases + # the hold on the discrete GPU after 10 seconds. + if not self._IsDualGPUMacLaptop(): + logging.info('Skipping test because not running on dual-GPU Mac laptop') + return + # Start with a clean browser instance to ensure the GPU process is in a + # clean state. + self.RestartBrowserWithArgs(self._AddDefaultArgs([])) + # Wait a few seconds for the system to dispatch any GPU switched + # notifications. + time.sleep(3) + self._NavigateAndWait(test_path) + # Create a new tab and navigate it to the high-power WebGL test. + webgl_tab = self.browser.tabs.New() + webgl_tab.Activate() + webgl_url = self.UrlOfStaticFilePath( + 'gpu/functional_webgl_high_performance.html') + webgl_tab.action_runner.Navigate( + webgl_url, script_to_evaluate_on_commit=test_harness_script) + self._WaitForTestCompletion(webgl_tab) + # Verify that the high-performance GPU is active. + if self._IsIntelGPUActive(): + self.fail( + 'High-performance WebGL context did not activate the high-performance ' + 'GPU') + # Close the high-performance WebGL tab. + webgl_tab.Close() + # Sleep for >10 seconds in order to wait for the hold on the + # high-performance GPU to be released. + time.sleep(15) + if not self._IsIntelGPUActive(): + self.fail( + 'Backgrounded high-performance WebGL context did not release the hold ' + 'on the high-performance GPU') + @classmethod def ExpectationsFiles(cls): return [
diff --git a/content/test/gpu/gpu_tests/pixel_integration_test.py b/content/test/gpu/gpu_tests/pixel_integration_test.py index e5119d2..d8bc6959 100644 --- a/content/test/gpu/gpu_tests/pixel_integration_test.py +++ b/content/test/gpu/gpu_tests/pixel_integration_test.py
@@ -2,8 +2,10 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import logging import os import sys +import time from gpu_tests import gpu_integration_test from gpu_tests import pixel_test_pages @@ -62,6 +64,10 @@ # pages += namespace.SwiftShaderPages(cls.test_base_name) if sys.platform.startswith('darwin'): pages += namespace.MacSpecificPages(cls.test_base_name) + # Unfortunately we don't have a browser instance here so can't tell + # whether we should really run these tests. They're short-circuited to a + # certain degree on the other platforms. + pages += namespace.DualGPUMacSpecificPages(cls.test_base_name) if sys.platform.startswith('win'): pages += namespace.DirectCompositionPages(cls.test_base_name) pages += namespace.LowLatencySwapChainPages(cls.test_base_name) @@ -165,6 +171,42 @@ dummy_tab.action_runner.Wait(2) tab.Activate() + def _RunTestWithHighPerformanceTab(self, tab, page): + if not self._IsDualGPUMacLaptop(): + # Short-circuit this test. + logging.info('Short-circuiting test because not running on dual-GPU Mac ' + 'laptop') + tab.EvaluateJavaScript('initialize()') + tab.action_runner.WaitForJavaScriptCondition( + 'domAutomationController._readyForActions', timeout=30) + tab.EvaluateJavaScript('runToCompletion()') + return + # Reset the ready state of the harness. + tab.EvaluateJavaScript('domAutomationController._readyForActions = false') + high_performance_tab = tab.browser.tabs.New() + high_performance_tab.Navigate(self.UrlOfStaticFilePath( + skia_gold_integration_test_base.GPU_RELATIVE_PATH + + 'functional_webgl_high_performance.html'), + script_to_evaluate_on_commit=test_harness_script) + high_performance_tab.action_runner.WaitForJavaScriptCondition( + 'domAutomationController._finished', timeout=30) + # Wait a few seconds for the GPU switched notification to propagate + # throughout the system. + time.sleep(5) + # Switch back to the main tab and quickly start its rendering, while the + # high-power GPU is still active. + tab.Activate() + tab.EvaluateJavaScript('initialize()') + tab.action_runner.WaitForJavaScriptCondition( + 'domAutomationController._readyForActions', timeout=30) + # Close the high-performance tab. + high_performance_tab.Close() + # Wait for ~15 seconds for the system to switch back to the + # integrated GPU. + time.sleep(15) + # Run the page to completion. + tab.EvaluateJavaScript('runToCompletion()') + @classmethod def ExpectationsFiles(cls): return [
diff --git a/content/test/gpu/gpu_tests/pixel_test_pages.py b/content/test/gpu/gpu_tests/pixel_test_pages.py index 244466c..c7a89f95 100644 --- a/content/test/gpu/gpu_tests/pixel_test_pages.py +++ b/content/test/gpu/gpu_tests/pixel_test_pages.py
@@ -1169,6 +1169,41 @@ ]), ] + # Pages that should be run only on dual-GPU MacBook Pros (at the + # present time, anyway). + @staticmethod + def DualGPUMacSpecificPages(base_name): + return [ + PixelTestPage( + 'pixel_webgl_high_to_low_power.html', + base_name + '_WebGLHighToLowPower', + test_rect=[0, 0, 300, 300], + tolerance=3, + expected_colors=[ + { + 'comment': 'solid green', + 'location': [100, 100], + 'size': [100, 100], + 'color': [0, 255, 0], + } + ], + optional_action='RunTestWithHighPerformanceTab'), + + PixelTestPage( + 'pixel_webgl_low_to_high_power.html', + base_name + '_WebGLLowToHighPower', + test_rect=[0, 0, 300, 300], + tolerance=3, + expected_colors=[ + { + 'comment': 'solid green', + 'location': [100, 100], + 'size': [100, 100], + 'color': [0, 255, 0], + } + ]), + ] + @staticmethod def DirectCompositionPages(base_name): browser_args = [
diff --git a/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt index bc9154b..85cdbd9 100644 --- a/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt
@@ -45,3 +45,9 @@ crbug.com/609629 [ android qualcomm-adreno-(tm)-420 ] GpuCrash_GPUProcessCrashesExactlyOncePerVisitToAboutGpuCrash [ Skip ] crbug.com/609629 [ android qualcomm-adreno-(tm)-420 ] ContextLost_WebGLContextLostFromGPUProcessExit [ Skip ] crbug.com/609629 [ android qualcomm-adreno-(tm)-420 ] ContextLost_WebGLContextLostInHiddenTab [ Skip ] + +# TODO(crbug.com/681341): enable these new tests immediately after they land. +# Disabled upon landing only to avoid having the entire CL reverted if the new +# tests turn out to be flaky. +crbug.com/681341 ContextLost_MacWebGLMultisamplingHighPowerSwitchLosesContext [ Skip ] +crbug.com/681341 ContextLost_MacWebGLPreserveDBHighPowerSwitchLosesContext [ Skip ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt index 71e3a1b..f4f7d48 100644 --- a/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt
@@ -6,3 +6,10 @@ # Seems to have become flaky on Windows recently. crbug.com/700522 [ win ] GpuProcess_one_extra_workaround [ RetryOnFailure ] +# TODO(crbug.com/681341): enable these new tests immediately after they land. +# Disabled upon landing only to avoid having the entire CL reverted if the new +# tests turn out to be flaky. +crbug.com/681341 GpuProcess_mac_webgl_backgrounded_high_performance [ Skip ] +crbug.com/681341 GpuProcess_mac_webgl_high_performance [ Skip ] +crbug.com/681341 GpuProcess_mac_webgl_low_power [ Skip ] +crbug.com/681341 GpuProcess_mac_webgl_terminated_high_performance [ Skip ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt index fe863b3c..21297a3 100644 --- a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
@@ -262,3 +262,9 @@ crbug.com/1019462 [ android nvidia no-skia-renderer ] Pixel_Video_MP4_Rounded_Corner [ RetryOnFailure ] crbug.com/1019462 [ android nvidia no-skia-renderer ] Pixel_Video_Context_Loss_VP9 [ RetryOnFailure ] crbug.com/1019462 [ android nvidia no-skia-renderer ] Pixel_WebGL2_BlitFramebuffer_Result_Displayed [ RetryOnFailure ] + +# TODO(crbug.com/681341): enable these new tests immediately after they land. +# Disabled upon landing only to avoid having the entire CL reverted if the new +# tests turn out to be flaky. +crbug.com/681341 [ mac ] Pixel_WebGLHighToLowPower [ Skip ] +crbug.com/681341 [ mac ] Pixel_WebGLLowToHighPower [ Skip ]
diff --git a/device/vr/BUILD.gn b/device/vr/BUILD.gn index 2670b19..e47ed6b 100644 --- a/device/vr/BUILD.gn +++ b/device/vr/BUILD.gn
@@ -249,8 +249,6 @@ "test/fake_vr_device.h", "test/fake_vr_device_provider.cc", "test/fake_vr_device_provider.h", - "test/fake_vr_display_impl_client.cc", - "test/fake_vr_display_impl_client.h", "test/fake_vr_service_client.cc", "test/fake_vr_service_client.h", "vr_export.h",
diff --git a/device/vr/android/gvr/gvr_delegate_provider.h b/device/vr/android/gvr/gvr_delegate_provider.h index 17625ee..a7391d2 100644 --- a/device/vr/android/gvr/gvr_delegate_provider.h +++ b/device/vr/android/gvr/gvr_delegate_provider.h
@@ -24,7 +24,6 @@ mojom::XRRuntimeSessionOptionsPtr options, base::OnceCallback<void(device::mojom::XRSessionPtr)> callback) = 0; virtual void ExitWebVRPresent() = 0; - virtual void OnListeningForActivateChanged(bool listening) = 0; protected: virtual ~GvrDelegateProvider() = default;
diff --git a/device/vr/android/gvr/gvr_device.cc b/device/vr/android/gvr/gvr_device.cc index 7a56b30..c1c7e59 100644 --- a/device/vr/android/gvr/gvr_device.cc +++ b/device/vr/android/gvr/gvr_device.cc
@@ -254,13 +254,6 @@ exclusive_controller_receiver_.reset(); } -void GvrDevice::OnListeningForActivate(bool listening) { - GvrDelegateProvider* delegate_provider = GetGvrDelegateProvider(); - if (!delegate_provider) - return; - delegate_provider->OnListeningForActivateChanged(listening); -} - void GvrDevice::PauseTracking() { paused_ = true; if (gvr_api_ && non_presenting_context_.obj()) { @@ -297,11 +290,6 @@ SetVRDisplayInfo(CreateVRDisplayInfo(gvr_api_.get(), GetId())); } -void GvrDevice::Activate(mojom::VRDisplayEventReason reason, - base::Callback<void(bool)> on_handled) { - OnActivate(reason, std::move(on_handled)); -} - void GvrDevice::Init(base::OnceCallback<void(bool)> on_finished) { GvrDelegateProvider* delegate_provider = GetGvrDelegateProvider(); if (!delegate_provider || delegate_provider->ShouldDisableGvrDevice()) {
diff --git a/device/vr/android/gvr/gvr_device.h b/device/vr/android/gvr/gvr_device.h index 22aebae0..e44b9cb 100644 --- a/device/vr/android/gvr/gvr_device.h +++ b/device/vr/android/gvr/gvr_device.h
@@ -38,13 +38,7 @@ JNIEnv* env, const base::android::JavaRef<jobject>& obj); - void Activate(mojom::VRDisplayEventReason reason, - base::Callback<void(bool)> on_handled); - private: - // VRDeviceBase - void OnListeningForActivate(bool listening) override; - void OnStartPresentResult(mojom::XRSessionPtr session); // XRSessionController
diff --git a/device/vr/public/mojom/isolated_xr_service.mojom b/device/vr/public/mojom/isolated_xr_service.mojom index 07234ee6..163c9b4 100644 --- a/device/vr/public/mojom/isolated_xr_service.mojom +++ b/device/vr/public/mojom/isolated_xr_service.mojom
@@ -27,13 +27,6 @@ // A device has changed its display information. OnDisplayInfoChanged(device.mojom.VRDisplayInfo display_info); - // A device has indicated that it is in use. - OnDeviceActivated(device.mojom.VRDisplayEventReason reason) => - (bool will_not_present); - - // A device has indicated that it is idle. - OnDeviceIdle(device.mojom.VRDisplayEventReason reason); - // A device has indicated that the visibility of the content it's displaying // has changed. OnVisibilityStateChanged(device.mojom.XRVisibilityState visibility_state); @@ -88,8 +81,6 @@ // GvrDevice::RequestSession(). EnsureInitialized() => (); - SetListeningForActivate(bool listen_for_activation); - SetInlinePosesEnabled(bool enable); };
diff --git a/device/vr/public/mojom/vr_service.mojom b/device/vr/public/mojom/vr_service.mojom index b4c7045..f8c86aa 100644 --- a/device/vr/public/mojom/vr_service.mojom +++ b/device/vr/public/mojom/vr_service.mojom
@@ -465,13 +465,6 @@ XRHitTestSubscriptionResultsData? hit_test_subscription_results; }; -enum VRDisplayEventReason { - NONE = 0, - NAVIGATION = 1, - MOUNTED = 2, - UNMOUNTED = 3 -}; - enum RequestSessionError { ORIGIN_NOT_SECURE = 1, EXISTING_IMMERSIVE_SESSION = 2, @@ -502,10 +495,6 @@ // A bad message will be reported if this is called multiple times. SetClient(pending_remote<VRServiceClient> client); - // WebVR 1.1 functionality compatibility method. To stop listening pass a null - // client. - SetListeningForActivate(pending_remote<VRDisplayClient>? client); - // Request to initialize a session in the browser process. If successful, the // XRSession struct with the requisite interfaces will be returned. RequestSession(XRSessionOptions options) => (RequestSessionResult result); @@ -724,15 +713,3 @@ // Indicates a change in the visibility of the WebXR content. OnVisibilityStateChanged(XRVisibilityState visibility_state); }; - -// Backwards compatibility events for WebVR 1.1. These are expected to not be -// used for WebXR. -interface VRDisplayClient { - // Inform the renderer that a headset has sent a signal indicating that the - // user has put it on. Returns an indicator of whether or not the page - // actually started a WebVR 1.1 presentation. - OnActivate(VRDisplayEventReason reason) => (bool will_not_present); - // Inform the renderer that a headset has sent a signal indicating that the - // user stopped using a headset. - OnDeactivate(VRDisplayEventReason reason); -};
diff --git a/device/vr/test/fake_vr_display_impl_client.cc b/device/vr/test/fake_vr_display_impl_client.cc deleted file mode 100644 index 09f64c69..0000000 --- a/device/vr/test/fake_vr_display_impl_client.cc +++ /dev/null
@@ -1,25 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "device/vr/test/fake_vr_display_impl_client.h" -#include "device/vr/test/fake_vr_service_client.h" - -namespace device { - -FakeVRDisplayImplClient::FakeVRDisplayImplClient( - mojo::PendingReceiver<mojom::VRDisplayClient> receiver) - : receiver_(this, std::move(receiver)) {} - -FakeVRDisplayImplClient::~FakeVRDisplayImplClient() {} - -void FakeVRDisplayImplClient::SetServiceClient( - FakeVRServiceClient* service_client) { - service_client_ = service_client; -} - -void FakeVRDisplayImplClient::OnChanged(mojom::VRDisplayInfoPtr display) { - service_client_->SetLastDeviceId(display->id); -} - -} // namespace device
diff --git a/device/vr/test/fake_vr_display_impl_client.h b/device/vr/test/fake_vr_display_impl_client.h deleted file mode 100644 index 836ff308..0000000 --- a/device/vr/test/fake_vr_display_impl_client.h +++ /dev/null
@@ -1,43 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef DEVICE_VR_TEST_FAKE_VR_DISPLAY_IMPL_CLIENT_H_ -#define DEVICE_VR_TEST_FAKE_VR_DISPLAY_IMPL_CLIENT_H_ - -#include "device/vr/public/mojom/vr_service.mojom.h" -#include "mojo/public/cpp/bindings/pending_receiver.h" -#include "mojo/public/cpp/bindings/receiver.h" - -namespace device { -class FakeVRServiceClient; - -class FakeVRDisplayImplClient : public mojom::VRDisplayClient, - public mojom::XRSessionClient { - public: - explicit FakeVRDisplayImplClient( - mojo::PendingReceiver<mojom::VRDisplayClient> receiver); - ~FakeVRDisplayImplClient() override; - - void SetServiceClient(FakeVRServiceClient* service_client); - // mojom::XRSessionClient overrides - void OnChanged(mojom::VRDisplayInfoPtr display) override; - void OnExitPresent() override {} - void OnVisibilityStateChanged( - mojom::XRVisibilityState visibility_state) override {} - // mojom::VRDisplayClient overrides - void OnActivate(mojom::VRDisplayEventReason reason, - OnActivateCallback callback) override {} - void OnDeactivate(mojom::VRDisplayEventReason reason) override {} - - private: - FakeVRServiceClient* service_client_; - mojom::VRDisplayInfoPtr last_display_; - mojo::Receiver<mojom::VRDisplayClient> receiver_; - - DISALLOW_COPY_AND_ASSIGN(FakeVRDisplayImplClient); -}; - -} // namespace device - -#endif // DEVICE_VR_TEST_FAKE_VR_DISPLAY_IMPL_CLIENT_H_
diff --git a/device/vr/test/fake_vr_service_client.cc b/device/vr/test/fake_vr_service_client.cc index 62e99f7e..c569673 100644 --- a/device/vr/test/fake_vr_service_client.cc +++ b/device/vr/test/fake_vr_service_client.cc
@@ -3,7 +3,6 @@ // found in the LICENSE file. #include "device/vr/test/fake_vr_service_client.h" -#include "device/vr/test/fake_vr_display_impl_client.h" namespace device {
diff --git a/device/vr/test/fake_vr_service_client.h b/device/vr/test/fake_vr_service_client.h index f52e660..68d8311 100644 --- a/device/vr/test/fake_vr_service_client.h +++ b/device/vr/test/fake_vr_service_client.h
@@ -11,8 +11,6 @@ #include "mojo/public/cpp/bindings/receiver.h" namespace device { -class FakeVRDisplayImplClient; - // TODO(mthiesse, crbug.com/769373): Remove DEVICE_VR_EXPORT. class DEVICE_VR_EXPORT FakeVRServiceClient : public mojom::VRServiceClient { public: @@ -25,8 +23,6 @@ bool CheckDeviceId(mojom::XRDeviceId id); private: - std::vector<mojom::VRDisplayInfoPtr> displays_; - std::vector<std::unique_ptr<FakeVRDisplayImplClient>> display_clients_; mojom::XRDeviceId last_device_id_ = static_cast<mojom::XRDeviceId>(0); mojo::Receiver<mojom::VRServiceClient> receiver_;
diff --git a/device/vr/vr_device_base.cc b/device/vr/vr_device_base.cc index dc5aa21..dabda27 100644 --- a/device/vr/vr_device_base.cc +++ b/device/vr/vr_device_base.cc
@@ -69,12 +69,6 @@ listener_->OnDisplayInfoChanged(display_info_.Clone()); } -void VRDeviceBase::OnActivate(mojom::VRDisplayEventReason reason, - base::Callback<void(bool)> on_handled) { - if (listener_) - listener_->OnDeviceActivated(reason, std::move(on_handled)); -} - void VRDeviceBase::OnVisibilityStateChanged( mojom::XRVisibilityState visibility_state) { if (listener_) @@ -86,12 +80,6 @@ return runtime_receiver_.BindNewPipeAndPassRemote(); } -void VRDeviceBase::OnListeningForActivate(bool listening) {} - -void VRDeviceBase::SetListeningForActivate(bool is_listening) { - OnListeningForActivate(is_listening); -} - void VRDeviceBase::EnsureInitialized(EnsureInitializedCallback callback) { std::move(callback).Run(); }
diff --git a/device/vr/vr_device_base.h b/device/vr/vr_device_base.h index 325981f..feffa80b 100644 --- a/device/vr/vr_device_base.h +++ b/device/vr/vr_device_base.h
@@ -33,7 +33,6 @@ void ListenToDeviceChanges( mojo::PendingAssociatedRemote<mojom::XRRuntimeEventListener> listener, mojom::XRRuntime::ListenToDeviceChangesCallback callback) final; - void SetListeningForActivate(bool is_listening) override; void EnsureInitialized(EnsureInitializedCallback callback) override; void SetInlinePosesEnabled(bool enable) override; void ShutdownSession(mojom::XRRuntime::ShutdownSessionCallback) override; @@ -67,8 +66,6 @@ void OnStartPresenting(); bool IsPresenting() { return presenting_; } // Exposed for test. void SetVRDisplayInfo(mojom::VRDisplayInfoPtr display_info); - void OnActivate(mojom::VRDisplayEventReason reason, - base::Callback<void(bool)> on_handled); void OnVisibilityStateChanged(mojom::XRVisibilityState visibility_state); mojom::VRDisplayInfoPtr display_info_; @@ -76,8 +73,6 @@ bool inline_poses_enabled_ = true; private: - // TODO(https://crbug.com/842227): Rename methods to HandleOnXXX - virtual void OnListeningForActivate(bool listening); mojo::AssociatedRemote<mojom::XRRuntimeEventListener> listener_;
diff --git a/device/vr/vr_device_base_unittest.cc b/device/vr/vr_device_base_unittest.cc index e3cc3978..b1dde911 100644 --- a/device/vr/vr_device_base_unittest.cc +++ b/device/vr/vr_device_base_unittest.cc
@@ -31,22 +31,11 @@ SetVRDisplayInfo(std::move(display_info)); } - void FireDisplayActivate() { - OnActivate(device::mojom::VRDisplayEventReason::MOUNTED, base::DoNothing()); - } - - bool ListeningForActivate() { return listening_for_activate; } - void RequestSession( mojom::XRRuntimeSessionOptionsPtr options, mojom::XRRuntime::RequestSessionCallback callback) override {} private: - void OnListeningForActivate(bool listening) override { - listening_for_activate = listening; - } - - bool listening_for_activate = false; DISALLOW_COPY_AND_ASSIGN(VRDeviceBaseForTesting); }; @@ -61,20 +50,8 @@ DoOnChanged(vr_device_info.get()); } - MOCK_METHOD2(DoOnDeviceActivated, - void(mojom::VRDisplayEventReason, - base::OnceCallback<void(bool)>)); - void OnDeviceActivated(mojom::VRDisplayEventReason reason, - base::OnceCallback<void(bool)> callback) override { - DoOnDeviceActivated(reason, base::DoNothing()); - // For now keep the test simple, and just call the callback: - std::move(callback).Run(true); - } - MOCK_METHOD0(OnExitPresent, void()); MOCK_METHOD1(OnVisibilityStateChanged, void(mojom::XRVisibilityState)); - MOCK_METHOD1(OnDeviceIdle, void(mojom::VRDisplayEventReason)); - MOCK_METHOD0(OnInitialized, void()); mojo::PendingAssociatedRemote<mojom::XRRuntimeEventListener> BindPendingRemote() { @@ -127,24 +104,4 @@ base::RunLoop().RunUntilIdle(); } -TEST_F(VRDeviceTest, DisplayActivateRegsitered) { - device::mojom::VRDisplayEventReason mounted = - device::mojom::VRDisplayEventReason::MOUNTED; - auto device = MakeVRDevice(); - mojo::Remote<mojom::XRRuntime> device_remote(device->BindXRRuntime()); - StubVRDeviceEventListener listener; - device_remote->ListenToDeviceChanges( - listener.BindPendingRemote(), - base::DoNothing()); // TODO: consider getting initial data - base::RunLoop().RunUntilIdle(); - - EXPECT_FALSE(device->ListeningForActivate()); - device->SetListeningForActivate(true); - EXPECT_TRUE(device->ListeningForActivate()); - - EXPECT_CALL(listener, DoOnDeviceActivated(mounted, testing::_)).Times(1); - device->FireDisplayActivate(); - base::RunLoop().RunUntilIdle(); -} - } // namespace device
diff --git a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc index c02807b..20724d5 100644 --- a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc +++ b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc
@@ -82,7 +82,6 @@ traffic_annotation_(traffic_annotation), proxied_loader_receiver_(this, std::move(loader_receiver)), target_client_(std::move(client)), - proxied_client_binding_(this), current_response_(network::mojom::URLResponseHead::New()), has_any_extra_headers_listeners_( network_service_request_id_ != 0 && @@ -108,7 +107,6 @@ original_initiator_(request.request_initiator), request_id_(request_id), proxied_loader_receiver_(this), - proxied_client_binding_(this), for_cors_preflight_(true), has_any_extra_headers_listeners_( ExtensionWebRequestEventRouter::GetInstance() @@ -204,9 +202,9 @@ // they respond. |continuation| above will be invoked asynchronously to // continue or cancel the request. // - // We pause the binding here to prevent further client message processing. - if (proxied_client_binding_.is_bound()) - proxied_client_binding_.PauseIncomingMethodCallProcessing(); + // We pause the receiver here to prevent further client message processing. + if (proxied_client_receiver_.is_bound()) + proxied_client_receiver_.Pause(); // Pause the header client, since we want to wait until OnBeforeRequest has // finished before processing any future events. @@ -395,7 +393,7 @@ header_client_receiver_.Bind(std::move(receiver)); if (for_cors_preflight_) { // In this case we don't have |target_loader_| and - // |proxied_client_binding_|, and |receiver| is the only connection to the + // |proxied_client_receiver_|, and |receiver| is the only connection to the // network service, so we observe mojo connection errors. header_client_receiver_.set_disconnect_handler(base::BindOnce( &WebRequestProxyingURLLoaderFactory::InProgressRequest::OnRequestError, @@ -453,7 +451,7 @@ // bugs. The latter doesn't know anything about the redirect. Continuing // the load with it gives unexpected results. See // https://crbug.com/882661#c72. - proxied_client_binding_.Close(); + proxied_client_receiver_.reset(); header_client_receiver_.reset(); target_loader_.reset(); @@ -523,8 +521,8 @@ return; } - if (proxied_client_binding_.is_bound()) - proxied_client_binding_.ResumeIncomingMethodCallProcessing(); + if (proxied_client_receiver_.is_bound()) + proxied_client_receiver_.Resume(); if (request_.url.SchemeIsHTTPOrHTTPS()) { // NOTE: While it does not appear to be documented (and in fact it may be @@ -551,8 +549,8 @@ // continue or cancel the request. // // We pause the binding here to prevent further client message processing. - if (proxied_client_binding_.is_bound()) - proxied_client_binding_.PauseIncomingMethodCallProcessing(); + if (proxied_client_receiver_.is_bound()) + proxied_client_receiver_.Pause(); return; } DCHECK_EQ(net::OK, result); @@ -579,8 +577,8 @@ return; } - if (proxied_client_binding_.is_bound()) - proxied_client_binding_.ResumeIncomingMethodCallProcessing(); + if (proxied_client_receiver_.is_bound()) + proxied_client_receiver_.Resume(); if (header_client_receiver_.is_bound()) header_client_receiver_.Resume(); @@ -596,7 +594,7 @@ // No extensions have cancelled us up to this point, so it's now OK to // initiate the real network request. network::mojom::URLLoaderClientPtr proxied_client; - proxied_client_binding_.Bind(mojo::MakeRequest(&proxied_client)); + proxied_client_receiver_.Bind(mojo::MakeRequest(&proxied_client)); uint32_t options = options_; // Even if this request does not use the header client, future redirects // might, so we need to set the option on the loader. @@ -651,8 +649,8 @@ pending_follow_redirect_params_.reset(); } - if (proxied_client_binding_.is_bound()) - proxied_client_binding_.ResumeIncomingMethodCallProcessing(); + if (proxied_client_receiver_.is_bound()) + proxied_client_receiver_.Resume(); if (request_.url.SchemeIsHTTPOrHTTPS()) { // NOTE: While it does not appear to be documented (and in fact it may be @@ -707,8 +705,8 @@ OnAuthRequestHandled( WebRequestAPI::AuthRequestCallback callback, ExtensionWebRequestEventRouter::AuthRequiredResponse response) { - if (proxied_client_binding_.is_bound()) - proxied_client_binding_.ResumeIncomingMethodCallProcessing(); + if (proxied_client_receiver_.is_bound()) + proxied_client_receiver_.Resume(); base::OnceClosure completion; switch (response) { @@ -781,8 +779,8 @@ return; } - if (proxied_client_binding_) - proxied_client_binding_.ResumeIncomingMethodCallProcessing(); + if (proxied_client_receiver_.is_bound()) + proxied_client_receiver_.Resume(); } void WebRequestProxyingURLLoaderFactory::InProgressRequest:: @@ -817,7 +815,7 @@ // These will get re-bound if a new request is initiated by // |FollowRedirect()|. - proxied_client_binding_.Close(); + proxied_client_receiver_.reset(); header_client_receiver_.reset(); target_loader_.reset(); @@ -827,7 +825,7 @@ info_->AddResponseInfoFromResourceResponse(*current_response_); - proxied_client_binding_.ResumeIncomingMethodCallProcessing(); + proxied_client_receiver_.Resume(); ExtensionWebRequestEventRouter::GetInstance()->OnResponseStarted( factory_->browser_context_, &info_.value(), net::OK); @@ -844,8 +842,8 @@ info_->AddResponseInfoFromResourceResponse(*current_response_); - if (proxied_client_binding_.is_bound()) - proxied_client_binding_.ResumeIncomingMethodCallProcessing(); + if (proxied_client_receiver_.is_bound()) + proxied_client_receiver_.Resume(); ExtensionWebRequestEventRouter::GetInstance()->OnBeforeRedirect( factory_->browser_context_, &info_.value(), redirect_info.new_url); @@ -884,14 +882,14 @@ } if (result == net::ERR_IO_PENDING) { - if (proxied_client_binding_.is_bound()) { + if (proxied_client_receiver_.is_bound()) { // One or more listeners is blocking, so the request must be paused // until they respond. |continuation| above will be invoked // asynchronously to continue or cancel the request. // - // We pause the binding here to prevent further client message + // We pause the receiver here to prevent further client message // processing. - proxied_client_binding_.PauseIncomingMethodCallProcessing(); + proxied_client_receiver_.Pause(); } return; }
diff --git a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h index 6d539b45..2b3eae7 100644 --- a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h +++ b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h
@@ -145,7 +145,8 @@ base::Optional<WebRequestInfo> info_; - mojo::Binding<network::mojom::URLLoaderClient> proxied_client_binding_; + mojo::Receiver<network::mojom::URLLoaderClient> proxied_client_receiver_{ + this}; network::mojom::URLLoaderPtr target_loader_; // NOTE: This is state which ExtensionWebRequestEventRouter needs to have
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h index 6eee8b7..5906339 100644 --- a/extensions/browser/extension_function_histogram_value.h +++ b/extensions/browser/extension_function_histogram_value.h
@@ -1466,6 +1466,7 @@ AUTOTESTPRIVATE_REMOVEACTIVEDESK = 1403, TERMINALPRIVATE_GETCROSHSETTINGS = 1404, AUTOTESTPRIVATE_ENABLEASSISTANTANDWAITFORREADY = 1405, + INPUTMETHODPRIVATE_FINISHCOMPOSINGTEXT = 1406, // Last entry: Add new entries above, then run: // python tools/metrics/histograms/update_extension_histograms.py ENUM_BOUNDARY
diff --git a/google_apis/gaia/gaia_auth_fetcher.cc b/google_apis/gaia/gaia_auth_fetcher.cc index 257e5dd..fb3a1c8 100644 --- a/google_apis/gaia/gaia_auth_fetcher.cc +++ b/google_apis/gaia/gaia_auth_fetcher.cc
@@ -620,16 +620,13 @@ } void GaiaAuthFetcher::StartTokenFetchForUberAuthExchange( - const std::string& access_token, - bool is_bound_to_channel_id) { + const std::string& access_token) { DCHECK(!fetch_pending_) << "Tried to fetch two things at once!"; VLOG(1) << "Starting StartTokenFetchForUberAuthExchange with access_token=" << access_token; std::string authentication_header = base::StringPrintf(kOAuthHeaderFormat, access_token.c_str()); - int load_flags = - is_bound_to_channel_id ? net::LOAD_NORMAL : kLoadFlagsIgnoreCookies; net::NetworkTrafficAnnotationTag traffic_annotation = net::DefineNetworkTrafficAnnotation("gaia_auth_fetch_for_uber", R"( semantics { @@ -658,7 +655,7 @@ } })"); CreateAndStartGaiaFetcher(std::string(), authentication_header, - uberauth_token_gurl_, load_flags, + uberauth_token_gurl_, kLoadFlagsIgnoreCookies, traffic_annotation); }
diff --git a/google_apis/gaia/gaia_auth_fetcher.h b/google_apis/gaia/gaia_auth_fetcher.h index 68cf5f3..bb7e3021 100644 --- a/google_apis/gaia/gaia_auth_fetcher.h +++ b/google_apis/gaia/gaia_auth_fetcher.h
@@ -143,13 +143,10 @@ // Start a request to exchange an OAuthLogin-scoped oauth2 access token for an // uber-auth token. The returned token can be used with the method // StartMergeSession(). - // If |is_bound_to_channel_id| is true, then the generated UberToken will - // be bound to the channel ID of the network context of |getter_|. // // Either OnUberAuthTokenSuccess or OnUberAuthTokenFailure will be // called on the consumer on the original thread. - void StartTokenFetchForUberAuthExchange(const std::string& access_token, - bool is_bound_to_channel_id); + void StartTokenFetchForUberAuthExchange(const std::string& access_token); // Start a request to exchange an OAuthLogin-scoped oauth2 access token for a // ClientLogin-style service tokens. The response to this request is the
diff --git a/google_apis/gaia/gaia_auth_fetcher_unittest.cc b/google_apis/gaia/gaia_auth_fetcher_unittest.cc index 018d8b8..86840c0 100644 --- a/google_apis/gaia/gaia_auth_fetcher_unittest.cc +++ b/google_apis/gaia/gaia_auth_fetcher_unittest.cc
@@ -464,8 +464,7 @@ EXPECT_CALL(consumer, OnUberAuthTokenSuccess("uberToken")).Times(1); TestGaiaAuthFetcher auth(&consumer, GetURLLoaderFactory()); - auth.StartTokenFetchForUberAuthExchange("myAccessToken", - true /* is_bound_to_channel_id */); + auth.StartTokenFetchForUberAuthExchange("myAccessToken"); EXPECT_TRUE(auth.HasPendingFetch()); auth.TestOnURLLoadCompleteInternal(net::OK, net::HTTP_OK, "uberToken");
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc index 914d6f12..3d6312a 100644 --- a/gpu/command_buffer/client/gles2_implementation.cc +++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -53,6 +53,7 @@ #include "gpu/command_buffer/common/sync_token.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect_f.h" +#include "ui/gl/gpu_preference.h" #if !defined(__native_client__) #include "ui/gfx/color_space.h" @@ -386,17 +387,19 @@ std::move(callback).Run(params); } -void GLES2Implementation::OnGpuSwitched() { - share_group_->SetGpuSwitched(true); +void GLES2Implementation::OnGpuSwitched( + gl::GpuPreference active_gpu_heuristic) { + gpu_switched_ = true; + active_gpu_heuristic_ = active_gpu_heuristic; } -GLboolean GLES2Implementation::DidGpuSwitch() { - // TODO(zmo): Redesign this code; it works for now because the share group - // only contains one context but in the future only the first OpenGL context - // in the share group will receive GL_TRUE as the return value. - bool gpu_changed = share_group_->GetGpuSwitched(); - share_group_->SetGpuSwitched(false); - return gpu_changed ? GL_TRUE : GL_FALSE; +GLboolean GLES2Implementation::DidGpuSwitch(gl::GpuPreference* active_gpu) { + if (gpu_switched_) { + *active_gpu = active_gpu_heuristic_; + } + GLboolean result = gpu_switched_ ? GL_TRUE : GL_FALSE; + gpu_switched_ = false; + return result; } void GLES2Implementation::SendErrorMessage(std::string message, int32_t id) {
diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h index 9f3d8b2b..0baea84 100644 --- a/gpu/command_buffer/client/gles2_implementation.h +++ b/gpu/command_buffer/client/gles2_implementation.h
@@ -99,7 +99,7 @@ // GLES2Interface implementation void FreeSharedMemory(void*) override; - GLboolean DidGpuSwitch() final; + GLboolean DidGpuSwitch(gl::GpuPreference* active_gpu) final; // Include the auto-generated part of this class. We split this because // it means we can easily edit the non-auto generated parts right here in @@ -400,7 +400,7 @@ void OnGpuControlErrorMessage(const char* message, int32_t id) final; void OnGpuControlSwapBuffersCompleted( const SwapBuffersCompleteParams& params) final; - void OnGpuSwitched() final; + void OnGpuSwitched(gl::GpuPreference active_gpu_heuristic) final; void OnSwapBufferPresented(uint64_t swap_id, const gfx::PresentationFeedback& feedback) final; void OnGpuControlReturnData(base::span<const uint8_t> data) final; @@ -860,6 +860,9 @@ std::string last_active_url_; + bool gpu_switched_ = false; + gl::GpuPreference active_gpu_heuristic_ = gl::GpuPreference::kDefault; + base::WeakPtrFactory<GLES2Implementation> weak_ptr_factory_{this}; DISALLOW_COPY_AND_ASSIGN(GLES2Implementation);
diff --git a/gpu/command_buffer/client/gles2_interface.cc b/gpu/command_buffer/client/gles2_interface.cc index 722a39b..6b345766 100644 --- a/gpu/command_buffer/client/gles2_interface.cc +++ b/gpu/command_buffer/client/gles2_interface.cc
@@ -9,7 +9,7 @@ namespace gpu { namespace gles2 { -GLboolean GLES2Interface::DidGpuSwitch() { +GLboolean GLES2Interface::DidGpuSwitch(gl::GpuPreference* active_gpu) { return GL_FALSE; }
diff --git a/gpu/command_buffer/client/gles2_interface.h b/gpu/command_buffer/client/gles2_interface.h index 1a6e382..ec6728c 100644 --- a/gpu/command_buffer/client/gles2_interface.h +++ b/gpu/command_buffer/client/gles2_interface.h
@@ -22,6 +22,10 @@ class Vector2dF; } // namespace gfx +namespace gl { +enum class GpuPreference; +} + extern "C" typedef struct _ClientBuffer* ClientBuffer; extern "C" typedef struct _GLColorSpace* GLColorSpace; extern "C" typedef struct _ClientGpuFence* ClientGpuFence; @@ -37,7 +41,11 @@ virtual void FreeSharedMemory(void*) {} - virtual GLboolean DidGpuSwitch(); + // Returns true if the active GPU switched since the last time this + // method was called. If so, |active_gpu| will be written with the + // results of the heuristic indicating which GPU is active; + // kDefault if "unknown", or kLowPower or kHighPerformance if known. + virtual GLboolean DidGpuSwitch(gl::GpuPreference* active_gpu); // Include the auto-generated part of this class. We split this because // it means we can easily edit the non-auto generated parts right here in
diff --git a/gpu/command_buffer/client/gpu_control_client.h b/gpu/command_buffer/client/gpu_control_client.h index a2bbec2..c88be16c0 100644 --- a/gpu/command_buffer/client/gpu_control_client.h +++ b/gpu/command_buffer/client/gpu_control_client.h
@@ -9,6 +9,7 @@ #include "base/containers/span.h" #include "ui/gfx/presentation_feedback.h" +#include "ui/gl/gpu_preference.h" namespace gpu { struct SwapBuffersCompleteParams; @@ -28,7 +29,7 @@ virtual void OnGpuControlErrorMessage(const char* message, int32_t id) = 0; virtual void OnGpuControlSwapBuffersCompleted( const SwapBuffersCompleteParams& params) = 0; - virtual void OnGpuSwitched() {} + virtual void OnGpuSwitched(gl::GpuPreference active_gpu_heuristic) {} virtual void OnSwapBufferPresented( uint64_t swap_id, const gfx::PresentationFeedback& feedback) = 0;
diff --git a/gpu/command_buffer/client/share_group.cc b/gpu/command_buffer/client/share_group.cc index ceb61d8..a923387 100644 --- a/gpu/command_buffer/client/share_group.cc +++ b/gpu/command_buffer/client/share_group.cc
@@ -401,16 +401,6 @@ return lost_; } -void ShareGroup::SetGpuSwitched(bool gpu_switched) { - base::AutoLock hold(gpu_switched_lock_); - gpu_switched_ = gpu_switched; -} - -bool ShareGroup::GetGpuSwitched() const { - base::AutoLock hold(gpu_switched_lock_); - return gpu_switched_; -} - void ShareGroup::SetProgramInfoManagerForTesting(ProgramInfoManager* manager) { program_info_manager_.reset(manager); }
diff --git a/gpu/command_buffer/client/share_group.h b/gpu/command_buffer/client/share_group.h index a1b6f74..7d074d1a 100644 --- a/gpu/command_buffer/client/share_group.h +++ b/gpu/command_buffer/client/share_group.h
@@ -165,9 +165,6 @@ // thread safe as contexts may be on different threads. bool IsLost() const; - void SetGpuSwitched(bool gpu_switched); - bool GetGpuSwitched() const; - private: friend class gpu::RefCountedThreadSafe<ShareGroup>; friend class gpu::gles2::GLES2ImplementationTest; @@ -189,9 +186,6 @@ mutable base::Lock lost_lock_; bool lost_ = false; - mutable base::Lock gpu_switched_lock_; - bool gpu_switched_ = false; - DISALLOW_COPY_AND_ASSIGN(ShareGroup); };
diff --git a/gpu/command_buffer/service/decoder_client.h b/gpu/command_buffer/service/decoder_client.h index 1583419..85ebf14c 100644 --- a/gpu/command_buffer/service/decoder_client.h +++ b/gpu/command_buffer/service/decoder_client.h
@@ -11,6 +11,7 @@ #include "base/containers/span.h" #include "gpu/gpu_export.h" +#include "ui/gl/gpu_preference.h" #include "url/gurl.h" namespace gpu { @@ -23,7 +24,7 @@ virtual void OnConsoleMessage(int32_t id, const std::string& message) = 0; // Notifies the renderer process that the active GPU changed. - virtual void OnGpuSwitched() {} + virtual void OnGpuSwitched(gl::GpuPreference active_gpu_heuristic) {} // Cache a newly linked shader. virtual void CacheShader(const std::string& key,
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 1e64f1a5..1b24f828 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -107,6 +107,7 @@ #include "ui/gl/gl_implementation.h" #include "ui/gl/gl_surface.h" #include "ui/gl/gl_version_info.h" +#include "ui/gl/gpu_preference.h" #include "ui/gl/gpu_switching_manager.h" #include "ui/gl/gpu_switching_observer.h" #include "ui/gl/gpu_timing.h" @@ -755,7 +756,7 @@ const gfx::Rect& cleared_rect) override; // Implements GpuSwitchingObserver. - void OnGpuSwitched() override; + void OnGpuSwitched(gl::GpuPreference active_gpu_heuristic) override; // Restores the current state to the user's settings. void RestoreCurrentFramebufferBindings(); @@ -5291,9 +5292,9 @@ 0 /* border */, format, type, cleared_rect); } -void GLES2DecoderImpl::OnGpuSwitched() { +void GLES2DecoderImpl::OnGpuSwitched(gl::GpuPreference active_gpu_heuristic) { // Send OnGpuSwitched notification to renderer process via decoder client. - client()->OnGpuSwitched(); + client()->OnGpuSwitched(active_gpu_heuristic); } void GLES2DecoderImpl::Destroy(bool have_context) {
diff --git a/gpu/ipc/client/command_buffer_proxy_impl.cc b/gpu/ipc/client/command_buffer_proxy_impl.cc index 1ea1ee14..2ba4395e 100644 --- a/gpu/ipc/client/command_buffer_proxy_impl.cc +++ b/gpu/ipc/client/command_buffer_proxy_impl.cc
@@ -38,6 +38,7 @@ #include "ui/gfx/geometry/size.h" #include "ui/gfx/gpu_fence.h" #include "ui/gl/gl_bindings.h" +#include "ui/gl/gpu_preference.h" namespace gpu { @@ -190,9 +191,10 @@ message.id); } -void CommandBufferProxyImpl::OnGpuSwitched() { +void CommandBufferProxyImpl::OnGpuSwitched( + gl::GpuPreference active_gpu_heuristic) { if (gpu_control_client_) - gpu_control_client_->OnGpuSwitched(); + gpu_control_client_->OnGpuSwitched(active_gpu_heuristic); } void CommandBufferProxyImpl::AddDeletionObserver(DeletionObserver* observer) {
diff --git a/gpu/ipc/client/command_buffer_proxy_impl.h b/gpu/ipc/client/command_buffer_proxy_impl.h index 67cecbdf..b2be647ee 100644 --- a/gpu/ipc/client/command_buffer_proxy_impl.h +++ b/gpu/ipc/client/command_buffer_proxy_impl.h
@@ -178,7 +178,7 @@ void OnDestroyed(gpu::error::ContextLostReason reason, gpu::error::Error error); void OnConsoleMessage(const GPUCommandBufferConsoleMessage& message); - void OnGpuSwitched(); + void OnGpuSwitched(gl::GpuPreference active_gpu_heuristic); void OnSignalAck(uint32_t id, const CommandBuffer::State& state); void OnSwapBuffersCompleted(const SwapBuffersCompleteParams& params); void OnBufferPresented(uint64_t swap_id,
diff --git a/gpu/ipc/common/gpu_messages.h b/gpu/ipc/common/gpu_messages.h index 2b8e00f1..37d9bee 100644 --- a/gpu/ipc/common/gpu_messages.h +++ b/gpu/ipc/common/gpu_messages.h
@@ -42,6 +42,7 @@ #include "ui/gfx/native_widget_types.h" #include "ui/gfx/presentation_feedback.h" #include "ui/gfx/swap_result.h" +#include "ui/gl/gpu_preference.h" #include "url/ipc/url_param_traits.h" #if defined(OS_MACOSX) @@ -296,7 +297,8 @@ GPUCommandBufferConsoleMessage /* msg */) // Sent by the GPU process to notify the renderer process of a GPU switch. -IPC_MESSAGE_ROUTED0(GpuCommandBufferMsg_GpuSwitched) +IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_GpuSwitched, + gl::GpuPreference /* active_gpu_heuristic */) // Register an existing shared memory transfer buffer. The id that can be // used to identify the transfer buffer from a command buffer.
diff --git a/gpu/ipc/service/gles2_command_buffer_stub.cc b/gpu/ipc/service/gles2_command_buffer_stub.cc index d13ef5e..34928936 100644 --- a/gpu/ipc/service/gles2_command_buffer_stub.cc +++ b/gpu/ipc/service/gles2_command_buffer_stub.cc
@@ -432,8 +432,9 @@ return context_group_->memory_tracker(); } -void GLES2CommandBufferStub::OnGpuSwitched() { - Send(new GpuCommandBufferMsg_GpuSwitched(route_id_)); +void GLES2CommandBufferStub::OnGpuSwitched( + gl::GpuPreference active_gpu_heuristic) { + Send(new GpuCommandBufferMsg_GpuSwitched(route_id_, active_gpu_heuristic)); } bool GLES2CommandBufferStub::HandleMessage(const IPC::Message& message) {
diff --git a/gpu/ipc/service/gles2_command_buffer_stub.h b/gpu/ipc/service/gles2_command_buffer_stub.h index 4625837..953919d 100644 --- a/gpu/ipc/service/gles2_command_buffer_stub.h +++ b/gpu/ipc/service/gles2_command_buffer_stub.h
@@ -40,7 +40,7 @@ MemoryTracker* GetMemoryTracker() const override; // DecoderClient implementation. - void OnGpuSwitched() override; + void OnGpuSwitched(gl::GpuPreference active_gpu_heuristic) override; // ImageTransportSurfaceDelegate implementation: #if defined(OS_WIN)
diff --git a/gpu/ipc/service/image_transport_surface_overlay_mac.h b/gpu/ipc/service/image_transport_surface_overlay_mac.h index f343b7e0..f65ad035 100644 --- a/gpu/ipc/service/image_transport_surface_overlay_mac.h +++ b/gpu/ipc/service/image_transport_surface_overlay_mac.h
@@ -82,7 +82,7 @@ bool IsSurfaceless() const override; // ui::GpuSwitchingObserver implementation. - void OnGpuSwitched() override; + void OnGpuSwitched(gl::GpuPreference active_gpu_heuristic) override; private: ~ImageTransportSurfaceOverlayMacBase() override;
diff --git a/gpu/ipc/service/image_transport_surface_overlay_mac.mm b/gpu/ipc/service/image_transport_surface_overlay_mac.mm index fa1ef9c9..c1af03a 100644 --- a/gpu/ipc/service/image_transport_surface_overlay_mac.mm +++ b/gpu/ipc/service/image_transport_surface_overlay_mac.mm
@@ -316,7 +316,8 @@ } template <typename BaseClass> -void ImageTransportSurfaceOverlayMacBase<BaseClass>::OnGpuSwitched() { +void ImageTransportSurfaceOverlayMacBase<BaseClass>::OnGpuSwitched( + gl::GpuPreference active_gpu_heuristic) { // Create a new context, and use the GL renderer ID that the new context gets. scoped_refptr<ui::IOSurfaceContext> context_on_new_gpu = ui::IOSurfaceContext::Get(ui::IOSurfaceContext::kCALayerContext);
diff --git a/ios/chrome/browser/infobars/confirm_infobar_metrics_recorder.h b/ios/chrome/browser/infobars/confirm_infobar_metrics_recorder.h index 2abd607..84d063a 100644 --- a/ios/chrome/browser/infobars/confirm_infobar_metrics_recorder.h +++ b/ios/chrome/browser/infobars/confirm_infobar_metrics_recorder.h
@@ -9,6 +9,12 @@ #import "ios/chrome/browser/infobars/infobar_type.h" +// Histogram names for InfobarConfirmTypeRestore. +extern const char kInfobarTypeRestoreEventHistogram[]; + +// Histogram names for ConfirmInfobarTypeBlockPopups. +extern const char kInfobarTypeBlockPopupsEventHistogram[]; + // Values for the UMA Mobile.Messages.Confirm.Event histogram. These values // are persisted to logs. Entries should not be renumbered and numeric values // should never be reused.
diff --git a/ios/chrome/browser/infobars/confirm_infobar_metrics_recorder.mm b/ios/chrome/browser/infobars/confirm_infobar_metrics_recorder.mm index 7db2a09..b02bd6a 100644 --- a/ios/chrome/browser/infobars/confirm_infobar_metrics_recorder.mm +++ b/ios/chrome/browser/infobars/confirm_infobar_metrics_recorder.mm
@@ -10,11 +10,11 @@ #error "This file requires ARC support." #endif -namespace { -// Histogram names for InfobarConfirmTypeRestore. const char kInfobarTypeRestoreEventHistogram[] = "Mobile.Messages.Confirm.Event.ConfirmInfobarTypeRestore"; -} // namespace + +const char kInfobarTypeBlockPopupsEventHistogram[] = + "Mobile.Messages.Confirm.Event.ConfirmInfobarTypeBlockPopups"; @implementation ConfirmInfobarMetricsRecorder @@ -24,6 +24,9 @@ case InfobarConfirmType::kInfobarConfirmTypeRestore: UMA_HISTOGRAM_ENUMERATION(kInfobarTypeRestoreEventHistogram, event); break; + case InfobarConfirmType::kInfobarConfirmTypeBlockPopups: + UMA_HISTOGRAM_ENUMERATION(kInfobarTypeBlockPopupsEventHistogram, event); + break; } }
diff --git a/ios/chrome/browser/infobars/infobar_type.h b/ios/chrome/browser/infobars/infobar_type.h index 6edda28..5273c55 100644 --- a/ios/chrome/browser/infobars/infobar_type.h +++ b/ios/chrome/browser/infobars/infobar_type.h
@@ -27,6 +27,8 @@ enum class InfobarConfirmType { // Confirm Infobar for enabling to "Restore Tabs" after a crash. kInfobarConfirmTypeRestore = 0, + // Confirm Infobar for blocking popups. + kInfobarConfirmTypeBlockPopups = 1, }; #endif // IOS_CHROME_BROWSER_INFOBARS_INFOBAR_TYPE_H_
diff --git a/ios/chrome/browser/web/BUILD.gn b/ios/chrome/browser/web/BUILD.gn index 3f1b4883..bb7cd64 100644 --- a/ios/chrome/browser/web/BUILD.gn +++ b/ios/chrome/browser/web/BUILD.gn
@@ -234,6 +234,7 @@ "//ios/chrome/browser/browser_state", "//ios/chrome/browser/content_settings", "//ios/chrome/browser/infobars", + "//ios/chrome/browser/infobars:public", "//ios/chrome/browser/passwords", "//ios/chrome/browser/reading_list", "//ios/chrome/browser/ssl", @@ -297,6 +298,7 @@ "//ios/chrome/browser/content_settings:content_settings", "//ios/chrome/browser/find_in_page", "//ios/chrome/browser/infobars", + "//ios/chrome/browser/infobars:public", "//ios/chrome/browser/passwords", "//ios/chrome/browser/web", "//ios/chrome/test/fakes",
diff --git a/ios/chrome/browser/web/blocked_popup_tab_helper.mm b/ios/chrome/browser/web/blocked_popup_tab_helper.mm index c2e770a..3f19a86 100644 --- a/ios/chrome/browser/web/blocked_popup_tab_helper.mm +++ b/ios/chrome/browser/web/blocked_popup_tab_helper.mm
@@ -19,6 +19,7 @@ #include "components/infobars/core/infobar.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" #include "ios/chrome/browser/content_settings/host_content_settings_map_factory.h" +#include "ios/chrome/browser/infobars/confirm_infobar_metrics_recorder.h" #include "ios/chrome/browser/infobars/infobar_manager_impl.h" #include "ios/chrome/grit/ios_strings.h" #include "ios/web/public/navigation/referrer.h" @@ -65,6 +66,10 @@ } bool Accept() override { + [ConfirmInfobarMetricsRecorder + recordConfirmInfobarEvent:MobileMessagesConfirmInfobarEvents::Accepted + forInfobarConfirmType:InfobarConfirmType:: + kInfobarConfirmTypeBlockPopups]; scoped_refptr<HostContentSettingsMap> host_content_map_settings( ios::HostContentSettingsMapFactory::GetForBrowserState(browser_state_)); for (auto& popup : popups_) { @@ -80,6 +85,13 @@ return true; } + void InfoBarDismissed() override { + [ConfirmInfobarMetricsRecorder + recordConfirmInfobarEvent:MobileMessagesConfirmInfobarEvents::Dismissed + forInfobarConfirmType:InfobarConfirmType:: + kInfobarConfirmTypeBlockPopups]; + } + int GetButtons() const override { return BUTTON_OK; } private: @@ -144,6 +156,10 @@ } else { infobar_ = infobar_manager->AddInfoBar(std::move(infobar)); } + [ConfirmInfobarMetricsRecorder + recordConfirmInfobarEvent:MobileMessagesConfirmInfobarEvents::Presented + forInfobarConfirmType:InfobarConfirmType:: + kInfobarConfirmTypeBlockPopups]; } ios::ChromeBrowserState* BlockedPopupTabHelper::GetBrowserState() const {
diff --git a/ios/chrome/browser/web/blocked_popup_tab_helper_unittest.mm b/ios/chrome/browser/web/blocked_popup_tab_helper_unittest.mm index 5da71578..315f123 100644 --- a/ios/chrome/browser/web/blocked_popup_tab_helper_unittest.mm +++ b/ios/chrome/browser/web/blocked_popup_tab_helper_unittest.mm
@@ -5,12 +5,14 @@ #import "ios/chrome/browser/web/blocked_popup_tab_helper.h" #include "base/memory/ptr_util.h" +#include "base/test/metrics/histogram_tester.h" #include "components/content_settings/core/browser/host_content_settings_map.h" #include "components/infobars/core/confirm_infobar_delegate.h" #include "components/infobars/core/infobar.h" #include "components/infobars/core/infobar_manager.h" #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h" #include "ios/chrome/browser/content_settings/host_content_settings_map_factory.h" +#include "ios/chrome/browser/infobars/confirm_infobar_metrics_recorder.h" #include "ios/chrome/browser/infobars/infobar_manager_impl.h" #import "ios/chrome/browser/web/chrome_web_test.h" #import "ios/web/public/test/fakes/test_navigation_manager.h" @@ -150,3 +152,55 @@ EXPECT_EQ(0U, GetInfobarManager()->infobar_count()); EXPECT_FALSE(IsObservingSources()); } + +// Tests that the Infobar presentation and dismissal histograms are recorded +// correctly. +TEST_F(BlockedPopupTabHelperTest, RecordDismissMetrics) { + base::HistogramTester histogram_tester; + + // Call |HandlePopup| to show an infobar and check that the Presented + // histogram was recorded correctly. + const GURL test_url("https://popups.example.com"); + GetBlockedPopupTabHelper()->HandlePopup(test_url, web::Referrer()); + ASSERT_EQ(1U, GetInfobarManager()->infobar_count()); + histogram_tester.ExpectUniqueSample( + "Mobile.Messages.Confirm.Event.ConfirmInfobarTypeBlockPopups", + static_cast<base::HistogramBase::Sample>( + MobileMessagesConfirmInfobarEvents::Presented), + 1); + + // Dismiss the infobar and check that the Dismiss histogram was recorded + // correctly. + GetInfobarManager()->infobar_at(0)->delegate()->InfoBarDismissed(); + histogram_tester.ExpectBucketCount( + kInfobarTypeBlockPopupsEventHistogram, + static_cast<base::HistogramBase::Sample>( + MobileMessagesConfirmInfobarEvents::Dismissed), + 1); +} + +// Tests that the Infobar accept histogram is recorded correctly. +TEST_F(BlockedPopupTabHelperTest, RecordAcceptMetrics) { + base::HistogramTester histogram_tester; + const GURL source_url("https://source-url"); + ASSERT_TRUE(GetBlockedPopupTabHelper()->ShouldBlockPopup(source_url)); + + // Block popup. + const GURL target_url("https://target-url"); + web::Referrer referrer(source_url, web::ReferrerPolicyDefault); + GetBlockedPopupTabHelper()->HandlePopup(target_url, referrer); + + // Accept the infobar and check that the Accepted histogram was recorded + // correctly. + ASSERT_EQ(1U, GetInfobarManager()->infobar_count()); + auto* delegate = GetInfobarManager() + ->infobar_at(0) + ->delegate() + ->AsConfirmInfoBarDelegate(); + delegate->Accept(); + histogram_tester.ExpectBucketCount( + kInfobarTypeBlockPopupsEventHistogram, + static_cast<base::HistogramBase::Sample>( + MobileMessagesConfirmInfobarEvents::Accepted), + 1); +}
diff --git a/media/filters/fuchsia/fuchsia_video_decoder.cc b/media/filters/fuchsia/fuchsia_video_decoder.cc index 870ef425..60fa9e72 100644 --- a/media/filters/fuchsia/fuchsia_video_decoder.cc +++ b/media/filters/fuchsia/fuchsia_video_decoder.cc
@@ -96,11 +96,16 @@ mailboxes[0].mailbox = mailbox_; mailboxes[0].sync_token = shared_image_interface_->GenUnverifiedSyncToken(); - return VideoFrame::WrapNativeTextures( + auto frame = VideoFrame::WrapNativeTextures( pixel_format, mailboxes, BindToCurrentLoop(base::BindOnce(&OutputMailbox::OnFrameDestroyed, base::Unretained(this))), coded_size, visible_rect, natural_size, timestamp); + + // Request a fence we'll wait on before reusing the buffer. + frame->metadata()->SetBoolean(VideoFrameMetadata::READ_LOCK_FENCES_ENABLED, + true); + return frame; } // Called by FuchsiaVideoDecoder when it no longer needs this mailbox.
diff --git a/media/gpu/test/video_decode_accelerator_unittest_helpers.cc b/media/gpu/test/video_decode_accelerator_unittest_helpers.cc index 3253c8ae..e1f1cdc 100644 --- a/media/gpu/test/video_decode_accelerator_unittest_helpers.cc +++ b/media/gpu/test/video_decode_accelerator_unittest_helpers.cc
@@ -73,7 +73,10 @@ size_t pos = start_pos; if (pos + 4 > data_.size()) return pos; - LOG_ASSERT(IsNALHeader(data_, pos)); + if (!IsNALHeader(data_, pos)) { + ADD_FAILURE(); + return std::numeric_limits<std::size_t>::max(); + } pos += 4; while (pos + 4 <= data_.size() && !IsNALHeader(data_, pos)) { ++pos;
diff --git a/media/gpu/test/video_frame_file_writer.cc b/media/gpu/test/video_frame_file_writer.cc index a88ddb43..5e46a79 100644 --- a/media/gpu/test/video_frame_file_writer.cc +++ b/media/gpu/test/video_frame_file_writer.cc
@@ -14,6 +14,7 @@ #include "build/build_config.h" #include "media/gpu/video_frame_mapper.h" #include "media/gpu/video_frame_mapper_factory.h" +#include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/codec/png_codec.h" namespace media { @@ -127,7 +128,7 @@ !video_frame_mapper_) { video_frame_mapper_ = VideoFrameMapperFactory::CreateMapper( video_frame->format(), video_frame->storage_type()); - LOG_ASSERT(video_frame_mapper_) << "Failed to create VideoFrameMapper"; + ASSERT_TRUE(video_frame_mapper_) << "Failed to create VideoFrameMapper"; } #endif @@ -180,7 +181,7 @@ argb_out_frame->stride(VideoFrame::kARGBPlane), true, /* discard_transparency */ std::vector<gfx::PNGCodec::Comment>(), &png_output); - LOG_ASSERT(png_encode_status); + ASSERT_TRUE(png_encode_status); // Write the PNG data to file. base::FilePath file_path( @@ -188,7 +189,7 @@ const int size = base::checked_cast<int>(png_output.size()); const int bytes_written = base::WriteFile( file_path, reinterpret_cast<char*>(png_output.data()), size); - LOG_ASSERT(bytes_written == size); + ASSERT_TRUE(bytes_written == size); } void VideoFrameFileWriter::WriteVideoFrameYUV( @@ -235,7 +236,7 @@ VideoFrame::Rows(i, pixel_format, visible_size.height()); const int row_bytes = VideoFrame::RowBytes(i, pixel_format, visible_size.width()); - LOG_ASSERT(stride > 0); + ASSERT_TRUE(stride > 0); for (size_t row = 0; row < rows; ++row) { if (yuv_file.WriteAtCurrentPos( reinterpret_cast<const char*>(data + (stride * row)),
diff --git a/media/gpu/test/video_player/test_vda_video_decoder.cc b/media/gpu/test/video_player/test_vda_video_decoder.cc index fc65575..99cf150 100644 --- a/media/gpu/test/video_player/test_vda_video_decoder.cc +++ b/media/gpu/test/video_player/test_vda_video_decoder.cc
@@ -107,7 +107,7 @@ } if (!decoder_factory) { - LOG_ASSERT(decoder_) << "Failed to create VideoDecodeAccelerator factory"; + ASSERT_TRUE(decoder_) << "Failed to create VideoDecodeAccelerator factory"; std::move(init_cb).Run(false); return; } @@ -128,7 +128,7 @@ this, vda_config, gpu_driver_bug_workarounds, gpu_preferences); if (!decoder_) { - LOG_ASSERT(decoder_) << "Failed to create VideoDecodeAccelerator factory"; + ASSERT_TRUE(decoder_) << "Failed to create VideoDecodeAccelerator factory"; std::move(init_cb).Run(false); return; } @@ -229,7 +229,7 @@ gfx::BufferUsage::SCANOUT_VDA_WRITE); #endif // BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION) - LOG_ASSERT(video_frame) << "Failed to create video frame"; + ASSERT_TRUE(video_frame) << "Failed to create video frame"; video_frames_.emplace(picture_buffer.id(), video_frame); gfx::GpuMemoryBufferHandle handle; @@ -240,7 +240,7 @@ NOTREACHED(); #endif // BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION) - LOG_ASSERT(!handle.is_null()) << "Failed to create GPU memory handle"; + ASSERT_TRUE(!handle.is_null()) << "Failed to create GPU memory handle"; decoder_->ImportBufferForPicture(picture_buffer.id(), format, std::move(handle)); } @@ -252,7 +252,7 @@ uint32_t texture_id; auto video_frame = frame_renderer_->CreateVideoFrame( format, dimensions, texture_target, &texture_id); - LOG_ASSERT(video_frame) << "Failed to create video frame"; + ASSERT_TRUE(video_frame) << "Failed to create video frame"; int32_t picture_buffer_id = GetNextPictureBufferId(); PictureBuffer::TextureIds texture_ids(1, texture_id); picture_buffers.emplace_back(picture_buffer_id, dimensions, texture_ids, @@ -282,7 +282,7 @@ DVLOGF(4) << "Picture buffer ID: " << picture.picture_buffer_id(); auto it = video_frames_.find(picture.picture_buffer_id()); - LOG_ASSERT(it != video_frames_.end()); + ASSERT_TRUE(it != video_frames_.end()); scoped_refptr<VideoFrame> video_frame = it->second; // Look up the time at which the decode started. @@ -359,7 +359,7 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(vda_wrapper_sequence_checker_); auto it = decode_cbs_.find(bitstream_buffer_id); - LOG_ASSERT(it != decode_cbs_.end()) + ASSERT_TRUE(it != decode_cbs_.end()) << "Couldn't find decode callback for picture buffer with id " << bitstream_buffer_id;
diff --git a/media/gpu/test/video_test_environment.cc b/media/gpu/test/video_test_environment.cc index 773f51c..1533829 100644 --- a/media/gpu/test/video_test_environment.cc +++ b/media/gpu/test/video_test_environment.cc
@@ -32,7 +32,8 @@ logging::LoggingSettings settings; settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG | logging::LOG_TO_STDERR; - LOG_ASSERT(logging::InitLogging(settings)); + if (!logging::InitLogging(settings)) + ADD_FAILURE(); // Setting up a task environment will create a task runner for the current // thread and allow posting tasks to other threads. This is required for video
diff --git a/mojo/public/cpp/bindings/README.md b/mojo/public/cpp/bindings/README.md index 9403a416..19cbf66 100644 --- a/mojo/public/cpp/bindings/README.md +++ b/mojo/public/cpp/bindings/README.md
@@ -384,7 +384,7 @@ Regardless of the underlying cause, when a connection error is encountered on a receiver endpoint, that endpoint's **disconnect handler** (if set) is -invoked. This handler is a simple `base::Closure` and may only be invoked +invoked. This handler is a simple `base::OnceClosure` and may only be invoked *once* as long as the endpoint is bound to the same pipe. Typically clients and implementations use this handler to do some kind of cleanup or -- particuarly if the error was unexpected -- create a new pipe and attempt to establish a new @@ -1733,7 +1733,7 @@ version: ```cpp -void QueryVersion(const base::Callback<void(uint32_t)>& callback); +void QueryVersion(base::OnceCallback<void(uint32_t)> callback); ``` This queries the remote endpoint for the version number of its binding. When a
diff --git a/mojo/public/cpp/bindings/associated_group.h b/mojo/public/cpp/bindings/associated_group.h index 1a31f904..bae09eed 100644 --- a/mojo/public/cpp/bindings/associated_group.h +++ b/mojo/public/cpp/bindings/associated_group.h
@@ -42,7 +42,7 @@ AssociatedGroupController* GetController(); private: - base::Callback<AssociatedGroupController*()> controller_getter_; + base::RepeatingCallback<AssociatedGroupController*()> controller_getter_; scoped_refptr<AssociatedGroupController> controller_; };
diff --git a/mojo/public/cpp/bindings/associated_interface_ptr.h b/mojo/public/cpp/bindings/associated_interface_ptr.h index ab77a77f..95def73 100644 --- a/mojo/public/cpp/bindings/associated_interface_ptr.h +++ b/mojo/public/cpp/bindings/associated_interface_ptr.h
@@ -95,8 +95,8 @@ // 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(const base::Callback<void(uint32_t)>& callback) { - internal_state_.QueryVersion(callback); + 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
diff --git a/mojo/public/cpp/bindings/interface_ptr.h b/mojo/public/cpp/bindings/interface_ptr.h index af383ed1..9032c2c 100644 --- a/mojo/public/cpp/bindings/interface_ptr.h +++ b/mojo/public/cpp/bindings/interface_ptr.h
@@ -111,8 +111,8 @@ // 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 interface pointer will also be updated. - void QueryVersion(const base::Callback<void(uint32_t)>& callback) { - internal_state_.QueryVersionDeprecated(callback); + 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 its
diff --git a/mojo/public/cpp/bindings/interface_ptr_set.h b/mojo/public/cpp/bindings/interface_ptr_set.h index c782e15..616f594a 100644 --- a/mojo/public/cpp/bindings/interface_ptr_set.h +++ b/mojo/public/cpp/bindings/interface_ptr_set.h
@@ -90,7 +90,7 @@ class Element { public: explicit Element(Ptr<Interface> ptr) : ptr_(std::move(ptr)) { - ptr_.set_connection_error_handler(base::Bind(&DeleteElement, this)); + ptr_.set_connection_error_handler(base::BindOnce(&DeleteElement, this)); } ~Element() {}
diff --git a/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.cc b/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.cc index fa8c7d0..6f6d4abc 100644 --- a/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.cc +++ b/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.cc
@@ -14,12 +14,12 @@ AssociatedInterfacePtrStateBase::~AssociatedInterfacePtrStateBase() = default; void AssociatedInterfacePtrStateBase::QueryVersion( - const base::Callback<void(uint32_t)>& callback) { + base::OnceCallback<void(uint32_t)> callback) { // It is safe to capture |this| because the callback won't be run after this // object goes away. endpoint_client_->QueryVersion( - base::Bind(&AssociatedInterfacePtrStateBase::OnQueryVersion, - base::Unretained(this), callback)); + base::BindOnce(&AssociatedInterfacePtrStateBase::OnQueryVersion, + base::Unretained(this), std::move(callback))); } void AssociatedInterfacePtrStateBase::RequireVersion(uint32_t version) { @@ -31,10 +31,10 @@ } void AssociatedInterfacePtrStateBase::OnQueryVersion( - const base::Callback<void(uint32_t)>& callback, + base::OnceCallback<void(uint32_t)> callback, uint32_t version) { version_ = version; - callback.Run(version); + std::move(callback).Run(version); } void AssociatedInterfacePtrStateBase::FlushForTesting() {
diff --git a/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h b/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h index f8dea18..23fc89f 100644 --- a/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h +++ b/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h
@@ -37,7 +37,7 @@ uint32_t version() const { return version_; } - void QueryVersion(const base::Callback<void(uint32_t)>& callback); + void QueryVersion(base::OnceCallback<void(uint32_t)> callback); void RequireVersion(uint32_t version); void FlushForTesting(); void CloseWithReason(uint32_t custom_reason, const std::string& description); @@ -93,7 +93,7 @@ InterfaceEndpointClient* endpoint_client() { return endpoint_client_.get(); } private: - void OnQueryVersion(const base::Callback<void(uint32_t)>& callback, + void OnQueryVersion(base::OnceCallback<void(uint32_t)> callback, uint32_t version); std::unique_ptr<InterfaceEndpointClient> endpoint_client_;
diff --git a/mojo/public/cpp/bindings/lib/connector.cc b/mojo/public/cpp/bindings/lib/connector.cc index f29ee91..5f77d2d 100644 --- a/mojo/public/cpp/bindings/lib/connector.cc +++ b/mojo/public/cpp/bindings/lib/connector.cc
@@ -520,7 +520,8 @@ handle_watcher_->set_heap_profiler_tag(heap_profiler_tag_); MojoResult rv = handle_watcher_->Watch( message_pipe_.get(), MOJO_HANDLE_SIGNAL_READABLE, - base::Bind(&Connector::OnWatcherHandleReady, base::Unretained(this))); + base::BindRepeating(&Connector::OnWatcherHandleReady, + base::Unretained(this))); if (message_pipe_.is_valid()) { peer_remoteness_tracker_.emplace(
diff --git a/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc b/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc index f4bb42d..ad1d872 100644 --- a/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc +++ b/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc
@@ -165,7 +165,7 @@ dispatcher_.SetValidator(std::move(payload_validator)); if (handle_.pending_association()) { - handle_.SetAssociationEventHandler(base::Bind( + handle_.SetAssociationEventHandler(base::BindOnce( &InterfaceEndpointClient::OnAssociationEvent, base::Unretained(this))); } else { InitControllerIfNecessary();
diff --git a/mojo/public/cpp/bindings/lib/interface_ptr_state.h b/mojo/public/cpp/bindings/lib/interface_ptr_state.h index 31b71f83..f3f64fe 100644 --- a/mojo/public/cpp/bindings/lib/interface_ptr_state.h +++ b/mojo/public/cpp/bindings/lib/interface_ptr_state.h
@@ -136,10 +136,6 @@ #endif } - void QueryVersionDeprecated(const base::Callback<void(uint32_t)>& callback) { - QueryVersion(base::BindOnce(callback)); - } - void QueryVersion(base::OnceCallback<void(uint32_t)> callback) { ConfigureProxyIfNecessary(); InterfacePtrStateBase::QueryVersion(std::move(callback));
diff --git a/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc b/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc index 9ccae37b22..bcddf8b 100644 --- a/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc +++ b/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc
@@ -372,12 +372,12 @@ state_.swap(new_state); } -base::Callback<AssociatedGroupController*()> +base::RepeatingCallback<AssociatedGroupController*()> ScopedInterfaceEndpointHandle::CreateGroupControllerGetter() const { // We allow this callback to be run on any sequence. If this handle is created // in non-pending state, we don't have a lock but it should still be safe // because the group controller never changes. - return base::Bind(&State::group_controller, state_); + return base::BindRepeating(&State::group_controller, state_); } } // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/sync_event_watcher.cc b/mojo/public/cpp/bindings/lib/sync_event_watcher.cc index 1716591..98ccf45 100644 --- a/mojo/public/cpp/bindings/lib/sync_event_watcher.cc +++ b/mojo/public/cpp/bindings/lib/sync_event_watcher.cc
@@ -12,9 +12,9 @@ namespace mojo { SyncEventWatcher::SyncEventWatcher(base::WaitableEvent* event, - const base::Closure& callback) + base::RepeatingClosure callback) : event_(event), - callback_(callback), + callback_(std::move(callback)), registry_(SyncHandleRegistry::current()), destroyed_(new base::RefCountedData<bool>(false)) {}
diff --git a/mojo/public/cpp/bindings/lib/sync_handle_registry.cc b/mojo/public/cpp/bindings/lib/sync_handle_registry.cc index b91d5f9..5a349aa 100644 --- a/mojo/public/cpp/bindings/lib/sync_handle_registry.cc +++ b/mojo/public/cpp/bindings/lib/sync_handle_registry.cc
@@ -33,7 +33,7 @@ bool SyncHandleRegistry::RegisterHandle(const Handle& handle, MojoHandleSignals handle_signals, - const HandleCallback& callback) { + HandleCallback callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (base::Contains(handles_, handle)) @@ -43,7 +43,7 @@ if (result != MOJO_RESULT_OK) return false; - handles_[handle] = callback; + handles_[handle] = std::move(callback); return true; } @@ -58,7 +58,7 @@ } void SyncHandleRegistry::RegisterEvent(base::WaitableEvent* event, - const base::Closure& callback) { + base::RepeatingClosure callback) { auto it = events_.find(event); if (it == events_.end()) { auto result = events_.emplace(event, EventCallbackList{}); @@ -70,11 +70,11 @@ // callbacks to see if any are valid. wait_set_.AddEvent(event); - it->second.container().push_back(callback); + it->second.container().push_back(std::move(callback)); } void SyncHandleRegistry::UnregisterEvent(base::WaitableEvent* event, - const base::Closure& callback) { + base::RepeatingClosure callback) { auto it = events_.find(event); if (it == events_.end()) return; @@ -174,10 +174,11 @@ void SyncHandleRegistry::RemoveInvalidEventCallbacks() { for (auto it = events_.begin(); it != events_.end();) { auto& callbacks = it->second.container(); - callbacks.erase( - std::remove_if(callbacks.begin(), callbacks.end(), - [](const base::Closure& callback) { return !callback; }), - callbacks.end()); + callbacks.erase(std::remove_if(callbacks.begin(), callbacks.end(), + [](const base::RepeatingClosure& callback) { + return !callback; + }), + callbacks.end()); if (callbacks.empty()) events_.erase(it++); else
diff --git a/mojo/public/cpp/bindings/lib/validation_errors.cc b/mojo/public/cpp/bindings/lib/validation_errors.cc index 472e8661..477eb35 100644 --- a/mojo/public/cpp/bindings/lib/validation_errors.cc +++ b/mojo/public/cpp/bindings/lib/validation_errors.cc
@@ -119,8 +119,8 @@ } ValidationErrorObserverForTesting::ValidationErrorObserverForTesting( - const base::Closure& callback) - : last_error_(VALIDATION_ERROR_NONE), callback_(callback) { + base::RepeatingClosure callback) + : last_error_(VALIDATION_ERROR_NONE), callback_(std::move(callback)) { DCHECK(!g_validation_error_observer); g_validation_error_observer = this; }
diff --git a/mojo/public/cpp/bindings/lib/validation_errors.h b/mojo/public/cpp/bindings/lib/validation_errors.h index ddb9872..d8916aca 100644 --- a/mojo/public/cpp/bindings/lib/validation_errors.h +++ b/mojo/public/cpp/bindings/lib/validation_errors.h
@@ -111,7 +111,7 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE) ValidationErrorObserverForTesting { public: - explicit ValidationErrorObserverForTesting(const base::Closure& callback); + explicit ValidationErrorObserverForTesting(base::RepeatingClosure callback); ~ValidationErrorObserverForTesting(); ValidationError last_error() const { return last_error_; } @@ -122,7 +122,7 @@ private: ValidationError last_error_; - base::Closure callback_; + base::RepeatingClosure callback_; DISALLOW_COPY_AND_ASSIGN(ValidationErrorObserverForTesting); };
diff --git a/mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h b/mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h index 6b77758..aa406f9 100644 --- a/mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h +++ b/mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h
@@ -109,8 +109,8 @@ // asssociation, the return value of the getter will initially be null, // change to non-null when the handle is associated, and remain unchanged // ever since. - base::Callback<AssociatedGroupController*()> CreateGroupControllerGetter() - const; + base::RepeatingCallback<AssociatedGroupController*()> + CreateGroupControllerGetter() const; scoped_refptr<State> state_;
diff --git a/mojo/public/cpp/bindings/strong_associated_binding.h b/mojo/public/cpp/bindings/strong_associated_binding.h index f734772..9c552ee 100644 --- a/mojo/public/cpp/bindings/strong_associated_binding.h +++ b/mojo/public/cpp/bindings/strong_associated_binding.h
@@ -97,7 +97,7 @@ scoped_refptr<base::SequencedTaskRunner> task_runner) : impl_(std::move(impl)), binding_(impl_.get(), std::move(request), std::move(task_runner)) { - binding_.set_connection_error_with_reason_handler(base::Bind( + binding_.set_connection_error_with_reason_handler(base::BindOnce( &StrongAssociatedBinding::OnConnectionError, base::Unretained(this))); }
diff --git a/mojo/public/cpp/bindings/strong_binding.h b/mojo/public/cpp/bindings/strong_binding.h index d9ebbb80..315ad0f0 100644 --- a/mojo/public/cpp/bindings/strong_binding.h +++ b/mojo/public/cpp/bindings/strong_binding.h
@@ -104,8 +104,8 @@ scoped_refptr<base::SequencedTaskRunner> task_runner) : impl_(std::move(impl)), binding_(impl_.get(), std::move(request), std::move(task_runner)) { - binding_.set_connection_error_with_reason_handler( - base::Bind(&StrongBinding::OnConnectionError, base::Unretained(this))); + binding_.set_connection_error_with_reason_handler(base::BindOnce( + &StrongBinding::OnConnectionError, base::Unretained(this))); } ~StrongBinding() {}
diff --git a/mojo/public/cpp/bindings/sync_event_watcher.h b/mojo/public/cpp/bindings/sync_event_watcher.h index 2f33681..139c383 100644 --- a/mojo/public/cpp/bindings/sync_event_watcher.h +++ b/mojo/public/cpp/bindings/sync_event_watcher.h
@@ -24,7 +24,7 @@ // This class is not thread safe. class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) SyncEventWatcher { public: - SyncEventWatcher(base::WaitableEvent* event, const base::Closure& callback); + SyncEventWatcher(base::WaitableEvent* event, base::RepeatingClosure callback); ~SyncEventWatcher(); @@ -51,7 +51,7 @@ void DecrementRegisterCount(); base::WaitableEvent* const event_; - const base::Closure callback_; + const base::RepeatingClosure callback_; // Whether |event_| has been registered with SyncHandleRegistry. bool registered_ = false;
diff --git a/mojo/public/cpp/bindings/sync_handle_registry.h b/mojo/public/cpp/bindings/sync_handle_registry.h index b3daf8e..f3dc89c 100644 --- a/mojo/public/cpp/bindings/sync_handle_registry.h +++ b/mojo/public/cpp/bindings/sync_handle_registry.h
@@ -29,14 +29,14 @@ // Returns a sequence-local object. static scoped_refptr<SyncHandleRegistry> current(); - using HandleCallback = base::Callback<void(MojoResult)>; + using HandleCallback = base::RepeatingCallback<void(MojoResult)>; // Registers a |Handle| to be watched for |handle_signals|. If any such // signals are satisfied during a Wait(), the Wait() is woken up and // |callback| is run. bool RegisterHandle(const Handle& handle, MojoHandleSignals handle_signals, - const HandleCallback& callback); + HandleCallback callback); void UnregisterHandle(const Handle& handle); @@ -44,11 +44,12 @@ // Wait() before any handle signals. |event| is not owned, and if it signals // during Wait(), |callback| is invoked. Note that |event| may be registered // multiple times with different callbacks. - void RegisterEvent(base::WaitableEvent* event, const base::Closure& callback); + void RegisterEvent(base::WaitableEvent* event, + base::RepeatingClosure callback); // Unregisters a specific |event|+|callback| pair. void UnregisterEvent(base::WaitableEvent* event, - const base::Closure& callback); + base::RepeatingClosure callback); // Waits on all the registered handles and events and runs callbacks // synchronously for any that become ready. @@ -60,7 +61,7 @@ private: friend class base::RefCounted<SyncHandleRegistry>; - using EventCallbackList = base::StackVector<base::Closure, 1>; + using EventCallbackList = base::StackVector<base::RepeatingClosure, 1>; using EventMap = std::map<base::WaitableEvent*, EventCallbackList>; SyncHandleRegistry();
diff --git a/mojo/public/cpp/bindings/tests/associated_interface_unittest.cc b/mojo/public/cpp/bindings/tests/associated_interface_unittest.cc index 864a9da..227bf227 100644 --- a/mojo/public/cpp/bindings/tests/associated_interface_unittest.cc +++ b/mojo/public/cpp/bindings/tests/associated_interface_unittest.cc
@@ -267,11 +267,11 @@ CHECK(task_runner()->RunsTasksInCurrentSequence()); impl0_.reset(new IntegerSenderImpl(std::move(receiver0))); - impl0_->set_notify_send_method_called( - base::Bind(&TestReceiver::SendMethodCalled, base::Unretained(this))); + impl0_->set_notify_send_method_called(base::BindRepeating( + &TestReceiver::SendMethodCalled, base::Unretained(this))); impl1_.reset(new IntegerSenderImpl(std::move(receiver1))); - impl1_->set_notify_send_method_called( - base::Bind(&TestReceiver::SendMethodCalled, base::Unretained(this))); + impl1_->set_notify_send_method_called(base::BindRepeating( + &TestReceiver::SendMethodCalled, base::Unretained(this))); expected_calls_ = expected_calls; notify_finish_ = std::move(notify_finish);
diff --git a/mojo/public/cpp/bindings/tests/bindings_perftest.cc b/mojo/public/cpp/bindings/tests/bindings_perftest.cc index 283a2b2c..4c0ecd19 100644 --- a/mojo/public/cpp/bindings/tests/bindings_perftest.cc +++ b/mojo/public/cpp/bindings/tests/bindings_perftest.cc
@@ -63,7 +63,7 @@ void OnPingDone() { current_iterations_++; if (current_iterations_ >= iterations_to_run_) { - quit_closure_.Run(); + std::move(quit_closure_).Run(); return; } @@ -75,7 +75,7 @@ unsigned int iterations_to_run_; unsigned int current_iterations_; - base::Closure quit_closure_; + base::OnceClosure quit_closure_; DISALLOW_COPY_AND_ASSIGN(PingPongTest); }; @@ -183,7 +183,7 @@ base::TimeTicks end_time_; uint32_t expected_count_ = 0; MessageReceiver* sender_; - base::Closure quit_closure_; + base::RepeatingClosure quit_closure_; }; TEST_F(MojoBindingsPerftest, MultiplexRouterPingPong) {
diff --git a/mojo/public/cpp/bindings/tests/connector_unittest.cc b/mojo/public/cpp/bindings/tests/connector_unittest.cc index e16cf5c..ddd70b2 100644 --- a/mojo/public/cpp/bindings/tests/connector_unittest.cc +++ b/mojo/public/cpp/bindings/tests/connector_unittest.cc
@@ -27,12 +27,12 @@ class MessageAccumulator : public MessageReceiver { public: MessageAccumulator() {} - explicit MessageAccumulator(const base::Closure& closure) - : closure_(closure) {} + explicit MessageAccumulator(base::OnceClosure closure) + : closure_(std::move(closure)) {} bool Accept(Message* message) override { queue_.Push(message); - if (!closure_.is_null()) + if (closure_) std::move(closure_).Run(); return true; } @@ -41,13 +41,13 @@ void Pop(Message* message) { queue_.Pop(message); } - void set_closure(const base::Closure& closure) { closure_ = closure; } + void set_closure(base::OnceClosure closure) { closure_ = std::move(closure); } size_t size() const { return queue_.size(); } private: MessageQueue queue_; - base::Closure closure_; + base::OnceClosure closure_; }; class ConnectorDeletingMessageAccumulator : public MessageAccumulator { @@ -405,9 +405,9 @@ ASSERT_EQ(2, accumulator.number_of_calls()); } -void ForwardErrorHandler(bool* called, const base::Closure& callback) { +void ForwardErrorHandler(bool* called, base::OnceClosure callback) { *called = true; - callback.Run(); + std::move(callback).Run(); } TEST_F(ConnectorTest, RaiseError) { @@ -415,13 +415,13 @@ Connector connector0(std::move(handle0_), Connector::SINGLE_THREADED_SEND, base::ThreadTaskRunnerHandle::Get()); bool error_handler_called0 = false; - connector0.set_connection_error_handler(base::Bind( + connector0.set_connection_error_handler(base::BindOnce( &ForwardErrorHandler, &error_handler_called0, run_loop.QuitClosure())); Connector connector1(std::move(handle1_), Connector::SINGLE_THREADED_SEND, base::ThreadTaskRunnerHandle::Get()); bool error_handler_called1 = false; - connector1.set_connection_error_handler(base::Bind( + connector1.set_connection_error_handler(base::BindOnce( &ForwardErrorHandler, &error_handler_called1, run_loop2.QuitClosure())); const char kText[] = "hello world"; @@ -462,9 +462,9 @@ } void PauseConnectorAndRunClosure(Connector* connector, - const base::Closure& closure) { + base::OnceClosure closure) { connector->PauseIncomingMethodCallProcessing(); - closure.Run(); + std::move(closure).Run(); } TEST_F(ConnectorTest, PauseWithQueuedMessages) { @@ -484,7 +484,7 @@ base::RunLoop run_loop; // Configure the accumulator such that it pauses after the first message is // received. - MessageAccumulator accumulator(base::Bind( + MessageAccumulator accumulator(base::BindOnce( &PauseConnectorAndRunClosure, &connector1, run_loop.QuitClosure())); connector1.set_incoming_receiver(&accumulator); @@ -496,11 +496,11 @@ } void AccumulateWithNestedLoop(MessageAccumulator* accumulator, - const base::Closure& closure) { + base::OnceClosure closure) { base::RunLoop nested_run_loop(base::RunLoop::Type::kNestableTasksAllowed); accumulator->set_closure(nested_run_loop.QuitClosure()); nested_run_loop.Run(); - closure.Run(); + std::move(closure).Run(); } TEST_F(ConnectorTest, ProcessWhenNested) { @@ -521,8 +521,8 @@ MessageAccumulator accumulator; // When the accumulator gets the first message it spins a nested message // loop. The loop is quit when another message is received. - accumulator.set_closure(base::Bind(&AccumulateWithNestedLoop, &accumulator, - run_loop.QuitClosure())); + accumulator.set_closure(base::BindOnce(&AccumulateWithNestedLoop, + &accumulator, run_loop.QuitClosure())); connector1.set_incoming_receiver(&accumulator); run_loop.Run();
diff --git a/mojo/public/cpp/bindings/tests/e2e_perftest.cc b/mojo/public/cpp/bindings/tests/e2e_perftest.cc index e0c6b68..e11be65 100644 --- a/mojo/public/cpp/bindings/tests/e2e_perftest.cc +++ b/mojo/public/cpp/bindings/tests/e2e_perftest.cc
@@ -122,8 +122,8 @@ base::RunLoop run_loop; runner->PostTaskAndReply( FROM_HERE, - base::Bind(&MojoE2EPerftest::RunTests, base::Unretained(this), - client_mp, test_name), + base::BindOnce(&MojoE2EPerftest::RunTests, base::Unretained(this), + client_mp, test_name), run_loop.QuitClosure()); run_loop.Run(); }
diff --git a/mojo/public/cpp/bindings/tests/handle_passing_unittest.cc b/mojo/public/cpp/bindings/tests/handle_passing_unittest.cc index 4d5210d..8f79c1f 100644 --- a/mojo/public/cpp/bindings/tests/handle_passing_unittest.cc +++ b/mojo/public/cpp/bindings/tests/handle_passing_unittest.cc
@@ -24,16 +24,16 @@ const char kText2[] = "world"; void RecordString(std::string* storage, - const base::Closure& closure, + base::OnceClosure closure, const std::string& str) { *storage = str; - closure.Run(); + std::move(closure).Run(); } -base::Callback<void(const std::string&)> MakeStringRecorder( +base::OnceCallback<void(const std::string&)> MakeStringRecorder( std::string* storage, - const base::Closure& closure) { - return base::Bind(&RecordString, storage, closure); + base::OnceClosure closure) { + return base::BindOnce(&RecordString, storage, std::move(closure)); } class ImportedInterfaceImpl : public imported::ImportedInterface { @@ -162,7 +162,7 @@ void DoStuff(bool* got_response, std::string* got_text_reply, - const base::Closure& closure, + base::OnceClosure closure, sample::ResponsePtr response, const std::string& text_reply) { *got_text_reply = text_reply; @@ -183,16 +183,16 @@ } *got_response = true; - closure.Run(); + std::move(closure).Run(); } void DoStuff2(bool* got_response, std::string* got_text_reply, - const base::Closure& closure, + base::OnceClosure closure, const std::string& text_reply) { *got_response = true; *got_text_reply = text_reply; - closure.Run(); + std::move(closure).Run(); } TEST_P(HandlePassingTest, Basic) { @@ -216,8 +216,8 @@ std::string got_text_reply; base::RunLoop run_loop2; factory->DoStuff(std::move(request), std::move(pipe0.handle0), - base::Bind(&DoStuff, &got_response, &got_text_reply, - run_loop2.QuitClosure())); + base::BindOnce(&DoStuff, &got_response, &got_text_reply, + run_loop2.QuitClosure())); EXPECT_FALSE(got_response); int count_before = ImportedInterfaceImpl::do_something_count(); @@ -241,8 +241,8 @@ std::string got_text_reply; base::RunLoop run_loop; factory->DoStuff(std::move(request), ScopedMessagePipeHandle(), - base::Bind(&DoStuff, &got_response, &got_text_reply, - run_loop.QuitClosure())); + base::BindOnce(&DoStuff, &got_response, &got_text_reply, + run_loop.QuitClosure())); EXPECT_FALSE(got_response); @@ -276,8 +276,8 @@ std::string got_text_reply; base::RunLoop run_loop; factory->DoStuff2(std::move(consumer_handle), - base::Bind(&DoStuff2, &got_response, &got_text_reply, - run_loop.QuitClosure())); + base::BindOnce(&DoStuff2, &got_response, &got_text_reply, + run_loop.QuitClosure())); EXPECT_FALSE(got_response);
diff --git a/mojo/public/cpp/bindings/tests/multiplex_router_unittest.cc b/mojo/public/cpp/bindings/tests/multiplex_router_unittest.cc index c18e806..d845c97 100644 --- a/mojo/public/cpp/bindings/tests/multiplex_router_unittest.cc +++ b/mojo/public/cpp/bindings/tests/multiplex_router_unittest.cc
@@ -221,9 +221,9 @@ std::string(reinterpret_cast<const char*>(response.payload()))); } -void ForwardErrorHandler(bool* called, const base::Closure& callback) { +void ForwardErrorHandler(bool* called, base::OnceClosure callback) { *called = true; - callback.Run(); + std::move(callback).Run(); } // Tests that if the receiving application destroys the responder_ without @@ -235,9 +235,8 @@ std::move(endpoint0_), nullptr, base::WrapUnique(new PassThroughFilter()), false, base::ThreadTaskRunnerHandle::Get(), 0u, kTestInterfaceName); bool error_handler_called0 = false; - client0.set_connection_error_handler( - base::Bind(&ForwardErrorHandler, &error_handler_called0, - run_loop0.QuitClosure())); + client0.set_connection_error_handler(base::BindOnce( + &ForwardErrorHandler, &error_handler_called0, run_loop0.QuitClosure())); base::RunLoop run_loop3; LazyResponseGenerator generator(run_loop3.QuitClosure()); @@ -246,9 +245,8 @@ false, base::ThreadTaskRunnerHandle::Get(), 0u, kTestInterfaceName); bool error_handler_called1 = false; - client1.set_connection_error_handler( - base::Bind(&ForwardErrorHandler, &error_handler_called1, - run_loop1.QuitClosure())); + client1.set_connection_error_handler(base::BindOnce( + &ForwardErrorHandler, &error_handler_called1, run_loop1.QuitClosure())); Message request; AllocRequestMessage(1, "hello", &request);
diff --git a/mojo/public/cpp/bindings/tests/pickle_unittest.cc b/mojo/public/cpp/bindings/tests/pickle_unittest.cc index e233a2506f..959c7bf 100644 --- a/mojo/public/cpp/bindings/tests/pickle_unittest.cc +++ b/mojo/public/cpp/bindings/tests/pickle_unittest.cc
@@ -25,16 +25,17 @@ namespace { template <typename T> -void DoExpectResult(int foo, int bar, const base::Closure& callback, T actual) { +void DoExpectResult(int foo, int bar, base::OnceClosure callback, T actual) { EXPECT_EQ(foo, actual.foo()); EXPECT_EQ(bar, actual.bar()); - callback.Run(); + std::move(callback).Run(); } template <typename T> -base::Callback<void(T)> ExpectResult(const T& t, - const base::Closure& callback) { - return base::Bind(&DoExpectResult<T>, t.foo(), t.bar(), callback); +base::OnceCallback<void(T)> ExpectResult(const T& t, + base::OnceClosure callback) { + return base::BindOnce(&DoExpectResult<T>, t.foo(), t.bar(), + std::move(callback)); } template <typename T> @@ -43,19 +44,19 @@ } template <typename T> -base::Callback<void(T)> Fail(const std::string& reason) { - return base::Bind(&DoFail<T>, reason); +base::OnceCallback<void(T)> Fail(const std::string& reason) { + return base::BindOnce(&DoFail<T>, reason); } template <typename T> -void DoExpectEnumResult(T expected, const base::Closure& callback, T actual) { +void DoExpectEnumResult(T expected, base::OnceClosure callback, T actual) { EXPECT_EQ(expected, actual); - callback.Run(); + std::move(callback).Run(); } template <typename T> -base::Callback<void(T)> ExpectEnumResult(T t, const base::Closure& callback) { - return base::Bind(&DoExpectEnumResult<T>, t, callback); +base::OnceCallback<void(T)> ExpectEnumResult(T t, base::OnceClosure callback) { + return base::BindOnce(&DoExpectEnumResult<T>, t, std::move(callback)); } template <typename T> @@ -64,8 +65,8 @@ } template <typename T> -base::Callback<void(T)> EnumFail(const std::string& reason) { - return base::Bind(&DoEnumFail<T>, reason); +base::OnceCallback<void(T)> EnumFail(const std::string& reason) { + return base::BindOnce(&DoEnumFail<T>, reason); } template <typename T> @@ -77,8 +78,8 @@ void RunSimpleLambda(Func func, Arg arg) { func(std::move(arg)); } template <typename Arg, typename Func> -base::Callback<void(Arg)> BindSimpleLambda(Func func) { - return base::Bind(&RunSimpleLambda<Func, Arg>, func); +base::OnceCallback<void(Arg)> BindSimpleLambda(Func func) { + return base::BindOnce(&RunSimpleLambda<Func, Arg>, func); } // This implements the generated Chromium variant of PicklePasser.
diff --git a/mojo/public/cpp/bindings/tests/receiver_set_unittest.cc b/mojo/public/cpp/bindings/tests/receiver_set_unittest.cc index b88d676..e2ed86e9 100644 --- a/mojo/public/cpp/bindings/tests/receiver_set_unittest.cc +++ b/mojo/public/cpp/bindings/tests/receiver_set_unittest.cc
@@ -212,9 +212,9 @@ std::string last_received_error; core::SetDefaultProcessErrorCallback( - base::Bind([](std::string* out_error, - const std::string& error) { *out_error = error; }, - &last_received_error)); + base::BindRepeating([](std::string* out_error, + const std::string& error) { *out_error = error; }, + &last_received_error)); ReceiverSet<PingService, int> receivers; Remote<PingService> ping_a, ping_b; @@ -225,7 +225,7 @@ impl.set_ping_handler(ReportBadMessage(&receivers, "message 1")); base::RunLoop loop; ping_a.set_disconnect_handler(loop.QuitClosure()); - ping_a->Ping(base::Bind([] {})); + ping_a->Ping(base::BindOnce([] {})); loop.Run(); EXPECT_EQ("message 1", last_received_error); } @@ -234,7 +234,7 @@ impl.set_ping_handler(ReportBadMessage(&receivers, "message 2")); base::RunLoop loop; ping_b.set_disconnect_handler(loop.QuitClosure()); - ping_b->Ping(base::Bind([] {})); + ping_b->Ping(base::BindOnce([] {})); loop.Run(); EXPECT_EQ("message 2", last_received_error); } @@ -249,9 +249,9 @@ std::string last_received_error; core::SetDefaultProcessErrorCallback( - base::Bind([](std::string* out_error, - const std::string& error) { *out_error = error; }, - &last_received_error)); + base::BindRepeating([](std::string* out_error, + const std::string& error) { *out_error = error; }, + &last_received_error)); ReceiverSet<PingService, int> receivers; Remote<PingService> ping_a, ping_b; @@ -299,9 +299,9 @@ std::string last_received_error; core::SetDefaultProcessErrorCallback( - base::Bind([](std::string* out_error, - const std::string& error) { *out_error = error; }, - &last_received_error)); + base::BindRepeating([](std::string* out_error, + const std::string& error) { *out_error = error; }, + &last_received_error)); ReportBadMessageCallback bad_message_callback; { @@ -329,12 +329,12 @@ void set_new_ping_context(int context) { new_ping_context_ = context; } - void set_new_ping_handler(const base::RepeatingClosure& handler) { - new_ping_handler_ = handler; + void set_new_ping_handler(base::RepeatingClosure handler) { + new_ping_handler_ = std::move(handler); } - void set_ping_handler(const base::RepeatingClosure& handler) { - ping_handler_ = handler; + void set_ping_handler(base::RepeatingClosure handler) { + ping_handler_ = std::move(handler); } AssociatedReceiverSet<PingService, int>& ping_receivers() { @@ -358,8 +358,8 @@ AssociatedReceiverSet<PingService, int> ping_receivers_; int new_ping_context_ = -1; - base::Closure ping_handler_; - base::Closure new_ping_handler_; + base::RepeatingClosure ping_handler_; + base::RepeatingClosure new_ping_handler_; }; TEST_P(ReceiverSetTest, AssociatedReceiverSetContext) {
diff --git a/mojo/public/cpp/bindings/tests/remote_unittest.cc b/mojo/public/cpp/bindings/tests/remote_unittest.cc index e56a31e..36f7b3d 100644 --- a/mojo/public/cpp/bindings/tests/remote_unittest.cc +++ b/mojo/public/cpp/bindings/tests/remote_unittest.cc
@@ -322,7 +322,7 @@ EXPECT_EQ(2.0, calculator_ui.GetOutput()); EXPECT_TRUE(calculator_ui.is_connected()); - calculator_ui.Multiply(5.0, base::Closure()); + calculator_ui.Multiply(5.0, base::OnceClosure()); EXPECT_TRUE(calculator_ui.is_connected()); calc_impl.receiver().reset(); @@ -358,7 +358,7 @@ EXPECT_EQ(2.0, calculator_ui.GetOutput()); EXPECT_TRUE(calculator_ui.is_connected()); - calculator_ui.Multiply(5.0, base::Closure()); + calculator_ui.Multiply(5.0, base::OnceClosure()); EXPECT_TRUE(calculator_ui.is_connected()); calc_impl.receiver().reset();
diff --git a/mojo/public/cpp/bindings/tests/report_bad_message_unittest.cc b/mojo/public/cpp/bindings/tests/report_bad_message_unittest.cc index 1394c86..f468325 100644 --- a/mojo/public/cpp/bindings/tests/report_bad_message_unittest.cc +++ b/mojo/public/cpp/bindings/tests/report_bad_message_unittest.cc
@@ -63,7 +63,7 @@ ReportBadMessageTest() = default; void SetUp() override { - mojo::core::SetDefaultProcessErrorCallback(base::Bind( + mojo::core::SetDefaultProcessErrorCallback(base::BindRepeating( &ReportBadMessageTest::OnProcessError, base::Unretained(this))); impl_.Bind(remote_.BindNewPipeAndPassReceiver());
diff --git a/mojo/public/cpp/bindings/tests/router_test_util.cc b/mojo/public/cpp/bindings/tests/router_test_util.cc index b36de55..48539dca 100644 --- a/mojo/public/cpp/bindings/tests/router_test_util.cc +++ b/mojo/public/cpp/bindings/tests/router_test_util.cc
@@ -35,16 +35,15 @@ } MessageAccumulator::MessageAccumulator(MessageQueue* queue, - const base::Closure& closure) - : queue_(queue), closure_(closure) {} + base::OnceClosure closure) + : queue_(queue), closure_(std::move(closure)) {} MessageAccumulator::~MessageAccumulator() {} bool MessageAccumulator::Accept(Message* message) { queue_->Push(message); - if (!closure_.is_null()) { - closure_.Run(); - closure_.Reset(); + if (closure_) { + std::move(closure_).Run(); } return true; } @@ -79,8 +78,11 @@ return responder->Accept(&response); } -LazyResponseGenerator::LazyResponseGenerator(const base::Closure& closure) - : responder_(nullptr), name_(0), request_id_(0), closure_(closure) {} +LazyResponseGenerator::LazyResponseGenerator(base::OnceClosure closure) + : responder_(nullptr), + name_(0), + request_id_(0), + closure_(std::move(closure)) {} LazyResponseGenerator::~LazyResponseGenerator() = default; @@ -92,9 +94,8 @@ request_string_ = std::string(reinterpret_cast<const char*>(message->payload())); responder_ = std::move(responder); - if (!closure_.is_null()) { - closure_.Run(); - closure_.Reset(); + if (closure_) { + std::move(closure_).Run(); } return true; }
diff --git a/mojo/public/cpp/bindings/tests/router_test_util.h b/mojo/public/cpp/bindings/tests/router_test_util.h index 6d18a03..946f5f7 100644 --- a/mojo/public/cpp/bindings/tests/router_test_util.h +++ b/mojo/public/cpp/bindings/tests/router_test_util.h
@@ -8,6 +8,7 @@ #include <stdint.h> #include <string> +#include <utility> #include "base/callback.h" #include "mojo/public/cpp/bindings/message.h" @@ -26,14 +27,14 @@ class MessageAccumulator : public MessageReceiver { public: MessageAccumulator(MessageQueue* queue, - const base::Closure& closure = base::Closure()); + base::OnceClosure closure = base::OnceClosure()); ~MessageAccumulator() override; bool Accept(Message* message) override; private: MessageQueue* queue_; - base::Closure closure_; + base::OnceClosure closure_; }; class ResponseGenerator : public MessageReceiverWithResponderStatus { @@ -54,7 +55,7 @@ class LazyResponseGenerator : public ResponseGenerator { public: explicit LazyResponseGenerator( - const base::Closure& closure = base::Closure()); + base::OnceClosure closure = base::OnceClosure()); ~LazyResponseGenerator() override; @@ -66,7 +67,7 @@ bool responder_is_valid() const { return responder_->IsConnected(); } - void set_closure(const base::Closure& closure) { closure_ = closure; } + void set_closure(base::OnceClosure closure) { closure_ = std::move(closure); } // Sends the response and delete the responder. void CompleteWithResponse() { Complete(true); } @@ -83,7 +84,7 @@ uint32_t name_; uint64_t request_id_; std::string request_string_; - base::Closure closure_; + base::OnceClosure closure_; }; } // namespace test
diff --git a/mojo/public/cpp/bindings/tests/struct_traits_unittest.cc b/mojo/public/cpp/bindings/tests/struct_traits_unittest.cc index 76e1702..b251b04 100644 --- a/mojo/public/cpp/bindings/tests/struct_traits_unittest.cc +++ b/mojo/public/cpp/bindings/tests/struct_traits_unittest.cc
@@ -28,19 +28,19 @@ template <typename T> void DoExpectResult(const T& expected, - const base::Closure& callback, + base::OnceClosure callback, const T& actual) { EXPECT_EQ(expected.x(), actual.x()); EXPECT_EQ(expected.y(), actual.y()); EXPECT_EQ(expected.width(), actual.width()); EXPECT_EQ(expected.height(), actual.height()); - callback.Run(); + std::move(callback).Run(); } template <typename T> -base::Callback<void(const T&)> ExpectResult(const T& r, - const base::Closure& callback) { - return base::Bind(&DoExpectResult<T>, r, callback); +base::OnceCallback<void(const T&)> ExpectResult(const T& r, + base::OnceClosure callback) { + return base::BindOnce(&DoExpectResult<T>, r, std::move(callback)); } template <typename T> @@ -49,8 +49,8 @@ } template <typename T> -base::Callback<void(const T&)> Fail(const std::string& reason) { - return base::Bind(&DoFail<T>, reason); +base::OnceCallback<void(const T&)> Fail(const std::string& reason) { + return base::BindOnce(&DoFail<T>, reason); } template <typename T> @@ -292,7 +292,7 @@ } void ExpectStructWithTraits(const StructWithTraitsImpl& expected, - const base::Closure& closure, + base::OnceClosure closure, const StructWithTraitsImpl& passed) { EXPECT_EQ(expected.get_enum(), passed.get_enum()); EXPECT_EQ(expected.get_bool(), passed.get_bool()); @@ -303,7 +303,7 @@ EXPECT_EQ(expected.get_struct(), passed.get_struct()); EXPECT_EQ(expected.get_struct_array(), passed.get_struct_array()); EXPECT_EQ(expected.get_struct_map(), passed.get_struct_map()); - closure.Run(); + std::move(closure).Run(); } TEST_F(StructTraitsTest, EchoStructWithTraits) { @@ -341,10 +341,10 @@ } void ExpectTrivialStructWithTraits(TrivialStructWithTraitsImpl expected, - const base::Closure& closure, + base::OnceClosure closure, TrivialStructWithTraitsImpl passed) { EXPECT_EQ(expected.value, passed.value); - closure.Run(); + std::move(closure).Run(); } TEST_F(StructTraitsTest, EchoTrivialStructWithTraits) { @@ -361,11 +361,11 @@ } void CaptureMessagePipe(ScopedMessagePipeHandle* storage, - const base::Closure& closure, + base::OnceClosure closure, MoveOnlyStructWithTraitsImpl passed) { storage->reset(MessagePipeHandle( passed.get_mutable_handle().release().value())); - closure.Run(); + std::move(closure).Run(); } TEST_F(StructTraitsTest, EchoMoveOnlyStructWithTraits) { @@ -403,10 +403,10 @@ void CaptureNullableMoveOnlyStructWithTraitsImpl( base::Optional<MoveOnlyStructWithTraitsImpl>* storage, - const base::Closure& closure, + base::OnceClosure closure, base::Optional<MoveOnlyStructWithTraitsImpl> passed) { *storage = std::move(passed); - closure.Run(); + std::move(closure).Run(); } TEST_F(StructTraitsTest, EchoNullableMoveOnlyStructWithTraits) { @@ -424,10 +424,10 @@ } void ExpectEnumWithTraits(EnumWithTraitsImpl expected_value, - const base::Closure& closure, + base::OnceClosure closure, EnumWithTraitsImpl value) { EXPECT_EQ(expected_value, value); - closure.Run(); + std::move(closure).Run(); } TEST_F(StructTraitsTest, EchoEnumWithTraits) { @@ -475,12 +475,12 @@ } void ExpectUniquePtr(std::unique_ptr<int> expected, - const base::Closure& closure, + base::OnceClosure closure, std::unique_ptr<int> value) { ASSERT_EQ(!expected, !value); if (expected) EXPECT_EQ(*expected, *value); - closure.Run(); + std::move(closure).Run(); } TEST_F(StructTraitsTest, TypemapUniquePtr) { @@ -512,13 +512,13 @@ proxy->EchoUnionWithTraits( std::move(input), base::BindOnce( - [](const base::Closure& quit_closure, + [](base::OnceClosure quit_closure, std::unique_ptr<test::UnionWithTraitsBase> passed) { ASSERT_EQ(test::UnionWithTraitsBase::Type::INT32, passed->type()); EXPECT_EQ(1234, static_cast<test::UnionWithTraitsInt32*>(passed.get()) ->value()); - quit_closure.Run(); + std::move(quit_closure).Run(); }, loop.QuitClosure())); loop.Run(); @@ -531,7 +531,7 @@ proxy->EchoUnionWithTraits( std::move(input), base::BindOnce( - [](const base::Closure& quit_closure, + [](base::OnceClosure quit_closure, std::unique_ptr<test::UnionWithTraitsBase> passed) { ASSERT_EQ(test::UnionWithTraitsBase::Type::STRUCT, passed->type()); @@ -539,7 +539,7 @@ static_cast<test::UnionWithTraitsStruct*>(passed.get()) ->get_struct() .value); - quit_closure.Run(); + std::move(quit_closure).Run(); }, loop.QuitClosure())); loop.Run();
diff --git a/mojo/public/cpp/bindings/tests/sync_handle_registry_unittest.cc b/mojo/public/cpp/bindings/tests/sync_handle_registry_unittest.cc index 2f17fc7..89bd80d 100644 --- a/mojo/public/cpp/bindings/tests/sync_handle_registry_unittest.cc +++ b/mojo/public/cpp/bindings/tests/sync_handle_registry_unittest.cc
@@ -28,8 +28,8 @@ bool called1 = false; bool called2 = false; auto callback = [](bool* called) { *called = true; }; - auto callback1 = base::Bind(callback, &called1); - auto callback2 = base::Bind(callback, &called2); + auto callback1 = base::BindRepeating(callback, &called1); + auto callback2 = base::BindRepeating(callback, &called2); base::WaitableEvent e(base::WaitableEvent::ResetPolicy::MANUAL, base::WaitableEvent::InitialState::SIGNALED); @@ -60,15 +60,17 @@ bool called1 = false; bool called2 = false; bool called3 = false; - auto callback1 = base::Bind([](bool* called) { *called = true; }, &called1); - auto callback2 = base::Bind( - [](base::WaitableEvent* e, const base::Closure& other_callback, + auto callback1 = + base::BindRepeating([](bool* called) { *called = true; }, &called1); + auto callback2 = base::BindRepeating( + [](base::WaitableEvent* e, base::RepeatingClosure other_callback, scoped_refptr<SyncHandleRegistry> registry, bool* called) { registry->UnregisterEvent(e, other_callback); *called = true; }, &e, callback1, registry(), &called2); - auto callback3 = base::Bind([](bool* called) { *called = true; }, &called3); + auto callback3 = + base::BindRepeating([](bool* called) { *called = true; }, &called3); registry()->RegisterEvent(&e, callback1); registry()->RegisterEvent(&e, callback2); @@ -101,10 +103,10 @@ base::WaitableEvent::ResetPolicy::MANUAL, base::WaitableEvent::InitialState::SIGNALED); bool called = false; - base::Closure callback_holder; - auto callback = base::Bind( + base::RepeatingClosure callback_holder; + auto callback = base::BindRepeating( [](std::unique_ptr<base::WaitableEvent>* e, - base::Closure* callback_holder, + base::RepeatingClosure* callback_holder, scoped_refptr<SyncHandleRegistry> registry, bool* called) { EXPECT_FALSE(*called); @@ -116,8 +118,8 @@ base::WaitableEvent::ResetPolicy::MANUAL, base::WaitableEvent::InitialState::SIGNALED); bool nested_called = false; - auto nested_callback = - base::Bind([](bool* called) { *called = true; }, &nested_called); + auto nested_callback = base::BindRepeating( + [](bool* called) { *called = true; }, &nested_called); registry->RegisterEvent(&nested_event, nested_callback); const bool* stop_flag = &nested_called; registry->Wait(&stop_flag, 1); @@ -137,9 +139,9 @@ base::WaitableEvent e(base::WaitableEvent::ResetPolicy::MANUAL, base::WaitableEvent::InitialState::SIGNALED); bool called = false; - base::Closure callback_holder; - auto callback = base::Bind( - [](base::WaitableEvent* e, base::Closure* callback_holder, + base::RepeatingClosure callback_holder; + auto callback = base::BindRepeating( + [](base::WaitableEvent* e, base::RepeatingClosure* callback_holder, scoped_refptr<SyncHandleRegistry> registry, bool* called) { EXPECT_FALSE(*called); @@ -147,8 +149,8 @@ *called = true; bool nested_called = false; - auto nested_callback = - base::Bind([](bool* called) { *called = true; }, &nested_called); + auto nested_callback = base::BindRepeating( + [](bool* called) { *called = true; }, &nested_called); registry->RegisterEvent(e, nested_callback); const bool* stop_flag = &nested_called; registry->Wait(&stop_flag, 1); @@ -171,7 +173,7 @@ base::WaitableEvent::InitialState::SIGNALED); bool called = false; int call_count = 0; - auto callback = base::Bind( + auto callback = base::BindRepeating( [](base::WaitableEvent* e, scoped_refptr<SyncHandleRegistry> registry, bool* called, int* call_count) { // Don't re-enter. @@ -183,7 +185,7 @@ bool called2 = false; auto callback2 = - base::Bind([](bool* called) { *called = true; }, &called2); + base::BindRepeating([](bool* called) { *called = true; }, &called2); registry->RegisterEvent(e, callback2); const bool* stop_flag = &called2; @@ -212,10 +214,11 @@ base::WaitableEvent::InitialState::SIGNALED); bool called1 = false; bool called2 = false; - auto callback1 = base::Bind([](bool* called) { *called = true; }, &called1); - auto callback2 = base::Bind( + auto callback1 = + base::BindRepeating([](bool* called) { *called = true; }, &called1); + auto callback2 = base::BindRepeating( [](std::unique_ptr<base::WaitableEvent>* e1, - const base::Closure& other_callback, + base::RepeatingClosure other_callback, scoped_refptr<SyncHandleRegistry> registry, bool* called) { // Prevent re-entrancy. if (*called) @@ -228,7 +231,7 @@ // Nest another wait. bool called3 = false; auto callback3 = - base::Bind([](bool* called) { *called = true; }, &called3); + base::BindRepeating([](bool* called) { *called = true; }, &called3); base::WaitableEvent e3(base::WaitableEvent::ResetPolicy::MANUAL, base::WaitableEvent::InitialState::SIGNALED); registry->RegisterEvent(&e3, callback3);
diff --git a/mojo/public/cpp/bindings/tests/wtf_types_unittest.cc b/mojo/public/cpp/bindings/tests/wtf_types_unittest.cc index d25238ba..15059e2 100644 --- a/mojo/public/cpp/bindings/tests/wtf_types_unittest.cc +++ b/mojo/public/cpp/bindings/tests/wtf_types_unittest.cc
@@ -84,25 +84,25 @@ } void ExpectString(const WTF::String& expected_string, - const base::Closure& closure, + base::OnceClosure closure, const WTF::String& string) { EXPECT_EQ(expected_string, string); - closure.Run(); + std::move(closure).Run(); } void ExpectStringArray(base::Optional<WTF::Vector<WTF::String>>* expected_arr, - const base::Closure& closure, + base::OnceClosure closure, const base::Optional<WTF::Vector<WTF::String>>& arr) { EXPECT_EQ(*expected_arr, arr); - closure.Run(); + std::move(closure).Run(); } void ExpectStringMap( base::Optional<WTF::HashMap<WTF::String, WTF::String>>* expected_map, - const base::Closure& closure, + base::OnceClosure closure, const base::Optional<WTF::HashMap<WTF::String, WTF::String>>& map) { EXPECT_EQ(*expected_map, map); - closure.Run(); + std::move(closure).Run(); } } // namespace
diff --git a/mojo/public/cpp/bindings/thread_safe_forwarder_base.cc b/mojo/public/cpp/bindings/thread_safe_forwarder_base.cc index 2d8fbdd..56239ff 100644 --- a/mojo/public/cpp/bindings/thread_safe_forwarder_base.cc +++ b/mojo/public/cpp/bindings/thread_safe_forwarder_base.cc
@@ -15,12 +15,12 @@ ThreadSafeForwarderBase::ThreadSafeForwarderBase( scoped_refptr<base::SequencedTaskRunner> task_runner, - const ForwardMessageCallback& forward, - const ForwardMessageWithResponderCallback& forward_with_responder, + ForwardMessageCallback forward, + ForwardMessageWithResponderCallback forward_with_responder, const AssociatedGroup& associated_group) : task_runner_(std::move(task_runner)), - forward_(forward), - forward_with_responder_(forward_with_responder), + forward_(std::move(forward)), + forward_with_responder_(std::move(forward_with_responder)), associated_group_(associated_group), sync_calls_(new InProgressSyncCalls()) {} @@ -52,7 +52,7 @@ associated_group_.GetController()); } task_runner_->PostTask(FROM_HERE, - base::BindOnce(forward_, base::Passed(message))); + base::BindOnce(forward_, std::move(*message))); return true; } @@ -72,9 +72,8 @@ auto reply_forwarder = std::make_unique<ForwardToCallingThread>(std::move(responder)); task_runner_->PostTask( - FROM_HERE, - base::BindOnce(forward_with_responder_, base::Passed(message), - std::move(reply_forwarder))); + FROM_HERE, base::BindOnce(forward_with_responder_, std::move(*message), + std::move(reply_forwarder))); return true; } @@ -90,7 +89,7 @@ auto response = base::MakeRefCounted<SyncResponseInfo>(); auto response_signaler = std::make_unique<SyncResponseSignaler>(response); task_runner_->PostTask( - FROM_HERE, base::BindOnce(forward_with_responder_, base::Passed(message), + FROM_HERE, base::BindOnce(forward_with_responder_, std::move(*message), std::move(response_signaler))); // Save the pending SyncResponseInfo so that if the sync call deletes @@ -105,7 +104,7 @@ auto assign_true = [](bool* b) { *b = true; }; bool event_signaled = false; SyncEventWatcher watcher(&response->event, - base::Bind(assign_true, &event_signaled)); + base::BindRepeating(assign_true, &event_signaled)); const bool* stop_flags[] = {&event_signaled}; watcher.SyncWatch(stop_flags, 1);
diff --git a/mojo/public/cpp/bindings/thread_safe_forwarder_base.h b/mojo/public/cpp/bindings/thread_safe_forwarder_base.h index b1c3f8e..cf11165 100644 --- a/mojo/public/cpp/bindings/thread_safe_forwarder_base.h +++ b/mojo/public/cpp/bindings/thread_safe_forwarder_base.h
@@ -24,14 +24,14 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) ThreadSafeForwarderBase : public MessageReceiverWithResponder { public: - using ForwardMessageCallback = base::Callback<void(Message)>; + using ForwardMessageCallback = base::RepeatingCallback<void(Message)>; using ForwardMessageWithResponderCallback = - base::Callback<void(Message, std::unique_ptr<MessageReceiver>)>; + base::RepeatingCallback<void(Message, std::unique_ptr<MessageReceiver>)>; ThreadSafeForwarderBase( scoped_refptr<base::SequencedTaskRunner> task_runner, - const ForwardMessageCallback& forward, - const ForwardMessageWithResponderCallback& forward_with_responder, + ForwardMessageCallback forward, + ForwardMessageWithResponderCallback forward_with_responder, const AssociatedGroup& associated_group); ~ThreadSafeForwarderBase() override;
diff --git a/mojo/public/cpp/bindings/thread_safe_interface_ptr.h b/mojo/public/cpp/bindings/thread_safe_interface_ptr.h index 4f347bc0..bba6d3b 100644 --- a/mojo/public/cpp/bindings/thread_safe_interface_ptr.h +++ b/mojo/public/cpp/bindings/thread_safe_interface_ptr.h
@@ -51,12 +51,12 @@ // method. ThreadSafeForwarder( scoped_refptr<base::SequencedTaskRunner> task_runner, - const ForwardMessageCallback& forward, - const ForwardMessageWithResponderCallback& forward_with_responder, + ForwardMessageCallback forward, + ForwardMessageWithResponderCallback forward_with_responder, const AssociatedGroup& associated_group) : ThreadSafeForwarderBase(std::move(task_runner), - forward, - forward_with_responder, + std::move(forward), + std::move(forward_with_responder), associated_group), proxy_(this) {} @@ -151,8 +151,8 @@ std::unique_ptr<ThreadSafeForwarder<InterfaceType>> CreateForwarder() { return std::make_unique<ThreadSafeForwarder<InterfaceType>>( - task_runner_, base::Bind(&PtrWrapper::Accept, this), - base::Bind(&PtrWrapper::AcceptWithResponder, this), + task_runner_, base::BindRepeating(&PtrWrapper::Accept, this), + base::BindRepeating(&PtrWrapper::AcceptWithResponder, this), associated_group_); }
diff --git a/mojo/public/tools/bindings/chromium_bindings_configuration.gni b/mojo/public/tools/bindings/chromium_bindings_configuration.gni index 1e19276..ef2d02a0 100644 --- a/mojo/public/tools/bindings/chromium_bindings_configuration.gni +++ b/mojo/public/tools/bindings/chromium_bindings_configuration.gni
@@ -58,6 +58,7 @@ "//ui/display/mojom/typemaps.gni", "//ui/events/mojom/typemaps.gni", "//ui/gfx/typemaps.gni", + "//ui/gl/typemaps.gni", "//ui/latency/mojom/typemaps.gni", "//ui/ozone/public/mojom/typemaps.gni", "//url/mojom/typemaps.gni",
diff --git a/mojo/public/tools/fuzzers/fuzz_impl.cc b/mojo/public/tools/fuzzers/fuzz_impl.cc index 23816fd..9fbecda 100644 --- a/mojo/public/tools/fuzzers/fuzz_impl.cc +++ b/mojo/public/tools/fuzzers/fuzz_impl.cc
@@ -4,11 +4,12 @@ #include <utility> +#include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/tools/fuzzers/fuzz.mojom.h" #include "mojo/public/tools/fuzzers/fuzz_impl.h" -FuzzImpl::FuzzImpl(fuzz::mojom::FuzzInterfaceRequest request) - : binding_(this, std::move(request)) {} +FuzzImpl::FuzzImpl(mojo::PendingReceiver<fuzz::mojom::FuzzInterface> receiver) + : receiver_(this, std::move(receiver)) {} FuzzImpl::~FuzzImpl() {}
diff --git a/mojo/public/tools/fuzzers/fuzz_impl.h b/mojo/public/tools/fuzzers/fuzz_impl.h index d8f7f566..77f882db 100644 --- a/mojo/public/tools/fuzzers/fuzz_impl.h +++ b/mojo/public/tools/fuzzers/fuzz_impl.h
@@ -6,14 +6,15 @@ #define MOJO_PUBLIC_TOOLS_FUZZERS_FUZZ_IMPL_H_ #include "mojo/public/cpp/bindings/associated_receiver_set.h" -#include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/bindings/pending_associated_receiver.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" +#include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/tools/fuzzers/fuzz.mojom.h" class FuzzImpl : public fuzz::mojom::FuzzInterface, public fuzz::mojom::FuzzDummyInterface { public: - explicit FuzzImpl(fuzz::mojom::FuzzInterfaceRequest request); + explicit FuzzImpl(mojo::PendingReceiver<fuzz::mojom::FuzzInterface> receiver); ~FuzzImpl() override; // fuzz::mojom::FuzzInterface: @@ -38,7 +39,7 @@ void Ping() override; /* Expose the binding to the fuzz harness. */ - mojo::Binding<FuzzInterface> binding_; + mojo::Receiver<FuzzInterface> receiver_; private: mojo::AssociatedReceiverSet<FuzzDummyInterface> associated_receivers_;
diff --git a/mojo/public/tools/fuzzers/mojo_fuzzer_message_dump.cc b/mojo/public/tools/fuzzers/mojo_fuzzer_message_dump.cc index b81f8c4..32ea91d 100644 --- a/mojo/public/tools/fuzzers/mojo_fuzzer_message_dump.cc +++ b/mojo/public/tools/fuzzers/mojo_fuzzer_message_dump.cc
@@ -14,6 +14,7 @@ #include "base/task/thread_pool/thread_pool_instance.h" #include "mojo/core/embedder/embedder.h" #include "mojo/public/cpp/bindings/associated_remote.h" +#include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/tools/fuzzers/fuzz.mojom.h" #include "mojo/public/tools/fuzzers/fuzz_impl.h" @@ -227,13 +228,15 @@ /* Invokes each method in the FuzzInterface and dumps the messages to the * supplied directory. */ void DumpMessages(std::string output_directory) { - fuzz::mojom::FuzzInterfacePtr fuzz; + mojo::Remote<fuzz::mojom::FuzzInterface> fuzz; mojo::AssociatedRemote<fuzz::mojom::FuzzDummyInterface> dummy; /* Create the impl and add a MessageDumper to the filter chain. */ - env->impl = std::make_unique<FuzzImpl>(MakeRequest(&fuzz)); - env->impl->binding_.RouterForTesting()->SetIncomingMessageFilter( - std::make_unique<MessageDumper>(output_directory)); + env->impl = std::make_unique<FuzzImpl>(fuzz.BindNewPipeAndPassReceiver()); + env->impl->receiver_.internal_state() + ->RouterForTesting() + ->SetIncomingMessageFilter( + std::make_unique<MessageDumper>(output_directory)); /* Call methods in various ways to generate interesting messages. */ fuzz->FuzzBasic();
diff --git a/mojo/public/tools/fuzzers/mojo_parse_message_fuzzer.cc b/mojo/public/tools/fuzzers/mojo_parse_message_fuzzer.cc index b145959..74691fa 100644 --- a/mojo/public/tools/fuzzers/mojo_parse_message_fuzzer.cc +++ b/mojo/public/tools/fuzzers/mojo_parse_message_fuzzer.cc
@@ -8,13 +8,13 @@ #include "base/task/single_thread_task_executor.h" #include "base/task/thread_pool/thread_pool_instance.h" #include "mojo/core/embedder/embedder.h" -#include "mojo/public/cpp/bindings/binding.h" +#include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/tools/fuzzers/fuzz_impl.h" void FuzzMessage(const uint8_t* data, size_t size, base::RunLoop* run) { - fuzz::mojom::FuzzInterfacePtr fuzz; - auto impl = std::make_unique<FuzzImpl>(MakeRequest(&fuzz)); - auto router = impl->binding_.RouterForTesting(); + mojo::PendingRemote<fuzz::mojom::FuzzInterface> fuzz; + auto impl = std::make_unique<FuzzImpl>(fuzz.InitWithNewPipeAndPassReceiver()); + auto router = impl->receiver_.internal_state()->RouterForTesting(); /* Create a mojo message with the appropriate payload size. */ mojo::Message message(0, 0, size, 0, nullptr);
diff --git a/mojo/public/tools/fuzzers/mojo_parse_message_proto_fuzzer.cc b/mojo/public/tools/fuzzers/mojo_parse_message_proto_fuzzer.cc index ec76724..303e62a 100644 --- a/mojo/public/tools/fuzzers/mojo_parse_message_proto_fuzzer.cc +++ b/mojo/public/tools/fuzzers/mojo_parse_message_proto_fuzzer.cc
@@ -11,7 +11,7 @@ #include "base/task/single_thread_task_executor.h" #include "base/task/thread_pool/thread_pool_instance.h" #include "mojo/core/embedder/embedder.h" -#include "mojo/public/cpp/bindings/binding.h" +#include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/tools/fuzzers/fuzz_impl.h" #include "mojo/public/tools/fuzzers/mojo_fuzzer.pb.h" #include "testing/libfuzzer/proto/lpm_interface.h" @@ -20,9 +20,9 @@ void FuzzMessage(const MojoFuzzerMessages& mojo_fuzzer_messages, base::RunLoop* run) { - fuzz::mojom::FuzzInterfacePtr fuzz; - auto impl = std::make_unique<FuzzImpl>(MakeRequest(&fuzz)); - auto router = impl->binding_.RouterForTesting(); + mojo::PendingRemote<fuzz::mojom::FuzzInterface> fuzz; + auto impl = std::make_unique<FuzzImpl>(fuzz.InitWithNewPipeAndPassReceiver()); + auto router = impl->receiver_.internal_state()->RouterForTesting(); for (auto& message_str : mojo_fuzzer_messages.messages()) { // Create a mojo message with the appropriate payload size.
diff --git a/net/base/features.cc b/net/base/features.cc index 1224a854..f94fe645 100644 --- a/net/base/features.cc +++ b/net/base/features.cc
@@ -42,6 +42,9 @@ const base::Feature kTLS13KeyUpdate{"TLS13KeyUpdate", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kPostQuantumCECPQ2{"PostQuantumCECPQ2", + base::FEATURE_DISABLED_BY_DEFAULT}; + const base::Feature kNetUnusedIdleSocketTimeout{ "NetUnusedIdleSocketTimeout", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/net/base/features.h b/net/base/features.h index 1e68a63..f0b10453 100644 --- a/net/base/features.h +++ b/net/base/features.h
@@ -62,6 +62,9 @@ // servers. NET_EXPORT extern const base::Feature kTLS13KeyUpdate; +// Enables CECPQ2, a post-quantum key-agreement, in TLS 1.3 connections. +NET_EXPORT extern const base::Feature kPostQuantumCECPQ2; + // Changes the timeout after which unused sockets idle sockets are cleaned up. NET_EXPORT extern const base::Feature kNetUnusedIdleSocketTimeout;
diff --git a/net/socket/ssl_client_socket_impl.cc b/net/socket/ssl_client_socket_impl.cc index dbb7f97..48af2a1 100644 --- a/net/socket/ssl_client_socket_impl.cc +++ b/net/socket/ssl_client_socket_impl.cc
@@ -323,6 +323,12 @@ ssl_ctx_.get(), TLSEXT_cert_compression_brotli, nullptr /* compression not supported */, DecompressBrotliCert); #endif + + if (base::FeatureList::IsEnabled(features::kPostQuantumCECPQ2)) { + static const int kCurves[] = {NID_CECPQ2, NID_X25519, + NID_X9_62_prime256v1, NID_secp384r1}; + SSL_CTX_set1_curves(ssl_ctx_.get(), kCurves, base::size(kCurves)); + } } static int ClientCertRequestCallback(SSL* ssl, void* arg) {
diff --git a/services/device/generic_sensor/platform_sensor_reader_winrt.cc b/services/device/generic_sensor/platform_sensor_reader_winrt.cc index e568c1a3..94aa8702 100644 --- a/services/device/generic_sensor/platform_sensor_reader_winrt.cc +++ b/services/device/generic_sensor/platform_sensor_reader_winrt.cc
@@ -126,35 +126,6 @@ client_ = client; } -// static -template <wchar_t const* runtime_class_id, - class ISensorWinrtStatics, - class ISensorWinrtClass, - class ISensorReadingChangedHandler, - class ISensorReadingChangedEventArgs> -bool PlatformSensorReaderWinrtBase<runtime_class_id, - ISensorWinrtStatics, - ISensorWinrtClass, - ISensorReadingChangedHandler, - ISensorReadingChangedEventArgs>:: - IsSensorCreateSuccess(SensorWinrtCreateFailure create_return_code) { - switch (create_return_code) { - case SensorWinrtCreateFailure::kErrorISensorWinrtStaticsActivationFailed: - // Failing to query the default report interval is not a fatal error. The - // consumer (PlatformSensorWin) should be able to handle this and return a - // default report interval instead. - FALLTHROUGH; - case SensorWinrtCreateFailure::kOk: - return true; - case SensorWinrtCreateFailure::kErrorGetDefaultSensorFailed: - FALLTHROUGH; - case SensorWinrtCreateFailure::kErrorDefaultSensorNull: - FALLTHROUGH; - case SensorWinrtCreateFailure::kErrorGetMinReportIntervalFailed: - return false; - } -} - template <wchar_t const* runtime_class_id, class ISensorWinrtStatics, class ISensorWinrtClass, @@ -183,35 +154,42 @@ class ISensorWinrtClass, class ISensorReadingChangedHandler, class ISensorReadingChangedEventArgs> -SensorWinrtCreateFailure -PlatformSensorReaderWinrtBase<runtime_class_id, - ISensorWinrtStatics, - ISensorWinrtClass, - ISensorReadingChangedHandler, - ISensorReadingChangedEventArgs>::Initialize() { +bool PlatformSensorReaderWinrtBase< + runtime_class_id, + ISensorWinrtStatics, + ISensorWinrtClass, + ISensorReadingChangedHandler, + ISensorReadingChangedEventArgs>::Initialize() { ComPtr<ISensorWinrtStatics> sensor_statics; HRESULT hr = get_sensor_factory_callback_.Run(&sensor_statics); - if (FAILED(hr)) - return SensorWinrtCreateFailure::kErrorISensorWinrtStaticsActivationFailed; + if (FAILED(hr)) { + DLOG(ERROR) << "Failed to get sensor activation factory: " + << logging::SystemErrorCodeToString(hr); + return false; + } hr = sensor_statics->GetDefault(&sensor_); base::UmaHistogramSparse("Sensors.Windows.WinRT.Activation.Result", hr); if (FAILED(hr)) { - return SensorWinrtCreateFailure::kErrorGetDefaultSensorFailed; + DLOG(ERROR) << "Failed to query default sensor: " + << logging::SystemErrorCodeToString(hr); + return false; } // GetDefault() returns null if the sensor does not exist - if (!sensor_) - return SensorWinrtCreateFailure::kErrorDefaultSensorNull; + if (!sensor_) { + VLOG(1) << "Sensor does not exist on system"; + return false; + } minimum_report_interval_ = GetMinimumReportIntervalFromSensor(); if (minimum_report_interval_.is_zero()) - return SensorWinrtCreateFailure::kErrorGetMinReportIntervalFailed; + DLOG(WARNING) << "Failed to get sensor minimum report interval"; - return SensorWinrtCreateFailure::kOk; + return true; } template <wchar_t const* runtime_class_id, @@ -348,7 +326,7 @@ std::unique_ptr<PlatformSensorReaderWinBase> PlatformSensorReaderWinrtLightSensor::Create() { auto light_sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>(); - if (IsSensorCreateSuccess(light_sensor->Initialize())) { + if (light_sensor->Initialize()) { return light_sensor; } return nullptr; @@ -406,7 +384,7 @@ PlatformSensorReaderWinrtAccelerometer::Create() { auto accelerometer = std::make_unique<PlatformSensorReaderWinrtAccelerometer>(); - if (IsSensorCreateSuccess(accelerometer->Initialize())) { + if (accelerometer->Initialize()) { return accelerometer; } return nullptr; @@ -486,7 +464,7 @@ std::unique_ptr<PlatformSensorReaderWinBase> PlatformSensorReaderWinrtGyrometer::Create() { auto gyrometer = std::make_unique<PlatformSensorReaderWinrtGyrometer>(); - if (IsSensorCreateSuccess(gyrometer->Initialize())) { + if (gyrometer->Initialize()) { return gyrometer; } return nullptr; @@ -565,7 +543,7 @@ std::unique_ptr<PlatformSensorReaderWinBase> PlatformSensorReaderWinrtMagnetometer::Create() { auto magnetometer = std::make_unique<PlatformSensorReaderWinrtMagnetometer>(); - if (IsSensorCreateSuccess(magnetometer->Initialize())) { + if (magnetometer->Initialize()) { return magnetometer; } return nullptr; @@ -642,7 +620,7 @@ PlatformSensorReaderWinrtAbsOrientationEulerAngles::Create() { auto inclinometer = std::make_unique<PlatformSensorReaderWinrtAbsOrientationEulerAngles>(); - if (IsSensorCreateSuccess(inclinometer->Initialize())) { + if (inclinometer->Initialize()) { return inclinometer; } return nullptr; @@ -720,7 +698,7 @@ PlatformSensorReaderWinrtAbsOrientationQuaternion::Create() { auto orientation = std::make_unique<PlatformSensorReaderWinrtAbsOrientationQuaternion>(); - if (IsSensorCreateSuccess(orientation->Initialize())) { + if (orientation->Initialize()) { return orientation; } return nullptr;
diff --git a/services/device/generic_sensor/platform_sensor_reader_winrt.h b/services/device/generic_sensor/platform_sensor_reader_winrt.h index 7736a3d..84c0b85 100644 --- a/services/device/generic_sensor/platform_sensor_reader_winrt.h +++ b/services/device/generic_sensor/platform_sensor_reader_winrt.h
@@ -32,14 +32,6 @@ mojom::SensorType type); }; -enum SensorWinrtCreateFailure { - kOk = 0, - kErrorISensorWinrtStaticsActivationFailed = 1, - kErrorGetDefaultSensorFailed = 2, - kErrorDefaultSensorNull = 3, - kErrorGetMinReportIntervalFailed = 4 -}; - // Base class that contains common helper functions used between all low // level sensor types based on the Windows.Devices.Sensors API. Derived // classes will specialize the template into a specific sensor. See @@ -65,11 +57,15 @@ // Allows tests to specify their own implementation of the underlying sensor. // This function should be called before Initialize(). - void InitForTests(GetSensorFactoryFunctor get_sensor_factory_callback) { + void InitForTesting(GetSensorFactoryFunctor get_sensor_factory_callback) { get_sensor_factory_callback_ = get_sensor_factory_callback; } - SensorWinrtCreateFailure Initialize() WARN_UNUSED_RESULT; + // Returns true if the underlying WinRT sensor object is valid, meant + // for testing purposes. + bool IsUnderlyingWinrtObjectValidForTesting() { return sensor_; } + + bool Initialize() WARN_UNUSED_RESULT; bool StartSensor(const PlatformSensorConfiguration& configuration) override WARN_UNUSED_RESULT; @@ -80,11 +76,6 @@ PlatformSensorReaderWinrtBase(); virtual ~PlatformSensorReaderWinrtBase(); - // Determines if the SensorWinrtCreateFailure code means a WinRT sensor - // was successfully created or not. - static bool IsSensorCreateSuccess( - SensorWinrtCreateFailure create_return_code); - // Derived classes should implement this function to handle sensor specific // parsing of the sensor reading. virtual HRESULT OnReadingChangedCallback(
diff --git a/services/device/generic_sensor/platform_sensor_reader_winrt_unittests.cc b/services/device/generic_sensor/platform_sensor_reader_winrt_unittests.cc index de39df4..ac140e1 100644 --- a/services/device/generic_sensor/platform_sensor_reader_winrt_unittests.cc +++ b/services/device/generic_sensor/platform_sensor_reader_winrt_unittests.cc
@@ -558,23 +558,31 @@ ABI::Windows::Devices::Sensors::ILightSensorReadingChangedEventArgs, ABI::Windows::Devices::Sensors::LightSensorReadingChangedEventArgs>>(); + // Case: sensor was created successfully auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>(); - sensor->InitForTests(base::BindLambdaForTesting( + sensor->InitForTesting(base::BindLambdaForTesting( [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory) -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); })); + EXPECT_TRUE(sensor->Initialize()); + EXPECT_TRUE(sensor->IsUnderlyingWinrtObjectValidForTesting()); - EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk); - + // Case: failed to query sensor fake_sensor_factory->SetGetDefaultReturnCode(E_FAIL); - EXPECT_EQ(sensor->Initialize(), - SensorWinrtCreateFailure::kErrorGetDefaultSensorFailed); + EXPECT_FALSE(sensor->Initialize()); + EXPECT_FALSE(sensor->IsUnderlyingWinrtObjectValidForTesting()); + fake_sensor_factory->SetGetDefaultReturnCode(S_OK); - sensor->InitForTests(base::BindLambdaForTesting( + // Case: Sensor does not exist on system + fake_sensor_factory->fake_sensor_ = nullptr; + EXPECT_FALSE(sensor->Initialize()); + EXPECT_FALSE(sensor->IsUnderlyingWinrtObjectValidForTesting()); + + // Case:: failed to activate sensor factory + sensor->InitForTesting(base::BindLambdaForTesting( [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory) -> HRESULT { return E_FAIL; })); - EXPECT_EQ( - sensor->Initialize(), - SensorWinrtCreateFailure::kErrorISensorWinrtStaticsActivationFailed); + EXPECT_FALSE(sensor->Initialize()); + EXPECT_FALSE(sensor->IsUnderlyingWinrtObjectValidForTesting()); } // Tests that PlatformSensorReaderWinrtBase returns the right @@ -590,10 +598,10 @@ auto fake_sensor = fake_sensor_factory->fake_sensor_; auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>(); - sensor->InitForTests(base::BindLambdaForTesting( + sensor->InitForTesting(base::BindLambdaForTesting( [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory) -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); })); - EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk); + EXPECT_TRUE(sensor->Initialize()); EXPECT_EQ(sensor->GetMinimalReportingInterval().InMilliseconds(), kExpectedMinimumReportInterval); @@ -613,11 +621,10 @@ auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>(); fake_sensor->SetGetMinimumReportIntervalReturnCode(E_FAIL); - sensor->InitForTests(base::BindLambdaForTesting( + sensor->InitForTesting(base::BindLambdaForTesting( [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory) -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); })); - EXPECT_EQ(sensor->Initialize(), - SensorWinrtCreateFailure::kErrorGetMinReportIntervalFailed); + EXPECT_TRUE(sensor->Initialize()); EXPECT_EQ(sensor->GetMinimalReportingInterval().InMilliseconds(), 0); } @@ -636,10 +643,10 @@ auto fake_sensor = fake_sensor_factory->fake_sensor_; auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>(); - sensor->InitForTests(base::BindLambdaForTesting( + sensor->InitForTesting(base::BindLambdaForTesting( [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory) -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); })); - EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk); + EXPECT_TRUE(sensor->Initialize()); auto mock_client = std::make_unique<testing::NiceMock<MockClient>>(); @@ -688,10 +695,10 @@ auto fake_sensor = fake_sensor_factory->fake_sensor_; auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>(); - sensor->InitForTests(base::BindLambdaForTesting( + sensor->InitForTesting(base::BindLambdaForTesting( [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory) -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); })); - EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk); + EXPECT_TRUE(sensor->Initialize()); PlatformSensorConfiguration sensor_config(kExpectedReportFrequencySet); EXPECT_TRUE(sensor->StartSensor(sensor_config)); @@ -722,10 +729,10 @@ auto fake_sensor = fake_sensor_factory->fake_sensor_; auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>(); - sensor->InitForTests(base::BindLambdaForTesting( + sensor->InitForTesting(base::BindLambdaForTesting( [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory) -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); })); - EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk); + EXPECT_TRUE(sensor->Initialize()); PlatformSensorConfiguration sensor_config(kExpectedReportFrequencySet); EXPECT_TRUE(sensor->StartSensor(sensor_config)); @@ -748,10 +755,10 @@ auto fake_sensor = fake_sensor_factory->fake_sensor_; auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>(); - sensor->InitForTests(base::BindLambdaForTesting( + sensor->InitForTesting(base::BindLambdaForTesting( [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory) -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); })); - EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk); + EXPECT_TRUE(sensor->Initialize()); fake_sensor->SetPutReportIntervalReturnCode(E_FAIL); @@ -777,10 +784,10 @@ auto fake_sensor = fake_sensor_factory->fake_sensor_; auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>(); - sensor->InitForTests(base::BindLambdaForTesting( + sensor->InitForTesting(base::BindLambdaForTesting( [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory) -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); })); - EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk); + EXPECT_TRUE(sensor->Initialize()); PlatformSensorConfiguration sensor_config(kExpectedReportFrequencySet); EXPECT_TRUE(sensor->StartSensor(sensor_config)); @@ -803,10 +810,10 @@ auto fake_sensor = fake_sensor_factory->fake_sensor_; auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>(); - sensor->InitForTests(base::BindLambdaForTesting( + sensor->InitForTesting(base::BindLambdaForTesting( [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory) -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); })); - EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk); + EXPECT_TRUE(sensor->Initialize()); auto mock_client = std::make_unique<testing::NiceMock<MockClient>>(); @@ -844,10 +851,10 @@ auto fake_sensor = fake_sensor_factory->fake_sensor_; auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>(); - sensor->InitForTests(base::BindLambdaForTesting( + sensor->InitForTesting(base::BindLambdaForTesting( [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory) -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); })); - EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk); + EXPECT_TRUE(sensor->Initialize()); auto mock_client = std::make_unique<testing::NiceMock<MockClient>>(); @@ -886,12 +893,12 @@ auto fake_sensor = fake_sensor_factory->fake_sensor_; auto sensor = std::make_unique<PlatformSensorReaderWinrtAccelerometer>(); - sensor->InitForTests(base::BindLambdaForTesting( + sensor->InitForTesting(base::BindLambdaForTesting( [&](ABI::Windows::Devices::Sensors::IAccelerometerStatics** sensor_factory) -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); })); - EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk); + EXPECT_TRUE(sensor->Initialize()); auto mock_client = std::make_unique<testing::NiceMock<MockClient>>(); EXPECT_CALL(*mock_client, OnReadingUpdated(::testing::_)) @@ -927,12 +934,12 @@ auto fake_sensor = fake_sensor_factory->fake_sensor_; auto sensor = std::make_unique<PlatformSensorReaderWinrtAccelerometer>(); - sensor->InitForTests(base::BindLambdaForTesting( + sensor->InitForTesting(base::BindLambdaForTesting( [&](ABI::Windows::Devices::Sensors::IAccelerometerStatics** sensor_factory) -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); })); - EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk); + EXPECT_TRUE(sensor->Initialize()); auto mock_client = std::make_unique<testing::NiceMock<MockClient>>(); sensor->SetClient(mock_client.get()); @@ -976,10 +983,10 @@ auto fake_sensor = fake_sensor_factory->fake_sensor_; auto sensor = std::make_unique<PlatformSensorReaderWinrtGyrometer>(); - sensor->InitForTests(base::BindLambdaForTesting( + sensor->InitForTesting(base::BindLambdaForTesting( [&](ABI::Windows::Devices::Sensors::IGyrometerStatics** sensor_factory) -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); })); - EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk); + EXPECT_TRUE(sensor->Initialize()); auto mock_client = std::make_unique<testing::NiceMock<MockClient>>(); EXPECT_CALL(*mock_client, OnReadingUpdated(::testing::_)) @@ -1013,10 +1020,10 @@ auto fake_sensor = fake_sensor_factory->fake_sensor_; auto sensor = std::make_unique<PlatformSensorReaderWinrtGyrometer>(); - sensor->InitForTests(base::BindLambdaForTesting( + sensor->InitForTesting(base::BindLambdaForTesting( [&](ABI::Windows::Devices::Sensors::IGyrometerStatics** sensor_factory) -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); })); - EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk); + EXPECT_TRUE(sensor->Initialize()); auto mock_client = std::make_unique<testing::NiceMock<MockClient>>(); sensor->SetClient(mock_client.get()); @@ -1060,10 +1067,10 @@ auto fake_sensor = fake_sensor_factory->fake_sensor_; auto sensor = std::make_unique<PlatformSensorReaderWinrtMagnetometer>(); - sensor->InitForTests(base::BindLambdaForTesting( + sensor->InitForTesting(base::BindLambdaForTesting( [&](ABI::Windows::Devices::Sensors::IMagnetometerStatics** sensor_factory) -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); })); - EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk); + EXPECT_TRUE(sensor->Initialize()); auto mock_client = std::make_unique<testing::NiceMock<MockClient>>(); EXPECT_CALL(*mock_client, OnReadingUpdated(::testing::_)) @@ -1097,10 +1104,10 @@ auto fake_sensor = fake_sensor_factory->fake_sensor_; auto sensor = std::make_unique<PlatformSensorReaderWinrtMagnetometer>(); - sensor->InitForTests(base::BindLambdaForTesting( + sensor->InitForTesting(base::BindLambdaForTesting( [&](ABI::Windows::Devices::Sensors::IMagnetometerStatics** sensor_factory) -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); })); - EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk); + EXPECT_TRUE(sensor->Initialize()); auto mock_client = std::make_unique<testing::NiceMock<MockClient>>(); sensor->SetClient(mock_client.get()); @@ -1145,10 +1152,10 @@ auto sensor = std::make_unique<PlatformSensorReaderWinrtAbsOrientationEulerAngles>(); - sensor->InitForTests(base::BindLambdaForTesting( + sensor->InitForTesting(base::BindLambdaForTesting( [&](ABI::Windows::Devices::Sensors::IInclinometerStatics** sensor_factory) -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); })); - EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk); + EXPECT_TRUE(sensor->Initialize()); auto mock_client = std::make_unique<testing::NiceMock<MockClient>>(); EXPECT_CALL(*mock_client, OnReadingUpdated(::testing::_)) @@ -1183,10 +1190,10 @@ auto sensor = std::make_unique<PlatformSensorReaderWinrtAbsOrientationEulerAngles>(); - sensor->InitForTests(base::BindLambdaForTesting( + sensor->InitForTesting(base::BindLambdaForTesting( [&](ABI::Windows::Devices::Sensors::IInclinometerStatics** sensor_factory) -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); })); - EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk); + EXPECT_TRUE(sensor->Initialize()); auto mock_client = std::make_unique<testing::NiceMock<MockClient>>(); sensor->SetClient(mock_client.get()); @@ -1233,12 +1240,12 @@ auto sensor = std::make_unique<PlatformSensorReaderWinrtAbsOrientationQuaternion>(); - sensor->InitForTests(base::BindLambdaForTesting( + sensor->InitForTesting(base::BindLambdaForTesting( [&](ABI::Windows::Devices::Sensors::IOrientationSensorStatics** sensor_factory) -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); })); - EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk); + EXPECT_TRUE(sensor->Initialize()); auto mock_client = std::make_unique<testing::NiceMock<MockClient>>(); EXPECT_CALL(*mock_client, OnReadingUpdated(::testing::_)) @@ -1276,12 +1283,12 @@ auto sensor = std::make_unique<PlatformSensorReaderWinrtAbsOrientationQuaternion>(); - sensor->InitForTests(base::BindLambdaForTesting( + sensor->InitForTesting(base::BindLambdaForTesting( [&](ABI::Windows::Devices::Sensors::IOrientationSensorStatics** sensor_factory) -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); })); - EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk); + EXPECT_TRUE(sensor->Initialize()); auto mock_client = std::make_unique<testing::NiceMock<MockClient>>(); sensor->SetClient(mock_client.get()); @@ -1311,10 +1318,10 @@ auto fake_sensor = fake_sensor_factory->fake_sensor_; auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>(); - sensor->InitForTests(base::BindLambdaForTesting( + sensor->InitForTesting(base::BindLambdaForTesting( [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory) -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); })); - EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk); + EXPECT_TRUE(sensor->Initialize()); auto mock_client = std::make_unique<testing::NiceMock<MockClient>>(); @@ -1367,12 +1374,12 @@ auto fake_sensor = fake_sensor_factory->fake_sensor_; auto sensor = std::make_unique<PlatformSensorReaderWinrtAccelerometer>(); - sensor->InitForTests(base::BindLambdaForTesting( + sensor->InitForTesting(base::BindLambdaForTesting( [&](ABI::Windows::Devices::Sensors::IAccelerometerStatics** sensor_factory) -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); })); - EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk); + EXPECT_TRUE(sensor->Initialize()); auto mock_client = std::make_unique<testing::NiceMock<MockClient>>(); @@ -1437,10 +1444,10 @@ auto fake_sensor = fake_sensor_factory->fake_sensor_; auto sensor = std::make_unique<PlatformSensorReaderWinrtGyrometer>(); - sensor->InitForTests(base::BindLambdaForTesting( + sensor->InitForTesting(base::BindLambdaForTesting( [&](ABI::Windows::Devices::Sensors::IGyrometerStatics** sensor_factory) -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); })); - EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk); + EXPECT_TRUE(sensor->Initialize()); auto mock_client = std::make_unique<testing::NiceMock<MockClient>>(); @@ -1505,10 +1512,10 @@ auto fake_sensor = fake_sensor_factory->fake_sensor_; auto sensor = std::make_unique<PlatformSensorReaderWinrtMagnetometer>(); - sensor->InitForTests(base::BindLambdaForTesting( + sensor->InitForTesting(base::BindLambdaForTesting( [&](ABI::Windows::Devices::Sensors::IMagnetometerStatics** sensor_factory) -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); })); - EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk); + EXPECT_TRUE(sensor->Initialize()); auto mock_client = std::make_unique<testing::NiceMock<MockClient>>(); @@ -1580,10 +1587,10 @@ auto sensor = std::make_unique<PlatformSensorReaderWinrtAbsOrientationEulerAngles>(); - sensor->InitForTests(base::BindLambdaForTesting( + sensor->InitForTesting(base::BindLambdaForTesting( [&](ABI::Windows::Devices::Sensors::IInclinometerStatics** sensor_factory) -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); })); - EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk); + EXPECT_TRUE(sensor->Initialize()); auto mock_client = std::make_unique<testing::NiceMock<MockClient>>(); @@ -1665,12 +1672,12 @@ auto sensor = std::make_unique<PlatformSensorReaderWinrtAbsOrientationQuaternion>(); - sensor->InitForTests(base::BindLambdaForTesting( + sensor->InitForTesting(base::BindLambdaForTesting( [&](ABI::Windows::Devices::Sensors::IOrientationSensorStatics** sensor_factory) -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); })); - EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk); + EXPECT_TRUE(sensor->Initialize()); auto mock_client = std::make_unique<testing::NiceMock<MockClient>>(); @@ -1728,13 +1735,13 @@ ABI::Windows::Devices::Sensors::LightSensorReadingChangedEventArgs>>(); auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>(); - sensor->InitForTests(base::BindLambdaForTesting( + sensor->InitForTesting(base::BindLambdaForTesting( [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory) -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); })); base::HistogramTester histogram_tester; // Trigger S_OK - EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk); + EXPECT_TRUE(sensor->Initialize()); EXPECT_EQ(histogram_tester.GetBucketCount( "Sensors.Windows.WinRT.Activation.Result", S_OK), @@ -1742,15 +1749,13 @@ // Trigger E_ACCESSDENIED twice fake_sensor_factory->SetGetDefaultReturnCode(E_ACCESSDENIED); - EXPECT_EQ(sensor->Initialize(), - SensorWinrtCreateFailure::kErrorGetDefaultSensorFailed); + EXPECT_FALSE(sensor->Initialize()); EXPECT_EQ(histogram_tester.GetBucketCount( "Sensors.Windows.WinRT.Activation.Result", E_ACCESSDENIED), 1); - EXPECT_EQ(sensor->Initialize(), - SensorWinrtCreateFailure::kErrorGetDefaultSensorFailed); + EXPECT_FALSE(sensor->Initialize()); EXPECT_EQ(histogram_tester.GetBucketCount( "Sensors.Windows.WinRT.Activation.Result", E_ACCESSDENIED), @@ -1773,10 +1778,10 @@ auto fake_sensor = fake_sensor_factory->fake_sensor_; auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>(); - sensor->InitForTests(base::BindLambdaForTesting( + sensor->InitForTesting(base::BindLambdaForTesting( [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory) -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); })); - EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk); + EXPECT_TRUE(sensor->Initialize()); base::HistogramTester histogram_tester; // Trigger S_OK @@ -1823,10 +1828,10 @@ auto fake_sensor = fake_sensor_factory->fake_sensor_; auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>(); - sensor->InitForTests(base::BindLambdaForTesting( + sensor->InitForTesting(base::BindLambdaForTesting( [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory) -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); })); - EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk); + EXPECT_TRUE(sensor->Initialize()); base::HistogramTester histogram_tester; // Trigger E_UNEXPECTED
diff --git a/services/network/cors/cors_url_loader.cc b/services/network/cors/cors_url_loader.cc index 1d8339b..53e8891 100644 --- a/services/network/cors/cors_url_loader.cc +++ b/services/network/cors/cors_url_loader.cc
@@ -98,7 +98,6 @@ options_(options), delete_callback_(std::move(delete_callback)), network_loader_factory_(network_loader_factory), - network_client_binding_(this), request_(resource_request), forwarding_client_(std::move(client)), traffic_annotation_(traffic_annotation), @@ -114,9 +113,9 @@ } CorsURLLoader::~CorsURLLoader() { - // Close pipes first to ignore possible subsequent callback invocations - // cased by |network_loader_| - network_client_binding_.Close(); + // Reset pipes first to ignore possible subsequent callback invocations + // caused by |network_loader_| + network_client_receiver_.reset(); } void CorsURLLoader::Start() { @@ -217,7 +216,7 @@ (!original_fetch_cors_flag && fetch_cors_flag_) || (fetch_cors_flag_ && original_method != request_.method)) { DCHECK_NE(request_.mode, mojom::RequestMode::kNoCors); - network_client_binding_.Unbind(); + network_client_receiver_.reset(); StartRequest(); return; } @@ -491,10 +490,10 @@ : mojom::CredentialsMode::kOmit; mojom::URLLoaderClientPtr network_client; - network_client_binding_.Bind(mojo::MakeRequest(&network_client)); + network_client_receiver_.Bind(mojo::MakeRequest(&network_client)); // Binding |this| as an unretained pointer is safe because - // |network_client_binding_| shares this object's lifetime. - network_client_binding_.set_connection_error_handler( + // |network_client_receiver_| shares this object's lifetime. + network_client_receiver_.set_disconnect_handler( base::BindOnce(&CorsURLLoader::OnMojoDisconnect, base::Unretained(this))); network_loader_factory_->CreateLoaderAndStart( mojo::MakeRequest(&network_loader_), routing_id_, request_id_, options_,
diff --git a/services/network/cors/cors_url_loader.h b/services/network/cors/cors_url_loader.h index e3da283..8299d05d 100644 --- a/services/network/cors/cors_url_loader.h +++ b/services/network/cors/cors_url_loader.h
@@ -128,7 +128,7 @@ // For the actual request. mojom::URLLoaderPtr network_loader_; - mojo::Binding<mojom::URLLoaderClient> network_client_binding_; + mojo::Receiver<mojom::URLLoaderClient> network_client_receiver_{this}; ResourceRequest request_; // To be a URLLoader for the client.
diff --git a/services/network/public/cpp/content_security_policy.cc b/services/network/public/cpp/content_security_policy.cc index 0181a63d..b86517e 100644 --- a/services/network/public/cpp/content_security_policy.cc +++ b/services/network/public/cpp/content_security_policy.cc
@@ -155,81 +155,67 @@ // Parses an ancestor source expression. // https://www.w3.org/TR/CSP3/#grammardef-ancestor-source -base::Optional<mojom::CSPSourcePtr> ParseAncestorSource( - base::StringPiece source) { - if (base::EqualsCaseInsensitiveASCII(source, "'none'")) - return base::nullopt; +// +// Return false on errors. +bool ParseAncestorSource(base::StringPiece expression, + mojom::CSPSource* csp_source) { + // TODO(arthursonzogni): Blink reports an invalid source expression when + // 'none' is parsed here. + if (base::EqualsCaseInsensitiveASCII(expression, "'none'")) + return false; - mojom::CSPSource csp_source; - - if (base::EqualsCaseInsensitiveASCII(source, "*")) { - csp_source.is_host_wildcard = true; - return csp_source.Clone(); - } - - if (base::EqualsCaseInsensitiveASCII(source, "'self'")) { - csp_source.allow_self = true; - return csp_source.Clone(); - } - - size_t position = source.find_first_of(":/"); - if (position != std::string::npos && source[position] == ':') { + size_t position = expression.find_first_of(":/"); + if (position != std::string::npos && expression[position] == ':') { // scheme: // ^ - if (position + 1 == source.size()) { - if (ParseScheme(source.substr(0, position), &csp_source)) - return csp_source.Clone(); - return base::nullopt; - } + if (position + 1 == expression.size()) + return ParseScheme(expression.substr(0, position), csp_source); - if (source[position + 1] == '/') { + if (expression[position + 1] == '/') { // scheme:// // ^ - if (position + 2 >= source.size() || source[position + 2] != '/') - return base::nullopt; - if (!ParseScheme(source.substr(0, position), &csp_source)) - return base::nullopt; - source = source.substr(position + 3); - position = source.find_first_of(":/"); + if (position + 2 >= expression.size() || expression[position + 2] != '/') + return false; + if (!ParseScheme(expression.substr(0, position), csp_source)) + return false; + expression = expression.substr(position + 3); + position = expression.find_first_of(":/"); } } // host // ^ - if (!ParseHost(source.substr(0, position), &csp_source)) - return base::nullopt; + if (!ParseHost(expression.substr(0, position), csp_source)) + return false; // If there's nothing more to parse (no port or path specified), return. if (position == std::string::npos) - return csp_source.Clone(); + return true; - source = source.substr(position); + expression = expression.substr(position); // :\d* // ^ - if (source[0] == ':') { - size_t port_end = source.find_first_of("/"); - base::StringPiece port = source.substr( + if (expression[0] == ':') { + size_t port_end = expression.find_first_of("/"); + base::StringPiece port = expression.substr( 1, port_end == std::string::npos ? std::string::npos : port_end - 1); - if (!ParsePort(port, &csp_source)) - return base::nullopt; + if (!ParsePort(port, csp_source)) + return false; if (port_end == std::string::npos) - return csp_source.Clone(); + return true; - source = source.substr(port_end); + expression = expression.substr(port_end); } // / // ^ - if (!source.empty() && !ParsePath(source, &csp_source)) - return base::nullopt; - - return csp_source.Clone(); + return expression.empty() || ParsePath(expression, csp_source); } // Parse ancestor-source-list grammar. // https://www.w3.org/TR/CSP3/#directive-frame-ancestors -base::Optional<mojom::CSPSourceListPtr> ParseFrameAncestorsDirective( +mojom::CSPSourceListPtr ParseFrameAncestorsDirective( base::StringPiece frame_ancestors_value) { base::StringPiece value = base::TrimString( frame_ancestors_value, base::kWhitespaceASCII, base::TRIM_ALL); @@ -237,20 +223,36 @@ std::vector<mojom::CSPSourcePtr> sources; if (frame_ancestors_value.empty()) - return base::nullopt; + return {}; + + auto directive = mojom::CSPSourceList::New(); if (base::EqualsCaseInsensitiveASCII(value, "'none'")) - return mojom::CSPSourceList::New(std::move(sources)); + return directive; - for (const auto& source : base::SplitStringPiece( + for (const auto& expression : base::SplitStringPiece( value, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) { - if (auto csp_source = ParseAncestorSource(source)) - sources.push_back(std::move(*csp_source)); - else - return base::nullopt; + if (base::EqualsCaseInsensitiveASCII(expression, "'self'")) { + directive->allow_self = true; + continue; + } + + if (base::EqualsCaseInsensitiveASCII(expression, "*")) { + directive->allow_star = true; + continue; + } + + auto csp_source = mojom::CSPSource::New(); + if (ParseAncestorSource(expression, csp_source.get())) { + directive->sources.push_back(std::move(csp_source)); + continue; + } + + // Parsing error. + return {}; } - return mojom::CSPSourceList::New(std::move(sources)); + return directive; } // Parses a reporting directive. @@ -361,10 +363,8 @@ if (content_security_policy_ptr_->frame_ancestors) return true; - if (auto parsed_frame_ancestors = - ParseFrameAncestorsDirective(frame_ancestors_value)) { - content_security_policy_ptr_->frame_ancestors = - std::move(*parsed_frame_ancestors); + if (auto directive = ParseFrameAncestorsDirective(frame_ancestors_value)) { + content_security_policy_ptr_->frame_ancestors = std::move(directive); return true; }
diff --git a/services/network/public/cpp/content_security_policy_unittest.cc b/services/network/public/cpp/content_security_policy_unittest.cc index d11a3d1..a759cf5 100644 --- a/services/network/public/cpp/content_security_policy_unittest.cc +++ b/services/network/public/cpp/content_security_policy_unittest.cc
@@ -12,17 +12,17 @@ namespace { struct ExpectedResult { - size_t size; struct ParsedSource { std::string scheme; std::string host; - int port; - std::string path; - bool is_host_wildcard; - bool is_port_wildcard; - bool allow_self; + int port = url::PORT_UNSPECIFIED; + std::string path = ""; + bool is_host_wildcard = false; + bool is_port_wildcard = false; }; std::vector<ParsedSource> parsed_sources; + bool allow_self = false; + bool allow_star = false; }; struct TestData { @@ -48,7 +48,8 @@ return; } auto& frame_ancestors = policy.content_security_policy_ptr()->frame_ancestors; - EXPECT_EQ(frame_ancestors->sources.size(), expected_result->size); + EXPECT_EQ(frame_ancestors->sources.size(), + expected_result->parsed_sources.size()); for (size_t i = 0; i < expected_result->parsed_sources.size(); i++) { EXPECT_EQ(frame_ancestors->sources[i]->scheme, expected_result->parsed_sources[i].scheme); @@ -62,9 +63,9 @@ expected_result->parsed_sources[i].is_host_wildcard); EXPECT_EQ(frame_ancestors->sources[i]->is_port_wildcard, expected_result->parsed_sources[i].is_port_wildcard); - EXPECT_EQ(frame_ancestors->sources[i]->allow_self, - expected_result->parsed_sources[i].allow_self); } + EXPECT_EQ(frame_ancestors->allow_self, expected_result->allow_self); + EXPECT_EQ(frame_ancestors->allow_star, expected_result->allow_star); } } // namespace @@ -76,62 +77,54 @@ {":"}, // First character is alpha/non-alpha. - {"a:", {1, {{"a", "", url::PORT_UNSPECIFIED, "", false, false, false}}}}, + {"a:", {{{"a", ""}}}}, {"1ba:"}, {"-:"}, // Remaining characters. - {"abcd:", - {1, {{"abcd", "", url::PORT_UNSPECIFIED, "", false, false, false}}}}, - {"a123:", - {1, {{"a123", "", url::PORT_UNSPECIFIED, "", false, false, false}}}}, - {"a+-:", - {1, {{"a+-", "", url::PORT_UNSPECIFIED, "", false, false, false}}}}, - {"a1+-:", - {1, {{"a1+-", "", url::PORT_UNSPECIFIED, "", false, false, false}}}}, + {"abcd:", {{{"abcd", ""}}}}, + {"a123:", {{{"a123", ""}}}}, + {"a+-:", {{{"a+-", ""}}}}, + {"a1+-:", {{{"a1+-", ""}}}}, // Invalid character. {"wrong_scheme"}, + {"wrong_scheme://"}, // Parse host. - // Wildcards. - {"*", {1, {{"", "", url::PORT_UNSPECIFIED, "", true, false, false}}}}, {"*."}, - {"*.a", {1, {{"", "a", url::PORT_UNSPECIFIED, "", true, false, false}}}}, + {"*.a", {{{"", "a", url::PORT_UNSPECIFIED, "", true, false}}}}, {"a.*"}, {"a.*.b"}, {"*a"}, // Dot separation. - {"a", {1, {{"", "a", url::PORT_UNSPECIFIED, "", false, false, false}}}}, - {"a.b.c", - {1, {{"", "a.b.c", url::PORT_UNSPECIFIED, "", false, false, false}}}}, + {"a", {{{"", "a"}}}}, + {"a.b.c", {{{"", "a.b.c"}}}}, {"a.b."}, {".b.c"}, {"a..c"}, // Valid/Invalid characters. - {"az09-", - {1, {{"", "az09-", url::PORT_UNSPECIFIED, "", false, false, false}}}}, + {"az09-", {{{"", "az09-"}}}}, {"+"}, // Strange host. - {"---.com", - {1, {{"", "---.com", url::PORT_UNSPECIFIED, "", false, false, false}}}}, + {"---.com", {{{"", "---.com"}}}}, // Parse port. // Empty port. {"scheme://host:"}, // Common case. - {"a:80", {1, {{"", "a", 80, "", false, false, false}}}}, + {"a:80", {{{"", "a", 80, ""}}}}, // Wildcard port. - {"a:*", {1, {{"", "a", url::PORT_UNSPECIFIED, "", false, true, false}}}}, + {"a:*", {{{"", "a", url::PORT_UNSPECIFIED, "", false, true}}}}, // Leading zeroes. - {"a:000", {1, {{"", "a", 0, "", false, false, false}}}}, - {"a:0", {1, {{"", "a", 0, "", false, false, false}}}}, + {"a:000", {{{"", "a", 0, ""}}}}, + {"a:0", {{{"", "a", 0, ""}}}}, // Invalid chars. {"a:-1"}, @@ -140,47 +133,33 @@ // Parse path. // Encoded. {"example.com/%48%65%6c%6c%6f%20%57%6f%72%6c%64", - {1, - {{"", "example.com", url::PORT_UNSPECIFIED, "/Hello World", false, - false, false}}}}, + {{{"", "example.com", url::PORT_UNSPECIFIED, "/Hello World"}}}}, + + // Special keyword. + {"'none'", {{}, false, false}}, + {"'self'", {{}, true, false}}, + {"*", {{}, false, true}}, + + // Invalid 'none' + {"example.com 'none'"}, // Other. - {"*:*", {1, {{"", "", url::PORT_UNSPECIFIED, "", true, true, false}}}}, - {"http:", - {1, {{"http", "", url::PORT_UNSPECIFIED, "", false, false, false}}}}, - {"https://*", - {1, {{"https", "", url::PORT_UNSPECIFIED, "", true, false, false}}}}, + {"*:*", {{{"", "", url::PORT_UNSPECIFIED, "", true, true}}}}, + {"http:", {{{"http", ""}}}}, + {"https://*", {{{"https", "", url::PORT_UNSPECIFIED, "", true}}}}, {"http:/example.com"}, {"http://"}, - {"example.com", - {1, - {{"", "example.com", url::PORT_UNSPECIFIED, "", false, false, false}}}}, + {"example.com", {{{"", "example.com"}}}}, {"example.com/path", - {1, - {{"", "example.com", url::PORT_UNSPECIFIED, "/path", false, false, - false}}}}, - {"https://example.com", - {1, - {{"https", "example.com", url::PORT_UNSPECIFIED, "", false, false, - false}}}}, + {{{"", "example.com", url::PORT_UNSPECIFIED, "/path"}}}}, + {"https://example.com", {{{"https", "example.com"}}}}, {"https://example.com/path", - {1, - {{"https", "example.com", url::PORT_UNSPECIFIED, "/path", false, false, - false}}}}, - {"https://example.com:1234", - {1, {{"https", "example.com", 1234, "", false, false, false}}}}, + {{{"https", "example.com", url::PORT_UNSPECIFIED, "/path"}}}}, + {"https://example.com:1234", {{{"https", "example.com", 1234, ""}}}}, {"https://example.com:2345/some/path", - {1, - {{"https", "example.com", 2345, "/some/path", false, false, false}}}}, - {"example.com example.org", - {2, - {{"", "example.com", url::PORT_UNSPECIFIED, "", false, false, false}, - {"", "example.org", url::PORT_UNSPECIFIED, "", false, false, false}}}}, + {{{"https", "example.com", 2345, "/some/path"}}}}, + {"example.com example.org", {{{"", "example.com"}, {"", "example.org"}}}}, {"about:blank"}, - {"'none'", {0, {}}}, - {"'self'", - {1, {{"", "", url::PORT_UNSPECIFIED, "", false, false, true}}}}, - {"example.com 'none'"}, {""}, }; @@ -208,7 +187,7 @@ EXPECT_EQ(frame_ancestors->sources[0]->path, ""); EXPECT_EQ(frame_ancestors->sources[0]->is_host_wildcard, false); EXPECT_EQ(frame_ancestors->sources[0]->is_port_wildcard, false); - EXPECT_EQ(frame_ancestors->sources[0]->allow_self, false); + EXPECT_EQ(frame_ancestors->allow_self, false); } // Skip the first directive, which is not frame-ancestors. @@ -230,7 +209,8 @@ EXPECT_EQ(frame_ancestors->sources[0]->path, ""); EXPECT_EQ(frame_ancestors->sources[0]->is_host_wildcard, false); EXPECT_EQ(frame_ancestors->sources[0]->is_port_wildcard, false); - EXPECT_EQ(frame_ancestors->sources[0]->allow_self, false); + EXPECT_EQ(frame_ancestors->allow_self, false); + EXPECT_EQ(frame_ancestors->allow_star, false); } // Multiple CSP headers with multiple frame-ancestors directives present. Only @@ -252,7 +232,8 @@ EXPECT_EQ(frame_ancestors->sources[0]->path, ""); EXPECT_EQ(frame_ancestors->sources[0]->is_host_wildcard, false); EXPECT_EQ(frame_ancestors->sources[0]->is_port_wildcard, false); - EXPECT_EQ(frame_ancestors->sources[0]->allow_self, false); + EXPECT_EQ(frame_ancestors->allow_self, false); + EXPECT_EQ(frame_ancestors->allow_star, false); } // Multiple CSP headers separated by ',' (RFC2616 section 4.2). @@ -274,7 +255,8 @@ EXPECT_EQ(frame_ancestors->sources[0]->path, ""); EXPECT_EQ(frame_ancestors->sources[0]->is_host_wildcard, false); EXPECT_EQ(frame_ancestors->sources[0]->is_port_wildcard, false); - EXPECT_EQ(frame_ancestors->sources[0]->allow_self, false); + EXPECT_EQ(frame_ancestors->allow_self, false); + EXPECT_EQ(frame_ancestors->allow_star, false); } // Multiple CSP headers separated by ',', with multiple frame-ancestors @@ -297,7 +279,8 @@ EXPECT_EQ(frame_ancestors->sources[0]->path, ""); EXPECT_EQ(frame_ancestors->sources[0]->is_host_wildcard, false); EXPECT_EQ(frame_ancestors->sources[0]->is_port_wildcard, false); - EXPECT_EQ(frame_ancestors->sources[0]->allow_self, false); + EXPECT_EQ(frame_ancestors->allow_self, false); + EXPECT_EQ(frame_ancestors->allow_star, false); } // Both frame-ancestors and report-to directives present. @@ -325,7 +308,8 @@ EXPECT_EQ(frame_ancestors->sources[0]->path, ""); EXPECT_EQ(frame_ancestors->sources[0]->is_host_wildcard, false); EXPECT_EQ(frame_ancestors->sources[0]->is_port_wildcard, false); - EXPECT_EQ(frame_ancestors->sources[0]->allow_self, false); + EXPECT_EQ(frame_ancestors->allow_self, false); + EXPECT_EQ(frame_ancestors->allow_star, false); } }
diff --git a/services/network/public/cpp/simple_url_loader.cc b/services/network/public/cpp/simple_url_loader.cc index 1cc4198..cd555af 100644 --- a/services/network/public/cpp/simple_url_loader.cc +++ b/services/network/public/cpp/simple_url_loader.cc
@@ -26,8 +26,8 @@ #include "base/threading/sequenced_task_runner_handle.h" #include "base/time/time.h" #include "base/timer/timer.h" -#include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/bindings/pending_remote.h" +#include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/bindings/receiver_set.h" #include "mojo/public/cpp/bindings/remote.h" #include "mojo/public/cpp/system/data_pipe.h" @@ -324,9 +324,9 @@ return task_priority; } - // Bound to the URLLoaderClient message pipe (|client_binding_|) via - // set_connection_error_handler. - void OnConnectionError(); + // Bound to the URLLoaderClient message pipe (|client_receiver_|) via + // set_disconnect_handler. + void OnMojoDisconnect(); // Completes the request by calling FinishWithResult() if OnComplete() was // called and either no body pipe was ever received, or the body pipe was @@ -357,7 +357,7 @@ mojo::Remote<mojom::URLLoaderFactory> url_loader_factory_remote_; std::unique_ptr<BodyHandler> body_handler_; - mojo::Binding<mojom::URLLoaderClient> client_binding_; + mojo::Receiver<mojom::URLLoaderClient> client_receiver_{this}; mojom::URLLoaderPtr url_loader_; std::unique_ptr<StringUploadDataPipeGetter> string_upload_data_pipe_getter_; @@ -1150,7 +1150,6 @@ const net::NetworkTrafficAnnotationTag& annotation_tag) : resource_request_(std::move(resource_request)), annotation_tag_(annotation_tag), - client_binding_(this), request_state_(std::make_unique<RequestState>()), final_url_(resource_request_->url), timeout_timer_(timeout_tick_clock_) { @@ -1457,7 +1456,7 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!request_state_->finished); - client_binding_.Close(); + client_receiver_.reset(); url_loader_.reset(); timeout_timer_.Stop(); @@ -1509,9 +1508,9 @@ resource_request_->enable_upload_progress = true; mojom::URLLoaderClientPtr client_ptr; - client_binding_.Bind(mojo::MakeRequest(&client_ptr)); - client_binding_.set_connection_error_handler(base::BindOnce( - &SimpleURLLoaderImpl::OnConnectionError, base::Unretained(this))); + client_receiver_.Bind(mojo::MakeRequest(&client_ptr)); + client_receiver_.set_disconnect_handler(base::BindOnce( + &SimpleURLLoaderImpl::OnMojoDisconnect, base::Unretained(this))); // Data elements that use pipes aren't reuseable, currently (Since the IPC // code doesn't call the Clone() method), so need to create another one, if // uploading a string via a data pipe. @@ -1546,7 +1545,7 @@ DCHECK_GT(remaining_retries_, 0); --remaining_retries_; - client_binding_.Close(); + client_receiver_.reset(); url_loader_.reset(); request_state_ = std::make_unique<RequestState>(); @@ -1659,8 +1658,8 @@ DCHECK(!request_state_->finished); DCHECK(!request_state_->request_completed); - // Close pipes to ignore any subsequent close notification. - client_binding_.Close(); + // Reset pipes to ignore any subsequent close notification. + client_receiver_.reset(); url_loader_.reset(); request_state_->request_completed = true; @@ -1675,7 +1674,7 @@ MaybeComplete(); } -void SimpleURLLoaderImpl::OnConnectionError() { +void SimpleURLLoaderImpl::OnMojoDisconnect() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // |this| closes the pipe to the URLLoader in OnComplete(), so this method // being called indicates the pipe was closed before completion, most likely
diff --git a/services/network/public/mojom/content_security_policy.mojom b/services/network/public/mojom/content_security_policy.mojom index 99fcf2d..6685a7d 100644 --- a/services/network/public/mojom/content_security_policy.mojom +++ b/services/network/public/mojom/content_security_policy.mojom
@@ -6,6 +6,15 @@ import "url/mojom/url.mojom"; +// A CSPSource represents an expression that matches a set of urls. +// Examples of CSPSource: +// - domain.example.com +// - *.example.com +// - https://cdn.com +// - data: +// - 'none' +// - 'self' +// - * struct CSPSource { string scheme; string host; @@ -13,11 +22,15 @@ string path; bool is_host_wildcard = false; bool is_port_wildcard = false; - bool allow_self = false; }; struct CSPSourceList { array<CSPSource> sources; + + // Wildcard hosts and 'self' aren't stored in |sources|, but as attributes + // on the source list itself. + bool allow_self = false; + bool allow_star = false; }; struct ContentSecurityPolicy {
diff --git a/services/network/websocket.cc b/services/network/websocket.cc index 9e39295..ea5e5391 100644 --- a/services/network/websocket.cc +++ b/services/network/websocket.cc
@@ -205,7 +205,6 @@ DVLOG(3) << "WebSocketEventHandler::OnDataFrame @" << reinterpret_cast<void*>(this) << " fin=" << fin << " type=" << type << " data is " << payload.size() << " bytes"; - // TODO(yoichio): Merge OnDataFrame mojo channel into data pipe. impl_->client_->OnDataFrame(fin, OpCodeToMessageType(type), payload.size()); if (payload.size() > 0) { impl_->pending_data_frames_.push(payload);
diff --git a/services/service_manager/sandbox/sandbox_type.cc b/services/service_manager/sandbox/sandbox_type.cc index 2655d1f..fe4bcf3d 100644 --- a/services/service_manager/sandbox/sandbox_type.cc +++ b/services/service_manager/sandbox/sandbox_type.cc
@@ -193,14 +193,16 @@ return SANDBOX_TYPE_UTILITY; } -static bool g_audio_sandbox_enabled = true; - -SERVICE_MANAGER_SANDBOX_EXPORT void EnableAudioSandbox(bool enable) { - g_audio_sandbox_enabled = enable; +void EnableAudioSandbox(bool enable) { + if (enable) { + base::CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kEnableAudioServiceSandbox); + } } bool IsAudioSandboxEnabled() { - return g_audio_sandbox_enabled; + return base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableAudioServiceSandbox); } } // namespace service_manager
diff --git a/services/service_manager/sandbox/switches.cc b/services/service_manager/sandbox/switches.cc index 6e2f2f6b..b17da8f 100644 --- a/services/service_manager/sandbox/switches.cc +++ b/services/service_manager/sandbox/switches.cc
@@ -62,6 +62,9 @@ // Disables the Win32K process mitigation policy for child processes. const char kDisableWin32kLockDown[] = "disable-win32k-lockdown"; +// Command line flag to enable the audio service sandbox. +const char kEnableAudioServiceSandbox[] = "enable-audio-service-sandbox"; + // Allows shmat() system call in the GPU sandbox. const char kGpuSandboxAllowSysVShm[] = "gpu-sandbox-allow-sysv-shm";
diff --git a/services/service_manager/sandbox/switches.h b/services/service_manager/sandbox/switches.h index 2281bb3..e27f58ae 100644 --- a/services/service_manager/sandbox/switches.h +++ b/services/service_manager/sandbox/switches.h
@@ -41,6 +41,7 @@ SERVICE_MANAGER_SANDBOX_EXPORT extern const char kDisableSeccompFilterSandbox[]; SERVICE_MANAGER_SANDBOX_EXPORT extern const char kDisableSetuidSandbox[]; SERVICE_MANAGER_SANDBOX_EXPORT extern const char kDisableWin32kLockDown[]; +SERVICE_MANAGER_SANDBOX_EXPORT extern const char kEnableAudioServiceSandbox[]; SERVICE_MANAGER_SANDBOX_EXPORT extern const char kGpuSandboxAllowSysVShm[]; SERVICE_MANAGER_SANDBOX_EXPORT extern const char kGpuSandboxFailuresFatal[]; SERVICE_MANAGER_SANDBOX_EXPORT extern const char kNoSandbox[];
diff --git a/services/viz/privileged/mojom/gl/BUILD.gn b/services/viz/privileged/mojom/gl/BUILD.gn index cea0dd64..8aab87a4 100644 --- a/services/viz/privileged/mojom/gl/BUILD.gn +++ b/services/viz/privileged/mojom/gl/BUILD.gn
@@ -16,6 +16,7 @@ "//media/mojo/mojom", "//ui/gfx/geometry/mojom", "//ui/gfx/mojom", + "//ui/gl/mojom", "//url/mojom:url_mojom_gurl", ] if (is_chromeos) {
diff --git a/services/viz/privileged/mojom/gl/gpu_service.mojom b/services/viz/privileged/mojom/gl/gpu_service.mojom index c4da750..e1156e1 100644 --- a/services/viz/privileged/mojom/gl/gpu_service.mojom +++ b/services/viz/privileged/mojom/gl/gpu_service.mojom
@@ -24,6 +24,7 @@ import "media/mojo/mojom/video_encode_accelerator.mojom"; import "ui/gfx/geometry/mojom/geometry.mojom"; import "ui/gfx/mojom/buffer_types.mojom"; +import "ui/gl/mojom/gpu_preference.mojom"; interface GpuService { // Tells the GPU service to create a new channel for communication with a @@ -116,7 +117,7 @@ // Tells GPU that host has seen a GPU switch. This can happen when the display // is reconfigured, for example. - GpuSwitched(); + GpuSwitched(gl.mojom.GpuPreference active_gpu_heuristic); DestroyAllChannels();
diff --git a/skia/BUILD.gn b/skia/BUILD.gn index dd36d2a..99da57ad 100644 --- a/skia/BUILD.gn +++ b/skia/BUILD.gn
@@ -190,11 +190,7 @@ # assembly code contains flow control(jmp or jcc) statements. "/wd4800", # forcing value to bool 'true/false'(assigning int to bool). - "/wd5041", # out-of-line definition for constexpr static data member is not needed and is deprecated in C++17 ] - cflags_cc = [ "/std:c++17" ] - } else { - cflags_cc = [ "-std=c++17" ] } }
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 9485104c..969b9c1 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -546,6 +546,9 @@ "experiments": [ { "name": "Enabled", + "params": { + "show_confirmation_button": "false" + }, "enable_features": [ "TouchToFillAndroid" ]
diff --git a/third_party/blink/public/platform/platform.h b/third_party/blink/public/platform/platform.h index a363c7f..e2cc612 100644 --- a/third_party/blink/public/platform/platform.h +++ b/third_party/blink/public/platform/platform.h
@@ -516,8 +516,7 @@ // backed by an independent context. Returns null if the context cannot be // created or initialized. virtual std::unique_ptr<WebGraphicsContext3DProvider> - CreateWebGPUGraphicsContext3DProvider(const WebURL& top_document_url, - GraphicsInfo*); + CreateWebGPUGraphicsContext3DProvider(const WebURL& top_document_url); virtual gpu::GpuMemoryBufferManager* GetGpuMemoryBufferManager() { return nullptr;
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.cc b/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.cc index 22f10d1..955e03e 100644 --- a/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.cc +++ b/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.cc
@@ -80,13 +80,25 @@ const v8::PropertyDescriptor& descriptor) { DCHECK(descriptor.has_configurable()); DCHECK(descriptor.has_enumerable()); - DCHECK(descriptor.has_value()); - DCHECK(descriptor.has_writable()); + if (descriptor.has_value()) { + // Data property + DCHECK(descriptor.has_writable()); + info.GetReturnValue().Set( + V8ObjectBuilder(ScriptState::ForCurrentRealm(info)) + .Add("configurable", descriptor.configurable()) + .Add("enumerable", descriptor.enumerable()) + .Add("value", descriptor.value()) + .Add("writable", descriptor.writable()) + .V8Value()); + return; + } + // Accessor property + DCHECK(descriptor.has_get() || descriptor.has_set()); info.GetReturnValue().Set(V8ObjectBuilder(ScriptState::ForCurrentRealm(info)) .Add("configurable", descriptor.configurable()) .Add("enumerable", descriptor.enumerable()) - .Add("value", descriptor.value()) - .Add("writable", descriptor.writable()) + .Add("get", descriptor.get()) + .Add("set", descriptor.set()) .V8Value()); }
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/__init__.py b/third_party/blink/renderer/bindings/scripts/bind_gen/__init__.py index 8109fdb8..10a4b43c 100644 --- a/third_party/blink/renderer/bindings/scripts/bind_gen/__init__.py +++ b/third_party/blink/renderer/bindings/scripts/bind_gen/__init__.py
@@ -29,7 +29,11 @@ _setup_sys_path() -from .clang_format import init_clang_format + +from . import clang_format +from .example import run_example +from .interface import generate_interfaces +from .path_manager import PathManager def _setup_clang_format(): @@ -44,10 +48,13 @@ command_path = os.path.abspath( os.path.join(root_dir, 'third_party', 'depot_tools', command_name)) - init_clang_format(command_path=command_path) + clang_format.init(command_path=command_path) -_setup_clang_format() - -from .example import run_example -from .interface import generate_interfaces +def init(output_dirs): + """ + Args: + output_dirs: Pairs of component and output directory. + """ + _setup_clang_format() + PathManager.init(output_dirs)
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/blink_v8_bridge.py b/third_party/blink/renderer/bindings/scripts/bind_gen/blink_v8_bridge.py index e60e363..954d786 100644 --- a/third_party/blink/renderer/bindings/scripts/bind_gen/blink_v8_bridge.py +++ b/third_party/blink/renderer/bindings/scripts/bind_gen/blink_v8_bridge.py
@@ -15,6 +15,23 @@ _format = CodeNode.format_template +def blink_class_name(idl_definition): + """ + Returns the class name of Blink implementation. + """ + try: + class_name = idl_definition.extended_attributes.get( + "ImplementedAs").value + except: + class_name = idl_definition.identifier + + if isinstance(idl_definition, + (web_idl.CallbackFunction, web_idl.CallbackInterface)): + return name_style.class_("v8", class_name) + else: + return name_style.class_(class_name) + + def blink_type_info(idl_type): """ Returns the types of Blink implementation corresponding to the given IDL
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/clang_format.py b/third_party/blink/renderer/bindings/scripts/bind_gen/clang_format.py index 3f41f65..ac060bc8 100644 --- a/third_party/blink/renderer/bindings/scripts/bind_gen/clang_format.py +++ b/third_party/blink/renderer/bindings/scripts/bind_gen/clang_format.py
@@ -8,7 +8,11 @@ _clang_format_command_path = None -def init_clang_format(command_path): +def init(command_path): + """ + Args: + command_path: Path to the clang_format command. + """ assert isinstance(command_path, str) assert os.path.exists(command_path)
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/code_generation_accumulator.py b/third_party/blink/renderer/bindings/scripts/bind_gen/code_generation_accumulator.py new file mode 100644 index 0000000..9da5dc9 --- /dev/null +++ b/third_party/blink/renderer/bindings/scripts/bind_gen/code_generation_accumulator.py
@@ -0,0 +1,36 @@ +# 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. + + +class CodeGenerationAccumulator(object): + """ + Accumulates a variety of information and helps generate code based on the + information. + """ + + def __init__(self): + # Headers to be included + self._include_headers = set() + # Forward declarations of C++ class + self._class_decls = set() + + @property + def include_headers(self): + return self._include_headers + + def add_include_header(self, header): + self._include_headers.add(header) + + def add_include_headers(self, headers): + self._include_headers.update(headers) + + @property + def class_decls(self): + return self._class_decls + + def add_class_decl(self, class_name): + self._class_decls.add(class_name) + + def add_class_decls(self, class_names): + self._class_decls.update(class_names)
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/code_node.py b/third_party/blink/renderer/bindings/scripts/bind_gen/code_node.py index 049fea09..88a6800 100644 --- a/third_party/blink/renderer/bindings/scripts/bind_gen/code_node.py +++ b/third_party/blink/renderer/bindings/scripts/bind_gen/code_node.py
@@ -11,6 +11,7 @@ import copy import string +from .code_generation_accumulator import CodeGenerationAccumulator from .mako_renderer import MakoRenderer @@ -145,6 +146,9 @@ # Mako's template text, bindings dict, and the renderer object self._template_text = template_text self._template_vars = {} + + self._accumulator = None + self._renderer = renderer self._render_state = CodeNode._RenderState() @@ -275,6 +279,18 @@ self.add_template_var(name, value) @property + def accumulator(self): + # Always consistently use the accumulator of the root node. + if self.outer is not None: + return self.outer.accumulator + return self._accumulator + + def set_accumulator(self, accumulator): + assert isinstance(accumulator, CodeGenerationAccumulator) + assert self._accumulator is None + self._accumulator = accumulator + + @property def renderer(self): # Always use the renderer of the root node in order not to mix renderers # during rendering of a single code node tree. @@ -282,6 +298,11 @@ return self.outer.renderer return self._renderer + def set_renderer(self, renderer): + assert isinstance(renderer, MakoRenderer) + assert self._renderer is None + self._renderer = renderer + @property def current_render_state(self): assert self._is_rendering @@ -337,8 +358,6 @@ """ def __init__(self, literal_text, renderer=None): - assert isinstance(literal_text, str) - literal_text_gensym = CodeNode.gensym() template_text = CodeNode.format_template( "${{{literal_text}}}", literal_text=literal_text_gensym)
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_utils.py b/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_utils.py index 75e3394..c9c71e2 100644 --- a/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_utils.py +++ b/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_utils.py
@@ -2,10 +2,14 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import web_idl + from .clang_format import clang_format +from .code_generation_accumulator import CodeGenerationAccumulator from .code_node import CodeNode from .code_node import LiteralNode from .code_node import SymbolScopeNode +from .path_manager import PathManager def make_copyright_header(): @@ -16,6 +20,22 @@ """) +def make_header_include_directives(accumulator): + assert isinstance(accumulator, CodeGenerationAccumulator) + + class HeaderIncludeDirectives(object): + def __init__(self, accumulator): + self._accumulator = accumulator + + def __str__(self): + return "\n".join([ + "#include \"{}\"".format(header) + for header in sorted(self._accumulator.include_headers) + ]) + + return LiteralNode(HeaderIncludeDirectives(accumulator)) + + def enclose_with_header_guard(code_node, header_guard): assert isinstance(code_node, CodeNode) assert isinstance(header_guard, str) @@ -43,6 +63,62 @@ ]) +def traverse_idl_types(idl_definition, callback): + """ + Traverses in the given |idl_definition| to find all the web_idl.IdlType used + in the IDL definition. Invokes |callback| with each web_idl.IdlType. + """ + assert callable(callback) + + def get(obj, attr): + try: + return getattr(obj, attr) + except: + return () + + xs = (get(idl_definition, "attributes") + get(idl_definition, "constants") + + get(idl_definition, "own_members") + (idl_definition, )) + for x in xs: + idl_type = get(x, "idl_type") + if idl_type: + callback(idl_type) + + xs = (get(idl_definition, "constructors") + get(idl_definition, + "operations")) + for x in xs: + for argument in x.arguments: + callback(argument.idl_type) + if x.return_type is not None: + callback(x.return_type) + + xs = get(idl_definition, "flattened_member_types") + for x in xs: + callback(x) + + +def collect_include_headers(idl_definition): + """ + Returns a list of include headers that are required by generated bindings of + |idl_definition|. + """ + type_def_objs = set() + + def collect_type_def_obj(idl_type): + type_def_obj = idl_type.unwrap().type_definition_object + if type_def_obj is not None: + type_def_objs.add(type_def_obj) + + traverse_idl_types(idl_definition, collect_type_def_obj) + + header_paths = set() + for type_def_obj in type_def_objs: + if isinstance(type_def_obj, web_idl.Enumeration): + continue + header_paths.add(PathManager(type_def_obj).blink_path(ext="h")) + + return header_paths + + def render_code_node(code_node): """ Renders |code_node| and turns it into text letting |code_node| apply all
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py b/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py index 78075e5..2eca39ab5 100644 --- a/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py +++ b/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
@@ -7,6 +7,7 @@ from . import name_style from .blink_v8_bridge import blink_type_info from .blink_v8_bridge import make_v8_to_blink_value +from .code_generation_accumulator import CodeGenerationAccumulator from .code_generation_context import CodeGenerationContext from .code_node import CodeNode from .code_node import FunctionDefinitionNode @@ -16,8 +17,10 @@ from .code_node import SymbolScopeNode from .code_node import TextNode from .code_node import UnlikelyExitNode +from .codegen_utils import collect_include_headers from .codegen_utils import enclose_with_namespace from .codegen_utils import make_copyright_header +from .codegen_utils import make_header_include_directives from .codegen_utils import write_code_node_to_file from .mako_renderer import MakoRenderer @@ -382,10 +385,17 @@ filename = "v8_example_interface.cc" filepath = os.path.join(output_dirs['core'], filename) - interface = web_idl_database.find("TestNamespace") + interface = web_idl_database.find("Node") cg_context = CodeGenerationContext(interface=interface) + root_node = SymbolScopeNode(separator_last="\n") + root_node.set_accumulator(CodeGenerationAccumulator()) + root_node.set_renderer(MakoRenderer()) + + root_node.accumulator.add_include_headers( + collect_include_headers(interface)) + code_node = SymbolScopeNode() for attribute in interface.attributes: @@ -401,10 +411,11 @@ code_node.append(make_install_interface_template_def(cg_context)) - root_node = SymbolScopeNode(separator_last="\n", renderer=MakoRenderer()) root_node.extend([ make_copyright_header(), LiteralNode(""), + make_header_include_directives(root_node.accumulator), + LiteralNode(""), enclose_with_namespace(code_node, name_style.namespace("blink")), ])
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/path_manager.py b/third_party/blink/renderer/bindings/scripts/bind_gen/path_manager.py index e939165d..b8243b6 100644 --- a/third_party/blink/renderer/bindings/scripts/bind_gen/path_manager.py +++ b/third_party/blink/renderer/bindings/scripts/bind_gen/path_manager.py
@@ -4,7 +4,10 @@ import os.path +import web_idl + from . import name_style +from .blink_v8_bridge import blink_class_name class PathManager(object): @@ -19,41 +22,71 @@ Everything is generated in a single component. """ - def __init__(self, idl_definition, output_dirs): + _REQUIRE_INIT_MESSAGE = ("PathManager.init must be called in advance.") + _is_initialized = False + + @classmethod + def init(cls, output_dirs): + """ + Args: + output_dirs: Pairs of component and output directory. + """ + assert not cls._is_initialized + assert isinstance(output_dirs, dict) + cls._output_dirs = output_dirs + cls._blink_path_prefix = os.path.sep + os.path.join( + "third_party", "blink", "renderer", "") + cls._is_initialized = True + + def __init__(self, idl_definition): + assert self._is_initialized, self._REQUIRE_INIT_MESSAGE + idl_path = idl_definition.debug_info.location.filepath self._idl_basepath, _ = os.path.splitext(idl_path) self._idl_dir, self._idl_basename = os.path.split(self._idl_basepath) - components = idl_definition.components - assert 0 < len(components) + components = sorted(idl_definition.components) if len(components) == 1: component = components[0] self._is_cross_components = False self._api_component = component self._impl_component = component - else: - assert ("core", "modules") == sorted(components) + elif len(components) == 2: + assert components[0] == "core" + assert components[1] == "modules" self._is_cross_components = True self._api_component = "core" self._impl_component = "modules" + else: + assert False - self._api_dir = output_dirs[self._api_component] - self._impl_dir = output_dirs[self._impl_component] - + self._api_dir = self._output_dirs[self._api_component] + self._impl_dir = self._output_dirs[self._impl_component] self._out_basename = name_style.file("v8", idl_definition.identifier) + if isinstance(idl_definition, + (web_idl.CallbackFunction, web_idl.CallbackInterface)): + self._blink_dir = self._api_dir + else: + self._blink_dir = self._idl_dir + self._blink_basename = name_style.file( + blink_class_name(idl_definition)) + @property def idl_dir(self): return self._idl_dir def blink_path(self, filename=None, ext=None): - # The IDL file and Blink headers are supposed to exist in the same - # directory. - return self._join( - dirpath=self.idl_dir, - filename=(filename or self._idl_basename), - ext=ext) + """ + Returns a path to a Blink implementation file relative to the project + root directory, e.g. "third_party/blink/renderer/..." + """ + return self._rel_to_root( + self._join( + dirpath=self._blink_dir, + filename=(filename or self._blink_basename), + ext=ext)) @property def is_cross_components(self): @@ -87,7 +120,14 @@ filename=(filename or self._out_basename), ext=ext) + def _rel_to_root(self, path): + index = path.find(self._blink_path_prefix) + if index < 0: + assert path.startswith(self._blink_path_prefix[1:]) + return path + return path[index + 1:] + def _join(self, dirpath, filename, ext=None): if ext is not None: - filename = "{}.{}".format(filename, ext) + filename = os.path.extsep.join([filename, ext]) return os.path.join(dirpath, filename)
diff --git a/third_party/blink/renderer/bindings/scripts/generate_bindings.py b/third_party/blink/renderer/bindings/scripts/generate_bindings.py index e8f122ce..cdce8ee 100644 --- a/third_party/blink/renderer/bindings/scripts/generate_bindings.py +++ b/third_party/blink/renderer/bindings/scripts/generate_bindings.py
@@ -53,6 +53,8 @@ web_idl.Component('modules'): options.output_dir_modules, } + bind_gen.init(output_dirs) + for task in tasks: dispatch_table[task](web_idl_database=web_idl_database, output_dirs=output_dirs)
diff --git a/third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps b/third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps index c329ec7..442951c8 100644 --- a/third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps +++ b/third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps
@@ -29,6 +29,7 @@ bind_gen/__init__.py bind_gen/blink_v8_bridge.py bind_gen/clang_format.py +bind_gen/code_generation_accumulator.py bind_gen/code_generation_context.py bind_gen/code_node.py bind_gen/codegen_utils.py @@ -36,6 +37,7 @@ bind_gen/interface.py bind_gen/mako_renderer.py bind_gen/name_style.py +bind_gen/path_manager.py generate_bindings.py web_idl/__init__.py web_idl/argument.py
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/runtime_enabled_features.py b/third_party/blink/renderer/bindings/scripts/web_idl/runtime_enabled_features.py index 57ece2b..7421e6f 100644 --- a/third_party/blink/renderer/bindings/scripts/web_idl/runtime_enabled_features.py +++ b/third_party/blink/renderer/bindings/scripts/web_idl/runtime_enabled_features.py
@@ -10,6 +10,7 @@ _REQUIRE_INIT_MESSAGE = ( "RuntimeEnabledFeatures.init must be called in advance.") + _is_initialized = False @classmethod def init(cls, filepaths): @@ -18,6 +19,7 @@ filepaths: Paths to the definition files of runtime-enabled features ("runtime_enabled_features.json5"). """ + assert not cls._is_initialized assert isinstance(filepaths, list) assert all(isinstance(filepath, str) for filepath in filepaths) @@ -36,7 +38,7 @@ @classmethod def is_context_dependent(cls, feature_name): """Returns True if the feature may be enabled per-context.""" - assert cls._is_initialized, _REQUIRE_INIT_MESSAGE + assert cls._is_initialized, cls._REQUIRE_INIT_MESSAGE assert isinstance(feature_name, str) assert feature_name in cls._features, ( "Unknown runtime-enabled feature: {}".format(feature_name))
diff --git a/third_party/blink/renderer/core/css/resolver/style_adjuster.cc b/third_party/blink/renderer/core/css/resolver/style_adjuster.cc index c424eee..30053d7 100644 --- a/third_party/blink/renderer/core/css/resolver/style_adjuster.cc +++ b/third_party/blink/renderer/core/css/resolver/style_adjuster.cc
@@ -654,6 +654,11 @@ // Columns don't apply to svg text elements. if (IsSVGTextElement(*element)) style.ClearMultiCol(); + } else if (element && element->IsMathMLElement()) { + if (style.Display() == EDisplay::kContents) { + // https://drafts.csswg.org/css-display/#unbox-mathml + style.SetDisplay(EDisplay::kNone); + } } // If this node is sticky it marks the creation of a sticky subtree, which we
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc b/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc index 9194196..4a82fa0b 100644 --- a/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc +++ b/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
@@ -961,7 +961,7 @@ EXPECT_EQ(GetDocument().ActivationBlockingDisplayLockCount(), 0); auto* template_el = - ToHTMLTemplateElement(GetDocument().getElementById("template")); + To<HTMLTemplateElement>(GetDocument().getElementById("template")); auto* child = To<Element>(template_el->content()->firstChild()); EXPECT_FALSE(child->isConnected());
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc index a7a291b..0483a982 100644 --- a/third_party/blink/renderer/core/dom/element.cc +++ b/third_party/blink/renderer/core/dom/element.cc
@@ -4395,11 +4395,12 @@ void Element::ForceLegacyLayoutInFormattingContext( const ComputedStyle& new_style) { - if (DefinitelyNewFormattingContext(*this, new_style)) - return; - - bool found_bfc = false; - for (Element* ancestor = this; !found_bfc;) { + // TableNG requires that table elements are either all NG, or all Legacy. + bool needs_traverse_to_table = + RuntimeEnabledFeatures::LayoutNGTableEnabled() && + new_style.IsDisplayTableType(); + bool found_bfc = DefinitelyNewFormattingContext(*this, new_style); + for (Element* ancestor = this; !found_bfc || needs_traverse_to_table;) { ancestor = DynamicTo<Element>(LayoutTreeBuilderTraversal::Parent(*ancestor)); if (!ancestor || ancestor->ShouldForceLegacyLayout()) @@ -4407,7 +4408,17 @@ const ComputedStyle* style = ancestor->GetComputedStyle(); if (style->Display() == EDisplay::kNone) break; - found_bfc = DefinitelyNewFormattingContext(*ancestor, *style); + found_bfc = found_bfc || DefinitelyNewFormattingContext(*ancestor, *style); + if (found_bfc && !needs_traverse_to_table) { + needs_traverse_to_table = + RuntimeEnabledFeatures::LayoutNGTableEnabled() && + style->IsDisplayTableType(); + } + if (needs_traverse_to_table) { + EDisplay display = style->Display(); + if (display == EDisplay::kTable || display == EDisplay::kInlineTable) + needs_traverse_to_table = false; + } ancestor->SetShouldForceLegacyLayoutForChild(true); ancestor->SetNeedsReattachLayoutTree(); }
diff --git a/third_party/blink/renderer/core/editing/testing/selection_sample.cc b/third_party/blink/renderer/core/editing/testing/selection_sample.cc index 0d1b3a50..9ae865e 100644 --- a/third_party/blink/renderer/core/editing/testing/selection_sample.cc +++ b/third_party/blink/renderer/core/editing/testing/selection_sample.cc
@@ -41,9 +41,9 @@ Document* const document = element.ownerDocument(); ShadowRoot& shadow_root = parent->AttachShadowRootInternal(ShadowRootType::kOpen); - Node* const fragment = - document->importNode(ToHTMLTemplateElement(template_element)->content(), - true, ASSERT_NO_EXCEPTION); + Node* const fragment = document->importNode( + To<HTMLTemplateElement>(template_element)->content(), true, + ASSERT_NO_EXCEPTION); shadow_root.AppendChild(fragment); } }
diff --git a/third_party/blink/renderer/core/fetch/fetch_response_data.cc b/third_party/blink/renderer/core/fetch/fetch_response_data.cc index 9d096bb..11a632a 100644 --- a/third_party/blink/renderer/core/fetch/fetch_response_data.cc +++ b/third_party/blink/renderer/core/fetch/fetch_response_data.cc
@@ -293,9 +293,13 @@ String::FromUTF8(csp_source->scheme), String::FromUTF8(csp_source->host), csp_source->port, String::FromUTF8(csp_source->path), - csp_source->is_host_wildcard, csp_source->is_port_wildcard, - csp_source->allow_self)); + csp_source->is_host_wildcard, + csp_source->is_port_wildcard)); } + blink_frame_ancestors->allow_self = + frame_ancestors_directive->allow_self; + blink_frame_ancestors->allow_star = + frame_ancestors_directive->allow_star; } for (auto& endpoints :
diff --git a/third_party/blink/renderer/core/html/html_template_element.cc b/third_party/blink/renderer/core/html/html_template_element.cc index 8787c5d..56bb1f30 100644 --- a/third_party/blink/renderer/core/html/html_template_element.cc +++ b/third_party/blink/renderer/core/html/html_template_element.cc
@@ -60,8 +60,10 @@ CloneChildrenFlag flag) { if (flag == CloneChildrenFlag::kSkip) return; - if (ToHTMLTemplateElement(source).content_) - content()->CloneChildNodesFrom(*ToHTMLTemplateElement(source).content()); + + auto& html_template_element = To<HTMLTemplateElement>(source); + if (html_template_element.content_) + content()->CloneChildNodesFrom(*html_template_element.content()); } void HTMLTemplateElement::DidMoveToNewDocument(Document& old_document) {
diff --git a/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc b/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc index a995ac65..ca06e24b 100644 --- a/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc +++ b/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
@@ -958,6 +958,10 @@ LayoutUnit border_scrollbar_padding_before) { DCHECK(IsColumnFlow()); DCHECK(Style()->ResolvedIsColumnReverseFlexDirection()); + DCHECK(all_items_.IsEmpty() || IsNGFlexBox()) + << "This method relies on NG having passed in 0 for initial main axis " + "offset for column-reverse flex boxes. That needs to be fixed if this " + "method is to be used in legacy."; for (FlexLine& line_context : FlexLines()) { for (wtf_size_t child_number = 0; child_number < line_context.line_items.size(); ++child_number) { @@ -966,12 +970,11 @@ // We passed 0 as the initial main_axis offset to ComputeLineItemsPosition // for ColumnReverse containers so here we have to add the // border_scrollbar_padding of the container. - // TODO(dgrogan): I think - // wpt/css/css-flexbox/flex-lines/multi-line-wrap-with-column-reverse.html - // fails because this totally ignores margins. flex_item.desired_location.SetX( main_axis_content_size + border_scrollbar_padding_before - - flex_item.desired_location.X() - item_main_size); + flex_item.desired_location.X() - item_main_size - + flex_item.box->MarginAfter(Style()) + + flex_item.box->MarginBefore(Style())); } } }
diff --git a/third_party/blink/renderer/core/layout/layout_inline.cc b/third_party/blink/renderer/core/layout/layout_inline.cc index 5eee459..bd469763 100644 --- a/third_party/blink/renderer/core/layout/layout_inline.cc +++ b/third_party/blink/renderer/core/layout/layout_inline.cc
@@ -1070,14 +1070,9 @@ *ContainingNGBlockFlow()->PaintFragment())); DCHECK(container_fragment->PhysicalFragment().IsInline() || container_fragment->PhysicalFragment().IsLineBox()); - NGInlineCursor cursor; - cursor.MoveTo(*this); - for (; cursor; cursor.MoveToNextForSameLayoutObject()) { - if (!cursor.CurrentPaintFragment()->IsDescendantOfNotSelf( - *container_fragment)) - continue; + NGInlineCursor cursor(*container_fragment); + for (cursor.MoveTo(*this); cursor; cursor.MoveToNextForSameLayoutObject()) yield(cursor.CurrentRect()); - } } else { DCHECK(!ContainingNGBlockFlow()); CollectCulledLineBoxRects(yield);
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.h b/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.h index 6d0d0720..cd9d204 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.h +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.h
@@ -32,12 +32,6 @@ public: bool IsNull() const { return cursor.IsNull(); } - // TODO(yosin): We'll remove |NGCaretPosition::PaintFragment()|, once all - // clients work with |NGInlineCursor|. - const NGPaintFragment* PaintFragment() const { - return cursor.CurrentPaintFragment(); - } - Position ToPositionInDOMTree() const; PositionWithAffinity ToPositionInDOMTreeWithAffinity() const;
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_device_observer.cc b/third_party/blink/renderer/modules/mediastream/media_stream_device_observer.cc index 0ff66af2..b4563f7e 100644 --- a/third_party/blink/renderer/modules/mediastream/media_stream_device_observer.cc +++ b/third_party/blink/renderer/modules/mediastream/media_stream_device_observer.cc
@@ -135,6 +135,9 @@ void MediaStreamDeviceObserver::BindMediaStreamDeviceObserverReceiver( mojo::PendingReceiver<mojom::blink::MediaStreamDeviceObserver> receiver) { + if (receiver_.is_bound()) + return; + receiver_.Bind(std::move(receiver)); }
diff --git a/third_party/blink/renderer/modules/modules_idl_files.gni b/third_party/blink/renderer/modules/modules_idl_files.gni index 3371822..9cb9f43 100644 --- a/third_party/blink/renderer/modules/modules_idl_files.gni +++ b/third_party/blink/renderer/modules/modules_idl_files.gni
@@ -867,8 +867,8 @@ "webgpu/gpu_texture_view_descriptor.idl", "webgpu/gpu_uncaptured_error_event_init.idl", "webgpu/gpu_vertex_attribute_descriptor.idl", - "webgpu/gpu_vertex_buffer_descriptor.idl", - "webgpu/gpu_vertex_input_descriptor.idl", + "webgpu/gpu_vertex_buffer_layout_descriptor.idl", + "webgpu/gpu_vertex_state_descriptor.idl", "webmidi/midi_connection_event_init.idl", "webmidi/midi_message_event_init.idl", "webmidi/midi_options.idl", @@ -1011,6 +1011,7 @@ "webgpu/gpu_programmable_pass_encoder.idl", "webgpu/gpu_render_encoder_base.idl", "webgpu/navigator_gpu.idl", + "webgpu/worker_navigator_gpu.idl", "webmidi/navigator_web_midi.idl", "webshare/navigator_share.idl", "webusb/navigator_usb.idl",
diff --git a/third_party/blink/renderer/modules/webgl/DEPS b/third_party/blink/renderer/modules/webgl/DEPS index fd5693a..7f39fad4 100644 --- a/third_party/blink/renderer/modules/webgl/DEPS +++ b/third_party/blink/renderer/modules/webgl/DEPS
@@ -5,4 +5,5 @@ "+gpu/command_buffer/common/capabilities.h", "+gpu/config/gpu_feature_info.h", "+skia/ext", + "+ui/gl/gpu_preference.h", ]
diff --git a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc index b61e9566..5c05aa57 100644 --- a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc +++ b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc
@@ -931,6 +931,8 @@ } renderbuffer_binding_->SetInternalFormat(internalformat); renderbuffer_binding_->SetSize(width, height); + UpdateNumberOfUserAllocatedMultisampledRenderbuffers( + renderbuffer_binding_->UpdateMultisampleState(samples > 0)); } void WebGL2RenderingContextBase::renderbufferStorageMultisample(
diff --git a/third_party/blink/renderer/modules/webgl/webgl_context_attribute_helpers.cc b/third_party/blink/renderer/modules/webgl/webgl_context_attribute_helpers.cc index 4e3e5be0..810e91b 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_context_attribute_helpers.cc +++ b/third_party/blink/renderer/modules/webgl/webgl_context_attribute_helpers.cc
@@ -5,6 +5,7 @@ #include "third_party/blink/renderer/modules/webgl/webgl_context_attribute_helpers.h" #include "third_party/blink/renderer/core/frame/settings.h" +#include "ui/gl/gpu_preference.h" namespace blink { @@ -30,6 +31,8 @@ Platform::ContextType context_type, bool support_own_offscreen_surface) { Platform::ContextAttributes result; + // Must keep the meaning of the "default" GPU choice in sync with the code + // below, in PowerPreferenceToGpuPreference. result.prefer_low_power_gpu = attrs.power_preference == "low-power"; result.fail_if_major_performance_caveat = attrs.fail_if_major_performance_caveat; @@ -45,4 +48,12 @@ return result; } +gl::GpuPreference PowerPreferenceToGpuPreference(String power_preference) { + // Must keep the interpretation of the "default" GPU in sync with the code + // above which sets the prefer_low_power_gpu attribute. + if (power_preference == "low-power") + return gl::GpuPreference::kLowPower; + return gl::GpuPreference::kHighPerformance; +} + } // namespace blink
diff --git a/third_party/blink/renderer/modules/webgl/webgl_context_attribute_helpers.h b/third_party/blink/renderer/modules/webgl/webgl_context_attribute_helpers.h index ea8c979..61988273 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_context_attribute_helpers.h +++ b/third_party/blink/renderer/modules/webgl/webgl_context_attribute_helpers.h
@@ -8,6 +8,11 @@ #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/renderer/core/html/canvas/canvas_context_creation_attributes_core.h" #include "third_party/blink/renderer/modules/webgl/webgl_context_attributes.h" +#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" + +namespace gl { +enum class GpuPreference; +} namespace blink { @@ -21,6 +26,12 @@ Platform::ContextType context_type, bool support_own_offscreen_surface); +// Turns the powerPreference context creation attribute into the +// gl::GpuPreference enum which is sent along with GPU switching +// notifications. This must not return the kDefault constant, but +// choose either the low-power or high-performance GPU. +gl::GpuPreference PowerPreferenceToGpuPreference(String power_preference); + } // namespace blink #endif // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGL_WEBGL_CONTEXT_ATTRIBUTE_HELPERS_H_
diff --git a/third_party/blink/renderer/modules/webgl/webgl_renderbuffer.cc b/third_party/blink/renderer/modules/webgl/webgl_renderbuffer.cc index cecfa2b..34255af 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_renderbuffer.cc +++ b/third_party/blink/renderer/modules/webgl/webgl_renderbuffer.cc
@@ -39,6 +39,7 @@ internal_format_(GL_RGBA4), width_(0), height_(0), + is_multisampled_(false), has_ever_been_bound_(false) { GLuint rbo; ctx->ContextGL()->GenRenderbuffers(1, &rbo); @@ -52,6 +53,16 @@ object_ = 0; } +int WebGLRenderbuffer::UpdateMultisampleState(bool multisampled) { + int result = 0; + if (!is_multisampled_ && multisampled) + result = 1; + if (is_multisampled_ && !multisampled) + result = -1; + is_multisampled_ = multisampled; + return result; +} + void WebGLRenderbuffer::Trace(blink::Visitor* visitor) { WebGLSharedPlatform3DObject::Trace(visitor); }
diff --git a/third_party/blink/renderer/modules/webgl/webgl_renderbuffer.h b/third_party/blink/renderer/modules/webgl/webgl_renderbuffer.h index 7ce5daaf..dd1897f 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_renderbuffer.h +++ b/third_party/blink/renderer/modules/webgl/webgl_renderbuffer.h
@@ -52,8 +52,15 @@ GLsizei Width() const { return width_; } GLsizei Height() const { return height_; } - bool HasEverBeenBound() const { return Object() && has_ever_been_bound_; } + // Returns: + // -1 if the renderbuffer *used to be* multisampled and *is now* + // single-sampled + // 0 if the renderbuffer's multisample state hasn't changed + // 1 if the renderbuffer *used to be* single-sampled and *is now* + // multisampled + int UpdateMultisampleState(bool multisampled); + bool HasEverBeenBound() const { return Object() && has_ever_been_bound_; } void SetHasEverBeenBound() { has_ever_been_bound_ = true; } void Trace(blink::Visitor*) override; @@ -66,6 +73,7 @@ GLenum internal_format_; GLsizei width_, height_; + bool is_multisampled_; bool has_ever_been_bound_; };
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc index 65d7ab0..a3420be 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc +++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
@@ -837,6 +837,12 @@ return xr_compatible_; } +void WebGLRenderingContextBase:: + UpdateNumberOfUserAllocatedMultisampledRenderbuffers(int delta) { + DCHECK(delta >= -1 && delta <= 1); + number_of_user_allocated_multisampled_renderbuffers_ += delta; +} + namespace { // Exposed by GL_ANGLE_depth_texture @@ -1010,7 +1016,8 @@ feature_handle_for_scheduler_( host->GetTopExecutionContext()->GetScheduler()->RegisterFeature( SchedulingPolicy::Feature::kWebGL, - {SchedulingPolicy::RecordMetricsForBackForwardCache()})) { + {SchedulingPolicy::RecordMetricsForBackForwardCache()})), + number_of_user_allocated_multisampled_renderbuffers_(0) { DCHECK(context_provider); // TODO(http://crbug.com/876140) Make sure this is being created on a @@ -1065,14 +1072,15 @@ scoped_refptr<DrawingBuffer> WebGLRenderingContextBase::CreateDrawingBuffer( std::unique_ptr<WebGraphicsContext3DProvider> context_provider, bool using_gpu_compositing) { - bool premultiplied_alpha = CreationAttributes().premultiplied_alpha; - bool want_alpha_channel = CreationAttributes().alpha; - bool want_depth_buffer = CreationAttributes().depth; - bool want_stencil_buffer = CreationAttributes().stencil; - bool want_antialiasing = CreationAttributes().antialias; - DrawingBuffer::PreserveDrawingBuffer preserve = - CreationAttributes().preserve_drawing_buffer ? DrawingBuffer::kPreserve - : DrawingBuffer::kDiscard; + const CanvasContextCreationAttributesCore& attrs = CreationAttributes(); + bool premultiplied_alpha = attrs.premultiplied_alpha; + bool want_alpha_channel = attrs.alpha; + bool want_depth_buffer = attrs.depth; + bool want_stencil_buffer = attrs.stencil; + bool want_antialiasing = attrs.antialias; + DrawingBuffer::PreserveDrawingBuffer preserve = attrs.preserve_drawing_buffer + ? DrawingBuffer::kPreserve + : DrawingBuffer::kDiscard; DrawingBuffer::WebGLVersion web_gl_version = DrawingBuffer::kWebGL1; if (context_type_ == Platform::kWebGL1ContextType) { web_gl_version = DrawingBuffer::kWebGL1; @@ -1099,13 +1107,14 @@ bool using_swap_chain = base::FeatureList::IsEnabled(kLowLatencyWebGLSwapChain) && context_provider->GetCapabilities().shared_image_swap_chain && - CreationAttributes().desynchronized; + attrs.desynchronized; return DrawingBuffer::Create( std::move(context_provider), using_gpu_compositing, using_swap_chain, this, ClampedCanvasSize(), premultiplied_alpha, want_alpha_channel, want_depth_buffer, want_stencil_buffer, want_antialiasing, preserve, - web_gl_version, chromium_image_usage, ColorParams()); + web_gl_version, chromium_image_usage, ColorParams(), + PowerPreferenceToGpuPreference(attrs.power_preference)); } void WebGLRenderingContextBase::InitializeNewContext() { @@ -1257,6 +1266,8 @@ supported_tex_image_source_types_.clear(); ADD_VALUES_TO_SET(supported_tex_image_source_types_, kSupportedTypesES2); + number_of_user_allocated_multisampled_renderbuffers_ = 0; + // The DrawingBuffer was unable to store the state that dirtied when it was // initialized. Restore it now. GetDrawingBuffer()->RestoreAllState(); @@ -4508,6 +4519,8 @@ "invalid internalformat"); break; } + UpdateNumberOfUserAllocatedMultisampledRenderbuffers( + renderbuffer_binding_->UpdateMultisampleState(false)); } void WebGLRenderingContextBase::renderbufferStorage(GLenum target, @@ -6783,6 +6796,17 @@ void WebGLRenderingContextBase:: DrawingBufferClientRestorePixelPackBufferBinding() {} +bool WebGLRenderingContextBase:: + DrawingBufferClientUserAllocatedMultisampledRenderbuffers() { + return number_of_user_allocated_multisampled_renderbuffers_ > 0; +} + +void WebGLRenderingContextBase:: + DrawingBufferClientForceLostContextWithAutoRecovery() { + ForceLostContext(WebGLRenderingContextBase::kSyntheticLostContext, + WebGLRenderingContextBase::kAuto); +} + ScriptValue WebGLRenderingContextBase::GetBooleanParameter( ScriptState* script_state, GLenum pname) {
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h index 8368b276..9549f51 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h +++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h
@@ -619,6 +619,8 @@ ScriptPromise makeXRCompatible(ScriptState*); bool IsXRCompatible(); + void UpdateNumberOfUserAllocatedMultisampledRenderbuffers(int delta); + protected: friend class EXTDisjointTimerQuery; friend class EXTDisjointTimerQueryWebGL2; @@ -681,6 +683,8 @@ void DrawingBufferClientRestoreFramebufferBinding() override; void DrawingBufferClientRestorePixelUnpackBufferBinding() override; void DrawingBufferClientRestorePixelPackBufferBinding() override; + bool DrawingBufferClientUserAllocatedMultisampledRenderbuffers() override; + void DrawingBufferClientForceLostContextWithAutoRecovery() override; virtual void DestroyContext(); void MarkContextChanged(ContentChangeType); @@ -1761,6 +1765,8 @@ FrameOrWorkerScheduler::SchedulingAffectingFeatureHandle feature_handle_for_scheduler_; + int number_of_user_allocated_multisampled_renderbuffers_; + DISALLOW_COPY_AND_ASSIGN(WebGLRenderingContextBase); };
diff --git a/third_party/blink/renderer/modules/webgpu/BUILD.gn b/third_party/blink/renderer/modules/webgpu/BUILD.gn index ef46d40..4f2d528 100644 --- a/third_party/blink/renderer/modules/webgpu/BUILD.gn +++ b/third_party/blink/renderer/modules/webgpu/BUILD.gn
@@ -71,6 +71,8 @@ "gpu_validation_error.h", "navigator_gpu.cc", "navigator_gpu.h", + "worker_navigator_gpu.cc", + "worker_navigator_gpu.h", ] deps = [ "//third_party/dawn/src/dawn:dawn_headers",
diff --git a/third_party/blink/renderer/modules/webgpu/gpu.cc b/third_party/blink/renderer/modules/webgpu/gpu.cc index 75c6433..30f7ef5 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu.cc +++ b/third_party/blink/renderer/modules/webgpu/gpu.cc
@@ -15,27 +15,67 @@ #include "third_party/blink/renderer/modules/webgpu/gpu_adapter.h" #include "third_party/blink/renderer/modules/webgpu/gpu_request_adapter_options.h" #include "third_party/blink/renderer/platform/graphics/gpu/dawn_control_client_holder.h" +#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h" +#include "third_party/blink/renderer/platform/scheduler/public/thread.h" +#include "third_party/blink/renderer/platform/weborigin/kurl.h" +#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h" namespace blink { +namespace { + +void CreateContextProvider( + const KURL& url, + base::WaitableEvent* waitable_event, + std::unique_ptr<WebGraphicsContext3DProvider>* created_context_provider) { + DCHECK(IsMainThread()); + *created_context_provider = + Platform::Current()->CreateWebGPUGraphicsContext3DProvider(url); + waitable_event->Signal(); +} + +std::unique_ptr<WebGraphicsContext3DProvider> CreateContextProviderOnMainThread( + const KURL& url) { + scoped_refptr<base::SingleThreadTaskRunner> task_runner = + Thread::MainThread()->GetTaskRunner(); + + base::WaitableEvent waitable_event; + std::unique_ptr<WebGraphicsContext3DProvider> created_context_provider; + PostCrossThreadTask( + *task_runner, FROM_HERE, + CrossThreadBindOnce(&CreateContextProvider, url, + CrossThreadUnretained(&waitable_event), + CrossThreadUnretained(&created_context_provider))); + + waitable_event.Wait(); + return created_context_provider; +} + +} // anonymous namespace + // static GPU* GPU::Create(ExecutionContext& execution_context) { - const auto& url = execution_context.Url(); - Platform::GraphicsInfo info; + const KURL& url = execution_context.Url(); - std::unique_ptr<WebGraphicsContext3DProvider> context_provider = - Platform::Current()->CreateWebGPUGraphicsContext3DProvider(url, &info); + std::unique_ptr<WebGraphicsContext3DProvider> context_provider; + if (IsMainThread()) { + context_provider = + Platform::Current()->CreateWebGPUGraphicsContext3DProvider(url); + } else { + context_provider = CreateContextProviderOnMainThread(url); + } // TODO(kainino): we will need a better way of accessing the GPU interface // from multiple threads than BindToCurrentThread et al. - if (context_provider && context_provider->BindToCurrentThread()) { - info.error_message = - String("bindToCurrentThread failed: " + String(info.error_message)); + if (context_provider && !context_provider->BindToCurrentThread()) { + // TODO(crbug.com/973017): Collect GPU info and surface context creation + // error. + return nullptr; } if (!context_provider) { - // TODO(kainino): send the error message somewhere - // (see ExtractWebGLContextCreationError). + // TODO(crbug.com/973017): Collect GPU info and surface context creation + // error. return nullptr; }
diff --git a/third_party/blink/renderer/modules/webgpu/gpu.idl b/third_party/blink/renderer/modules/webgpu/gpu.idl index 393ae11..44736c7 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu.idl
@@ -10,7 +10,7 @@ typedef (sequence<unsigned long> or GPUOrigin3DDict) GPUOrigin3D; [ - RuntimeEnabled=WebGPU + Exposed(Window WebGPU, Worker WebGPU) ] interface GPU { [ RuntimeEnabled=WebGPU,
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_adapter.idl b/third_party/blink/renderer/modules/webgpu/gpu_adapter.idl index 0c14346..a5d12ecc 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_adapter.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_adapter.idl
@@ -5,7 +5,7 @@ // https://gpuweb.github.io/gpuweb/ [ - RuntimeEnabled=WebGPU + Exposed(Window WebGPU, Worker WebGPU) ] interface GPUAdapter { readonly attribute DOMString name;
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_bind_group.idl b/third_party/blink/renderer/modules/webgpu/gpu_bind_group.idl index 7affa268..dbb19a65 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_bind_group.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_bind_group.idl
@@ -5,6 +5,6 @@ // https://gpuweb.github.io/gpuweb/ [ - RuntimeEnabled=WebGPU + Exposed(Window WebGPU, Worker WebGPU) ] interface GPUBindGroup { };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.idl b/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.idl index 00c5707..20dafb87 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.idl
@@ -5,6 +5,6 @@ // https://gpuweb.github.io/gpuweb/ [ - RuntimeEnabled=WebGPU + Exposed(Window WebGPU, Worker WebGPU) ] interface GPUBindGroupLayout { };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_buffer.idl b/third_party/blink/renderer/modules/webgpu/gpu_buffer.idl index 1728f46..2db4c05 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_buffer.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_buffer.idl
@@ -5,7 +5,7 @@ // https://gpuweb.github.io/gpuweb/ [ - RuntimeEnabled=WebGPU + Exposed(Window WebGPU, Worker WebGPU) ] interface GPUBuffer { [RaisesException] void setSubData( unsigned long long dstOffset,
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_buffer_usage.idl b/third_party/blink/renderer/modules/webgpu/gpu_buffer_usage.idl index b49cc104..a1706b7 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_buffer_usage.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_buffer_usage.idl
@@ -6,7 +6,7 @@ typedef unsigned long GPUBufferUsageFlags; [ - RuntimeEnabled=WebGPU + Exposed(Window WebGPU, Worker WebGPU) ] interface GPUBufferUsage { const GPUBufferUsageFlags MAP_READ = 1; const GPUBufferUsageFlags MAP_WRITE = 2;
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.idl b/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.idl index feb476c..d5eb80d 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.idl
@@ -5,7 +5,7 @@ // https://gpuweb.github.io/gpuweb/ [ - RuntimeEnabled=WebGPU + Exposed(Window WebGPU, Worker WebGPU) ] interface GPUCanvasContext { GPUSwapChain configureSwapChain(GPUSwapChainDescriptor descriptor);
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_color_write.idl b/third_party/blink/renderer/modules/webgpu/gpu_color_write.idl index a71fbafd..69bdf6e 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_color_write.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_color_write.idl
@@ -6,7 +6,7 @@ typedef unsigned long GPUColorWriteFlags; [ - RuntimeEnabled=WebGPU + Exposed(Window WebGPU, Worker WebGPU) ] interface GPUColorWrite { const GPUColorWriteFlags RED = 1; const GPUColorWriteFlags GREEN = 2;
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_command_buffer.idl b/third_party/blink/renderer/modules/webgpu/gpu_command_buffer.idl index 6c6af47..75b5b25 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_command_buffer.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_command_buffer.idl
@@ -5,6 +5,6 @@ // https://gpuweb.github.io/gpuweb/ [ - RuntimeEnabled=WebGPU + Exposed(Window WebGPU, Worker WebGPU) ] interface GPUCommandBuffer { };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.idl b/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.idl index 574ec01e..e93ef35 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.idl
@@ -5,7 +5,7 @@ // https://gpuweb.github.io/gpuweb/ [ - RuntimeEnabled=WebGPU + Exposed(Window WebGPU, Worker WebGPU) ] interface GPUCommandEncoder { [RaisesException] GPURenderPassEncoder beginRenderPass(GPURenderPassDescriptor descriptor); GPUComputePassEncoder beginComputePass(optional GPUComputePassDescriptor descriptor = {});
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_compute_pass_encoder.idl b/third_party/blink/renderer/modules/webgpu/gpu_compute_pass_encoder.idl index dd75cea..dec314d 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_compute_pass_encoder.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_compute_pass_encoder.idl
@@ -5,7 +5,7 @@ // https://gpuweb.github.io/gpuweb/ [ - RuntimeEnabled=WebGPU + Exposed(Window WebGPU, Worker WebGPU) ] interface GPUComputePassEncoder { void setPipeline(GPUComputePipeline pipeline); void dispatch(unsigned long x,
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_compute_pipeline.idl b/third_party/blink/renderer/modules/webgpu/gpu_compute_pipeline.idl index 9fb2b5c..49ac61d 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_compute_pipeline.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_compute_pipeline.idl
@@ -5,6 +5,6 @@ // https://gpuweb.github.io/gpuweb/ [ - RuntimeEnabled=WebGPU + Exposed(Window WebGPU, Worker WebGPU) ] interface GPUComputePipeline { };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_device.idl b/third_party/blink/renderer/modules/webgpu/gpu_device.idl index 56e9b38..f245caf5 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_device.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_device.idl
@@ -5,7 +5,7 @@ // https://gpuweb.github.io/gpuweb/ [ - RuntimeEnabled=WebGPU + Exposed(Window WebGPU, Worker WebGPU) ] interface GPUDevice : EventTarget { readonly attribute GPUAdapter adapter; [CallWith=ScriptState] readonly attribute Promise<GPUDeviceLostInfo> lost;
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_fence.idl b/third_party/blink/renderer/modules/webgpu/gpu_fence.idl index df7c035..51633406 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_fence.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_fence.idl
@@ -5,7 +5,7 @@ // https://gpuweb.github.io/gpuweb/ [ - RuntimeEnabled=WebGPU + Exposed(Window WebGPU, Worker WebGPU) ] interface GPUFence { unsigned long long getCompletedValue(); [CallWith=ScriptState] Promise<void> onCompletion(unsigned long long completionValue);
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_out_of_memory_error.idl b/third_party/blink/renderer/modules/webgpu/gpu_out_of_memory_error.idl index 83002f7..bd16e3b0e 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_out_of_memory_error.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_out_of_memory_error.idl
@@ -6,6 +6,6 @@ [ Constructor(), - RuntimeEnabled=WebGPU + Exposed(Window WebGPU, Worker WebGPU) ] interface GPUOutOfMemoryError { };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.idl b/third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.idl index 3fbf4922..f192dea 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.idl
@@ -5,6 +5,6 @@ // https://gpuweb.github.io/gpuweb/ [ - RuntimeEnabled=WebGPU + Exposed(Window WebGPU, Worker WebGPU) ] interface GPUPipelineLayout { };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_queue.idl b/third_party/blink/renderer/modules/webgpu/gpu_queue.idl index 2cb3f9c..fd6251e 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_queue.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_queue.idl
@@ -5,7 +5,7 @@ // https://gpuweb.github.io/gpuweb/ [ - RuntimeEnabled=WebGPU + Exposed(Window WebGPU, Worker WebGPU) ] interface GPUQueue { void submit(sequence<GPUCommandBuffer> buffers);
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_render_bundle.idl b/third_party/blink/renderer/modules/webgpu/gpu_render_bundle.idl index c6f5c5ec..ba301eb 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_render_bundle.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_render_bundle.idl
@@ -5,6 +5,6 @@ // https://gpuweb.github.io/gpuweb/ [ - RuntimeEnabled=WebGPU + Exposed(Window WebGPU, Worker WebGPU) ] interface GPURenderBundle { };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_render_bundle_encoder.idl b/third_party/blink/renderer/modules/webgpu/gpu_render_bundle_encoder.idl index 1ee00378..98355ab 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_render_bundle_encoder.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_render_bundle_encoder.idl
@@ -5,7 +5,7 @@ // https://gpuweb.github.io/gpuweb/ [ - RuntimeEnabled=WebGPU + Exposed(Window WebGPU, Worker WebGPU) ] interface GPURenderBundleEncoder { GPURenderBundle finish(optional GPURenderBundleDescriptor descriptor = {}); };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_render_pass_encoder.idl b/third_party/blink/renderer/modules/webgpu/gpu_render_pass_encoder.idl index 524f750..867958c 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_render_pass_encoder.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_render_pass_encoder.idl
@@ -5,7 +5,7 @@ // https://gpuweb.github.io/gpuweb/ [ - RuntimeEnabled=WebGPU + Exposed(Window WebGPU, Worker WebGPU) ] interface GPURenderPassEncoder { void setViewport(float x, float y, float width, float height,
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.cc b/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.cc index 56fc21a3..afb92057 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.cc +++ b/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.cc
@@ -4,7 +4,7 @@ #include "third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.h" -#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_vertex_buffer_descriptor.h" +#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_vertex_buffer_layout_descriptor.h" #include "third_party/blink/renderer/modules/webgpu/dawn_conversions.h" #include "third_party/blink/renderer/modules/webgpu/gpu_blend_descriptor.h" #include "third_party/blink/renderer/modules/webgpu/gpu_color_state_descriptor.h" @@ -12,8 +12,8 @@ #include "third_party/blink/renderer/modules/webgpu/gpu_device.h" #include "third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.h" #include "third_party/blink/renderer/modules/webgpu/gpu_render_pipeline_descriptor.h" -#include "third_party/blink/renderer/modules/webgpu/gpu_vertex_buffer_descriptor.h" -#include "third_party/blink/renderer/modules/webgpu/gpu_vertex_input_descriptor.h" +#include "third_party/blink/renderer/modules/webgpu/gpu_vertex_buffer_layout_descriptor.h" +#include "third_party/blink/renderer/modules/webgpu/gpu_vertex_state_descriptor.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/bindings/script_state.h" @@ -84,21 +84,21 @@ return dawn_desc; } -using WGPUVertexInputInfo = std::tuple<WGPUVertexInputDescriptor, - Vector<WGPUVertexBufferDescriptor>, +using WGPUVertexStateInfo = std::tuple<WGPUVertexStateDescriptor, + Vector<WGPUVertexBufferLayoutDescriptor>, Vector<WGPUVertexAttributeDescriptor>>; -WGPUVertexInputInfo GPUVertexInputAsWGPUInputState( +WGPUVertexStateInfo GPUVertexStateAsWGPUVertexState( v8::Isolate* isolate, - const GPUVertexInputDescriptor* descriptor, + const GPUVertexStateDescriptor* descriptor, ExceptionState& exception_state) { - WGPUVertexInputDescriptor dawn_desc = {}; + WGPUVertexStateDescriptor dawn_desc = {}; dawn_desc.indexFormat = AsDawnEnum<WGPUIndexFormat>(descriptor->indexFormat()); - dawn_desc.bufferCount = 0; - dawn_desc.buffers = nullptr; + dawn_desc.vertexBufferCount = 0; + dawn_desc.vertexBuffers = nullptr; - Vector<WGPUVertexBufferDescriptor> dawn_vertex_buffers; + Vector<WGPUVertexBufferLayoutDescriptor> dawn_vertex_buffers; Vector<WGPUVertexAttributeDescriptor> dawn_vertex_attributes; if (descriptor->hasVertexBuffers()) { @@ -116,18 +116,18 @@ v8::Local<v8::Array> vertex_buffers = vertex_buffers_value.As<v8::Array>(); // First we collect all the descriptors but we don't set - // WGPUVertexBufferDescriptor::attributes + // WGPUVertexBufferLayoutDescriptor::attributes // TODO(cwallez@chromium.org): Should we validate the Length() first so we - // don't risk creating HUGE vectors of WGPUVertexBufferDescriptor from the - // sparse array? + // don't risk creating HUGE vectors of WGPUVertexBufferLayoutDescriptor from + // the sparse array? for (uint32_t i = 0; i < vertex_buffers->Length(); ++i) { // This array can be sparse. Skip empty slots. v8::MaybeLocal<v8::Value> maybe_value = vertex_buffers->Get(context, i); v8::Local<v8::Value> value; if (!maybe_value.ToLocal(&value) || value.IsEmpty() || value->IsNullOrUndefined()) { - WGPUVertexBufferDescriptor dawn_vertex_buffer = {}; - dawn_vertex_buffer.stride = 0; + WGPUVertexBufferLayoutDescriptor dawn_vertex_buffer = {}; + dawn_vertex_buffer.arrayStride = 0; dawn_vertex_buffer.stepMode = WGPUInputStepMode_Vertex; dawn_vertex_buffer.attributeCount = 0; dawn_vertex_buffer.attributes = nullptr; @@ -135,26 +135,26 @@ continue; } - GPUVertexBufferDescriptor vertex_buffer; - V8GPUVertexBufferDescriptor::ToImpl(isolate, value, &vertex_buffer, - exception_state); + GPUVertexBufferLayoutDescriptor vertex_buffer; + V8GPUVertexBufferLayoutDescriptor::ToImpl(isolate, value, &vertex_buffer, + exception_state); if (exception_state.HadException()) { return std::make_tuple(dawn_desc, std::move(dawn_vertex_buffers), std::move(dawn_vertex_attributes)); } - WGPUVertexBufferDescriptor dawn_vertex_buffer = {}; - dawn_vertex_buffer.stride = vertex_buffer.stride(); + WGPUVertexBufferLayoutDescriptor dawn_vertex_buffer = {}; + dawn_vertex_buffer.arrayStride = vertex_buffer.arrayStride(); dawn_vertex_buffer.stepMode = AsDawnEnum<WGPUInputStepMode>(vertex_buffer.stepMode()); dawn_vertex_buffer.attributeCount = - static_cast<uint32_t>(vertex_buffer.attributeSet().size()); + static_cast<uint32_t>(vertex_buffer.attributes().size()); dawn_vertex_buffer.attributes = nullptr; dawn_vertex_buffers.push_back(dawn_vertex_buffer); - for (wtf_size_t j = 0; j < vertex_buffer.attributeSet().size(); ++j) { + for (wtf_size_t j = 0; j < vertex_buffer.attributes().size(); ++j) { const GPUVertexAttributeDescriptor* attribute = - vertex_buffer.attributeSet()[j]; + vertex_buffer.attributes()[j]; WGPUVertexAttributeDescriptor dawn_vertex_attribute = {}; dawn_vertex_attribute.shaderLocation = attribute->shaderLocation(); dawn_vertex_attribute.offset = attribute->offset(); @@ -164,10 +164,11 @@ } } - // Set up pointers in DawnVertexBufferDescriptor::attributes only after we - // stopped appending to the vector so the pointers aren't invalidated. + // Set up pointers in DawnVertexBufferLayoutDescriptor::attributes only + // after we stopped appending to the vector so the pointers aren't + // invalidated. uint32_t attributeIndex = 0; - for (WGPUVertexBufferDescriptor& buffer : dawn_vertex_buffers) { + for (WGPUVertexBufferLayoutDescriptor& buffer : dawn_vertex_buffers) { if (buffer.attributeCount == 0) { continue; } @@ -176,8 +177,9 @@ } } - dawn_desc.bufferCount = static_cast<uint32_t>(dawn_vertex_buffers.size()); - dawn_desc.buffers = dawn_vertex_buffers.data(); + dawn_desc.vertexBufferCount = + static_cast<uint32_t>(dawn_vertex_buffers.size()); + dawn_desc.vertexBuffers = dawn_vertex_buffers.data(); return std::make_tuple(dawn_desc, std::move(dawn_vertex_buffers), std::move(dawn_vertex_attributes)); @@ -226,13 +228,12 @@ dawn_desc.fragmentStage = nullptr; } - // TODO(crbug.com/dawn/131): Update Dawn to match WebGPU vertex input v8::Isolate* isolate = script_state->GetIsolate(); ExceptionState exception_state(isolate, ExceptionState::kConstructionContext, - "GPUVertexInputDescriptor"); - WGPUVertexInputInfo vertex_input_info = GPUVertexInputAsWGPUInputState( - isolate, webgpu_desc->vertexInput(), exception_state); - dawn_desc.vertexInput = &std::get<0>(vertex_input_info); + "GPUVertexStateDescriptor"); + WGPUVertexStateInfo vertex_state_info = GPUVertexStateAsWGPUVertexState( + isolate, webgpu_desc->vertexState(), exception_state); + dawn_desc.vertexState = &std::get<0>(vertex_state_info); if (exception_state.HadException()) { return nullptr;
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.idl b/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.idl index a4a1c7f1..deeddd5c 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.idl
@@ -5,6 +5,6 @@ // https://gpuweb.github.io/gpuweb/ [ - RuntimeEnabled=WebGPU + Exposed(Window WebGPU, Worker WebGPU) ] interface GPURenderPipeline { };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline_descriptor.idl b/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline_descriptor.idl index 0017094..79572d9 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline_descriptor.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline_descriptor.idl
@@ -12,7 +12,7 @@ GPURasterizationStateDescriptor rasterizationState = {}; required sequence<GPUColorStateDescriptor> colorStates; GPUDepthStencilStateDescriptor depthStencilState; - GPUVertexInputDescriptor vertexInput = {}; + GPUVertexStateDescriptor vertexState = {}; unsigned long sampleCount = 1;
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_sampler.idl b/third_party/blink/renderer/modules/webgpu/gpu_sampler.idl index 96599ce..afb0b4e 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_sampler.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_sampler.idl
@@ -5,6 +5,6 @@ // https://gpuweb.github.io/gpuweb/ [ - RuntimeEnabled=WebGPU + Exposed(Window WebGPU, Worker WebGPU) ] interface GPUSampler { };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_shader_module.idl b/third_party/blink/renderer/modules/webgpu/gpu_shader_module.idl index dd63cdf2..e8d42b9 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_shader_module.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_shader_module.idl
@@ -5,6 +5,6 @@ // https://gpuweb.github.io/gpuweb/ [ - RuntimeEnabled=WebGPU + Exposed(Window WebGPU, Worker WebGPU) ] interface GPUShaderModule { };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_shader_stage.idl b/third_party/blink/renderer/modules/webgpu/gpu_shader_stage.idl index 546221e2..341d97054 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_shader_stage.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_shader_stage.idl
@@ -6,7 +6,7 @@ typedef unsigned long GPUShaderStageFlags; [ - RuntimeEnabled=WebGPU + Exposed(Window WebGPU, Worker WebGPU) ] interface GPUShaderStage { const GPUShaderStageFlags VERTEX = 1; const GPUShaderStageFlags FRAGMENT = 2;
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.idl b/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.idl index f89aead..d69ae91c 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.idl
@@ -5,7 +5,7 @@ // https://gpuweb.github.io/gpuweb/ [ - RuntimeEnabled=WebGPU + Exposed(Window WebGPU, Worker WebGPU) ] interface GPUSwapChain { GPUTexture getCurrentTexture(); };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_texture.idl b/third_party/blink/renderer/modules/webgpu/gpu_texture.idl index 67904ef..868ea15 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_texture.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_texture.idl
@@ -5,7 +5,7 @@ // https://gpuweb.github.io/gpuweb/ [ - RuntimeEnabled=WebGPU + Exposed(Window WebGPU, Worker WebGPU) ] interface GPUTexture { GPUTextureView createView(optional GPUTextureViewDescriptor descriptor = {}); void destroy();
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_texture_usage.idl b/third_party/blink/renderer/modules/webgpu/gpu_texture_usage.idl index d8139ba..50775c3 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_texture_usage.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_texture_usage.idl
@@ -6,7 +6,7 @@ typedef unsigned long GPUTextureUsageFlags; [ - RuntimeEnabled=WebGPU + Exposed(Window WebGPU, Worker WebGPU) ] interface GPUTextureUsage { const GPUTextureUsageFlags COPY_SRC = 1; const GPUTextureUsageFlags COPY_DST = 2;
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_texture_view.idl b/third_party/blink/renderer/modules/webgpu/gpu_texture_view.idl index db31277..03d3626 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_texture_view.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_texture_view.idl
@@ -5,6 +5,6 @@ // https://gpuweb.github.io/gpuweb/ [ - RuntimeEnabled=WebGPU + Exposed(Window WebGPU, Worker WebGPU) ] interface GPUTextureView { };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_uncaptured_error_event.idl b/third_party/blink/renderer/modules/webgpu/gpu_uncaptured_error_event.idl index 80bed55..a45cdd5 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_uncaptured_error_event.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_uncaptured_error_event.idl
@@ -6,7 +6,7 @@ [ Constructor(DOMString type, GPUUncapturedErrorEventInit gpuUncapturedErrorEventInitDict), - RuntimeEnabled=WebGPU + Exposed(Window WebGPU, Worker WebGPU) ] interface GPUUncapturedErrorEvent : Event { readonly attribute GPUError error; };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_validation_error.idl b/third_party/blink/renderer/modules/webgpu/gpu_validation_error.idl index 0b93ed1b..d372e5f 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_validation_error.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_validation_error.idl
@@ -6,7 +6,7 @@ [ Constructor(DOMString message), - RuntimeEnabled=WebGPU + Exposed(Window WebGPU, Worker WebGPU) ] interface GPUValidationError { readonly attribute DOMString message; };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_vertex_buffer_descriptor.idl b/third_party/blink/renderer/modules/webgpu/gpu_vertex_buffer_layout_descriptor.idl similarity index 67% rename from third_party/blink/renderer/modules/webgpu/gpu_vertex_buffer_descriptor.idl rename to third_party/blink/renderer/modules/webgpu/gpu_vertex_buffer_layout_descriptor.idl index a696790..437fd68 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_vertex_buffer_descriptor.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_vertex_buffer_layout_descriptor.idl
@@ -4,10 +4,10 @@ // https://gpuweb.github.io/gpuweb/ -dictionary GPUVertexBufferDescriptor { - required GPUBufferSize stride; +dictionary GPUVertexBufferLayoutDescriptor { + required GPUBufferSize arrayStride; GPUInputStepMode stepMode = "vertex"; - required sequence<GPUVertexAttributeDescriptor> attributeSet; + required sequence<GPUVertexAttributeDescriptor> attributes; }; enum GPUInputStepMode {
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_vertex_input_descriptor.idl b/third_party/blink/renderer/modules/webgpu/gpu_vertex_state_descriptor.idl similarity index 84% rename from third_party/blink/renderer/modules/webgpu/gpu_vertex_input_descriptor.idl rename to third_party/blink/renderer/modules/webgpu/gpu_vertex_state_descriptor.idl index dc30a7c..7a991d1 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_vertex_input_descriptor.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_vertex_state_descriptor.idl
@@ -4,10 +4,10 @@ // https://gpuweb.github.io/gpuweb/ -dictionary GPUVertexInputDescriptor { +dictionary GPUVertexStateDescriptor { GPUIndexFormat indexFormat = "uint32"; // TODO(crbug.com/951629): Make this a sequence of nullables. - object vertexBuffers; // We validate this is an array of nullable GPUVertexBufferDescriptor + object vertexBuffers; // We validate this is an array of nullable GPUVertexBufferLayoutDescriptor }; enum GPUIndexFormat {
diff --git a/third_party/blink/renderer/modules/webgpu/navigator_gpu.cc b/third_party/blink/renderer/modules/webgpu/navigator_gpu.cc index 1a08230..a221d48 100644 --- a/third_party/blink/renderer/modules/webgpu/navigator_gpu.cc +++ b/third_party/blink/renderer/modules/webgpu/navigator_gpu.cc
@@ -11,6 +11,7 @@ namespace blink { +// static NavigatorGPU& NavigatorGPU::From(Navigator& navigator) { NavigatorGPU* supplement = Supplement<Navigator>::From<NavigatorGPU>(navigator);
diff --git a/third_party/blink/renderer/modules/webgpu/worker_navigator_gpu.cc b/third_party/blink/renderer/modules/webgpu/worker_navigator_gpu.cc new file mode 100644 index 0000000..8f5e7cb --- /dev/null +++ b/third_party/blink/renderer/modules/webgpu/worker_navigator_gpu.cc
@@ -0,0 +1,49 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/webgpu/worker_navigator_gpu.h" + +#include "third_party/blink/renderer/core/workers/worker_navigator.h" +#include "third_party/blink/renderer/modules/webgpu/gpu.h" + +namespace blink { + +// static +WorkerNavigatorGPU& WorkerNavigatorGPU::From(WorkerNavigator& navigator) { + WorkerNavigatorGPU* supplement = + Supplement<WorkerNavigator>::From<WorkerNavigatorGPU>(navigator); + if (!supplement) { + supplement = MakeGarbageCollected<WorkerNavigatorGPU>(navigator); + ProvideTo(navigator, supplement); + } + return *supplement; +} + +// static +GPU* WorkerNavigatorGPU::gpu(ScriptState* script_state, + WorkerNavigator& navigator) { + return WorkerNavigatorGPU::From(navigator).gpu(script_state); +} + +GPU* WorkerNavigatorGPU::gpu(ScriptState* script_state) { + if (!gpu_) { + ExecutionContext* context = ExecutionContext::From(script_state); + DCHECK(context); + + gpu_ = GPU::Create(*context); + } + return gpu_; +} + +void WorkerNavigatorGPU::Trace(blink::Visitor* visitor) { + visitor->Trace(gpu_); + Supplement<WorkerNavigator>::Trace(visitor); +} + +WorkerNavigatorGPU::WorkerNavigatorGPU(WorkerNavigator& navigator) + : Supplement<WorkerNavigator>(navigator) {} + +const char WorkerNavigatorGPU::kSupplementName[] = "WorkerNavigatorGPU"; + +} // namespace blink
diff --git a/third_party/blink/renderer/modules/webgpu/worker_navigator_gpu.h b/third_party/blink/renderer/modules/webgpu/worker_navigator_gpu.h new file mode 100644 index 0000000..0f8eabe1 --- /dev/null +++ b/third_party/blink/renderer/modules/webgpu/worker_navigator_gpu.h
@@ -0,0 +1,43 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_WORKER_NAVIGATOR_GPU_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_WORKER_NAVIGATOR_GPU_H_ + +#include "third_party/blink/renderer/core/workers/worker_navigator.h" +#include "third_party/blink/renderer/platform/heap/handle.h" +#include "third_party/blink/renderer/platform/supplementable.h" + +namespace blink { + +class GPU; +class WorkerNavigator; + +class WorkerNavigatorGPU final : public GarbageCollected<WorkerNavigatorGPU>, + public Supplement<WorkerNavigator> { + USING_GARBAGE_COLLECTED_MIXIN(WorkerNavigatorGPU); + + public: + static const char kSupplementName[]; + + // Gets, or creates, WorkerNavigatorGPU supplement on WorkerNavigator. + // See platform/Supplementable.h + static WorkerNavigatorGPU& From(WorkerNavigator&); + + static GPU* gpu(ScriptState* script_state, WorkerNavigator&); + GPU* gpu(ScriptState* script_state); + + explicit WorkerNavigatorGPU(WorkerNavigator&); + + void Trace(blink::Visitor*) override; + + private: + Member<GPU> gpu_; + + DISALLOW_COPY_AND_ASSIGN(WorkerNavigatorGPU); +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_WORKER_NAVIGATOR_GPU_H_
diff --git a/third_party/blink/renderer/modules/webgpu/worker_navigator_gpu.idl b/third_party/blink/renderer/modules/webgpu/worker_navigator_gpu.idl new file mode 100644 index 0000000..e69ee47 --- /dev/null +++ b/third_party/blink/renderer/modules/webgpu/worker_navigator_gpu.idl
@@ -0,0 +1,12 @@ +// 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. + +// https://gpuweb.github.io/gpuweb/ + +[ + Exposed=Worker, + ImplementedAs=WorkerNavigatorGPU +] partial interface WorkerNavigator { + [SameObject, RuntimeEnabled=WebGPU, CallWith=ScriptState] readonly attribute GPU gpu; +};
diff --git a/third_party/blink/renderer/platform/bindings/v8_private_property.h b/third_party/blink/renderer/platform/bindings/v8_private_property.h index 8201c9a..864454f1 100644 --- a/third_party/blink/renderer/platform/bindings/v8_private_property.h +++ b/third_party/blink/renderer/platform/bindings/v8_private_property.h
@@ -76,7 +76,6 @@ friend class V8PrivateProperty; // The following classes are exceptionally allowed to call to // getFromMainWorld. - friend class V8CustomEvent; friend class V8ExtendableMessageEvent; Symbol(v8::Isolate* isolate, v8::Local<v8::Private> private_symbol)
diff --git a/third_party/blink/renderer/platform/exported/platform.cc b/third_party/blink/renderer/platform/exported/platform.cc index c56556b..46ae6ea 100644 --- a/third_party/blink/renderer/platform/exported/platform.cc +++ b/third_party/blink/renderer/platform/exported/platform.cc
@@ -328,8 +328,8 @@ } std::unique_ptr<WebGraphicsContext3DProvider> -Platform::CreateWebGPUGraphicsContext3DProvider(const WebURL& top_document_url, - GraphicsInfo*) { +Platform::CreateWebGPUGraphicsContext3DProvider( + const WebURL& top_document_url) { return nullptr; }
diff --git a/third_party/blink/renderer/platform/graphics/gpu/DEPS b/third_party/blink/renderer/platform/graphics/gpu/DEPS index b7824e6..aa252c3 100644 --- a/third_party/blink/renderer/platform/graphics/gpu/DEPS +++ b/third_party/blink/renderer/platform/graphics/gpu/DEPS
@@ -15,4 +15,5 @@ "+gpu/config/gpu_driver_bug_workaround_type.h", "+gpu/config/gpu_feature_info.h", "+ui/gfx/gpu_fence.h", + "+ui/gl/gpu_preference.h", ]
diff --git a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc index f5fab0d..b3e1aee 100644 --- a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc +++ b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
@@ -64,6 +64,7 @@ #include "third_party/skia/include/core/SkSurface.h" #include "third_party/skia/include/gpu/GrContext.h" #include "third_party/skia/include/gpu/gl/GrGLTypes.h" +#include "ui/gl/gpu_preference.h" #include "v8/include/v8.h" namespace blink { @@ -90,7 +91,8 @@ PreserveDrawingBuffer preserve, WebGLVersion webgl_version, ChromiumImageUsage chromium_image_usage, - const CanvasColorParams& color_params) { + const CanvasColorParams& color_params, + gl::GpuPreference gpu_preference) { if (g_should_fail_drawing_buffer_creation_for_testing) { g_should_fail_drawing_buffer_creation_for_testing = false; return nullptr; @@ -141,7 +143,7 @@ std::move(extensions_util), client, discard_framebuffer_supported, want_alpha_channel, premultiplied_alpha, preserve, webgl_version, want_depth_buffer, want_stencil_buffer, chromium_image_usage, - color_params)); + color_params, gpu_preference)); if (!drawing_buffer->Initialize(size, multisample_supported)) { drawing_buffer->BeginDestruction(); return scoped_refptr<DrawingBuffer>(); @@ -167,7 +169,8 @@ bool want_depth, bool want_stencil, ChromiumImageUsage chromium_image_usage, - const CanvasColorParams& color_params) + const CanvasColorParams& color_params, + gl::GpuPreference gpu_preference) : client_(client), preserve_drawing_buffer_(preserve), webgl_version_(webgl_version), @@ -188,10 +191,15 @@ kF16CanvasPixelFormat), chromium_image_usage_(chromium_image_usage), opengl_flip_y_extension_( - ContextProvider()->GetCapabilities().mesa_framebuffer_flip_y) { + ContextProvider()->GetCapabilities().mesa_framebuffer_flip_y), + initial_gpu_(gpu_preference), + current_active_gpu_(gpu_preference) { // Used by browser tests to detect the use of a DrawingBuffer. TRACE_EVENT_INSTANT0("test_gpu", "DrawingBufferCreation", TRACE_EVENT_SCOPE_GLOBAL); + // PowerPreferenceToGpuPreference should have resolved the meaning + // of the "default" GPU already. + DCHECK(gpu_preference != gl::GpuPreference::kDefault); } DrawingBuffer::~DrawingBuffer() { @@ -345,15 +353,15 @@ ResolveIfNeeded(); if (!using_gpu_compositing_ && !force_gpu_result) { - FinishPrepareTransferableResourceSoftware(bitmap_registrar, out_resource, - out_release_callback); - } else { - FinishPrepareTransferableResourceGpu(out_resource, out_release_callback); + return FinishPrepareTransferableResourceSoftware( + bitmap_registrar, out_resource, out_release_callback); } - return true; + + return FinishPrepareTransferableResourceGpu(out_resource, + out_release_callback); } -void DrawingBuffer::FinishPrepareTransferableResourceSoftware( +bool DrawingBuffer::FinishPrepareTransferableResourceSoftware( cc::SharedBitmapIdRegistrar* bitmap_registrar, viz::TransferableResource* out_resource, std::unique_ptr<viz::SingleReleaseCallback>* out_release_callback) { @@ -391,9 +399,10 @@ *out_release_callback = viz::SingleReleaseCallback::Create(std::move(func)); ResetBuffersToAutoClear(); + return true; } -void DrawingBuffer::FinishPrepareTransferableResourceGpu( +bool DrawingBuffer::FinishPrepareTransferableResourceGpu( viz::TransferableResource* out_resource, std::unique_ptr<viz::SingleReleaseCallback>* out_release_callback) { DCHECK(state_restorer_); @@ -419,6 +428,10 @@ // into the mailbox, and allocate (or recycle) a new backbuffer. color_buffer_for_mailbox = back_color_buffer_; back_color_buffer_ = CreateOrRecycleColorBuffer(); + if (!back_color_buffer_) { + // Context is likely lost. + return false; + } AttachColorBufferToReadFramebuffer(); // Explicitly specify that m_fbo (which is now bound to the just-allocated @@ -437,6 +450,10 @@ // TODO(sunnyps): We can skip this test if explicit resolve is used since // we'll render to the multisample fbo which will be preserved. color_buffer_for_mailbox = CreateOrRecycleColorBuffer(); + if (!color_buffer_for_mailbox) { + // Context is likely lost. + return false; + } gl_->CopySubTextureCHROMIUM( back_color_buffer_->texture_id, 0, texture_target_, color_buffer_for_mailbox->texture_id, 0, 0, 0, 0, 0, size_.Width(), @@ -498,6 +515,7 @@ contents_changed_ = false; ResetBuffersToAutoClear(); + return true; } void DrawingBuffer::MailboxReleasedGpu(scoped_refptr<ColorBuffer> color_buffer, @@ -1223,13 +1241,45 @@ contents_change_resolved_ = true; auto* gl = ContextProvider()->ContextGL(); - if (gl->DidGpuSwitch() == GL_TRUE) { - // TODO(crbug.com/681341): handle preserveDrawingBuffer:true, and - // user-allocated multisampled renderbuffers, by dispatching a context lost - // event. - if (WantExplicitResolve()) { - ReallocateMultisampleRenderbuffer(size_); + gl::GpuPreference active_gpu = gl::GpuPreference::kDefault; + if (gl->DidGpuSwitch(&active_gpu) == GL_TRUE) { + // This code path is mainly taken on macOS (the only platform which, as of + // this writing, dispatches the GPU-switched notifications), and the + // comments below focus only on macOS. + // + // The code below attempts to deduce whether, if a GPU switch occurred, + // it's really necessary to lose the context because certain GPU resources + // are no longer accessible. Resources only become inaccessible if + // CGLSetVirtualScreen is explicitly called against a GL context to change + // its renderer ID. GPU switching notifications are highly asynchronous. + // + // The tests below, of the initial and currently active GPU, replicate + // some logic in GLContextCGL::ForceGpuSwitchIfNeeded. Basically, if a + // context requests the high-performance GPU, then CGLSetVirtualScreen + // will never be called to migrate that context to the low-power + // GPU. However, contexts that were allocated on the integrated GPU will + // be migrated to the discrete GPU, and back, when the discrete GPU is + // activated and deactivated. Also, if the high-performance GPU was + // requested, then that request took effect during context bringup, even + // though the GPU switching notification is generally dispatched a couple + // of seconds after that, so it's not necessary to either lose the context + // or reallocate the multisampled renderbuffers when that initial + // notification is received. + if (initial_gpu_ == gl::GpuPreference::kLowPower && + current_active_gpu_ != active_gpu) { + if ((WantExplicitResolve() && preserve_drawing_buffer_ == kPreserve) || + client_ + ->DrawingBufferClientUserAllocatedMultisampledRenderbuffers()) { + // In these situations there are multisampled renderbuffers whose + // content the application expects to be preserved, but which can not + // be. Forcing a lost context is the only option to keep applications + // rendering correctly. + client_->DrawingBufferClientForceLostContextWithAutoRecovery(); + } else if (WantExplicitResolve()) { + ReallocateMultisampleRenderbuffer(size_); + } } + current_active_gpu_ = active_gpu; } } @@ -1457,6 +1507,11 @@ scoped_refptr<DrawingBuffer::ColorBuffer> DrawingBuffer::CreateColorBuffer( const IntSize& size) { + if (size.IsEmpty()) { + // Context is likely lost. + return nullptr; + } + DCHECK(state_restorer_); state_restorer_->SetFramebufferBindingDirty(); state_restorer_->SetTextureBindingDirty();
diff --git a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.h b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.h index 28908a7..7b4807a0 100644 --- a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.h +++ b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.h
@@ -52,6 +52,7 @@ #include "third_party/khronos/GLES2/gl2.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/gfx/color_space.h" +#include "ui/gl/gpu_preference.h" namespace cc { class Layer; @@ -98,6 +99,9 @@ virtual void DrawingBufferClientRestoreFramebufferBinding() = 0; virtual void DrawingBufferClientRestorePixelUnpackBufferBinding() = 0; virtual void DrawingBufferClientRestorePixelPackBufferBinding() = 0; + virtual bool + DrawingBufferClientUserAllocatedMultisampledRenderbuffers() = 0; + virtual void DrawingBufferClientForceLostContextWithAutoRecovery() = 0; }; enum PreserveDrawingBuffer { @@ -129,7 +133,8 @@ PreserveDrawingBuffer, WebGLVersion, ChromiumImageUsage, - const CanvasColorParams&); + const CanvasColorParams&, + gl::GpuPreference); static void ForceNextDrawingBufferCreationToFail(); ~DrawingBuffer() override; @@ -284,7 +289,8 @@ bool wants_depth, bool wants_stencil, ChromiumImageUsage, - const CanvasColorParams&); + const CanvasColorParams&, + gl::GpuPreference gpu_preference); bool Initialize(const IntSize&, bool use_multisampling); @@ -399,10 +405,10 @@ bool force_gpu_result); // Helper functions to be called only by PrepareTransferableResourceInternal. - void FinishPrepareTransferableResourceGpu( + bool FinishPrepareTransferableResourceGpu( viz::TransferableResource* out_resource, std::unique_ptr<viz::SingleReleaseCallback>* out_release_callback); - void FinishPrepareTransferableResourceSoftware( + bool FinishPrepareTransferableResourceSoftware( cc::SharedBitmapIdRegistrar* bitmap_registrar, viz::TransferableResource* out_resource, std::unique_ptr<viz::SingleReleaseCallback>* out_release_callback); @@ -603,6 +609,9 @@ bool opengl_flip_y_extension_; + gl::GpuPreference initial_gpu_; + gl::GpuPreference current_active_gpu_; + DISALLOW_COPY_AND_ASSIGN(DrawingBuffer); };
diff --git a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test.cc b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test.cc index f3919c90..d721d47 100644 --- a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test.cc +++ b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test.cc
@@ -46,6 +46,7 @@ #include "third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test_helpers.h" #include "third_party/blink/renderer/platform/graphics/test/gpu_memory_buffer_test_platform.h" #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h" +#include "ui/gl/gpu_preference.h" #include "v8/include/v8.h" using testing::Test; @@ -726,7 +727,7 @@ IntSize(10, 10), premultiplied_alpha, want_alpha_channel, want_depth_buffer, want_stencil_buffer, want_antialiasing, preserve, DrawingBuffer::kWebGL1, DrawingBuffer::kAllowChromiumImage, - CanvasColorParams()); + CanvasColorParams(), gl::GpuPreference::kHighPerformance); // When we request a depth or a stencil buffer, we will get both. EXPECT_EQ(cases[i].request_depth || cases[i].request_stencil, @@ -796,7 +797,7 @@ nullptr, gpu_compositing, false /* using_swap_chain */, nullptr, too_big_size, false, false, false, false, false, DrawingBuffer::kDiscard, DrawingBuffer::kWebGL1, DrawingBuffer::kAllowChromiumImage, - CanvasColorParams()); + CanvasColorParams(), gl::GpuPreference::kHighPerformance); EXPECT_EQ(too_big_drawing_buffer, nullptr); drawing_buffer_->BeginDestruction(); }
diff --git a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test_helpers.h b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test_helpers.h index 2ef0b27f..8c4ad4b 100644 --- a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test_helpers.h +++ b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test_helpers.h
@@ -18,6 +18,7 @@ #include "third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.h" #include "third_party/blink/renderer/platform/graphics/gpu/extensions_3d_util.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" +#include "ui/gl/gpu_preference.h" namespace blink { @@ -329,6 +330,13 @@ void DrawingBufferClientRestorePixelPackBufferBinding() override { state_.pixel_pack_buffer_binding = saved_state_.pixel_pack_buffer_binding; } + bool DrawingBufferClientUserAllocatedMultisampledRenderbuffers() override { + // Not unit tested yet. Tested with end-to-end tests. + return false; + } + void DrawingBufferClientForceLostContextWithAutoRecovery() override { + // Not unit tested yet. Tested with end-to-end tests. + } // Testing methods. gpu::SyncToken MostRecentlyWaitedSyncToken() const { @@ -461,7 +469,8 @@ false /* wantDepth */, false /* wantStencil */, DrawingBuffer::kAllowChromiumImage /* ChromiumImageUsage */, - CanvasColorParams()), + CanvasColorParams(), + gl::GpuPreference::kHighPerformance), live_(nullptr) {} ~DrawingBufferForTests() override {
diff --git a/third_party/blink/renderer/platform/heap/unified_heap_controller.cc b/third_party/blink/renderer/platform/heap/unified_heap_controller.cc index 708d7c9..d618263 100644 --- a/third_party/blink/renderer/platform/heap/unified_heap_controller.cc +++ b/third_party/blink/renderer/platform/heap/unified_heap_controller.cc
@@ -146,7 +146,7 @@ bool UnifiedHeapController::IsRootForNonTracingGC( const v8::TracedReference<v8::Value>& handle) { - if (!IsTracingDone()) { + if (thread_state()->IsIncrementalMarking()) { // We have a non-tracing GC while unified GC is in progress. Treat all // objects as roots to avoid stale pointers in the marking worklists. return true; @@ -186,7 +186,7 @@ // potential in place rehashing. Both operations may trigger write barriers by // moving references. Such references may already be dead but not yet cleared // which would result in reporting dead objects to V8. - DCHECK(IsTracingDone()); + DCHECK(!thread_state()->IsIncrementalMarking()); // Clearing the wrapper below adjusts the DOM wrapper store which may // re-allocate its backing. We have to avoid report memory to V8 as that may // trigger GC during GC.
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index 865ae4ed..893757d 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -1044,7 +1044,7 @@ }, { name: "ModuleDedicatedWorker", - status: "experimental", + status: "stable", }, { name: "ModuleServiceWorker",
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 85739ca4..8ec5aef 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
@@ -614,6 +614,7 @@ # display-related types. 'allowed': [ 'base::MRUCache', + 'gl::GpuPreference', 'gpu::gles2::GLES2Interface', 'gpu::MailboxHolder', 'display::Display',
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/base.py b/third_party/blink/tools/blinkpy/web_tests/port/base.py index 573a573..8879f61f 100644 --- a/third_party/blink/tools/blinkpy/web_tests/port/base.py +++ b/third_party/blink/tools/blinkpy/web_tests/port/base.py
@@ -253,6 +253,12 @@ return 'Port{name=%s, version=%s, architecture=%s, test_configuration=%s}' % ( self._name, self._version, self._architecture, self._test_configuration) + def get_platform_tags(self): + """Returns system condition tags that are used to find active expectations + for a test run on a specific system""" + return frozenset([self._options.configuration.lower(), self._version, + self.port_name, self._architecture]) + @memoized def _flag_specific_config_name(self): """Returns the name of the flag-specific configuration which best matches
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/linux_unittest.py b/third_party/blink/tools/blinkpy/web_tests/port/linux_unittest.py index ad851beb..b23920cf 100644 --- a/third_party/blink/tools/blinkpy/web_tests/port/linux_unittest.py +++ b/third_party/blink/tools/blinkpy/web_tests/port/linux_unittest.py
@@ -72,6 +72,10 @@ for i, path in enumerate(expected_paths): self.assertTrue(port.baseline_search_path()[i].endswith(path)) + def test_get_platform_tags(self): + port = self.make_port() + self.assertEqual(port.get_platform_tags(), {'linux', 'trusty', 'x86_64', 'release'}) + def test_baseline_paths(self): self.assert_baseline_paths('linux', 'trusty', 'linux', '/win') self.assert_baseline_paths('linux-trusty', None, 'linux', '/win')
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/mac_unittest.py b/third_party/blink/tools/blinkpy/web_tests/port/mac_unittest.py index 670dbfe..ed4d465 100644 --- a/third_party/blink/tools/blinkpy/web_tests/port/mac_unittest.py +++ b/third_party/blink/tools/blinkpy/web_tests/port/mac_unittest.py
@@ -46,6 +46,10 @@ def test_operating_system(self): self.assertEqual('mac', self.make_port().operating_system()) + def test_get_platform_tags(self): + port = self.make_port() + self.assertEqual(port.get_platform_tags(), {'mac', 'mac10.12', 'x86', 'release'}) + def test_driver_name_option(self): self.assertTrue(self.make_port()._path_to_driver().endswith('Content Shell')) port = self.make_port(options=optparse.Values(dict(driver_name='OtherDriver')))
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/win_unittest.py b/third_party/blink/tools/blinkpy/web_tests/port/win_unittest.py index 5c73f13..bee0d49c 100644 --- a/third_party/blink/tools/blinkpy/web_tests/port/win_unittest.py +++ b/third_party/blink/tools/blinkpy/web_tests/port/win_unittest.py
@@ -53,6 +53,10 @@ port = self.make_port(port_name=port_name, os_version=os_version_string) self.assertEqual(expected, port.name()) + def test_get_platform_tags(self): + port = self.make_port() + self.assertEqual(port.get_platform_tags(), {'win', 'win7', 'x86', 'release'}) + def test_versions(self): port = self.make_port() self.assertIn(port.name(), ('win-win7', 'win-win10'))
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index dcb0aa6..78529ae44 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -1386,7 +1386,6 @@ crbug.com/591099 virtual/layout_ng_flex_box/css3/flexbox/flex-align-vertical-writing-mode.html [ Failure ] crbug.com/591099 virtual/layout_ng_flex_box/css3/flexbox/flex-align.html [ Failure ] crbug.com/591099 virtual/layout_ng_flex_box/css3/flexbox/flex-flow-2.html [ Failure ] -crbug.com/591099 virtual/layout_ng_flex_box/css3/flexbox/flex-flow-auto-margins.html [ Failure ] crbug.com/591099 virtual/layout_ng_flex_box/css3/flexbox/flex-flow-border.html [ Failure ] crbug.com/591099 virtual/layout_ng_flex_box/css3/flexbox/flex-flow-margins-auto-size.html [ Failure ] crbug.com/591099 virtual/layout_ng_flex_box/css3/flexbox/flex-flow-padding.html [ Failure ] @@ -1448,10 +1447,6 @@ crbug.com/591099 virtual/layout_ng_flex_box/external/wpt/css/css-flexbox/hittest-overlapping-margin.html [ Failure ] crbug.com/591099 virtual/layout_ng_flex_box/external/wpt/css/css-flexbox/hittest-overlapping-order.html [ Failure ] -### virtual/layout_ng_flex_box/external/wpt/css/css-flexbox/flex-lines/ -crbug.com/591099 virtual/layout_ng_flex_box/external/wpt/css/css-flexbox/flex-lines/multi-line-wrap-reverse-column-reverse.html [ Failure ] -crbug.com/591099 virtual/layout_ng_flex_box/external/wpt/css/css-flexbox/flex-lines/multi-line-wrap-with-column-reverse.html [ Failure ] - ### virtual/layout_ng_flex_box/external/wpt/css/css-flexbox/getcomputedstyle/ crbug.com/467127 virtual/layout_ng_flex_box/external/wpt/css/css-flexbox/getcomputedstyle/flexbox_computedstyle_flex-basis-0percent.html [ Failure ] crbug.com/467127 virtual/layout_ng_flex_box/external/wpt/css/css-flexbox/getcomputedstyle/flexbox_computedstyle_flex-shorthand-number.html [ Failure ] @@ -1581,7 +1576,6 @@ crbug.com/6606 external/wpt/mathml/relations/css-styling/color-003.html [ Failure ] crbug.com/6606 external/wpt/mathml/relations/css-styling/color-004.html [ Failure ] crbug.com/6606 external/wpt/mathml/relations/css-styling/display-1.html [ Failure ] -crbug.com/6606 external/wpt/mathml/relations/css-styling/display-contents.html [ Failure ] crbug.com/6606 external/wpt/mathml/relations/css-styling/displaystyle-011.html [ Failure ] crbug.com/6606 external/wpt/mathml/relations/css-styling/displaystyle-012.html [ Failure ] crbug.com/6606 external/wpt/mathml/relations/css-styling/displaystyle-013.html [ Failure ]
diff --git a/third_party/blink/web_tests/WebGPUExpectations b/third_party/blink/web_tests/WebGPUExpectations index 2a204f1a..d397c72 100644 --- a/third_party/blink/web_tests/WebGPUExpectations +++ b/third_party/blink/web_tests/WebGPUExpectations
@@ -9,38 +9,53 @@ # crbug.com/1014734 wpt_internal/webgpu/cts.html?q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type~{"bindingType":"readonly-storage-buffer"} [ Failure ] +crbug.com/1014734 wpt_internal/webgpu/cts.html?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type~{"bindingType":"readonly-storage-buffer"} [ Failure ] crbug.com/1014735 wpt_internal/webgpu/cts.html?q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type~{"bindingType":"storage-texture"} [ Failure ] +crbug.com/1014735 wpt_internal/webgpu/cts.html?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type~{"bindingType":"storage-texture"} [ Failure ] crbug.com/1014735 wpt_internal/webgpu/cts.html?q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"uniform-buffer","resourceType":"storage-texture"} [ Failure ] +crbug.com/1014735 wpt_internal/webgpu/cts.html?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"uniform-buffer","resourceType":"storage-texture"} [ Failure ] crbug.com/1014735 wpt_internal/webgpu/cts.html?q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"storage-buffer","resourceType":"storage-texture"} [ Failure ] +crbug.com/1014735 wpt_internal/webgpu/cts.html?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"storage-buffer","resourceType":"storage-texture"} [ Failure ] crbug.com/1014735 wpt_internal/webgpu/cts.html?q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"sampler","resourceType":"storage-texture"} [ Failure ] +crbug.com/1014735 wpt_internal/webgpu/cts.html?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"sampler","resourceType":"storage-texture"} [ Failure ] crbug.com/1014735 wpt_internal/webgpu/cts.html?q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"sampled-texture","resourceType":"storage-texture"} [ Failure ] +crbug.com/1014735 wpt_internal/webgpu/cts.html?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"sampled-texture","resourceType":"storage-texture"} [ Failure ] crbug.com/1014735 wpt_internal/webgpu/cts.html?q=cts:validation/createBindGroup:texture_binding_must_have_correct_usage={"type":"storage-texture"} [ Failure ] +crbug.com/1014735 wpt_internal/webgpu/cts.html?worker=1&q=cts:validation/createBindGroup:texture_binding_must_have_correct_usage={"type":"storage-texture"} [ Failure ] crbug.com/1014734 wpt_internal/webgpu/cts.html?q=cts:validation/createBindGroupLayout:dynamic_set_to_true_is_allowed_only_for_buffers={"type":"readonly-storage-buffer"} [ Failure ] +crbug.com/1014734 wpt_internal/webgpu/cts.html?worker=1&q=cts:validation/createBindGroupLayout:dynamic_set_to_true_is_allowed_only_for_buffers={"type":"readonly-storage-buffer"} [ Failure ] crbug.com/dawn/243 wpt_internal/webgpu/cts.html?q=cts:validation/createTexture:validation_of_sampleCount={"sampleCount":4,"arrayLayerCount":2} [ Failure ] +crbug.com/dawn/243 wpt_internal/webgpu/cts.html?worker=1&q=cts:validation/createTexture:validation_of_sampleCount={"sampleCount":4,"arrayLayerCount":2} [ Failure ] crbug.com/1014750 wpt_internal/webgpu/cts.html?q=cts:validation/createView:it_is_invalid_to_use_a_texture_view_created_from_a_destroyed_texture= [ Failure ] +crbug.com/1014750 wpt_internal/webgpu/cts.html?worker=1&q=cts:validation/createView:it_is_invalid_to_use_a_texture_view_created_from_a_destroyed_texture= [ Failure ] # # Mac (Metal) specific # crbug.com/1014744 [ Mac ] wpt_internal/webgpu/cts.html?q=cts:command_buffer/render/storeop:storeOp_controls_whether_1x1_drawn_quad_is_stored={"storeOp":"clear"} [ Failure ] +crbug.com/1014744 [ Mac ] wpt_internal/webgpu/cts.html?worker=1&q=cts:command_buffer/render/storeop:storeOp_controls_whether_1x1_drawn_quad_is_stored={"storeOp":"clear"} [ Failure ] # # Linux (Vulkan) specific # crbug.com/1014740 [ Linux ] wpt_internal/webgpu/cts.html?q=cts:buffers/map_oom:mapWriteAsync= [ Failure ] +crbug.com/1014740 [ Linux ] wpt_internal/webgpu/cts.html?worker=1&q=cts:buffers/map_oom:mapWriteAsync= [ Failure ] crbug.com/1014740 [ Linux ] wpt_internal/webgpu/cts.html?q=cts:buffers/map_oom:mapReadAsync= [ Failure ] +crbug.com/1014740 [ Linux ] wpt_internal/webgpu/cts.html?worker=1&q=cts:buffers/map_oom:mapReadAsync= [ Failure ] # # Windows (D3D12) specific # crbug.com/1014738 [ Win ] wpt_internal/webgpu/cts.html?q=cts:buffers/map_oom:mapWriteAsync= [ Failure ] +crbug.com/1014738 [ Win ] wpt_internal/webgpu/cts.html?worker=1&q=cts:buffers/map_oom:mapWriteAsync= [ Failure ] crbug.com/1014738 [ Win ] wpt_internal/webgpu/cts.html?q=cts:buffers/map_oom:mapReadAsync= [ Failure ] +crbug.com/1014738 [ Win ] wpt_internal/webgpu/cts.html?worker=1&q=cts:buffers/map_oom:mapReadAsync= [ Failure ]
diff --git a/third_party/blink/web_tests/external/wpt/webgpu/cts.html b/third_party/blink/web_tests/external/wpt/webgpu/cts.html index b66553d..13d8b7c8 100644 --- a/third_party/blink/web_tests/external/wpt/webgpu/cts.html +++ b/third_party/blink/web_tests/external/wpt/webgpu/cts.html
@@ -39,6 +39,17 @@ width: 100%; height: 15em; } + +/* Test Name column */ +#results > tbody > tr > td:nth-child(2) { + word-break: break-word; +} + +/* Message column */ +#results > tbody > tr > td:nth-child(3) { + white-space: pre-wrap; + word-break: break-word; +} </style> <textarea id=results></textarea> @@ -74,4 +85,4 @@ <meta name=variant content='?q=cts:validation/setStencilReference:'> <meta name=variant content='?q=cts:validation/setVertexBuffer:'> <meta name=variant content='?q=cts:validation/setViewport:'> -<meta name=variant content='?q=cts:validation/vertex_input:'> +<meta name=variant content='?q=cts:validation/vertex_state:'>
diff --git a/third_party/blink/web_tests/external/wpt/webgpu/framework/fixture.js b/third_party/blink/web_tests/external/wpt/webgpu/framework/fixture.js index 12793122..d976fa46 100644 --- a/third_party/blink/web_tests/external/wpt/webgpu/framework/fixture.js +++ b/third_party/blink/web_tests/external/wpt/webgpu/framework/fixture.js
@@ -27,11 +27,7 @@ async init() {} debug(msg) { - this.rec.debug(msg); - } - - log(msg) { - this.rec.log(msg); + this.rec.debug(new Error(msg)); } skip(msg) { @@ -47,11 +43,11 @@ } warn(msg) { - this.rec.warn(msg); + this.rec.warn(new Error(msg)); } fail(msg) { - this.rec.fail(msg); + this.rec.fail(new Error(msg)); } async immediateAsyncExpectation(fn) { @@ -62,35 +58,40 @@ } eventualAsyncExpectation(fn) { - const promise = fn(); + const promise = fn(new Error()); this.eventualExpectations.push(promise); return promise; } - expectErrorValue(expectedName, ex, m) { + expectErrorValue(expectedName, ex, niceStack) { if (!(ex instanceof Error)) { - this.fail('THREW non-error value, of type ' + typeof ex); + niceStack.message = 'THREW non-error value, of type ' + typeof ex + niceStack.message; + this.rec.fail(niceStack); return; } const actualName = ex.name; if (actualName !== expectedName) { - this.fail(`THREW ${actualName}, instead of ${expectedName}${m}`); + niceStack.message = `THREW ${actualName}, instead of ${expectedName}` + niceStack.message; + this.rec.fail(niceStack); } else { - this.debug(`OK: threw ${actualName}${m}`); + niceStack.message = 'OK: threw ' + actualName + niceStack.message; + this.rec.debug(niceStack); } } shouldReject(expectedName, p, msg) { - this.eventualAsyncExpectation(async () => { + this.eventualAsyncExpectation(async niceStack => { const m = msg ? ': ' + msg : ''; try { await p; - this.fail('DID NOT THROW' + m); + niceStack.message = 'DID NOT THROW' + m; + this.rec.fail(niceStack); } catch (ex) { - this.expectErrorValue(expectedName, ex, m); + niceStack.message = m; + this.expectErrorValue(expectedName, ex, niceStack); } }); } @@ -100,18 +101,18 @@ try { fn(); - this.fail('DID NOT THROW' + m); + this.rec.fail(new Error('DID NOT THROW' + m)); } catch (ex) { - this.expectErrorValue(expectedName, ex, m); + this.expectErrorValue(expectedName, ex, new Error(m)); } } expect(cond, msg) { if (cond) { const m = msg ? ': ' + msg : ''; - this.debug('expect OK' + m); + this.rec.debug(new Error('expect OK' + m)); } else { - this.rec.fail(msg); + this.rec.fail(new Error(msg)); } return cond;
diff --git a/third_party/blink/web_tests/external/wpt/webgpu/framework/logger.js b/third_party/blink/web_tests/external/wpt/webgpu/framework/logger.js index ee869196..5536e736 100644 --- a/third_party/blink/web_tests/external/wpt/webgpu/framework/logger.js +++ b/third_party/blink/web_tests/external/wpt/webgpu/framework/logger.js
@@ -9,6 +9,34 @@ import { extractPublicParams } from './url_query.js'; import { getStackTrace, now } from './util/index.js'; import { version } from './version.js'; + +class LogMessageWithStack extends Error { + constructor(name, ex) { + super(ex.message); + this.name = name; + this.stack = ex.stack; + } + + toJSON() { + let m = this.name; + + if (this.message) { + m += ': ' + this.message; + } + + m += '\n' + getStackTrace(this); + return m; + } + +} + +class LogMessageWithoutStack extends LogMessageWithStack { + toJSON() { + return this.message; + } + +} + export class Logger { constructor() { _defineProperty(this, "results", []); @@ -94,46 +122,27 @@ this.debugging = false; } - debug(msg) { + debug(ex) { if (!this.debugging) { return; } - this.log('DEBUG: ' + msg); + this.logs.push(new LogMessageWithoutStack('DEBUG', ex)); } - log(msg) { - this.logs.push(msg); - } - - warn(msg) { + warn(ex) { this.setState(PassState.warn); - let m = 'WARN'; - - if (msg) { - m += ': ' + msg; - } - - m += ' ' + getStackTrace(new Error()); - this.log(m); + this.logs.push(new LogMessageWithStack('WARN', ex)); } - fail(msg) { + fail(ex) { this.setState(PassState.fail); - let m = 'FAIL'; - - if (msg) { - m += ': ' + msg; - } - - m += '\n' + getStackTrace(new Error()); - this.log(m); + this.logs.push(new LogMessageWithStack('FAIL', ex)); } skipped(ex) { this.setState(PassState.skip); - const m = 'SKIPPED: ' + getStackTrace(ex); - this.log(m); + this.logs.push(new LogMessageWithStack('SKIP', ex)); } threw(ex) { @@ -143,7 +152,7 @@ } this.setState(PassState.fail); - this.log('EXCEPTION: ' + ex.name + ':\n' + ex.message + '\n' + getStackTrace(ex)); + this.logs.push(new LogMessageWithStack('EXCEPTION', ex)); } setState(state) {
diff --git a/third_party/blink/web_tests/external/wpt/webgpu/framework/version.js b/third_party/blink/web_tests/external/wpt/webgpu/framework/version.js index 154f062..e2c91190 100644 --- a/third_party/blink/web_tests/external/wpt/webgpu/framework/version.js +++ b/third_party/blink/web_tests/external/wpt/webgpu/framework/version.js
@@ -1,3 +1,3 @@ // AUTO-GENERATED - DO NOT EDIT. See tools/gen_version. -export const version = '3dc37c83a70667e9a92df773f34d154ec600d203'; +export const version = 'e114192747a54f34157eb65754e037701fbdf98b';
diff --git a/third_party/blink/web_tests/external/wpt/webgpu/runtime/wpt.js b/third_party/blink/web_tests/external/wpt/webgpu/runtime/wpt.js index e078f67..fd02f09 100644 --- a/third_party/blink/web_tests/external/wpt/webgpu/runtime/wpt.js +++ b/third_party/blink/web_tests/external/wpt/webgpu/runtime/wpt.js
@@ -41,7 +41,7 @@ this.step(() => { // Unfortunately, it seems not possible to surface any logs for warn/skip. if (r.status === 'fail') { - throw (r.logs || []).join('\n'); + throw (r.logs || []).map(s => s.toJSON()).join('\n\n'); } }); this.done();
diff --git a/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/command_buffer/render/rendering.spec.js b/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/command_buffer/render/rendering.spec.js index 43c4566..54c627d 100644 --- a/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/command_buffer/render/rendering.spec.js +++ b/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/command_buffer/render/rendering.spec.js
@@ -73,7 +73,7 @@ alphaBlend: {}, colorBlend: {} }], - vertexInput: { + vertexState: { indexFormat: 'uint16', vertexBuffers: [] }
diff --git a/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/gpu_test.js b/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/gpu_test.js index 272b1b8..a324e88 100644 --- a/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/gpu_test.js +++ b/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/gpu_test.js
@@ -112,41 +112,61 @@ const c = this.device.createCommandEncoder(); c.copyBufferToBuffer(src, 0, dst, 0, size); this.queue.submit([c.finish()]); - this.eventualAsyncExpectation(async () => { + this.eventualAsyncExpectation(async niceStack => { const actual = new Uint8Array((await dst.mapReadAsync())); - this.expectBuffer(actual, exp); + const check = this.checkBuffer(actual, exp); + + if (check !== undefined) { + niceStack.message = check; + this.rec.fail(niceStack); + } + dst.destroy(); }); } expectBuffer(actual, exp) { + const check = this.checkBuffer(actual, exp); + + if (check !== undefined) { + this.rec.fail(new Error(check)); + } + } + + checkBuffer(actual, exp) { const size = exp.byteLength; if (actual.byteLength !== size) { - this.rec.fail('size mismatch'); - return; + return 'size mismatch'; } + const lines = []; let failedPixels = 0; for (let i = 0; i < size; ++i) { if (actual[i] !== exp[i]) { if (failedPixels > 4) { - this.rec.fail('... and more'); + lines.push('... and more'); break; } failedPixels++; - this.rec.fail(`at [${i}], expected ${exp[i]}, got ${actual[i]}`); + lines.push(`at [${i}], expected ${exp[i]}, got ${actual[i]}`); } } if (size <= 256 && failedPixels > 0) { const expHex = Array.from(exp).map(x => x.toString(16).padStart(2, '0')).join(''); const actHex = Array.from(actual).map(x => x.toString(16).padStart(2, '0')).join(''); - this.rec.log('EXPECT: ' + expHex); - this.rec.log('ACTUAL: ' + actHex); + lines.push('EXPECT: ' + expHex); + lines.push('ACTUAL: ' + actHex); } + + if (failedPixels) { + return lines.join('\n'); + } + + return undefined; } }
diff --git a/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/index.js b/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/index.js index 33934cdd..d38bcc5 100644 --- a/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/index.js +++ b/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/index.js
@@ -130,7 +130,7 @@ "description": "setViewport validation tests." }, { - "path": "validation/vertex_input", - "description": "vertexInput validation tests." + "path": "validation/vertex_state", + "description": "vertexState validation tests." } ];
diff --git a/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/validation/setVertexBuffer.spec.js b/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/validation/setVertexBuffer.spec.js index 0f47e73..ba22ee2d 100644 --- a/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/validation/setVertexBuffer.spec.js +++ b/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/validation/setVertexBuffer.spec.js
@@ -29,11 +29,12 @@ colorStates: [{ format: 'rgba8unorm' }], - vertexInput: { + vertexState: { vertexBuffers: [{ - stride: 3 * 4, - attributeSet: range(bufferCount, i => ({ + arrayStride: 3 * 4, + attributes: range(bufferCount, i => ({ format: 'float3', + offset: 0, shaderLocation: i })) }]
diff --git a/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/validation/validation_test.js b/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/validation/validation_test.js index 099b820..dc5488e 100644 --- a/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/validation/validation_test.js +++ b/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/validation/validation_test.js
@@ -25,13 +25,15 @@ this.device.pushErrorScope('validation'); fn(); const promise = this.device.popErrorScope(); - this.eventualAsyncExpectation(async () => { + this.eventualAsyncExpectation(async niceStack => { const gpuValidationError = await promise; if (!gpuValidationError) { - this.fail('Validation error was expected.'); + niceStack.message = 'Validation error was expected.'; + this.rec.fail(niceStack); } else if (gpuValidationError instanceof GPUValidationError) { - this.debug(`Captured validation error - ${gpuValidationError.message}`); + niceStack.message = `Captured validation error - ${gpuValidationError.message}`; + this.rec.debug(niceStack); } }); }
diff --git a/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/validation/vertex_input.spec.js b/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/validation/vertex_input.spec.js deleted file mode 100644 index c5978025..0000000 --- a/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/validation/vertex_input.spec.js +++ /dev/null
@@ -1,623 +0,0 @@ -/** -* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts -**/ - -export const description = ` -vertexInput validation tests. -`; -import { TestGroup } from '../../../framework/index.js'; -import { ValidationTest } from './validation_test.js'; -const MAX_VERTEX_ATTRIBUTES = 16; -const MAX_VERTEX_BUFFER_END = 2048; -const MAX_VERTEX_BUFFER_STRIDE = 2048; -const MAX_VERTEX_BUFFERS = 16; -const VERTEX_SHADER_CODE_WITH_NO_INPUT = ` - #version 450 - void main() { - gl_Position = vec4(0.0); - } -`; - -function clone(descriptor) { - return JSON.parse(JSON.stringify(descriptor)); -} - -class F extends ValidationTest { - async init() { - await Promise.all([super.init(), this.initGLSL()]); - } - - getDescriptor(vertexInput, vertexShaderCode) { - const descriptor = { - vertexStage: this.getVertexStage(vertexShaderCode), - fragmentStage: this.getFragmentStage(), - layout: this.getPipelineLayout(), - primitiveTopology: 'triangle-list', - colorStates: [{ - format: 'rgba8unorm' - }], - vertexInput - }; - return descriptor; - } - - getVertexStage(code) { - return { - module: this.makeShaderModuleFromGLSL('vertex', code), - entryPoint: 'main' - }; - } - - getFragmentStage() { - const code = ` - #version 450 - layout(location = 0) out vec4 fragColor; - void main() { - fragColor = vec4(0.0, 1.0, 0.0, 1.0); - } - `; - return { - module: this.makeShaderModuleFromGLSL('fragment', code), - entryPoint: 'main' - }; - } - - getPipelineLayout() { - return this.device.createPipelineLayout({ - bindGroupLayouts: [] - }); - } - -} - -export const g = new TestGroup(F); -g.test('an empty vertex input is valid', t => { - const vertexInput = {}; - const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); -}); -g.test('a null buffer is valid', t => { - { - // One null buffer is OK - const vertexInput = { - vertexBuffers: [{ - stride: 0, - attributeSet: [] - }] - }; - const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } - { - // One null buffer followed by a buffer is OK - const vertexInput = { - vertexBuffers: [{ - stride: 0, - attributeSet: [] - }, { - stride: 0, - attributeSet: [{ - shaderLocation: 0, - format: 'float' - }] - }] - }; - const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } - { - // One null buffer sitting between buffers is OK - const vertexInput = { - vertexBuffers: [{ - stride: 0, - attributeSet: [{ - shaderLocation: 0, - format: 'float' - }] - }, { - stride: 0, - attributeSet: [] - }, { - stride: 0, - attributeSet: [{ - shaderLocation: 1, - format: 'float' - }] - }] - }; - const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } -}); -g.test('pipeline vertex buffers are backed by attributes in vertex input', async t => { - const vertexInput = { - vertexBuffers: [{ - stride: 2 * Float32Array.BYTES_PER_ELEMENT, - attributeSet: [{ - shaderLocation: 0, - format: 'float' - }, { - shaderLocation: 1, - format: 'float' - }] - }] - }; - { - // Control case: pipeline with one input per attribute - const code = ` - #version 450 - layout(location = 0) in vec4 a; - layout(location = 1) in vec4 b; - void main() { - gl_Position = vec4(0.0); - } - `; - const descriptor = t.getDescriptor(vertexInput, code); - t.device.createRenderPipeline(descriptor); - } - { - // Check it is valid for the pipeline to use a subset of the VertexInput - const code = ` - #version 450 - layout(location = 0) in vec4 a; - void main() { - gl_Position = vec4(0.0); - } - `; - const descriptor = t.getDescriptor(vertexInput, code); - t.device.createRenderPipeline(descriptor); - } - { - // Check for an error when the pipeline uses an attribute not in the vertex input - const code = ` - #version 450 - layout(location = 2) in vec4 a; - void main() { - gl_Position = vec4(0.0); - } - `; - const descriptor = t.getDescriptor(vertexInput, code); - t.expectValidationError(() => { - t.device.createRenderPipeline(descriptor); - }); - } -}); -g.test('a stride of 0 is valid', t => { - const vertexInput = { - vertexBuffers: [{ - stride: 0, - attributeSet: [{ - shaderLocation: 0, - format: 'float' - }] - }] - }; - { - // Works ok without attributes - const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } - { - // Works ok with attributes at a large-ish offset - vertexInput.vertexBuffers[0].attributeSet[0].offset = 128; - const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } -}); -g.test('offset should be within vertex buffer stride if stride is not zero', async t => { - const vertexInput = { - vertexBuffers: [{ - stride: 2 * Float32Array.BYTES_PER_ELEMENT, - attributeSet: [{ - shaderLocation: 0, - format: 'float' - }, { - offset: Float32Array.BYTES_PER_ELEMENT, - shaderLocation: 1, - format: 'float' - }] - }] - }; - { - // Control case, setting correct stride and offset - const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } - { - // Test vertex attribute offset exceed vertex buffer stride range - const badVertexInput = clone(vertexInput); - badVertexInput.vertexBuffers[0].attributeSet[1].format = 'float2'; - const descriptor = t.getDescriptor(badVertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.expectValidationError(() => { - t.device.createRenderPipeline(descriptor); - }); - } - { - // Test vertex attribute offset exceed vertex buffer stride range - const badVertexInput = clone(vertexInput); - badVertexInput.vertexBuffers[0].stride = Float32Array.BYTES_PER_ELEMENT; - const descriptor = t.getDescriptor(badVertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.expectValidationError(() => { - t.device.createRenderPipeline(descriptor); - }); - } - { - // It's OK if stride is zero - const goodVertexInput = clone(vertexInput); - goodVertexInput.vertexBuffers[0].stride = 0; - const descriptor = t.getDescriptor(goodVertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } -}); -g.test('check two attributes overlapping', async t => { - const vertexInput = { - vertexBuffers: [{ - stride: 2 * Float32Array.BYTES_PER_ELEMENT, - attributeSet: [{ - shaderLocation: 0, - format: 'float' - }, { - offset: Float32Array.BYTES_PER_ELEMENT, - shaderLocation: 1, - format: 'float' - }] - }] - }; - { - // Control case, setting correct stride and offset - const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } - { - // Test two attributes overlapping - const badVertexInput = clone(vertexInput); - badVertexInput.vertexBuffers[0].attributeSet[0].format = 'int2'; - const descriptor = t.getDescriptor(badVertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.expectValidationError(() => { - t.device.createRenderPipeline(descriptor); - }); - } -}); -g.test('check out of bounds condition on total number of vertex buffers', async t => { - const vertexBuffers = []; - - for (let i = 0; i < MAX_VERTEX_BUFFERS; i++) { - vertexBuffers.push({ - stride: 0, - attributeSet: [{ - shaderLocation: i, - format: 'float' - }] - }); - } - - { - // Control case, setting max vertex buffer number - const vertexInput = { - vertexBuffers - }; - const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } - { - // Test vertex buffer number exceed the limit - const vertexInput = { - vertexBuffers: [...vertexBuffers, { - stride: 0, - attributeSet: [{ - shaderLocation: MAX_VERTEX_BUFFERS, - format: 'float' - }] - }] - }; - const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.expectValidationError(() => { - t.device.createRenderPipeline(descriptor); - }); - } -}); -g.test('check out of bounds on number of vertex attributes on a single vertex buffer', async t => { - const vertexAttributes = []; - - for (let i = 0; i < MAX_VERTEX_ATTRIBUTES; i++) { - vertexAttributes.push({ - shaderLocation: i, - format: 'float' - }); - } - - { - // Control case, setting max vertex buffer number - const vertexInput = { - vertexBuffers: [{ - stride: 0, - attributeSet: vertexAttributes - }] - }; - const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } - { - // Test vertex attribute number exceed the limit - const vertexInput = { - vertexBuffers: [{ - stride: 0, - attributeSet: [...vertexAttributes, { - shaderLocation: MAX_VERTEX_ATTRIBUTES, - format: 'float' - }] - }] - }; - const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.expectValidationError(() => { - t.device.createRenderPipeline(descriptor); - }); - } -}); -g.test('check out of bounds on number of vertex attributes across vertex buffers', async t => { - const vertexBuffers = []; - - for (let i = 0; i < MAX_VERTEX_ATTRIBUTES; i++) { - vertexBuffers.push({ - stride: 0, - attributeSet: [{ - shaderLocation: i, - format: 'float' - }] - }); - } - - { - // Control case, setting max vertex buffer number - const vertexInput = { - vertexBuffers - }; - const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } - { - // Test vertex attribute number exceed the limit - vertexBuffers[MAX_VERTEX_ATTRIBUTES - 1].attributeSet.push({ - shaderLocation: MAX_VERTEX_ATTRIBUTES, - format: 'float' - }); - const vertexInput = { - vertexBuffers - }; - const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.expectValidationError(() => { - t.device.createRenderPipeline(descriptor); - }); - } -}); -g.test('check out of bounds condition on input strides', async t => { - const vertexInput = { - vertexBuffers: [{ - stride: MAX_VERTEX_BUFFER_STRIDE, - attributeSet: [] - }] - }; - { - // Control case, setting max input stride - const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } - { - // Test input stride OOB - vertexInput.vertexBuffers[0].stride = MAX_VERTEX_BUFFER_STRIDE + 4; - const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.expectValidationError(() => { - t.device.createRenderPipeline(descriptor); - }); - } -}); -g.test('check multiple of 4 bytes constraint on input stride', async t => { - const vertexInput = { - vertexBuffers: [{ - stride: 4, - attributeSet: [{ - shaderLocation: 0, - format: 'uchar2' - }] - }] - }; - { - // Control case, setting input stride 4 bytes - const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } - { - // Test input stride not multiple of 4 bytes - vertexInput.vertexBuffers[0].stride = 2; - const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.expectValidationError(() => { - t.device.createRenderPipeline(descriptor); - }); - } -}); -g.test('identical duplicate attributes are invalid', async t => { - const vertexInput = { - vertexBuffers: [{ - stride: 0, - attributeSet: [{ - shaderLocation: 0, - format: 'float' - }] - }] - }; - { - // Control case, setting attribute 0 - const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } - { - // Oh no, attribute 0 is set twice - vertexInput.vertexBuffers[0].attributeSet.push({ - shaderLocation: 0, - format: 'float' - }); - const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.expectValidationError(() => { - t.device.createRenderPipeline(descriptor); - }); - } -}); -g.test('we cannot set same shader location', async t => { - { - const vertexInput = { - vertexBuffers: [{ - stride: 0, - attributeSet: [{ - shaderLocation: 0, - format: 'float' - }, { - offset: Float32Array.BYTES_PER_ELEMENT, - shaderLocation: 1, - format: 'float' - }] - }] - }; - { - // Control case, setting different shader locations in two attributes - const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } - { - // Test same shader location in two attributes in the same buffer - vertexInput.vertexBuffers[0].attributeSet[1].shaderLocation = 0; - const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.expectValidationError(() => { - t.device.createRenderPipeline(descriptor); - }); - } - } - { - const vertexInput = { - vertexBuffers: [{ - stride: 0, - attributeSet: [{ - shaderLocation: 0, - format: 'float' - }] - }, { - stride: 0, - attributeSet: [{ - shaderLocation: 0, - format: 'float' - }] - }] - }; // Test same shader location in two attributes in different buffers - - const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.expectValidationError(() => { - t.device.createRenderPipeline(descriptor); - }); - } -}); -g.test('check out of bounds condition on attribute shader location', async t => { - const vertexInput = { - vertexBuffers: [{ - stride: 0, - attributeSet: [{ - shaderLocation: MAX_VERTEX_ATTRIBUTES - 1, - format: 'float' - }] - }] - }; - { - // Control case, setting last attribute shader location - const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } - { - // Test attribute location OOB - vertexInput.vertexBuffers[0].attributeSet[0].shaderLocation = MAX_VERTEX_ATTRIBUTES; - const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.expectValidationError(() => { - t.device.createRenderPipeline(descriptor); - }); - } -}); -g.test('check attribute offset out of bounds', async t => { - const vertexInput = { - vertexBuffers: [{ - stride: 0, - attributeSet: [{ - offset: MAX_VERTEX_BUFFER_END - 2 * Float32Array.BYTES_PER_ELEMENT, - shaderLocation: 0, - format: 'float2' - }] - }] - }; - { - // Control case, setting max attribute offset to MAX_VERTEX_BUFFER_END - 8 - const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } - { - // Control case, setting attribute offset to 8 - vertexInput.vertexBuffers[0].attributeSet[0].offset = 8; - const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } - { - // Test attribute offset out of bounds - vertexInput.vertexBuffers[0].attributeSet[0].offset = MAX_VERTEX_BUFFER_END - 4; - const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.expectValidationError(() => { - t.device.createRenderPipeline(descriptor); - }); - } -}); -g.test('check multiple of 4 bytes constraint on offset', async t => { - const vertexInput = { - vertexBuffers: [{ - stride: 0, - attributeSet: [{ - offset: Float32Array.BYTES_PER_ELEMENT, - shaderLocation: 0, - format: 'float' - }] - }] - }; - { - // Control case, setting offset 4 bytes - const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.device.createRenderPipeline(descriptor); - } - { - // Test offset of 2 bytes with uchar2 format - vertexInput.vertexBuffers[0].attributeSet[0].offset = 2; - vertexInput.vertexBuffers[0].attributeSet[0].format = 'uchar2'; - const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.expectValidationError(() => { - t.device.createRenderPipeline(descriptor); - }); - } - { - // Test offset of 2 bytes with float format - vertexInput.vertexBuffers[0].attributeSet[0].offset = 2; - vertexInput.vertexBuffers[0].attributeSet[0].format = 'float'; - const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.expectValidationError(() => { - t.device.createRenderPipeline(descriptor); - }); - } -}); -g.test('check attribute offset overflow', async t => { - const vertexInput = { - vertexBuffers: [{ - stride: 0, - attributeSet: [{ - offset: Number.MAX_SAFE_INTEGER, - shaderLocation: 0, - format: 'float' - }] - }] - }; - const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); - t.expectValidationError(() => { - t.device.createRenderPipeline(descriptor); - }); -}); -//# sourceMappingURL=vertex_input.spec.js.map \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/validation/vertex_state.spec.js b/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/validation/vertex_state.spec.js new file mode 100644 index 0000000..da619181 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/validation/vertex_state.spec.js
@@ -0,0 +1,644 @@ +/** +* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts +**/ + +export const description = ` +vertexState validation tests. +`; +import { TestGroup } from '../../../framework/index.js'; +import { ValidationTest } from './validation_test.js'; +const MAX_VERTEX_ATTRIBUTES = 16; +const MAX_VERTEX_BUFFER_END = 2048; +const MAX_VERTEX_BUFFER_ARRAY_STRIDE = 2048; +const MAX_VERTEX_BUFFERS = 16; +const VERTEX_SHADER_CODE_WITH_NO_INPUT = ` + #version 450 + void main() { + gl_Position = vec4(0.0); + } +`; + +function clone(descriptor) { + return JSON.parse(JSON.stringify(descriptor)); +} + +class F extends ValidationTest { + async init() { + await Promise.all([super.init(), this.initGLSL()]); + } + + getDescriptor(vertexState, vertexShaderCode) { + const descriptor = { + vertexStage: this.getVertexStage(vertexShaderCode), + fragmentStage: this.getFragmentStage(), + layout: this.getPipelineLayout(), + primitiveTopology: 'triangle-list', + colorStates: [{ + format: 'rgba8unorm' + }], + vertexState + }; + return descriptor; + } + + getVertexStage(code) { + return { + module: this.makeShaderModuleFromGLSL('vertex', code), + entryPoint: 'main' + }; + } + + getFragmentStage() { + const code = ` + #version 450 + layout(location = 0) out vec4 fragColor; + void main() { + fragColor = vec4(0.0, 1.0, 0.0, 1.0); + } + `; + return { + module: this.makeShaderModuleFromGLSL('fragment', code), + entryPoint: 'main' + }; + } + + getPipelineLayout() { + return this.device.createPipelineLayout({ + bindGroupLayouts: [] + }); + } + +} + +export const g = new TestGroup(F); +g.test('an empty vertex input is valid', t => { + const vertexState = {}; + const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); +}); +g.test('a null buffer is valid', t => { + { + // One null buffer is OK + const vertexState = { + vertexBuffers: [{ + arrayStride: 0, + attributes: [] + }] + }; + const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } + { + // One null buffer followed by a buffer is OK + const vertexState = { + vertexBuffers: [{ + arrayStride: 0, + attributes: [] + }, { + arrayStride: 0, + attributes: [{ + format: 'float', + offset: 0, + shaderLocation: 0 + }] + }] + }; + const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } + { + // One null buffer sitting between buffers is OK + const vertexState = { + vertexBuffers: [{ + arrayStride: 0, + attributes: [{ + format: 'float', + offset: 0, + shaderLocation: 0 + }] + }, { + arrayStride: 0, + attributes: [] + }, { + arrayStride: 0, + attributes: [{ + format: 'float', + offset: 0, + shaderLocation: 1 + }] + }] + }; + const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } +}); +g.test('pipeline vertex buffers are backed by attributes in vertex input', async t => { + const vertexState = { + vertexBuffers: [{ + arrayStride: 2 * Float32Array.BYTES_PER_ELEMENT, + attributes: [{ + format: 'float', + offset: 0, + shaderLocation: 0 + }, { + format: 'float', + offset: 0, + shaderLocation: 1 + }] + }] + }; + { + // Control case: pipeline with one input per attribute + const code = ` + #version 450 + layout(location = 0) in vec4 a; + layout(location = 1) in vec4 b; + void main() { + gl_Position = vec4(0.0); + } + `; + const descriptor = t.getDescriptor(vertexState, code); + t.device.createRenderPipeline(descriptor); + } + { + // Check it is valid for the pipeline to use a subset of the VertexState + const code = ` + #version 450 + layout(location = 0) in vec4 a; + void main() { + gl_Position = vec4(0.0); + } + `; + const descriptor = t.getDescriptor(vertexState, code); + t.device.createRenderPipeline(descriptor); + } + { + // Check for an error when the pipeline uses an attribute not in the vertex input + const code = ` + #version 450 + layout(location = 2) in vec4 a; + void main() { + gl_Position = vec4(0.0); + } + `; + const descriptor = t.getDescriptor(vertexState, code); + t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } +}); +g.test('an arrayStride of 0 is valid', t => { + const vertexState = { + vertexBuffers: [{ + arrayStride: 0, + attributes: [{ + format: 'float', + offset: 0, + shaderLocation: 0 + }] + }] + }; + { + // Works ok without attributes + const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } + { + // Works ok with attributes at a large-ish offset + vertexState.vertexBuffers[0].attributes[0].offset = 128; + const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } +}); +g.test('offset should be within vertex buffer arrayStride if arrayStride is not zero', async t => { + const vertexState = { + vertexBuffers: [{ + arrayStride: 2 * Float32Array.BYTES_PER_ELEMENT, + attributes: [{ + format: 'float', + offset: 0, + shaderLocation: 0 + }, { + format: 'float', + offset: Float32Array.BYTES_PER_ELEMENT, + shaderLocation: 1 + }] + }] + }; + { + // Control case, setting correct arrayStride and offset + const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } + { + // Test vertex attribute offset exceed vertex buffer arrayStride range + const badVertexState = clone(vertexState); + badVertexState.vertexBuffers[0].attributes[1].format = 'float2'; + const descriptor = t.getDescriptor(badVertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } + { + // Test vertex attribute offset exceed vertex buffer arrayStride range + const badVertexState = clone(vertexState); + badVertexState.vertexBuffers[0].arrayStride = Float32Array.BYTES_PER_ELEMENT; + const descriptor = t.getDescriptor(badVertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } + { + // It's OK if arrayStride is zero + const goodVertexState = clone(vertexState); + goodVertexState.vertexBuffers[0].arrayStride = 0; + const descriptor = t.getDescriptor(goodVertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } +}); +g.test('check two attributes overlapping', async t => { + const vertexState = { + vertexBuffers: [{ + arrayStride: 2 * Float32Array.BYTES_PER_ELEMENT, + attributes: [{ + format: 'float', + offset: 0, + shaderLocation: 0 + }, { + format: 'float', + offset: Float32Array.BYTES_PER_ELEMENT, + shaderLocation: 1 + }] + }] + }; + { + // Control case, setting correct arrayStride and offset + const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } + { + // Test two attributes overlapping + const badVertexState = clone(vertexState); + badVertexState.vertexBuffers[0].attributes[0].format = 'int2'; + const descriptor = t.getDescriptor(badVertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } +}); +g.test('check out of bounds condition on total number of vertex buffers', async t => { + const vertexBuffers = []; + + for (let i = 0; i < MAX_VERTEX_BUFFERS; i++) { + vertexBuffers.push({ + arrayStride: 0, + attributes: [{ + format: 'float', + offset: 0, + shaderLocation: i + }] + }); + } + + { + // Control case, setting max vertex buffer number + const vertexState = { + vertexBuffers + }; + const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } + { + // Test vertex buffer number exceed the limit + const vertexState = { + vertexBuffers: [...vertexBuffers, { + arrayStride: 0, + attributes: [{ + format: 'float', + offset: 0, + shaderLocation: MAX_VERTEX_BUFFERS + }] + }] + }; + const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } +}); +g.test('check out of bounds on number of vertex attributes on a single vertex buffer', async t => { + const vertexAttributes = []; + + for (let i = 0; i < MAX_VERTEX_ATTRIBUTES; i++) { + vertexAttributes.push({ + format: 'float', + offset: 0, + shaderLocation: i + }); + } + + { + // Control case, setting max vertex buffer number + const vertexState = { + vertexBuffers: [{ + arrayStride: 0, + attributes: vertexAttributes + }] + }; + const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } + { + // Test vertex attribute number exceed the limit + const vertexState = { + vertexBuffers: [{ + arrayStride: 0, + attributes: [...vertexAttributes, { + format: 'float', + offset: 0, + shaderLocation: MAX_VERTEX_ATTRIBUTES + }] + }] + }; + const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } +}); +g.test('check out of bounds on number of vertex attributes across vertex buffers', async t => { + const vertexBuffers = []; + + for (let i = 0; i < MAX_VERTEX_ATTRIBUTES; i++) { + vertexBuffers.push({ + arrayStride: 0, + attributes: [{ + format: 'float', + offset: 0, + shaderLocation: i + }] + }); + } + + { + // Control case, setting max vertex buffer number + const vertexState = { + vertexBuffers + }; + const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } + { + // Test vertex attribute number exceed the limit + vertexBuffers[MAX_VERTEX_ATTRIBUTES - 1].attributes.push({ + format: 'float', + offset: 0, + shaderLocation: MAX_VERTEX_ATTRIBUTES + }); + const vertexState = { + vertexBuffers + }; + const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } +}); +g.test('check out of bounds condition on input strides', async t => { + const vertexState = { + vertexBuffers: [{ + arrayStride: MAX_VERTEX_BUFFER_ARRAY_STRIDE, + attributes: [] + }] + }; + { + // Control case, setting max input arrayStride + const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } + { + // Test input arrayStride OOB + vertexState.vertexBuffers[0].arrayStride = MAX_VERTEX_BUFFER_ARRAY_STRIDE + 4; + const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } +}); +g.test('check multiple of 4 bytes constraint on input arrayStride', async t => { + const vertexState = { + vertexBuffers: [{ + arrayStride: 4, + attributes: [{ + format: 'uchar2', + offset: 0, + shaderLocation: 0 + }] + }] + }; + { + // Control case, setting input arrayStride 4 bytes + const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } + { + // Test input arrayStride not multiple of 4 bytes + vertexState.vertexBuffers[0].arrayStride = 2; + const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } +}); +g.test('identical duplicate attributes are invalid', async t => { + const vertexState = { + vertexBuffers: [{ + arrayStride: 0, + attributes: [{ + format: 'float', + offset: 0, + shaderLocation: 0 + }] + }] + }; + { + // Control case, setting attribute 0 + const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } + { + // Oh no, attribute 0 is set twice + vertexState.vertexBuffers[0].attributes.push({ + format: 'float', + offset: 0, + shaderLocation: 0 + }); + const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } +}); +g.test('we cannot set same shader location', async t => { + { + const vertexState = { + vertexBuffers: [{ + arrayStride: 0, + attributes: [{ + format: 'float', + offset: 0, + shaderLocation: 0 + }, { + format: 'float', + offset: Float32Array.BYTES_PER_ELEMENT, + shaderLocation: 1 + }] + }] + }; + { + // Control case, setting different shader locations in two attributes + const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } + { + // Test same shader location in two attributes in the same buffer + vertexState.vertexBuffers[0].attributes[1].shaderLocation = 0; + const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } + } + { + const vertexState = { + vertexBuffers: [{ + arrayStride: 0, + attributes: [{ + format: 'float', + offset: 0, + shaderLocation: 0 + }] + }, { + arrayStride: 0, + attributes: [{ + format: 'float', + offset: 0, + shaderLocation: 0 + }] + }] + }; // Test same shader location in two attributes in different buffers + + const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } +}); +g.test('check out of bounds condition on attribute shader location', async t => { + const vertexState = { + vertexBuffers: [{ + arrayStride: 0, + attributes: [{ + format: 'float', + offset: 0, + shaderLocation: MAX_VERTEX_ATTRIBUTES - 1 + }] + }] + }; + { + // Control case, setting last attribute shader location + const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } + { + // Test attribute location OOB + vertexState.vertexBuffers[0].attributes[0].shaderLocation = MAX_VERTEX_ATTRIBUTES; + const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } +}); +g.test('check attribute offset out of bounds', async t => { + const vertexState = { + vertexBuffers: [{ + arrayStride: 0, + attributes: [{ + format: 'float2', + offset: MAX_VERTEX_BUFFER_END - 2 * Float32Array.BYTES_PER_ELEMENT, + shaderLocation: 0 + }] + }] + }; + { + // Control case, setting max attribute offset to MAX_VERTEX_BUFFER_END - 8 + const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } + { + // Control case, setting attribute offset to 8 + vertexState.vertexBuffers[0].attributes[0].offset = 8; + const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } + { + // Test attribute offset out of bounds + vertexState.vertexBuffers[0].attributes[0].offset = MAX_VERTEX_BUFFER_END - 4; + const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } +}); +g.test('check multiple of 4 bytes constraint on offset', async t => { + const vertexState = { + vertexBuffers: [{ + arrayStride: 0, + attributes: [{ + format: 'float', + offset: Float32Array.BYTES_PER_ELEMENT, + shaderLocation: 0 + }] + }] + }; + { + // Control case, setting offset 4 bytes + const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } + { + // Test offset of 2 bytes with uchar2 format + vertexState.vertexBuffers[0].attributes[0].offset = 2; + vertexState.vertexBuffers[0].attributes[0].format = 'uchar2'; + const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } + { + // Test offset of 2 bytes with float format + vertexState.vertexBuffers[0].attributes[0].offset = 2; + vertexState.vertexBuffers[0].attributes[0].format = 'float'; + const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } +}); +g.test('check attribute offset overflow', async t => { + const vertexState = { + vertexBuffers: [{ + arrayStride: 0, + attributes: [{ + format: 'float', + offset: Number.MAX_SAFE_INTEGER, + shaderLocation: 0 + }] + }] + }; + const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); +}); +//# sourceMappingURL=vertex_state.spec.js.map \ No newline at end of file
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/cts.html b/third_party/blink/web_tests/wpt_internal/webgpu/cts.html index 95880efd..c67c0c8 100644 --- a/third_party/blink/web_tests/wpt_internal/webgpu/cts.html +++ b/third_party/blink/web_tests/wpt_internal/webgpu/cts.html
@@ -216,3 +216,198 @@ <meta name=variant content='?q=cts:validation/setScissorRect:'> <meta name=variant content='?q=cts:validation/setStencilReference:'> <meta name=variant content='?q=cts:validation/setViewport:'> + +<!-- Workers --> + +<meta name=variant content='?worker=1&q=cts:buffers/create_mapped:'> +<meta name=variant content='?worker=1&q=cts:buffers/map:'> +<meta name=variant content='?worker=1&q=cts:buffers/map_detach:'> + +<meta name=variant content='?worker=1&q=cts:buffers/map_oom:mapWriteAsync='> +<meta name=variant content='?worker=1&q=cts:buffers/map_oom:mapReadAsync='> +<meta name=variant content='?worker=1&q=cts:buffers/map_oom:createBufferMapped='> +<meta name=variant content='?worker=1&q=cts:buffers/map_oom:createBufferAsync='> + +<meta name=variant content='?worker=1&q=cts:canvas/context_creation:'> +<meta name=variant content='?worker=1&q=cts:command_buffer/basic:'> +<meta name=variant content='?worker=1&q=cts:command_buffer/compute/basic:'> +<meta name=variant content='?worker=1&q=cts:command_buffer/copies:'> +<meta name=variant content='?worker=1&q=cts:command_buffer/render/basic:'> +<meta name=variant content='?worker=1&q=cts:command_buffer/render/rendering:'> + +<meta name=variant content='?worker=1&q=cts:command_buffer/render/storeop:storeOp_controls_whether_1x1_drawn_quad_is_stored={"storeOp":"clear"}'> +<meta name=variant content='?worker=1&q=cts:command_buffer/render/storeop:storeOp_controls_whether_1x1_drawn_quad_is_stored={"storeOp":"store"}'> + +<meta name=variant content='?worker=1&q=cts:examples:'> +<meta name=variant content='?worker=1&q=cts:fences:'> + +<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:binding_count_mismatch='> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:binding_must_be_present_in_layout='> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"uniform-buffer","resourceType":"error"}'> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"uniform-buffer","resourceType":"uniform-buffer"}'> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"uniform-buffer","resourceType":"storage-buffer"}'> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"uniform-buffer","resourceType":"sampler"}'> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"uniform-buffer","resourceType":"sampled-texture"}'> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"uniform-buffer","resourceType":"storage-texture"}'> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"storage-buffer","resourceType":"error"}'> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"storage-buffer","resourceType":"uniform-buffer"}'> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"storage-buffer","resourceType":"storage-buffer"}'> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"storage-buffer","resourceType":"sampler"}'> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"storage-buffer","resourceType":"sampled-texture"}'> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"storage-buffer","resourceType":"storage-texture"}'> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type~{"bindingType":"readonly-storage-buffer"}'> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"sampler","resourceType":"error"}'> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"sampler","resourceType":"uniform-buffer"}'> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"sampler","resourceType":"storage-buffer"}'> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"sampler","resourceType":"sampler"}'> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"sampler","resourceType":"sampled-texture"}'> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"sampler","resourceType":"storage-texture"}'> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"sampled-texture","resourceType":"error"}'> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"sampled-texture","resourceType":"uniform-buffer"}'> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"sampled-texture","resourceType":"storage-buffer"}'> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"sampled-texture","resourceType":"sampler"}'> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"sampled-texture","resourceType":"sampled-texture"}'> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"sampled-texture","resourceType":"storage-texture"}'> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type~{"bindingType":"storage-texture"}'> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:texture_binding_must_have_correct_usage={"type":"sampled-texture"}'> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:texture_binding_must_have_correct_usage={"type":"storage-texture"}'> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:texture_must_have_correct_component_type~'> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:texture_must_have_correct_dimension='> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_offset_and_size_for_bind_groups_match~'> + +<meta name=variant content='?worker=1&q=cts:validation/createBindGroupLayout:some_binding_index_was_specified_more_than_once='> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroupLayout:negative_binding_index='> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroupLayout:Visibility_of_bindings_can_be_0='> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroupLayout:number_of_dynamic_buffers_exceeds_the_maximum_value~'> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroupLayout:dynamic_set_to_true_is_allowed_only_for_buffers={"type":"uniform-buffer"}'> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroupLayout:dynamic_set_to_true_is_allowed_only_for_buffers={"type":"storage-buffer"}'> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroupLayout:dynamic_set_to_true_is_allowed_only_for_buffers={"type":"readonly-storage-buffer"}'> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroupLayout:dynamic_set_to_true_is_allowed_only_for_buffers={"type":"sampler"}'> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroupLayout:dynamic_set_to_true_is_allowed_only_for_buffers={"type":"sampled-texture"}'> +<meta name=variant content='?worker=1&q=cts:validation/createBindGroupLayout:dynamic_set_to_true_is_allowed_only_for_buffers={"type":"storage-texture"}'> + +<meta name=variant content='?worker=1&q=cts:validation/createPipelineLayout:'> + +<meta name=variant content='?worker=1&q=cts:validation/createTexture:validation_of_sampleCount={"sampleCount":0}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:validation_of_sampleCount={"sampleCount":1}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:validation_of_sampleCount={"sampleCount":2}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:validation_of_sampleCount={"sampleCount":3}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:validation_of_sampleCount={"sampleCount":4}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:validation_of_sampleCount={"sampleCount":8}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:validation_of_sampleCount={"sampleCount":16}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:validation_of_sampleCount={"sampleCount":4,"mipLevelCount":2}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:validation_of_sampleCount={"sampleCount":4,"arrayLayerCount":2}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:validation_of_mipLevelCount={"width":32,"height":32,"mipLevelCount":1}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:validation_of_mipLevelCount={"width":32,"height":32,"mipLevelCount":0}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:validation_of_mipLevelCount={"width":32,"height":32,"mipLevelCount":6}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:validation_of_mipLevelCount={"width":31,"height":32,"mipLevelCount":7}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:validation_of_mipLevelCount={"width":32,"height":31,"mipLevelCount":7}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:validation_of_mipLevelCount={"width":32,"height":32,"mipLevelCount":100}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:validation_of_mipLevelCount={"width":32,"height":8,"mipLevelCount":6}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_valid_to_destroy_a_texture='> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_valid_to_destroy_a_destroyed_texture='> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_submit_a_destroyed_texture_before_and_after_encode={"destroyBeforeEncode":false,"destroyAfterEncode":false}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_submit_a_destroyed_texture_before_and_after_encode={"destroyBeforeEncode":true,"destroyAfterEncode":false}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_submit_a_destroyed_texture_before_and_after_encode={"destroyBeforeEncode":false,"destroyAfterEncode":true}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"r8unorm"}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"r8snorm"}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"r8uint"}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"r8sint"}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"r16uint"}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"r16sint"}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"r16float"}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rg8unorm"}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rg8snorm"}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rg8uint"}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rg8sint"}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"r32uint"}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"r32sint"}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"r32float"}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rg16uint"}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rg16sint"}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rg16float"}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rgba8unorm"}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rgba8unorm-srgb"}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rgba8snorm"}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rgba8uint"}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rgba8sint"}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"bgra8unorm"}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"bgra8unorm-srgb"}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rgb10a2unorm"}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rg11b10float"}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rg32uint"}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rg32sint"}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rg32float"}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rgba16uint"}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rgba16sint"}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rgba16float"}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rgba32uint"}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rgba32sint"}'> +<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rgba32float"}'> + +<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_non_array_texture={}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_non_array_texture={"arrayLayerCount":1}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_non_array_texture={"arrayLayerCount":2}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_non_array_texture={"dimension":"2d-array","arrayLayerCount":1}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_non_array_texture={"mipLevelCount":1,"baseMipLevel":5}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_non_array_texture={"mipLevelCount":2,"baseMipLevel":4}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_non_array_texture={"mipLevelCount":0,"baseMipLevel":0}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_non_array_texture={"mipLevelCount":0,"baseMipLevel":1}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_non_array_texture={"mipLevelCount":0,"baseMipLevel":5}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_non_array_texture={"mipLevelCount":0,"baseMipLevel":6}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_non_array_texture={"mipLevelCount":7,"baseMipLevel":0}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_non_array_texture={"mipLevelCount":6,"baseMipLevel":1}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_non_array_texture={"mipLevelCount":2,"baseMipLevel":5}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_non_array_texture={"mipLevelCount":1,"baseMipLevel":6}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_array_texture={}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_array_texture={"dimension":"2d","arrayLayerCount":1}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_array_texture={"arrayLayerCount":6}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_array_texture={"arrayLayerCount":0,"baseArrayLayer":0}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_array_texture={"arrayLayerCount":0,"baseArrayLayer":1}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_array_texture={"arrayLayerCount":0,"baseArrayLayer":5}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_array_texture={"arrayLayerCount":0,"baseArrayLayer":6}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_array_texture={"arrayLayerCount":7,"baseArrayLayer":0}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_array_texture={"arrayLayerCount":6,"baseArrayLayer":1}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_array_texture={"arrayLayerCount":2,"baseArrayLayer":5}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_array_texture={"arrayLayerCount":1,"baseArrayLayer":6}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:Using_defaults_validates_the_same_as_setting_values_for_more_than_1_array_layer={}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:Using_defaults_validates_the_same_as_setting_values_for_more_than_1_array_layer={"format":"rgba8unorm"}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:Using_defaults_validates_the_same_as_setting_values_for_more_than_1_array_layer={"format":"r8unorm"}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:Using_defaults_validates_the_same_as_setting_values_for_more_than_1_array_layer={"dimension":"2d-array"}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:Using_defaults_validates_the_same_as_setting_values_for_more_than_1_array_layer={"dimension":"2d"}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:Using_defaults_validates_the_same_as_setting_values_for_more_than_1_array_layer={"arrayLayerCount":6}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:Using_defaults_validates_the_same_as_setting_values_for_more_than_1_array_layer={"arrayLayerCount":6,"dimension":"2d-array"}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:Using_defaults_validates_the_same_as_setting_values_for_more_than_1_array_layer={"arrayLayerCount":6,"dimension":"2d-array","mipLevelCount":6}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:Using_defaults_validates_the_same_as_setting_values_for_only_1_array_layer={}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:Using_defaults_validates_the_same_as_setting_values_for_only_1_array_layer={"format":"rgba8unorm"}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:Using_defaults_validates_the_same_as_setting_values_for_only_1_array_layer={"format":"r8unorm"}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:Using_defaults_validates_the_same_as_setting_values_for_only_1_array_layer={"dimension":"2d-array"}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:Using_defaults_validates_the_same_as_setting_values_for_only_1_array_layer={"dimension":"2d"}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:Using_defaults_validates_the_same_as_setting_values_for_only_1_array_layer={"arrayLayerCount":0}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:Using_defaults_validates_the_same_as_setting_values_for_only_1_array_layer={"arrayLayerCount":1}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:Using_defaults_validates_the_same_as_setting_values_for_only_1_array_layer={"arrayLayerCount":2}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:Using_defaults_validates_the_same_as_setting_values_for_only_1_array_layer={"mipLevelCount":6}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:Using_defaults_validates_the_same_as_setting_values_for_only_1_array_layer={"mipLevelCount":1}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:creating_cube_map_texture_view={"dimension":"cube","arrayLayerCount":6}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:creating_cube_map_texture_view={"dimension":"cube","arrayLayerCount":3}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:creating_cube_map_texture_view={"dimension":"cube","arrayLayerCount":7}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:creating_cube_map_texture_view={"dimension":"cube","arrayLayerCount":12}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:creating_cube_map_texture_view={"dimension":"cube"}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:creating_cube_map_texture_view={"dimension":"cube-array","arrayLayerCount":12}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:creating_cube_map_texture_view={"dimension":"cube-array","arrayLayerCount":11}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:creating_cube_map_texture_view={"dimension":"cube-array","arrayLayerCount":13}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:creating_cube_map_texture_view_with_a_non_square_texture={"dimension":"cube","arrayLayerCount":6}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:creating_cube_map_texture_view_with_a_non_square_texture={"dimension":"cube-array","arrayLayerCount":12}'> +<meta name=variant content='?worker=1&q=cts:validation/createView:test_the_format_compatibility_rules_when_creating_a_texture_view='> +<meta name=variant content='?worker=1&q=cts:validation/createView:it_is_invalid_to_use_a_texture_view_created_from_a_destroyed_texture='> + +<meta name=variant content='?worker=1&q=cts:validation/error_scope:'> +<meta name=variant content='?worker=1&q=cts:validation/fences:'> +<meta name=variant content='?worker=1&q=cts:validation/queue_submit:'> +<meta name=variant content='?worker=1&q=cts:validation/render_pass:'> +<meta name=variant content='?worker=1&q=cts:validation/render_pass_descriptor:'> +<meta name=variant content='?worker=1&q=cts:validation/setBindGroup:'> +<meta name=variant content='?worker=1&q=cts:validation/setBlendColor:'> +<meta name=variant content='?worker=1&q=cts:validation/setScissorRect:'> +<meta name=variant content='?worker=1&q=cts:validation/setStencilReference:'> +<meta name=variant content='?worker=1&q=cts:validation/setViewport:'>
diff --git a/third_party/closure_compiler/externs/input_method_private.js b/third_party/closure_compiler/externs/input_method_private.js index e290c81..43461a9 100644 --- a/third_party/closure_compiler/externs/input_method_private.js +++ b/third_party/closure_compiler/externs/input_method_private.js
@@ -162,6 +162,13 @@ chrome.inputMethodPrivate.setXkbLayout = function(xkb_name, callback) {}; /** + * Commits the text currently being composed without moving the selected text + * range + * @param {function():void=} callback Called when the operation completes. + */ +chrome.inputMethodPrivate.finishComposingText = function(callback) {}; + +/** * Fires the input.ime.onMenuItemActivated event. * @param {string} engineID ID of the engine to use. * @param {string} name Name of the MenuItem which was activated
diff --git a/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar-plane-detection-anchors.html b/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar-plane-detection-anchors.html index b0fc160..c54c5a2 100644 --- a/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar-plane-detection-anchors.html +++ b/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar-plane-detection-anchors.html
@@ -388,8 +388,8 @@ addARObjectAt(event.frame.session, event.frame, hitResult.plane, - new XRRigidTransform(hitResult.hitMatrix), - hitResult.plane.plane_space); + new XRRigidTransform(hitResult.point_on_plane), + hitResult.plane.planeSpace); } else { console.log("Missed everything, placing an anchor at origin."); addARObjectAt(event.frame.session, @@ -474,8 +474,10 @@ // Called every time a XRSession requests that a new frame be drawn. async function onXRFrame(t, frame) { - let session = frame.session; + + session.requestAnimationFrame(onXRFrame); + let pose = frame.getViewerPose(xrRefSpace); let detected_planes = frame.worldInformation.detectedPlanes; @@ -581,8 +583,6 @@ scene.startFrame(); scene.drawXRFrame(frame, pose); scene.endFrame(); - - session.requestAnimationFrame(onXRFrame); } // Start the XR application.
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 2afc6959..bcb50d6 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -7914,6 +7914,7 @@ <int value="30" label="kTpmAttestationKeys"/> <int value="31" label="kStrikes"/> <int value="32" label="kLeakedCredentials"/> + <int value="33" label="kFieldInfo"/> </enum> <enum name="ChromeChannelForHistogram"> @@ -21264,6 +21265,7 @@ <int value="1403" label="AUTOTESTPRIVATE_REMOVEACTIVEDESK"/> <int value="1404" label="TERMINALPRIVATE_GETCROSHSETTINGS"/> <int value="1405" label="AUTOTESTPRIVATE_ENABLEASSISTANTANDWAITFORREADY"/> + <int value="1406" label="INPUTMETHODPRIVATE_FINISHCOMPOSINGTEXT"/> </enum> <enum name="ExtensionIconState"> @@ -37110,6 +37112,7 @@ <int value="-169745744" label="SyncPseudoUSSPreferences:enabled"/> <int value="-167744090" label="EnableHomeLauncher:enabled"/> <int value="-165756594" label="enable-touch-feedback"/> + <int value="-165006916" label="EnableNeuralPalmDetectionFilter:enabled"/> <int value="-164539906" label="OmniboxPreserveDefaultMatchAgainstAsyncUpdate:disabled"/> <int value="-161782023" label="AndroidMessagesProdEndpoint:enabled"/> @@ -37853,6 +37856,7 @@ <int value="787385958" label="RegionalLocalesAsDisplayUI:enabled"/> <int value="799680074" label="ContextualSearchTranslationModel:enabled"/> <int value="803282885" label="PreferHtmlOverPlugins:disabled"/> + <int value="806035639" label="EnableNeuralPalmDetectionFilter:disabled"/> <int value="806334184" label="AndroidSpellChecker:enabled"/> <int value="807447752" label="ChromeMemex:disabled"/> <int value="807734471" label="tab-management-experiment-type-disabled"/> @@ -38899,6 +38903,8 @@ <int value="6" label="Stats table failed initialization"/> <int value="7" label="Migration error"/> <int value="8" label="Commit transaction error"/> + <int value="9" label="Init leaked table error"/> + <int value="10" label="Init field info table error"/> </enum> <enum name="LoginFailureReason"> @@ -46575,6 +46581,12 @@ <int value="9" label="Optimization Guide Decider not initialized"> The OptimizationGuideDecider was not initialized yet. </int> + <int value="10" label="Hint was being fetched but was not available yet"> + A fetch for a hint that matches the page load from the remote Optimization + Guide Service was started but was not available in time to make a decision. + (Added in M80, Previously, this was combined with "No hint available + for page load".) + </int> </enum> <enum name="OptimizationGuideProcessHintsResult">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 43d7229..04333c0f 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -56323,6 +56323,17 @@ </summary> </histogram> +<histogram name="InputMethod.VirtualKeyboard.KeyboardShownLongTail" units="ms" + expires_after="2020-11-08"> + <owner>jopalmer@chromium.org</owner> + <owner>essential-inputs-team@google.com</owner> + <summary> + Time to show the on-screen keyboard in milliseconds. Similar to + InputMethod.VirtualKeyboard.KeyboardShown but with a larger maximum to + capture more of the distribution. + </summary> +</histogram> + <histogram name="InputMethod.VirtualKeyboard.Layout" enum="IMEVKLayout"> <owner>essential-inputs-team@google.com</owner> <summary> @@ -126214,7 +126225,7 @@ </histogram> <histogram name="SBClientDownload.ZipFileSuccess" enum="BooleanSuccess" - expires_after="M80"> + expires_after="M83"> <owner>drubery@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <summary> @@ -143103,7 +143114,7 @@ </histogram> <histogram name="Startup.WebFooterExperiment.DidFirstVisuallyNonEmptyPaint" - units="ms" expires_after="M80"> + units="ms" expires_after="M84"> <owner>pbos@chromium.org</owner> <owner>robliao@chromium.org</owner> <summary> @@ -143112,7 +143123,7 @@ </histogram> <histogram name="Startup.WebFooterExperiment.WebFooterCreation" units="ms" - expires_after="M80"> + expires_after="M84"> <owner>pbos@chromium.org</owner> <owner>robliao@chromium.org</owner> <summary> @@ -173924,6 +173935,8 @@ </histogram_suffixes> <histogram_suffixes name="Mobile.Messages.Confirm.Type" separator="."> + <suffix name="ConfirmInfobarTypeBlockPopups" + label="Recorded for Block Popups Confirm Messages."/> <suffix name="ConfirmInfobarTypeRestore" label="Recorded for Restore Tabs Confirm Messages."/> <affected-histogram name="Mobile.Messages.Confirm.Event"/>
diff --git a/ui/accelerated_widget_mac/io_surface_context.h b/ui/accelerated_widget_mac/io_surface_context.h index cf7770d..504a52b 100644 --- a/ui/accelerated_widget_mac/io_surface_context.h +++ b/ui/accelerated_widget_mac/io_surface_context.h
@@ -46,7 +46,7 @@ CGLContextObj cgl_context() const { return cgl_context_; } // ui::GpuSwitchingObserver implementation. - void OnGpuSwitched() override; + void OnGpuSwitched(gl::GpuPreference active_gpu_heuristic) override; private: friend class base::RefCounted<IOSurfaceContext>;
diff --git a/ui/accelerated_widget_mac/io_surface_context.mm b/ui/accelerated_widget_mac/io_surface_context.mm index bbfcb25d..50a7b9c1 100644 --- a/ui/accelerated_widget_mac/io_surface_context.mm +++ b/ui/accelerated_widget_mac/io_surface_context.mm
@@ -113,7 +113,7 @@ } } -void IOSurfaceContext::OnGpuSwitched() { +void IOSurfaceContext::OnGpuSwitched(gl::GpuPreference active_gpu_heuristic) { // Recreate all browser-side GL contexts whenever the GPU switches. If this // is not done, performance will suffer. // http://crbug.com/361493
diff --git a/ui/accessibility/ax_action_data.h b/ui/accessibility/ax_action_data.h index 519fcc20..2b5529b 100644 --- a/ui/accessibility/ax_action_data.h +++ b/ui/accessibility/ax_action_data.h
@@ -19,9 +19,6 @@ AXActionData(const AXActionData& other); ~AXActionData(); - // Return a string representation of this data, for debugging. - std::string ToString() const; - // This is a simple serializable struct. All member variables should be // public and copyable.
diff --git a/ui/base/ime/chromeos/input_method_chromeos.cc b/ui/base/ime/chromeos/input_method_chromeos.cc index 05beda6..5864c7b 100644 --- a/ui/base/ime/chromeos/input_method_chromeos.cc +++ b/ui/base/ime/chromeos/input_method_chromeos.cc
@@ -42,7 +42,7 @@ } InputMethodChromeOS::~InputMethodChromeOS() { - ConfirmCompositionText(/* reset_engine */ true); + ConfirmCompositionText(/* reset_engine */ true, /* keep_selection */ false); // We are dead, so we need to ask the client to stop relying on us. OnInputMethodChanged(); @@ -284,7 +284,7 @@ void InputMethodChromeOS::OnWillChangeFocusedClient( TextInputClient* focused_before, TextInputClient* focused) { - ConfirmCompositionText(/* reset_engine */ true); + ConfirmCompositionText(/* reset_engine */ true, /* keep_selection */ false); if (GetEngine()) GetEngine()->FocusOut(); @@ -344,8 +344,9 @@ } } -void InputMethodChromeOS::ConfirmCompositionText(bool reset_engine) { - InputMethodBase::ConfirmCompositionText(reset_engine); +void InputMethodChromeOS::ConfirmCompositionText(bool reset_engine, + bool keep_selection) { + InputMethodBase::ConfirmCompositionText(reset_engine, keep_selection); // See https://crbug.com/984472. ResetContext(reset_engine);
diff --git a/ui/base/ime/chromeos/input_method_chromeos.h b/ui/base/ime/chromeos/input_method_chromeos.h index 0c40e72..7955f75 100644 --- a/ui/base/ime/chromeos/input_method_chromeos.h +++ b/ui/base/ime/chromeos/input_method_chromeos.h
@@ -52,7 +52,7 @@ uint32_t before, uint32_t after, const std::vector<ui::ImeTextSpan>& text_spans) override; - void ConfirmCompositionText(bool reset_engine) override; + void ConfirmCompositionText(bool reset_engine, bool keep_selection) override; protected: // Converts |text| into CompositionText.
diff --git a/ui/base/ime/chromeos/input_method_chromeos_unittest.cc b/ui/base/ime/chromeos/input_method_chromeos_unittest.cc index 16e0be7c..d2fe588 100644 --- a/ui/base/ime/chromeos/input_method_chromeos_unittest.cc +++ b/ui/base/ime/chromeos/input_method_chromeos_unittest.cc
@@ -268,7 +268,12 @@ void SetCompositionText(const CompositionText& composition) override { composition_text_ = composition; } - void ConfirmCompositionText() override { + void ConfirmCompositionText(bool keep_selection) override { + // TODO(b/134473433) Modify this function so that when keep_selection is + // true, the selection is not changed when text committed + if (keep_selection) { + NOTIMPLEMENTED_LOG_ONCE(); + } confirmed_text_ = composition_text_; composition_text_ = CompositionText(); } @@ -910,7 +915,8 @@ input_type_ = TEXT_INPUT_TYPE_TEXT; ime_->OnTextInputTypeChanged(this); - ime_->ConfirmCompositionText(/* reset_engine */ true); + ime_->ConfirmCompositionText(/* reset_engine */ true, + /* keep_selection */ false); EXPECT_TRUE(confirmed_text_.text.empty()); EXPECT_TRUE(composition_text_.text.empty()); @@ -924,7 +930,8 @@ CompositionText composition_text; composition_text.text = base::UTF8ToUTF16("hello"); SetCompositionText(composition_text); - ime_->ConfirmCompositionText(/* reset_engine */ true); + ime_->ConfirmCompositionText(/* reset_engine */ true, + /* keep_selection */ false); EXPECT_EQ(base::ASCIIToUTF16("hello"), confirmed_text_.text); EXPECT_TRUE(composition_text_.text.empty()); @@ -941,7 +948,8 @@ // "abc" is in composition. Put the two characters in composition. ime_->SetCompositionRange(0, 2, {}); - ime_->ConfirmCompositionText(/* reset_engine */ true); + ime_->ConfirmCompositionText(/* reset_engine */ true, + /* keep_selection */ false); EXPECT_EQ(base::ASCIIToUTF16("ab"), confirmed_text_.text); EXPECT_TRUE(composition_text_.text.empty());
diff --git a/ui/base/ime/dummy_text_input_client.cc b/ui/base/ime/dummy_text_input_client.cc index da3fc28..0cd06f6 100644 --- a/ui/base/ime/dummy_text_input_client.cc +++ b/ui/base/ime/dummy_text_input_client.cc
@@ -35,8 +35,7 @@ composition_history_.push_back(composition); } -void DummyTextInputClient::ConfirmCompositionText() { -} +void DummyTextInputClient::ConfirmCompositionText(bool keep_selection) {} void DummyTextInputClient::ClearCompositionText() { SetCompositionText(CompositionText());
diff --git a/ui/base/ime/dummy_text_input_client.h b/ui/base/ime/dummy_text_input_client.h index 0d9f5053..b4bbc8be 100644 --- a/ui/base/ime/dummy_text_input_client.h +++ b/ui/base/ime/dummy_text_input_client.h
@@ -25,7 +25,7 @@ // Overriden from TextInputClient. void SetCompositionText(const CompositionText& composition) override; - void ConfirmCompositionText() override; + void ConfirmCompositionText(bool) override; void ClearCompositionText() override; void InsertText(const base::string16& text) override; void InsertChar(const KeyEvent& event) override;
diff --git a/ui/base/ime/ime_input_context_handler_interface.h b/ui/base/ime/ime_input_context_handler_interface.h index a62302c5..76c4496b 100644 --- a/ui/base/ime/ime_input_context_handler_interface.h +++ b/ui/base/ime/ime_input_context_handler_interface.h
@@ -53,7 +53,8 @@ // Commits any composition text. // Set |reset_engine| to false if this was triggered from the extension. - virtual void ConfirmCompositionText(bool reset_engine) = 0; + virtual void ConfirmCompositionText(bool reset_engine, + bool keep_selection) = 0; // Returns true if there is any composition text. virtual bool HasCompositionText() = 0;
diff --git a/ui/base/ime/input_method_base.cc b/ui/base/ime/input_method_base.cc index 7cebca9..fdecc84 100644 --- a/ui/base/ime/input_method_base.cc +++ b/ui/base/ime/input_method_base.cc
@@ -282,10 +282,11 @@ return this; } -void InputMethodBase::ConfirmCompositionText(bool reset_engine) { +void InputMethodBase::ConfirmCompositionText(bool reset_engine, + bool keep_selection) { TextInputClient* client = GetTextInputClient(); if (client && client->HasCompositionText()) - client->ConfirmCompositionText(); + client->ConfirmCompositionText(keep_selection); } bool InputMethodBase::HasCompositionText() {
diff --git a/ui/base/ime/input_method_base.h b/ui/base/ime/input_method_base.h index 914c4bd..2d63937f 100644 --- a/ui/base/ime/input_method_base.h +++ b/ui/base/ime/input_method_base.h
@@ -98,7 +98,7 @@ SurroundingTextInfo GetSurroundingTextInfo() override; void SendKeyEvent(KeyEvent* event) override; InputMethod* GetInputMethod() override; - void ConfirmCompositionText(bool reset_engine) override; + void ConfirmCompositionText(bool reset_engine, bool keep_selection) override; bool HasCompositionText() override; // Sends a fake key event for IME composing without physical key events.
diff --git a/ui/base/ime/linux/input_method_auralinux.cc b/ui/base/ime/linux/input_method_auralinux.cc index d14e686e..3f3663c3 100644 --- a/ui/base/ime/linux/input_method_auralinux.cc +++ b/ui/base/ime/linux/input_method_auralinux.cc
@@ -414,7 +414,7 @@ void InputMethodAuraLinux::OnWillChangeFocusedClient( TextInputClient* focused_before, TextInputClient* focused) { - ConfirmCompositionText(/* reset_engine */ true); + ConfirmCompositionText(/* reset_engine */ true, /* keep_selection */ false); } void InputMethodAuraLinux::OnDidChangeFocusedClient( @@ -451,8 +451,12 @@ return details; } -void InputMethodAuraLinux::ConfirmCompositionText(bool reset_engine) { - InputMethodBase::ConfirmCompositionText(reset_engine); +void InputMethodAuraLinux::ConfirmCompositionText(bool reset_engine, + bool keep_selection) { + if (keep_selection) { + NOTIMPLEMENTED_LOG_ONCE(); + } + InputMethodBase::ConfirmCompositionText(reset_engine, keep_selection); if (reset_engine && GetEngine()) GetEngine()->Reset(); ResetContext();
diff --git a/ui/base/ime/linux/input_method_auralinux.h b/ui/base/ime/linux/input_method_auralinux.h index fffef79..294979d 100644 --- a/ui/base/ime/linux/input_method_auralinux.h +++ b/ui/base/ime/linux/input_method_auralinux.h
@@ -47,7 +47,7 @@ TextInputClient* focused) override; void OnDidChangeFocusedClient(TextInputClient* focused_before, TextInputClient* focused) override; - void ConfirmCompositionText(bool reset_engine) override; + void ConfirmCompositionText(bool reset_engine, bool keep_selection) override; private: bool HasInputMethodResult();
diff --git a/ui/base/ime/linux/input_method_auralinux_unittest.cc b/ui/base/ime/linux/input_method_auralinux_unittest.cc index 9305047..02819b9 100644 --- a/ui/base/ime/linux/input_method_auralinux_unittest.cc +++ b/ui/base/ime/linux/input_method_auralinux_unittest.cc
@@ -215,7 +215,12 @@ bool HasCompositionText() const override { return !composition_text.empty(); } - void ConfirmCompositionText() override { + void ConfirmCompositionText(bool keep_selection) override { + // TODO(b/134473433) Modify this function so that when keep_selection is + // true, the selection is not changed when text committed + if (keep_selection) { + NOTIMPLEMENTED_LOG_ONCE(); + } TestResult::GetInstance()->RecordAction( base::ASCIIToUTF16("compositionend")); TestResult::GetInstance()->RecordAction(base::ASCIIToUTF16("textinput:") +
diff --git a/ui/base/ime/mock_ime_input_context_handler.cc b/ui/base/ime/mock_ime_input_context_handler.cc index bed1795..01e25ef6 100644 --- a/ui/base/ime/mock_ime_input_context_handler.cc +++ b/ui/base/ime/mock_ime_input_context_handler.cc
@@ -72,7 +72,13 @@ return nullptr; } -void MockIMEInputContextHandler::ConfirmCompositionText(bool reset_engine) { +void MockIMEInputContextHandler::ConfirmCompositionText(bool reset_engine, + bool keep_selection) { + // TODO(b/134473433) Modify this function so that when keep_selection is + // true, the selection is not changed when text committed + if (keep_selection) { + NOTIMPLEMENTED_LOG_ONCE(); + } if (!HasCompositionText()) return;
diff --git a/ui/base/ime/mock_ime_input_context_handler.h b/ui/base/ime/mock_ime_input_context_handler.h index d75e38b..fb0b849 100644 --- a/ui/base/ime/mock_ime_input_context_handler.h +++ b/ui/base/ime/mock_ime_input_context_handler.h
@@ -48,7 +48,7 @@ SurroundingTextInfo GetSurroundingTextInfo() override; void SendKeyEvent(KeyEvent* event) override; InputMethod* GetInputMethod() override; - void ConfirmCompositionText(bool reset_engine) override; + void ConfirmCompositionText(bool reset_engine, bool keep_selection) override; bool HasCompositionText() override; int commit_text_call_count() const { return commit_text_call_count_; }
diff --git a/ui/base/ime/text_input_client.h b/ui/base/ime/text_input_client.h index 24371492..ae47101 100644 --- a/ui/base/ime/text_input_client.h +++ b/ui/base/ime/text_input_client.h
@@ -61,7 +61,9 @@ virtual void SetCompositionText(const ui::CompositionText& composition) = 0; // Converts current composition text into final content. - virtual void ConfirmCompositionText() = 0; + // If keep_selection is true, keep the selected range unchanged + // otherwise, set it to be after the newly committed text. + virtual void ConfirmCompositionText(bool keep_selection) = 0; // Removes current composition text. virtual void ClearCompositionText() = 0;
diff --git a/ui/base/ime/win/input_method_win_imm32.cc b/ui/base/ime/win/input_method_win_imm32.cc index 2cc52439..7c0ee3e 100644 --- a/ui/base/ime/win/input_method_win_imm32.cc +++ b/ui/base/ime/win/input_method_win_imm32.cc
@@ -159,7 +159,8 @@ TextInputClient* focused_before, TextInputClient* focused) { if (IsWindowFocused(focused_before)) - ConfirmCompositionText(/* reset_engine */ true); + ConfirmCompositionText(/* reset_engine */ true, + /* keep_selection */ false); } void InputMethodWinImm32::OnDidChangeFocusedClient( @@ -322,8 +323,9 @@ } } -void InputMethodWinImm32::ConfirmCompositionText(bool reset_engine) { - InputMethodBase::ConfirmCompositionText(reset_engine); +void InputMethodWinImm32::ConfirmCompositionText(bool reset_engine, + bool keep_selection) { + InputMethodBase::ConfirmCompositionText(reset_engine, keep_selection); if (reset_engine) InputMethodWinBase::ResetEngine();
diff --git a/ui/base/ime/win/input_method_win_imm32.h b/ui/base/ime/win/input_method_win_imm32.h index 25922ff..c95a8ae7 100644 --- a/ui/base/ime/win/input_method_win_imm32.h +++ b/ui/base/ime/win/input_method_win_imm32.h
@@ -27,7 +27,7 @@ // Overridden from InputMethodBase: void OnFocus() override; - void ConfirmCompositionText(bool reset_engine) override; + void ConfirmCompositionText(bool reset_engine, bool keep_selection) override; // Overridden from InputMethod: bool OnUntranslatedIMEMessage(const MSG event,
diff --git a/ui/base/ime/win/input_method_win_tsf.cc b/ui/base/ime/win/input_method_win_tsf.cc index 37d2888..e0b9a87 100644 --- a/ui/base/ime/win/input_method_win_tsf.cc +++ b/ui/base/ime/win/input_method_win_tsf.cc
@@ -151,7 +151,8 @@ TextInputClient* focused_before, TextInputClient* focused) { if (IsWindowFocused(focused_before)) { - ConfirmCompositionText(/* reset_engine */ true); + ConfirmCompositionText(/* reset_engine */ true, + /* keep_selection */ false); ui::TSFBridge::GetInstance()->RemoveFocusedClient(focused_before); } } @@ -176,7 +177,13 @@ InputMethodWinBase::OnDidChangeFocusedClient(focused_before, focused); } -void InputMethodWinTSF::ConfirmCompositionText(bool reset_engine) { +void InputMethodWinTSF::ConfirmCompositionText(bool reset_engine, + bool keep_selection) { + // TODO(b/134473433) Modify this function so that when keep_selection is + // true, the selection is not changed when text committed + if (keep_selection) { + NOTIMPLEMENTED_LOG_ONCE(); + } if (IsTextInputTypeNone()) return;
diff --git a/ui/base/ime/win/input_method_win_tsf.h b/ui/base/ime/win/input_method_win_tsf.h index 58d7855..58e0cfe 100644 --- a/ui/base/ime/win/input_method_win_tsf.h +++ b/ui/base/ime/win/input_method_win_tsf.h
@@ -41,7 +41,7 @@ TextInputClient* focused) override; void OnDidChangeFocusedClient(TextInputClient* focused_before, TextInputClient* focused) override; - void ConfirmCompositionText(bool reset_engine) override; + void ConfirmCompositionText(bool reset_engine, bool keep_selection) override; void ShowVirtualKeyboardIfEnabled() override;
diff --git a/ui/base/ime/win/tsf_input_policy_unittest.cc b/ui/base/ime/win/tsf_input_policy_unittest.cc index 620f7df..3e31e57 100644 --- a/ui/base/ime/win/tsf_input_policy_unittest.cc +++ b/ui/base/ime/win/tsf_input_policy_unittest.cc
@@ -39,7 +39,7 @@ public: ~MockTextInputClient() {} MOCK_METHOD1(SetCompositionText, void(const ui::CompositionText&)); - MOCK_METHOD0(ConfirmCompositionText, void()); + MOCK_METHOD1(ConfirmCompositionText, void(bool)); MOCK_METHOD0(ClearCompositionText, void()); MOCK_METHOD1(InsertText, void(const base::string16&)); MOCK_METHOD1(InsertChar, void(const ui::KeyEvent&));
diff --git a/ui/base/ime/win/tsf_text_store_unittest.cc b/ui/base/ime/win/tsf_text_store_unittest.cc index fe4fdf1c..7909ade 100644 --- a/ui/base/ime/win/tsf_text_store_unittest.cc +++ b/ui/base/ime/win/tsf_text_store_unittest.cc
@@ -37,7 +37,7 @@ public: ~MockTextInputClient() {} MOCK_METHOD1(SetCompositionText, void(const ui::CompositionText&)); - MOCK_METHOD0(ConfirmCompositionText, void()); + MOCK_METHOD1(ConfirmCompositionText, void(bool)); MOCK_METHOD0(ClearCompositionText, void()); MOCK_METHOD1(InsertText, void(const base::string16&)); MOCK_METHOD1(InsertChar, void(const ui::KeyEvent&));
diff --git a/ui/file_manager/file_manager/foreground/elements/files_xf_elements_unittest.js b/ui/file_manager/file_manager/foreground/elements/files_xf_elements_unittest.js index 39bde07..f911e20 100644 --- a/ui/file_manager/file_manager/foreground/elements/files_xf_elements_unittest.js +++ b/ui/file_manager/file_manager/foreground/elements/files_xf_elements_unittest.js
@@ -134,6 +134,33 @@ done(); } +function testFilesDisplayPanelErrorText() { + // Get the host display panel container element. + /** @type {!DisplayPanel|!Element} */ + const displayPanel = assert(document.querySelector('#test-xf-display-panel')); + + // Add a panel item to the display panel container. + const panelItem = displayPanel.addPanelItem('testpanel'); + + // Change the primary and secondary text on the panel item. + panelItem.primaryText = 'foo'; + panelItem.secondaryText = 'bar'; + + // Check the primary and secondary text has been set on the panel. + assertEquals('foo', panelItem.primaryText); + assertEquals('bar', panelItem.secondaryText); + + // Change the panel item type to an error panel. + panelItem.panelType = panelItem.panelTypeError; + + // Check the default primary text displays a generic error message. + // Note, the i18n message gets smooshed into 'An error occurred.' in the app. + assertEquals('$i18n{FILE_ERROR_GENERIC}', panelItem.primaryText); + + // Check the secondary text is empty. + assertEquals('', panelItem.secondaryText); +} + // Override the formatting function for unit testing. util.strf = (end, option) => { return option + end;
diff --git a/ui/file_manager/file_manager/foreground/elements/xf_panel_item.js b/ui/file_manager/file_manager/foreground/elements/xf_panel_item.js index 2e01600..17b465c 100644 --- a/ui/file_manager/file_manager/foreground/elements/xf_panel_item.js +++ b/ui/file_manager/file_manager/foreground/elements/xf_panel_item.js
@@ -241,6 +241,8 @@ case this.panelTypeError: this.setAttribute('indicator', 'status'); this.setAttribute('status', 'failure'); + this.primaryText = '$i18n{FILE_ERROR_GENERIC}'; + this.secondaryText = ''; secondaryButton = document.createElement('xf-button'); secondaryButton.id = 'secondary-action'; secondaryButton.onclick = assert(this.onclick); @@ -516,6 +518,14 @@ } /** + * Getter for the primary text on the panel. + * @return {string} + */ + get primaryText() { + return this.getAttribute('primary-text'); + } + + /** * Setter to set the secondary text on the panel. * @param {string} text Text to be shown. */ @@ -524,6 +534,14 @@ } /** + * Getter for the secondary text on the panel. + * @return {string} + */ + get secondaryText() { + return this.getAttribute('secondary-text'); + } + + /** * Setter to set the panel type. * @param {number} type Enum value for the panel type. */
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js index e965c23..fd690fba 100644 --- a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js +++ b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
@@ -164,7 +164,7 @@ CommandUtil.forceDefaultHandler = (node, commandId) => { const doc = node.ownerDocument; const command = /** @type {!cr.ui.Command} */ ( - doc.querySelector('command[id="' + commandId + '"]')); + doc.body.querySelector('command[id="' + commandId + '"]')); node.addEventListener('keydown', e => { if (command.matchesEvent(e)) { // Prevent cr.ui.CommandManager of handling it and leave it
diff --git a/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js b/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js index bb3da3e..abc227c 100644 --- a/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js +++ b/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js
@@ -141,14 +141,14 @@ * @const */ this.copyCommand_ = /** @type {!cr.ui.Command} */ ( - queryRequiredElement('command#copy', this.document_)); + queryRequiredElement('command#copy', assert(this.document_.body))); /** * @private {!cr.ui.Command} * @const */ this.cutCommand_ = /** @type {!cr.ui.Command} */ ( - queryRequiredElement('command#cut', this.document_)); + queryRequiredElement('command#cut', assert(this.document_.body))); /** * @private {DirectoryEntry|FilesAppDirEntry} @@ -616,7 +616,7 @@ renderThumbnail_() { const length = this.selectionHandler_.selection.entries.length; const container = /** @type {HTMLElement} */ ( - this.document_.querySelector('#drag-container')); + this.document_.body.querySelector('#drag-container')); const contents = this.document_.createElement('div'); contents.className = 'drag-contents'; container.appendChild(contents); @@ -758,7 +758,7 @@ // This should be removed after the bug is fixed. this.touching_ = false; - const container = this.document_.querySelector('#drag-container'); + const container = this.document_.body.querySelector('#drag-container'); container.textContent = ''; this.clearDropTarget_(); delete window[DRAG_AND_DROP_GLOBAL_DATA]; @@ -1280,7 +1280,7 @@ * @private */ simulateCommand_(command, handler) { - const iframe = this.document_.querySelector('#command-dispatcher'); + const iframe = this.document_.body.querySelector('#command-dispatcher'); const doc = iframe.contentDocument; doc.addEventListener(command, handler); doc.execCommand(command);
diff --git a/ui/file_manager/file_manager/foreground/js/ui/commandbutton.js b/ui/file_manager/file_manager/foreground/js/ui/commandbutton.js index 6fed6ef..4170c12 100644 --- a/ui/file_manager/file_manager/foreground/js/ui/commandbutton.js +++ b/ui/file_manager/file_manager/foreground/js/ui/commandbutton.js
@@ -72,7 +72,7 @@ if (typeof command == 'string') { assert(command[0] == '#'); command = /** @type {!cr.ui.Command} */ - (this.ownerDocument.getElementById(command.slice(1))); + (this.ownerDocument.body.querySelector(command)); cr.ui.decorate(command, cr.ui.Command); }
diff --git a/ui/file_manager/file_manager/foreground/js/ui/multi_menu.js b/ui/file_manager/file_manager/foreground/js/ui/multi_menu.js index e06d978..36de11e 100644 --- a/ui/file_manager/file_manager/foreground/js/ui/multi_menu.js +++ b/ui/file_manager/file_manager/foreground/js/ui/multi_menu.js
@@ -119,7 +119,7 @@ } set menu(menu) { if (typeof menu == 'string' && menu[0] == '#') { - menu = assert(this.ownerDocument.getElementById(menu.slice(1))); + menu = assert(this.ownerDocument.body.querySelector(menu)); cr.ui.decorate(menu, cr.ui.Menu); }
diff --git a/ui/gl/gpu_switching_manager.cc b/ui/gl/gpu_switching_manager.cc index be715646..76a7821d 100644 --- a/ui/gl/gpu_switching_manager.cc +++ b/ui/gl/gpu_switching_manager.cc
@@ -23,9 +23,10 @@ observer_list_.RemoveObserver(observer); } -void GpuSwitchingManager::NotifyGpuSwitched() { +void GpuSwitchingManager::NotifyGpuSwitched( + gl::GpuPreference active_gpu_heuristic) { for (GpuSwitchingObserver& observer : observer_list_) - observer.OnGpuSwitched(); + observer.OnGpuSwitched(active_gpu_heuristic); } } // namespace ui
diff --git a/ui/gl/gpu_switching_manager.h b/ui/gl/gpu_switching_manager.h index eb7e480..fde5eafe 100644 --- a/ui/gl/gpu_switching_manager.h +++ b/ui/gl/gpu_switching_manager.h
@@ -9,6 +9,7 @@ #include "base/observer_list.h" #include "build/build_config.h" #include "ui/gl/gl_export.h" +#include "ui/gl/gpu_preference.h" #include "ui/gl/gpu_switching_observer.h" namespace ui { @@ -26,7 +27,11 @@ // occurs as a result of an IPC from the browser. The system observer is kept // in the browser process only so that any workarounds or blacklisting can // be applied there. - void NotifyGpuSwitched(); + // + // The GpuPreference argument is a heuristic indicating whether the + // system is known to be on the low-power or high-performance GPU. + // If this heuristic fails, then kDefault is passed as argument. + void NotifyGpuSwitched(gl::GpuPreference active_gpu_heuristic); private: friend struct base::DefaultSingletonTraits<GpuSwitchingManager>;
diff --git a/ui/gl/gpu_switching_observer.h b/ui/gl/gpu_switching_observer.h index 56f00db..b4e628c 100644 --- a/ui/gl/gpu_switching_observer.h +++ b/ui/gl/gpu_switching_observer.h
@@ -6,13 +6,14 @@ #define UI_GL_GPU_SWITCHING_OBSERVER_H_ #include "ui/gl/gl_export.h" +#include "ui/gl/gpu_preference.h" namespace ui { class GL_EXPORT GpuSwitchingObserver { public: // Called for any observer when the system switches to a different GPU. - virtual void OnGpuSwitched() {} + virtual void OnGpuSwitched(gl::GpuPreference active_gpu_heuristic) {} }; } // namespace ui
diff --git a/ui/gl/mojom/BUILD.gn b/ui/gl/mojom/BUILD.gn new file mode 100644 index 0000000..648b511 --- /dev/null +++ b/ui/gl/mojom/BUILD.gn
@@ -0,0 +1,25 @@ +# 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. + +import("//mojo/public/tools/bindings/mojom.gni") + +mojom("mojom") { + sources = [ + "gpu_preference.mojom", + ] + + public_deps = [ + "//mojo/public/mojom/base", + ] +} + +mojom("test_interfaces") { + sources = [ + "traits_test_service.mojom", + ] + + public_deps = [ + ":mojom", + ] +}
diff --git a/ui/gl/mojom/OWNERS b/ui/gl/mojom/OWNERS new file mode 100644 index 0000000..ae29a36aa --- /dev/null +++ b/ui/gl/mojom/OWNERS
@@ -0,0 +1,6 @@ +per-file *.mojom=set noparent +per-file *.mojom=file://ipc/SECURITY_OWNERS +per-file *_mojom_traits*.*=set noparent +per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS +per-file *.typemap=set noparent +per-file *.typemap=file://ipc/SECURITY_OWNERS
diff --git a/ui/gl/mojom/gpu_preference.mojom b/ui/gl/mojom/gpu_preference.mojom new file mode 100644 index 0000000..645f6fb --- /dev/null +++ b/ui/gl/mojom/gpu_preference.mojom
@@ -0,0 +1,12 @@ +// 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. + +module gl.mojom; + +// gl::GpuPreference +enum GpuPreference { + kDefault, + kLowPower, + kHighPerformance, +};
diff --git a/ui/gl/mojom/gpu_preference.typemap b/ui/gl/mojom/gpu_preference.typemap new file mode 100644 index 0000000..ec7a154 --- /dev/null +++ b/ui/gl/mojom/gpu_preference.typemap
@@ -0,0 +1,12 @@ +# 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. + +mojom = "//ui/gl/mojom/gpu_preference.mojom" +public_headers = [ "//ui/gl/gpu_preference.h" ] +traits_headers = [ "//ui/gl/mojom/gpu_preference_mojom_traits.h" ] +sources = [] +public_deps = [ + "//ui/gl", +] +type_mappings = [ "gl.mojom.GpuPreference=::gl::GpuPreference" ]
diff --git a/ui/gl/mojom/gpu_preference_mojom_traits.h b/ui/gl/mojom/gpu_preference_mojom_traits.h new file mode 100644 index 0000000..09deab4 --- /dev/null +++ b/ui/gl/mojom/gpu_preference_mojom_traits.h
@@ -0,0 +1,48 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_GL_MOJOM_GPU_PREFERENCE_MOJOM_TRAITS_H_ +#define UI_GL_MOJOM_GPU_PREFERENCE_MOJOM_TRAITS_H_ + +#include "ui/gl/gpu_preference.h" +#include "ui/gl/mojom/gpu_preference.mojom.h" + +namespace mojo { + +template <> +struct EnumTraits<gl::mojom::GpuPreference, gl::GpuPreference> { + static gl::mojom::GpuPreference ToMojom(gl::GpuPreference preference) { + switch (preference) { + case gl::GpuPreference::kDefault: + return gl::mojom::GpuPreference::kDefault; + case gl::GpuPreference::kLowPower: + return gl::mojom::GpuPreference::kLowPower; + case gl::GpuPreference::kHighPerformance: + return gl::mojom::GpuPreference::kHighPerformance; + } + NOTREACHED(); + return gl::mojom::GpuPreference::kDefault; + } + + static bool FromMojom(gl::mojom::GpuPreference input, + gl::GpuPreference* out) { + switch (input) { + case gl::mojom::GpuPreference::kDefault: + *out = gl::GpuPreference::kDefault; + return true; + case gl::mojom::GpuPreference::kLowPower: + *out = gl::GpuPreference::kLowPower; + return true; + case gl::mojom::GpuPreference::kHighPerformance: + *out = gl::GpuPreference::kHighPerformance; + return true; + } + NOTREACHED(); + return false; + } +}; + +} // namespace mojo + +#endif // UI_GL_MOJOM_GPU_PREFERENCE_MOJOM_TRAITS_H_
diff --git a/ui/gl/mojom/traits_test_service.mojom b/ui/gl/mojom/traits_test_service.mojom new file mode 100644 index 0000000..84bbddf --- /dev/null +++ b/ui/gl/mojom/traits_test_service.mojom
@@ -0,0 +1,14 @@ +// 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. + +module gl.mojom; + +import "ui/gl/mojom/gpu_preference.mojom"; + +// All functions on this interface echo their arguments to test StructTraits +// serialization and deserialization. +interface TraitsTestService { + [Sync] + EchoGpuPreference(GpuPreference g) => (GpuPreference pass); +};
diff --git a/ui/gl/typemaps.gni b/ui/gl/typemaps.gni new file mode 100644 index 0000000..f831c21b --- /dev/null +++ b/ui/gl/typemaps.gni
@@ -0,0 +1,5 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +typemaps = [ "//ui/gl/mojom/gpu_preference.typemap" ]
diff --git a/ui/ozone/platform/scenic/scenic_window.cc b/ui/ozone/platform/scenic/scenic_window.cc index 1133178..5ce4cd7 100644 --- a/ui/ozone/platform/scenic/scenic_window.cc +++ b/ui/ozone/platform/scenic/scenic_window.cc
@@ -63,19 +63,20 @@ void ScenicWindow::AttachSurfaceView( fuchsia::ui::views::ViewHolderToken token) { - scenic::ViewHolder surface_view_holder(&scenic_session_, std::move(token), - "chromium window surface"); + surface_view_holder_ = std::make_unique<scenic::ViewHolder>( + &scenic_session_, std::move(token), "chromium window surface"); // Configure the ViewHolder not to be focusable, or hit-testable, to ensure // that it cannot receive input. fuchsia::ui::gfx::ViewProperties view_properties; + view_properties.bounding_box = {{-0.5f, -0.5f, -0.5f}, {0.5f, 0.5f, 0.5f}}; view_properties.focus_change = false; - surface_view_holder.SetViewProperties(std::move(view_properties)); - surface_view_holder.SetHitTestBehavior( + surface_view_holder_->SetViewProperties(std::move(view_properties)); + surface_view_holder_->SetHitTestBehavior( fuchsia::ui::gfx::HitTestBehavior::kSuppress); render_node_.DetachChildren(); - render_node_.Attach(surface_view_holder); + render_node_.AddChild(*surface_view_holder_); scenic_session_.Present( /*presentation_time=*/0, [](fuchsia::images::PresentationInfo info) {});
diff --git a/ui/ozone/platform/scenic/scenic_window.h b/ui/ozone/platform/scenic/scenic_window.h index 2b6197b8..7277075 100644 --- a/ui/ozone/platform/scenic/scenic_window.h +++ b/ui/ozone/platform/scenic/scenic_window.h
@@ -116,6 +116,7 @@ // Node in |scenic_session_| for rendering (hit testing disabled). scenic::EntityNode render_node_; + std::unique_ptr<scenic::ViewHolder> surface_view_holder_; // The ratio used for translating device-independent coordinates to absolute // pixel coordinates.
diff --git a/ui/views/cocoa/text_input_host.mm b/ui/views/cocoa/text_input_host.mm index 9607e56..ddeba0c4 100644 --- a/ui/views/cocoa/text_input_host.mm +++ b/ui/views/cocoa/text_input_host.mm
@@ -301,7 +301,7 @@ void TextInputHost::ConfirmCompositionText() { if (!text_input_client_) return; - text_input_client_->ConfirmCompositionText(); + text_input_client_->ConfirmCompositionText(/* keep_selection */ false); } bool TextInputHost::HasCompositionText(bool* out_has_composition_text) {
diff --git a/ui/views/controls/prefix_selector.cc b/ui/views/controls/prefix_selector.cc index ceab3ca..4d9cde2 100644 --- a/ui/views/controls/prefix_selector.cc +++ b/ui/views/controls/prefix_selector.cc
@@ -41,8 +41,7 @@ const ui::CompositionText& composition) { } -void PrefixSelector::ConfirmCompositionText() { -} +void PrefixSelector::ConfirmCompositionText(bool keep_selection) {} void PrefixSelector::ClearCompositionText() { }
diff --git a/ui/views/controls/prefix_selector.h b/ui/views/controls/prefix_selector.h index 84a9657..9f08b202 100644 --- a/ui/views/controls/prefix_selector.h +++ b/ui/views/controls/prefix_selector.h
@@ -44,7 +44,7 @@ // ui::TextInputClient: void SetCompositionText(const ui::CompositionText& composition) override; - void ConfirmCompositionText() override; + void ConfirmCompositionText(bool keep_selection) override; void ClearCompositionText() override; void InsertText(const base::string16& text) override; void InsertChar(const ui::KeyEvent& event) override;
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc index 31985ec07..9e85918 100644 --- a/ui/views/controls/textfield/textfield.cc +++ b/ui/views/controls/textfield/textfield.cc
@@ -1462,7 +1462,12 @@ OnAfterUserAction(); } -void Textfield::ConfirmCompositionText() { +void Textfield::ConfirmCompositionText(bool keep_selection) { + // TODO(b/134473433) Modify this function so that when keep_selection is + // true, the selection is not changed when text committed + if (keep_selection) { + NOTIMPLEMENTED_LOG_ONCE(); + } if (!model_->HasCompositionText()) return;
diff --git a/ui/views/controls/textfield/textfield.h b/ui/views/controls/textfield/textfield.h index 9d31ab8..8357ff7 100644 --- a/ui/views/controls/textfield/textfield.h +++ b/ui/views/controls/textfield/textfield.h
@@ -339,7 +339,7 @@ // ui::TextInputClient overrides: void SetCompositionText(const ui::CompositionText& composition) override; - void ConfirmCompositionText() override; + void ConfirmCompositionText(bool keep_selection) override; void ClearCompositionText() override; void InsertText(const base::string16& text) override; void InsertChar(const ui::KeyEvent& event) override;
diff --git a/ui/views/controls/textfield/textfield_unittest.cc b/ui/views/controls/textfield/textfield_unittest.cc index 85bd50c..5ec471c 100644 --- a/ui/views/controls/textfield/textfield_unittest.cc +++ b/ui/views/controls/textfield/textfield_unittest.cc
@@ -222,7 +222,7 @@ ui::TextInputClient* focused) { ui::TextInputClient* client = GetTextInputClient(); if (client && client->HasCompositionText()) - client->ConfirmCompositionText(); + client->ConfirmCompositionText(/* keep_selection */ false); ClearComposition(); }
diff --git a/ui/views/controls/webview/web_dialog_view.cc b/ui/views/controls/webview/web_dialog_view.cc index fc3bb0b..f4a07f2 100644 --- a/ui/views/controls/webview/web_dialog_view.cc +++ b/ui/views/controls/webview/web_dialog_view.cc
@@ -268,10 +268,9 @@ return std::string(); } -void WebDialogView::OnDialogShown(content::WebUI* webui, - content::RenderViewHost* render_view_host) { +void WebDialogView::OnDialogShown(content::WebUI* webui) { if (delegate_) - delegate_->OnDialogShown(webui, render_view_host); + delegate_->OnDialogShown(webui); } void WebDialogView::OnDialogClosed(const std::string& json_retval) {
diff --git a/ui/views/controls/webview/web_dialog_view.h b/ui/views/controls/webview/web_dialog_view.h index e395998..50a6290 100644 --- a/ui/views/controls/webview/web_dialog_view.h +++ b/ui/views/controls/webview/web_dialog_view.h
@@ -114,8 +114,7 @@ void GetDialogSize(gfx::Size* size) const override; void GetMinimumDialogSize(gfx::Size* size) const override; std::string GetDialogArgs() const override; - void OnDialogShown(content::WebUI* webui, - content::RenderViewHost* render_view_host) override; + void OnDialogShown(content::WebUI* webui) override; void OnDialogClosed(const std::string& json_retval) override; void OnDialogCloseFromWebUI(const std::string& json_retval) override; void OnCloseContents(content::WebContents* source,
diff --git a/ui/web_dialogs/web_dialog_delegate.h b/ui/web_dialogs/web_dialog_delegate.h index 08a4dd5..9aa90df 100644 --- a/ui/web_dialogs/web_dialog_delegate.h +++ b/ui/web_dialogs/web_dialog_delegate.h
@@ -19,7 +19,6 @@ namespace content { class RenderFrameHost; -class RenderViewHost; class WebContents; class WebUI; class WebUIMessageHandler; @@ -88,9 +87,7 @@ // A callback to notify the delegate that a web dialog has been shown. // |webui| is the WebUI with which the dialog is associated. - // |render_view_host| is the RenderViewHost for the shown dialog. - virtual void OnDialogShown(content::WebUI* webui, - content::RenderViewHost* render_view_host) {} + virtual void OnDialogShown(content::WebUI* webui) {} // A callback to notify the delegate that the window is requesting to be // closed. If this returns true, the dialog is closed, otherwise the
diff --git a/ui/web_dialogs/web_dialog_ui.cc b/ui/web_dialogs/web_dialog_ui.cc index 15f230d..ca118e3 100644 --- a/ui/web_dialogs/web_dialog_ui.cc +++ b/ui/web_dialogs/web_dialog_ui.cc
@@ -10,7 +10,6 @@ #include "base/memory/ptr_util.h" #include "base/values.h" #include "content/public/browser/render_frame_host.h" -#include "content/public/browser/render_view_host.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_ui.h" #include "content/public/browser/web_ui_message_handler.h" @@ -95,7 +94,7 @@ web_ui_->AddMessageHandler(base::WrapUnique(handler)); if (delegate) - delegate->OnDialogShown(web_ui_, render_frame_host->GetRenderViewHost()); + delegate->OnDialogShown(web_ui_); } void WebDialogUIBase::OnDialogClosed(const base::ListValue* args) {
diff --git a/weblayer/public/java/org/chromium/weblayer/Browser.java b/weblayer/public/java/org/chromium/weblayer/Browser.java index deca88bc..5d59a4f 100644 --- a/weblayer/public/java/org/chromium/weblayer/Browser.java +++ b/weblayer/public/java/org/chromium/weblayer/Browser.java
@@ -162,7 +162,7 @@ * * @param callback The TabListCallback. */ - public void addTabListCallback(@NonNull TabListCallback callback) { + public void registerTabListCallback(@NonNull TabListCallback callback) { ThreadCheck.ensureOnUiThread(); mTabListCallbacks.addObserver(callback); } @@ -172,7 +172,7 @@ * * @param callback The TabListCallback. */ - public void removeTabListCallback(@NonNull TabListCallback callback) { + public void unregisterTabListCallback(@NonNull TabListCallback callback) { ThreadCheck.ensureOnUiThread(); mTabListCallbacks.removeObserver(callback); }
diff --git a/weblayer/public/java/org/chromium/weblayer/BrowsingDataType.java b/weblayer/public/java/org/chromium/weblayer/BrowsingDataType.java index 668ab96..2522c7f 100644 --- a/weblayer/public/java/org/chromium/weblayer/BrowsingDataType.java +++ b/weblayer/public/java/org/chromium/weblayer/BrowsingDataType.java
@@ -9,6 +9,9 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +/** + * @hide + */ @IntDef({BrowsingDataType.COOKIES_AND_SITE_DATA, BrowsingDataType.CACHE}) @Retention(RetentionPolicy.SOURCE) public @interface BrowsingDataType {
diff --git a/weblayer/public/java/org/chromium/weblayer/DownloadCallback.java b/weblayer/public/java/org/chromium/weblayer/DownloadCallback.java index 79cc7a55..37d8b8e 100644 --- a/weblayer/public/java/org/chromium/weblayer/DownloadCallback.java +++ b/weblayer/public/java/org/chromium/weblayer/DownloadCallback.java
@@ -19,6 +19,6 @@ * @param mimetype the mimetype of the content reported by the server * @param contentLength the file size reported by the server */ - public abstract void downloadRequested(@NonNull String url, @NonNull String userAgent, + public abstract void onDownloadRequested(@NonNull String url, @NonNull String userAgent, @NonNull String contentDisposition, @NonNull String mimetype, long contentLength); }
diff --git a/weblayer/public/java/org/chromium/weblayer/FullscreenCallback.java b/weblayer/public/java/org/chromium/weblayer/FullscreenCallback.java index 2ae2bc8..e66c989f 100644 --- a/weblayer/public/java/org/chromium/weblayer/FullscreenCallback.java +++ b/weblayer/public/java/org/chromium/weblayer/FullscreenCallback.java
@@ -19,10 +19,10 @@ * * NOTE: the Runnable must not be used synchronously. */ - public abstract void enterFullscreen(@NonNull Runnable exitFullscreenRunner); + public abstract void onEnterFullscreen(@NonNull Runnable exitFullscreenRunner); /** * The page has exited fullscreen mode and the system should be moved out of fullscreen mode. */ - public abstract void exitFullscreen(); + public abstract void onExitFullscreen(); }
diff --git a/weblayer/public/java/org/chromium/weblayer/NavigationCallback.java b/weblayer/public/java/org/chromium/weblayer/NavigationCallback.java index 543df4c5..d996b19 100644 --- a/weblayer/public/java/org/chromium/weblayer/NavigationCallback.java +++ b/weblayer/public/java/org/chromium/weblayer/NavigationCallback.java
@@ -39,14 +39,14 @@ * * @param navigation the unique object for this navigation. */ - public void navigationStarted(@NonNull Navigation navigation) {} + public void onNavigationStarted(@NonNull Navigation navigation) {} /** * Called when a navigation encountered a server redirect. * * @param navigation the unique object for this navigation. */ - public void navigationRedirected(@NonNull Navigation navigation) {} + public void onNavigationRedirected(@NonNull Navigation navigation) {} /** * Called when the navigation is ready to be committed in a renderer. This occurs when the @@ -61,7 +61,7 @@ * * @param navigation the unique object for this navigation. */ - public void readyToCommitNavigation(@NonNull Navigation navigation) {} + public void onReadyToCommitNavigation(@NonNull Navigation navigation) {} /** * Called when a navigation completes successfully in the Tab. @@ -79,7 +79,7 @@ * * @param navigation the unique object for this navigation. */ - public void navigationCompleted(@NonNull Navigation navigation) {} + public void onNavigationCompleted(@NonNull Navigation navigation) {} /** * Called when a navigation aborts in the Tab. @@ -89,7 +89,7 @@ * * @param navigation the unique object for this navigation. */ - public void navigationFailed(@NonNull Navigation navigation) {} + public void onNavigationFailed(@NonNull Navigation navigation) {} /** * The load state of the document has changed. @@ -98,14 +98,14 @@ * @param toDifferentDocument True if the main frame is loading a different document. Only valid * when |isLoading| is true. */ - public void loadStateChanged(boolean isLoading, boolean toDifferentDocument) {} + public void onLoadStateChanged(boolean isLoading, boolean toDifferentDocument) {} /** * The progress of loading the main frame in the document has changed. * * @param progress A value in the range of 0.0-1.0. */ - public void loadProgressChanged(double progress) {} + public void onLoadProgressChanged(double progress) {} /** * This is fired after each navigation has completed to indicate that the first paint after a
diff --git a/weblayer/public/java/org/chromium/weblayer/NavigationController.java b/weblayer/public/java/org/chromium/weblayer/NavigationController.java index 9273ee8..2879e86 100644 --- a/weblayer/public/java/org/chromium/weblayer/NavigationController.java +++ b/weblayer/public/java/org/chromium/weblayer/NavigationController.java
@@ -148,49 +148,49 @@ @Override public void navigationStarted(IClientNavigation navigation) { for (NavigationCallback callback : mCallbacks) { - callback.navigationStarted((Navigation) navigation); + callback.onNavigationStarted((Navigation) navigation); } } @Override public void navigationRedirected(IClientNavigation navigation) { for (NavigationCallback callback : mCallbacks) { - callback.navigationRedirected((Navigation) navigation); + callback.onNavigationRedirected((Navigation) navigation); } } @Override public void readyToCommitNavigation(IClientNavigation navigation) { for (NavigationCallback callback : mCallbacks) { - callback.readyToCommitNavigation((Navigation) navigation); + callback.onReadyToCommitNavigation((Navigation) navigation); } } @Override public void navigationCompleted(IClientNavigation navigation) { for (NavigationCallback callback : mCallbacks) { - callback.navigationCompleted((Navigation) navigation); + callback.onNavigationCompleted((Navigation) navigation); } } @Override public void navigationFailed(IClientNavigation navigation) { for (NavigationCallback callback : mCallbacks) { - callback.navigationFailed((Navigation) navigation); + callback.onNavigationFailed((Navigation) navigation); } } @Override public void loadStateChanged(boolean isLoading, boolean toDifferentDocument) { for (NavigationCallback callback : mCallbacks) { - callback.loadStateChanged(isLoading, toDifferentDocument); + callback.onLoadStateChanged(isLoading, toDifferentDocument); } } @Override public void loadProgressChanged(double progress) { for (NavigationCallback callback : mCallbacks) { - callback.loadProgressChanged(progress); + callback.onLoadProgressChanged(progress); } }
diff --git a/weblayer/public/java/org/chromium/weblayer/NewTabType.java b/weblayer/public/java/org/chromium/weblayer/NewTabType.java index 37aa62dd..9a87d28 100644 --- a/weblayer/public/java/org/chromium/weblayer/NewTabType.java +++ b/weblayer/public/java/org/chromium/weblayer/NewTabType.java
@@ -9,6 +9,9 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +/** + * @hide + */ @IntDef({NewTabType.FOREGROUND_TAB, NewTabType.BACKGROUND_TAB, NewTabType.NEW_POPUP, NewTabType.NEW_WINDOW}) @Retention(RetentionPolicy.SOURCE)
diff --git a/weblayer/public/java/org/chromium/weblayer/Tab.java b/weblayer/public/java/org/chromium/weblayer/Tab.java index 60b6055..f9f5a0c 100644 --- a/weblayer/public/java/org/chromium/weblayer/Tab.java +++ b/weblayer/public/java/org/chromium/weblayer/Tab.java
@@ -93,6 +93,7 @@ mBrowser = browser; } + @NonNull public Browser getBrowser() { ThreadCheck.ensureOnUiThread(); return mBrowser; @@ -128,6 +129,7 @@ } } + @Nullable public DownloadCallback getDownloadCallback() { ThreadCheck.ensureOnUiThread(); return mDownloadCallbackClient != null ? mDownloadCallbackClient.getCallback() : null; @@ -207,7 +209,7 @@ public void visibleUrlChanged(String url) { Uri uri = Uri.parse(url); for (TabCallback callback : mCallbacks) { - callback.visibleUrlChanged(uri); + callback.onVisibleUrlChanged(uri); } } @@ -238,7 +240,7 @@ @Override public void downloadRequested(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) { - mCallback.downloadRequested( + mCallback.onDownloadRequested( url, userAgent, contentDisposition, mimetype, contentLength); } } @@ -258,12 +260,12 @@ public void enterFullscreen(IObjectWrapper exitFullscreenWrapper) { ValueCallback<Void> exitFullscreenCallback = (ValueCallback<Void>) ObjectWrapper.unwrap( exitFullscreenWrapper, ValueCallback.class); - mCallback.enterFullscreen(() -> exitFullscreenCallback.onReceiveValue(null)); + mCallback.onEnterFullscreen(() -> exitFullscreenCallback.onReceiveValue(null)); } @Override public void exitFullscreen() { - mCallback.exitFullscreen(); + mCallback.onExitFullscreen(); } } }
diff --git a/weblayer/public/java/org/chromium/weblayer/TabCallback.java b/weblayer/public/java/org/chromium/weblayer/TabCallback.java index 7d139ce..045b9e3 100644 --- a/weblayer/public/java/org/chromium/weblayer/TabCallback.java +++ b/weblayer/public/java/org/chromium/weblayer/TabCallback.java
@@ -17,5 +17,5 @@ * * @param url The new user-visible url. */ - public void visibleUrlChanged(@NonNull Uri url) {} + public void onVisibleUrlChanged(@NonNull Uri url) {} }
diff --git a/weblayer/public/java/org/chromium/weblayer/WebLayer.java b/weblayer/public/java/org/chromium/weblayer/WebLayer.java index 84f60d2ad..ff289db0 100644 --- a/weblayer/public/java/org/chromium/weblayer/WebLayer.java +++ b/weblayer/public/java/org/chromium/weblayer/WebLayer.java
@@ -81,7 +81,7 @@ * completes */ @NonNull - public static ListenableFuture<WebLayer> create(Context appContext) + public static ListenableFuture<WebLayer> create(@NonNull Context appContext) throws UnsupportedVersionException { ThreadCheck.ensureOnUiThread(); if (sFuture == null) {
diff --git a/weblayer/shell/android/browsertests_apk/src/org/chromium/weblayer_browsertests_apk/WebLayerBrowserTestsActivity.java b/weblayer/shell/android/browsertests_apk/src/org/chromium/weblayer_browsertests_apk/WebLayerBrowserTestsActivity.java index c844ebb..062ba3c 100644 --- a/weblayer/shell/android/browsertests_apk/src/org/chromium/weblayer_browsertests_apk/WebLayerBrowserTestsActivity.java +++ b/weblayer/shell/android/browsertests_apk/src/org/chromium/weblayer_browsertests_apk/WebLayerBrowserTestsActivity.java
@@ -90,7 +90,7 @@ mTab = mBrowser.getActiveTab(); mTab.registerTabCallback(new TabCallback() { @Override - public void visibleUrlChanged(Uri uri) { + public void onVisibleUrlChanged(Uri uri) { mUrlView.setText(uri.toString()); } });
diff --git a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/BrowserFragmentLifecycleTest.java b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/BrowserFragmentLifecycleTest.java index 7a24248..4a734bfa 100644 --- a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/BrowserFragmentLifecycleTest.java +++ b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/BrowserFragmentLifecycleTest.java
@@ -57,7 +57,7 @@ NavigationController navigationController = activity.getTab().getNavigationController(); navigationController.registerNavigationCallback(new NavigationCallback() { @Override - public void readyToCommitNavigation(@NonNull Navigation navigation) { + public void onReadyToCommitNavigation(@NonNull Navigation navigation) { FragmentManager fm = activity.getSupportFragmentManager(); fm.beginTransaction() .remove(fm.getFragments().get(0))
diff --git a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/DownloadCallbackTest.java b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/DownloadCallbackTest.java index 3b8212d..33910bc 100644 --- a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/DownloadCallbackTest.java +++ b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/DownloadCallbackTest.java
@@ -5,7 +5,6 @@ package org.chromium.weblayer.test; import android.net.Uri; -import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; import android.util.Pair; @@ -19,7 +18,6 @@ import org.chromium.content_public.browser.test.util.Criteria; import org.chromium.content_public.browser.test.util.CriteriaHelper; import org.chromium.content_public.browser.test.util.TestThreadUtils; -import org.chromium.net.test.EmbeddedTestServer; import org.chromium.net.test.util.TestWebServer; import org.chromium.weblayer.DownloadCallback; import org.chromium.weblayer.shell.InstrumentationActivity; @@ -47,7 +45,7 @@ public long mContentLength; @Override - public void downloadRequested(String url, String userAgent, String contentDisposition, + public void onDownloadRequested(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) { mUrl = url; mUserAgent = userAgent; @@ -117,20 +115,11 @@ @Test @SmallTest public void testDownloadByLinkAttribute() { - EmbeddedTestServer testServer = new EmbeddedTestServer(); - - testServer.initializeNative(InstrumentationRegistry.getInstrumentation().getContext(), - EmbeddedTestServer.ServerHTTPSSetting.USE_HTTP); - testServer.addDefaultHandlers("weblayer/test/data"); - Assert.assertTrue(testServer.start(0)); - - String pageUrl = testServer.getURL("/download.html"); + String pageUrl = mActivityTestRule.getTestDataURL("download.html"); mActivityTestRule.navigateAndWait(pageUrl); EventUtils.simulateTouchCenterOfView(mActivity.getWindow().getDecorView()); mCallback.waitForDownload(); - Assert.assertEquals(testServer.getURL("/lorem_ipsum.txt"), mCallback.mUrl); - - testServer.stopAndDestroyServer(); + Assert.assertEquals(mActivityTestRule.getTestDataURL("lorem_ipsum.txt"), mCallback.mUrl); } }
diff --git a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/FullscreenCallbackTest.java b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/FullscreenCallbackTest.java index a74838e70..ba346b9 100644 --- a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/FullscreenCallbackTest.java +++ b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/FullscreenCallbackTest.java
@@ -4,10 +4,8 @@ package org.chromium.weblayer.test; -import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; -import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Rule; @@ -18,7 +16,6 @@ import org.chromium.content_public.browser.test.util.Criteria; import org.chromium.content_public.browser.test.util.CriteriaHelper; import org.chromium.content_public.browser.test.util.TestThreadUtils; -import org.chromium.net.test.EmbeddedTestServer; import org.chromium.weblayer.FullscreenCallback; import org.chromium.weblayer.shell.InstrumentationActivity; @@ -31,7 +28,6 @@ public InstrumentationActivityTestRule mActivityTestRule = new InstrumentationActivityTestRule(); - private EmbeddedTestServer mTestServer; private InstrumentationActivity mActivity; private Delegate mDelegate; @@ -41,13 +37,13 @@ public Runnable mExitFullscreenRunnable; @Override - public void enterFullscreen(Runnable exitFullscreenRunner) { + public void onEnterFullscreen(Runnable exitFullscreenRunner) { mEnterFullscreenCount++; mExitFullscreenRunnable = exitFullscreenRunner; } @Override - public void exitFullscreen() { + public void onExitFullscreen() { mExitFullscreenCount++; } @@ -72,13 +68,7 @@ @Before public void setUp() { - mTestServer = new EmbeddedTestServer(); - mTestServer.initializeNative(InstrumentationRegistry.getInstrumentation().getContext(), - EmbeddedTestServer.ServerHTTPSSetting.USE_HTTP); - mTestServer.addDefaultHandlers("weblayer/test/data"); - Assert.assertTrue(mTestServer.start(0)); - - String url = mTestServer.getURL("/fullscreen.html"); + String url = mActivityTestRule.getTestDataURL("fullscreen.html"); mActivity = mActivityTestRule.launchShellWithUrl(url); Assert.assertNotNull(mActivity); mDelegate = new Delegate(); @@ -91,11 +81,6 @@ Assert.assertEquals(1, mDelegate.mEnterFullscreenCount); } - @After - public void tearDown() { - mTestServer.stopAndDestroyServer(); - } - @Test @SmallTest public void testFullscreen() {
diff --git a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/InputTypesTest.java b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/InputTypesTest.java index 0a1a6cc..63587e9 100644 --- a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/InputTypesTest.java +++ b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/InputTypesTest.java
@@ -16,7 +16,6 @@ import android.os.Handler; import android.os.Parcelable; import android.provider.MediaStore; -import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; import android.support.v4.app.ActivityCompat; import android.support.v4.app.Fragment; @@ -34,7 +33,6 @@ import org.chromium.base.test.util.MinAndroidSdkLevel; import org.chromium.content_public.browser.test.util.CriteriaHelper; import org.chromium.content_public.browser.test.util.TestThreadUtils; -import org.chromium.net.test.EmbeddedTestServer; import org.chromium.weblayer.shell.InstrumentationActivity; import java.io.File; @@ -49,7 +47,6 @@ public InstrumentationActivityTestRule mActivityTestRule = new InstrumentationActivityTestRule(); - private EmbeddedTestServer mTestServer; private File mTempFile; private int mCameraPermission = PackageManager.PERMISSION_GRANTED; @@ -127,12 +124,6 @@ @Before public void setUp() throws Exception { - mTestServer = new EmbeddedTestServer(); - mTestServer.initializeNative(InstrumentationRegistry.getInstrumentation().getContext(), - EmbeddedTestServer.ServerHTTPSSetting.USE_HTTP); - mTestServer.addDefaultHandlers("weblayer/test/data"); - Assert.assertTrue(mTestServer.start(0)); - InstrumentationActivity activity = mActivityTestRule.launchShell(new Bundle()); TestThreadUtils.runOnUiThreadBlocking(() -> { activity.createWebLayer( @@ -148,7 +139,7 @@ null) .get(); }); - mActivityTestRule.navigateAndWait(mTestServer.getURL("/input_types.html")); + mActivityTestRule.navigateAndWait(mActivityTestRule.getTestDataURL("input_types.html")); mTempFile = File.createTempFile("file", null); activity.setIntentInterceptor(mIntentInterceptor); ActivityCompat.setPermissionCompatDelegate(mPermissionCompatDelegate);
diff --git a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/InstrumentationActivityTestRule.java b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/InstrumentationActivityTestRule.java index 0a796b53..83d3377 100644 --- a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/InstrumentationActivityTestRule.java +++ b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/InstrumentationActivityTestRule.java
@@ -16,10 +16,15 @@ import org.json.JSONException; import org.json.JSONObject; import org.junit.Assert; +import org.junit.Rule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; import org.chromium.base.test.util.CallbackHelper; import org.chromium.content_public.browser.test.util.CriteriaHelper; import org.chromium.content_public.browser.test.util.TestThreadUtils; +import org.chromium.net.test.EmbeddedTestServer; +import org.chromium.net.test.EmbeddedTestServerRule; import org.chromium.weblayer.Navigation; import org.chromium.weblayer.NavigationCallback; import org.chromium.weblayer.Tab; @@ -36,6 +41,9 @@ * Test can use this ActivityTestRule to launch or get InstrumentationActivity. */ public class InstrumentationActivityTestRule extends ActivityTestRule<InstrumentationActivity> { + @Rule + private EmbeddedTestServerRule mTestServerRule = new EmbeddedTestServerRule(); + private static final class NavigationWaiter { private String mUrl; private Tab mTab; @@ -46,7 +54,7 @@ private NavigationCallback mNavigationCallback = new NavigationCallback() { @Override - public void navigationCompleted(Navigation navigation) { + public void onNavigationCompleted(Navigation navigation) { if (navigation.getUri().toString().equals(mUrl)) { mNavigationComplete = true; checkComplete(); @@ -54,7 +62,7 @@ } @Override - public void loadStateChanged(boolean isLoading, boolean toDifferentDocument) { + public void onLoadStateChanged(boolean isLoading, boolean toDifferentDocument) { mDoneLoading = !isLoading; checkComplete(); } @@ -114,6 +122,11 @@ super(InstrumentationActivity.class, false, false); } + @Override + public Statement apply(final Statement base, Description description) { + return super.apply(mTestServerRule.apply(base, description), description); + } + public WebLayer getWebLayer() { return TestThreadUtils.runOnUiThreadBlockingNoException(() -> { return WebLayer @@ -249,4 +262,12 @@ String url = "data:text,foo"; return launchShellWithUrl(url, extras); } + + public EmbeddedTestServer getTestServer() { + return mTestServerRule.getServer(); + } + + public String getTestDataURL(String path) { + return getTestServer().getURL("/weblayer/test/data/" + path); + } }
diff --git a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/NavigationTest.java b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/NavigationTest.java index 64c0ac80..622c1e6 100644 --- a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/NavigationTest.java +++ b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/NavigationTest.java
@@ -110,17 +110,17 @@ public CallbackHelper onFirstContentfulPaintCallback = new CallbackHelper(); @Override - public void navigationStarted(Navigation navigation) { + public void onNavigationStarted(Navigation navigation) { onStartedCallback.notifyCalled(navigation.getUri()); } @Override - public void readyToCommitNavigation(Navigation navigation) { + public void onReadyToCommitNavigation(Navigation navigation) { onReadyToCommitCallback.notifyCalled(navigation.getUri()); } @Override - public void navigationCompleted(Navigation navigation) { + public void onNavigationCompleted(Navigation navigation) { onCompletedCallback.notifyCalled(navigation.getUri(), navigation.isSameDocument()); } @@ -130,13 +130,13 @@ } @Override - public void loadStateChanged(boolean isLoading, boolean toDifferentDocument) { + public void onLoadStateChanged(boolean isLoading, boolean toDifferentDocument) { loadStateChangedCallback.recordValue( Boolean.toString(isLoading) + " " + Boolean.toString(toDifferentDocument)); } @Override - public void loadProgressChanged(double progress) { + public void onLoadProgressChanged(double progress) { loadProgressChangedCallback.recordValue( progress == 1 ? "load complete" : "load started"); }
diff --git a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/NewTabCallbackTest.java b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/NewTabCallbackTest.java index 76fdeb8..ad9085b6 100644 --- a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/NewTabCallbackTest.java +++ b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/NewTabCallbackTest.java
@@ -4,19 +4,15 @@ package org.chromium.weblayer.test; -import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; -import org.junit.After; import org.junit.Assert; -import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.chromium.base.test.BaseJUnit4ClassRunner; import org.chromium.content_public.browser.test.util.TestThreadUtils; -import org.chromium.net.test.EmbeddedTestServer; import org.chromium.weblayer.Tab; import org.chromium.weblayer.shell.InstrumentationActivity; @@ -29,27 +25,12 @@ public InstrumentationActivityTestRule mActivityTestRule = new InstrumentationActivityTestRule(); - private EmbeddedTestServer mTestServer; private InstrumentationActivity mActivity; - @Before - public void setUp() { - mTestServer = new EmbeddedTestServer(); - mTestServer.initializeNative(InstrumentationRegistry.getInstrumentation().getContext(), - EmbeddedTestServer.ServerHTTPSSetting.USE_HTTP); - mTestServer.addDefaultHandlers("weblayer/test/data"); - Assert.assertTrue(mTestServer.start(0)); - } - - @After - public void tearDown() { - mTestServer.stopAndDestroyServer(); - } - @Test @SmallTest public void testNewBrowser() { - String url = mTestServer.getURL("/new_browser.html"); + String url = mActivityTestRule.getTestDataURL("new_browser.html"); mActivity = mActivityTestRule.launchShellWithUrl(url); Assert.assertNotNull(mActivity); NewTabCallbackImpl callback = new NewTabCallbackImpl();
diff --git a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/TabCallbackTest.java b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/TabCallbackTest.java index 7358a992..411e266d 100644 --- a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/TabCallbackTest.java +++ b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/TabCallbackTest.java
@@ -60,7 +60,7 @@ public TabCallbackValueRecorder visibleUrlChangedCallback = new TabCallbackValueRecorder(); @Override - public void visibleUrlChanged(Uri url) { + public void onVisibleUrlChanged(Uri url) { visibleUrlChangedCallback.recordValue(url.toString()); } }
diff --git a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/TabListCallbackTest.java b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/TabListCallbackTest.java index 7355230b..a38fbf66 100644 --- a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/TabListCallbackTest.java +++ b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/TabListCallbackTest.java
@@ -5,10 +5,8 @@ package org.chromium.weblayer.test; import android.os.Bundle; -import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; -import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Rule; @@ -17,7 +15,6 @@ import org.chromium.base.test.BaseJUnit4ClassRunner; import org.chromium.content_public.browser.test.util.TestThreadUtils; -import org.chromium.net.test.EmbeddedTestServer; import org.chromium.weblayer.Browser; import org.chromium.weblayer.Tab; import org.chromium.weblayer.TabListCallback; @@ -36,7 +33,6 @@ public InstrumentationActivityTestRule mActivityTestRule = new InstrumentationActivityTestRule(); - private EmbeddedTestServer mTestServer; private InstrumentationActivity mActivity; private Tab mFirstTab; private Tab mSecondTab; @@ -75,13 +71,7 @@ @Before public void setUp() { - mTestServer = new EmbeddedTestServer(); - mTestServer.initializeNative(InstrumentationRegistry.getInstrumentation().getContext(), - EmbeddedTestServer.ServerHTTPSSetting.USE_HTTP); - mTestServer.addDefaultHandlers("weblayer/test/data"); - Assert.assertTrue(mTestServer.start(0)); - - String url = mTestServer.getURL("/new_browser.html"); + String url = mActivityTestRule.getTestDataURL("new_browser.html"); mActivity = mActivityTestRule.launchShellWithUrl(url); Assert.assertNotNull(mActivity); NewTabCallbackImpl callback = new NewTabCallbackImpl(); @@ -100,17 +90,12 @@ }); } - @After - public void tearDown() { - mTestServer.stopAndDestroyServer(); - } - @Test @SmallTest public void testActiveTabChanged() { TestThreadUtils.runOnUiThreadBlocking(() -> { TabListCallbackImpl callback = new TabListCallbackImpl(); - mActivity.getBrowser().addTabListCallback(callback); + mActivity.getBrowser().registerTabListCallback(callback); mActivity.getBrowser().setActiveTab(mFirstTab); Assert.assertTrue(callback.getObservedValues().contains(TabListCallbackImpl.ACTIVE)); }); @@ -124,10 +109,10 @@ Browser.fromFragment(mActivity.createBrowserFragment(0, new Bundle())); Browser browser1 = mActivity.getBrowser(); TabListCallbackImpl callback1 = new TabListCallbackImpl(); - browser1.addTabListCallback(callback1); + browser1.registerTabListCallback(callback1); TabListCallbackImpl callback2 = new TabListCallbackImpl(); - browser2.addTabListCallback(callback2); + browser2.registerTabListCallback(callback2); // Move the active tab from browser1 to browser2. Tab tabToMove = browser1.getActiveTab(); @@ -157,7 +142,7 @@ TestThreadUtils.runOnUiThreadBlocking(() -> { TabListCallbackImpl callback = new TabListCallbackImpl(); Browser browser = mActivity.getBrowser(); - browser.addTabListCallback(callback); + browser.registerTabListCallback(callback); browser.destroyTab(mActivity.getBrowser().getActiveTab()); Assert.assertTrue(callback.getObservedValues().contains(TabListCallbackImpl.ACTIVE)); Assert.assertEquals(1, browser.getTabs().size());
diff --git a/weblayer/shell/android/shell_apk/src/org/chromium/weblayer/shell/InstrumentationActivity.java b/weblayer/shell/android/shell_apk/src/org/chromium/weblayer/shell/InstrumentationActivity.java index d427b53..5445c689 100644 --- a/weblayer/shell/android/shell_apk/src/org/chromium/weblayer/shell/InstrumentationActivity.java +++ b/weblayer/shell/android/shell_apk/src/org/chromium/weblayer/shell/InstrumentationActivity.java
@@ -135,7 +135,7 @@ mTab = mBrowser.getActiveTab(); mTab.registerTabCallback(new TabCallback() { @Override - public void visibleUrlChanged(Uri uri) { + public void onVisibleUrlChanged(Uri uri) { mUrlView.setText(uri.toString()); } });
diff --git a/weblayer/shell/android/shell_apk/src/org/chromium/weblayer/shell/WebLayerShellActivity.java b/weblayer/shell/android/shell_apk/src/org/chromium/weblayer/shell/WebLayerShellActivity.java index 5ba865b..f2a32bb9 100644 --- a/weblayer/shell/android/shell_apk/src/org/chromium/weblayer/shell/WebLayerShellActivity.java +++ b/weblayer/shell/android/shell_apk/src/org/chromium/weblayer/shell/WebLayerShellActivity.java
@@ -130,7 +130,7 @@ private int mSystemVisibilityToRestore; @Override - public void enterFullscreen(Runnable exitFullscreenRunnable) { + public void onEnterFullscreen(Runnable exitFullscreenRunnable) { // This comes from Chrome code to avoid an extra resize. final WindowManager.LayoutParams attrs = getWindow().getAttributes(); attrs.flags |= WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; @@ -150,7 +150,7 @@ } @Override - public void exitFullscreen() { + public void onExitFullscreen() { View decorView = getWindow().getDecorView(); decorView.setSystemUiVisibility(mSystemVisibilityToRestore); @@ -174,26 +174,25 @@ loadUrl(startupUrl); mTab.registerTabCallback(new TabCallback() { @Override - public void visibleUrlChanged(Uri uri) { + public void onVisibleUrlChanged(Uri uri) { mUrlView.setText(uri.toString()); } }); - mTab.getNavigationController().registerNavigationCallback( - new NavigationCallback() { - @Override - public void loadStateChanged(boolean isLoading, boolean toDifferentDocument) { - mLoadProgressBar.setVisibility( - isLoading && toDifferentDocument ? View.VISIBLE : View.INVISIBLE); - } + mTab.getNavigationController().registerNavigationCallback(new NavigationCallback() { + @Override + public void onLoadStateChanged(boolean isLoading, boolean toDifferentDocument) { + mLoadProgressBar.setVisibility( + isLoading && toDifferentDocument ? View.VISIBLE : View.INVISIBLE); + } - @Override - public void loadProgressChanged(double progress) { - mLoadProgressBar.setProgress((int) Math.round(100 * progress)); - } - }); + @Override + public void onLoadProgressChanged(double progress) { + mLoadProgressBar.setProgress((int) Math.round(100 * progress)); + } + }); mTab.setDownloadCallback(new DownloadCallback() { @Override - public void downloadRequested(String url, String userAgent, String contentDisposition, + public void onDownloadRequested(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) { DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url)); request.setNotificationVisibility(