chromium/chrome/browser/ui/ash/global_media_controls/global_media_controls_cast_start_browsertest.cc

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/root_window_controller.h"
#include "ash/shelf/shelf.h"
#include "ash/shell.h"
#include "ash/system/media/media_tray.h"
#include "ash/system/status_area_widget.h"
#include "base/test/scoped_feature_list.h"
#include "base/unguessable_token.h"
#include "chrome/browser/ash/crosapi/crosapi_ash.h"
#include "chrome/browser/ash/crosapi/crosapi_manager.h"
#include "chrome/browser/ash/crosapi/media_ui_ash.h"
#include "chrome/browser/media/router/media_router_feature.h"
#include "chrome/browser/ui/ash/global_media_controls/media_notification_provider_impl.h"
#include "chrome/browser/ui/views/global_media_controls/media_item_ui_device_selector_view.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "components/global_media_controls/public/mojom/device_service.mojom.h"
#include "components/global_media_controls/public/test/mock_device_service.h"
#include "components/global_media_controls/public/views/media_item_ui_list_view.h"
#include "components/global_media_controls/public/views/media_item_ui_view.h"
#include "content/public/test/browser_test.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/base_event_utils.h"
#include "ui/events/event.h"
#include "ui/views/test/button_test_api.h"

namespace ash {
namespace {
ui::MouseEvent pressed_event(ui::EventType::kMousePressed,
                             gfx::Point(),
                             gfx::Point(),
                             ui::EventTimeForNow(),
                             ui::EF_LEFT_MOUSE_BUTTON,
                             ui::EF_LEFT_MOUSE_BUTTON);
}  // namespace

class GlobalMediaControlsCastStartTest : public InProcessBrowserTest {
 public:
  GlobalMediaControlsCastStartTest() {
    feature_list_.InitAndEnableFeature(
        media_router::kGlobalMediaControlsCastStartStop);
  }

 protected:
  // Registers a DeviceService that will later bind a DeviceListHost when asked.
  // Returns the ID of the registered DeviceService.
  base::UnguessableToken RegisterDeviceService() {
    const base::UnguessableToken device_service_id =
        base::UnguessableToken::Create();
    EXPECT_CALL(device_service_, SetDevicePickerProvider)
        .WillOnce(testing::WithArg<0>(
            [&](mojo::PendingRemote<
                global_media_controls::mojom::DevicePickerProvider> provider) {
              picker_provider_.Bind(std::move(provider));
            }));
    media_ui_ash()->RegisterDeviceService(device_service_id,
                                          device_service_.PassRemote());
    device_service_.FlushForTesting();
    return device_service_id;
  }

  // `device_service_id` is the ID of the DeviceService resonsible for
  // binding the DeviceListHost that provides the list of devices.
  MediaItemUIDeviceSelectorView* ShowDevicePicker(
      const base::UnguessableToken& device_service_id) {
    CHECK(picker_provider_.is_bound());
    picker_provider_->CreateItem(device_service_id);
    picker_provider_->ShowItem();
    picker_provider_.FlushForTesting();

    EXPECT_CALL(device_service_, GetDeviceListHostForPresentation)
        .WillOnce(
            [&](mojo::PendingReceiver<
                    global_media_controls::mojom::DeviceListHost> host_receiver,
                mojo::PendingRemote<
                    global_media_controls::mojom::DeviceListClient>
                    client_remote) {
              device_list_host_.BindReceiver(std::move(host_receiver));
              device_list_client_.Bind(std::move(client_remote));
            });
    MediaTray* media_tray = Shell::GetPrimaryRootWindowController()
                                ->shelf()
                                ->GetStatusAreaWidget()
                                ->media_tray();
    media_tray->ShowBubble();
    device_service_.FlushForTesting();

    auto* list_view = static_cast<global_media_controls::MediaItemUIListView*>(
        media_tray->content_view_for_testing());
    auto* item_view = static_cast<global_media_controls::MediaItemUIView*>(
        list_view->contents()->children().at(0));
    return static_cast<MediaItemUIDeviceSelectorView*>(
        item_view->device_selector_view_for_testing());
  }

  // Returns the ID of the device that was added.
  std::string AddDevice() {
    const std::string device_id = "device123";
    global_media_controls::mojom::DevicePtr device =
        global_media_controls::mojom::Device::New();
    device->id = device_id;
    std::vector<global_media_controls::mojom::DevicePtr> devices;
    devices.push_back(std::move(device));
    CHECK(device_list_client_.is_bound());
    device_list_client_->OnDevicesUpdated(std::move(devices));
    device_list_client_.FlushForTesting();
    return device_id;
  }

  void SelectDeviceAndVerify(MediaItemUIDeviceSelectorView* selector_view,
                             const std::string& device_id) {
    EXPECT_CALL(device_list_host_, SelectDevice(device_id));
    views::test::ButtonTestApi(
        selector_view->GetCastDeviceEntryViewsForTesting().at(0))
        .NotifyClick(pressed_event);
    device_list_host_.FlushForTesting();
  }

  crosapi::MediaUIAsh* media_ui_ash() {
    return crosapi::CrosapiManager::Get()->crosapi_ash()->media_ui_ash();
  }

  base::test::ScopedFeatureList feature_list_;

  // Remotes to objects in Ash.
  mojo::Remote<global_media_controls::mojom::DevicePickerProvider>
      picker_provider_;
  mojo::Remote<global_media_controls::mojom::DeviceListClient>
      device_list_client_;

  // Mocks for objects in Lacros that communicate with Chromecast devices.
  global_media_controls::test::MockDeviceService device_service_;
  global_media_controls::test::MockDeviceListHost device_list_host_;
};

IN_PROC_BROWSER_TEST_F(GlobalMediaControlsCastStartTest, StartCasting) {
  base::UnguessableToken device_service_id = RegisterDeviceService();
  MediaItemUIDeviceSelectorView* device_picker =
      ShowDevicePicker(device_service_id);
  std::string device_id = AddDevice();
  SelectDeviceAndVerify(device_picker, device_id);
}

}  // namespace ash