910e62b5创建于 1月15日历史提交
// Copyright 2024 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/scanner/scanner_metrics.h"

#include "ash/app_list/app_list_model_provider.h"
#include "ash/app_list/app_list_public_test_util.h"
#include "ash/app_list/model/search/search_box_model.h"
#include "ash/app_list/views/app_list_bubble_view.h"
#include "ash/app_list/views/app_list_view.h"
#include "ash/app_list/views/search_box_view.h"
#include "ash/capture_mode/capture_mode_test_util.h"
#include "ash/constants/ash_features.h"
#include "ash/public/cpp/capture_mode/capture_mode_api.h"
#include "ash/public/cpp/scanner/scanner_delegate.h"
#include "ash/scanner/fake_scanner_profile_scoped_delegate.h"
#include "ash/scanner/scanner_controller.h"
#include "ash/shelf/home_button.h"
#include "ash/shelf/shelf.h"
#include "ash/shelf/shelf_navigation_widget.h"
#include "ash/shelf/shelf_widget.h"
#include "ash/shell.h"
#include "ash/test/ash_test_base.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/time/time.h"
#include "chromeos/ash/components/specialized_features/feature_access_checker.h"
#include "scanner_metrics.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/event.h"
#include "ui/events/event_constants.h"
#include "ui/events/types/event_type.h"

namespace ash {

namespace {

using enum ScannerFeatureUserState;
using ::testing::Return;

class ScannerMetricsParameterisedTest
    : public AshTestBase,
      public testing::WithParamInterface<ScannerFeatureUserState> {};

INSTANTIATE_TEST_SUITE_P(
    /* no prefix */,
    ScannerMetricsParameterisedTest,
    testing::ValuesIn<ScannerFeatureUserState>({
        kConsentDisclaimerAccepted,
        kConsentDisclaimerRejected,
        kSunfishScreenEnteredViaShortcut,
        kDeprecatedSunfishScreenInitialScreenCaptureSentToScannerServer,
        kScreenCaptureModeScannerButtonShown,
        kDeprecatedScreenCaptureModeInitialScreenCaptureSentToScannerServer,
        kNoActionsDetected,
        kNewCalendarEventActionDetected,
        kNewCalendarEventActionFinishedSuccessfully,
        kNewCalendarEventActionPopulationFailed,
        kNewContactActionDetected,
        kNewContactActionFinishedSuccessfully,
        kNewContactActionPopulationFailed,
        kNewGoogleSheetActionDetected,
        kNewGoogleSheetActionFinishedSuccessfully,
        kNewGoogleSheetActionPopulationFailed,
        kNewGoogleDocActionDetected,
        kNewGoogleDocActionFinishedSuccessfully,
        kNewGoogleDocActionPopulationFailed,
        kCopyToClipboardActionDetected,
        kCopyToClipboardActionFinishedSuccessfully,
        kCopyToClipboardActionPopulationFailed,
        kNewCalendarEventPopulatedActionExecutionFailed,
        kNewContactPopulatedActionExecutionFailed,
        kNewGoogleSheetPopulatedActionExecutionFailed,
        kNewGoogleDocPopulatedActionExecutionFailed,
        kCopyToClipboardPopulatedActionExecutionFailed,
        kCanShowUiReturnedFalse,
        kCanShowUiReturnedTrueWithoutConsent,
        kCanShowUiReturnedTrueWithConsent,
        kCanShowUiReturnedFalseDueToNoShellInstance,
        kCanShowUiReturnedFalseDueToNoControllerOnShell,
        kCanShowUiReturnedFalseDueToEnterprisePolicy,
        kCanShowUiReturnedFalseDueToNoProfileScopedDelegate,
        kCanShowUiReturnedFalseDueToSettingsToggle,
        kCanShowUiReturnedFalseDueToFeatureFlag,
        kCanShowUiReturnedFalseDueToFeatureManagement,
        kCanShowUiReturnedFalseDueToSecretKey,
        kCanShowUiReturnedFalseDueToAccountCapabilities,
        kCanShowUiReturnedFalseDueToCountry,
        kCanShowUiReturnedFalseDueToKioskMode,
        kLauncherShownWithoutSunfishSessionButton,
        kLauncherShownWithSunfishSessionButton,
        kSunfishSessionImageCapturedAndActionsNotFetched,
        kSunfishSessionImageCapturedAndActionsFetchStarted,
        kSmartActionsButtonImageCapturedAndActionsNotFetched,
        kSmartActionsButtonImageCapturedAndActionsFetchStarted,
        kSmartActionsButtonNotShownDueToFeatureChecks,
        kSmartActionsButtonNotShownDueToTextDetectionCancelled,
        kSmartActionsButtonNotShownDueToNoTextDetected,
        kSmartActionsButtonNotShownDueToCanShowUiFalse,
        kSmartActionsButtonNotShownDueToOffline,
    }));

TEST_P(ScannerMetricsParameterisedTest, Record) {
  base::HistogramTester histogram_tester;

  RecordScannerFeatureUserState(GetParam());

  histogram_tester.ExpectBucketCount("Ash.ScannerFeature.UserState", GetParam(),
                                     1);
}

TEST(ScannerMetricsNoFixtureTest, LauncherShownWithoutSunfishSessionButton) {
  base::HistogramTester histogram_tester;

  RecordSunfishSessionButtonVisibilityOnLauncherShown(/*is_visible=*/false);

  histogram_tester.ExpectBucketCount("Ash.ScannerFeature.UserState",
                                     kLauncherShownWithoutSunfishSessionButton,
                                     1);
}

TEST(ScannerMetricsNoFixtureTest, LauncherShownWithSunfishSessionButton) {
  base::HistogramTester histogram_tester;

  RecordSunfishSessionButtonVisibilityOnLauncherShown(/*is_visible=*/true);

  histogram_tester.ExpectBucketCount("Ash.ScannerFeature.UserState",
                                     kLauncherShownWithSunfishSessionButton, 1);
}

class ScannerMetricsTest : public AshTestBase {
 public:
  ScannerMetricsTest() {
    // Disable Sunfish so we can control `IsSunfishAllowedAndEnabled`.
    scoped_feature_list_.InitWithFeatures(
        /*enabled_features=*/{features::kScannerUpdate},
        /*disabled_features=*/{features::kSunfishFeature});
  }

 private:
  base::test::ScopedFeatureList scoped_feature_list_;
};

TEST_F(ScannerMetricsTest, ClamshellLauncherShownWithoutSunfishSessionButton) {
  base::HistogramTester histogram_tester;
  ScannerController* scanner_controller = Shell::Get()->scanner_controller();
  ASSERT_TRUE(scanner_controller);
  auto* delegate = static_cast<FakeScannerProfileScopedDelegate*>(
      scanner_controller->delegate_for_testing()->GetProfileScopedDelegate());
  ON_CALL(*delegate, CheckFeatureAccess)
      .WillByDefault(Return(specialized_features::FeatureAccessFailureSet{
          specialized_features::FeatureAccessFailure::kDisabledInSettings}));
  ASSERT_FALSE(CanShowSunfishOrScannerUi());

  // Open the app list by clicking on the home button.
  LeftClickOn(GetPrimaryShelf()->navigation_widget()->GetHomeButton());
  AppListBubbleView* bubble_view = GetAppListBubbleView();
  ASSERT_TRUE(bubble_view);
  views::ImageButton* sunfish_button =
      bubble_view->search_box_view()->sunfish_button();
  ASSERT_TRUE(sunfish_button);
  ASSERT_FALSE(sunfish_button->GetVisible());

  histogram_tester.ExpectBucketCount("Ash.ScannerFeature.UserState",
                                     kLauncherShownWithoutSunfishSessionButton,
                                     1);
}

TEST_F(ScannerMetricsTest, ClamshellLauncherShownWithSunfishSessionButton) {
  base::HistogramTester histogram_tester;
  ScannerController* scanner_controller = Shell::Get()->scanner_controller();
  ASSERT_TRUE(scanner_controller);
  auto* delegate = static_cast<FakeScannerProfileScopedDelegate*>(
      scanner_controller->delegate_for_testing()->GetProfileScopedDelegate());
  ON_CALL(*delegate, CheckFeatureAccess)
      .WillByDefault(Return(specialized_features::FeatureAccessFailureSet{}));
  ASSERT_TRUE(CanShowSunfishOrScannerUi());

  // Open the app list by clicking on the home button.
  LeftClickOn(GetPrimaryShelf()->navigation_widget()->GetHomeButton());
  AppListBubbleView* bubble_view = GetAppListBubbleView();
  ASSERT_TRUE(bubble_view);
  views::ImageButton* sunfish_button =
      bubble_view->search_box_view()->sunfish_button();
  ASSERT_TRUE(sunfish_button);
  ASSERT_TRUE(sunfish_button->GetVisible());

  histogram_tester.ExpectBucketCount("Ash.ScannerFeature.UserState",
                                     kLauncherShownWithSunfishSessionButton, 1);
}

TEST_F(ScannerMetricsTest, ClamshellLauncherButtonClicked) {
  base::HistogramTester histogram_tester;
  ScannerController* scanner_controller = Shell::Get()->scanner_controller();
  ASSERT_TRUE(scanner_controller);
  auto* delegate = static_cast<FakeScannerProfileScopedDelegate*>(
      scanner_controller->delegate_for_testing()->GetProfileScopedDelegate());
  ON_CALL(*delegate, CheckFeatureAccess)
      .WillByDefault(Return(specialized_features::FeatureAccessFailureSet{}));
  ASSERT_TRUE(CanShowSunfishOrScannerUi());

  // Open the app list by clicking on the home button.
  LeftClickOn(GetPrimaryShelf()->navigation_widget()->GetHomeButton());
  AppListBubbleView* bubble_view = GetAppListBubbleView();
  ASSERT_TRUE(bubble_view);
  views::ImageButton* sunfish_button =
      bubble_view->search_box_view()->sunfish_button();
  ASSERT_TRUE(sunfish_button);
  ASSERT_TRUE(sunfish_button->GetVisible());
  LeftClickOn(sunfish_button);

  histogram_tester.ExpectBucketCount("Ash.ScannerFeature.UserState",
                                     kSunfishSessionStartedFromLauncherButton,
                                     1);
}

TEST_F(ScannerMetricsTest, TabletLauncherShownWithoutSunfishSessionButton) {
  base::HistogramTester histogram_tester;
  ScannerController* scanner_controller = Shell::Get()->scanner_controller();
  ASSERT_TRUE(scanner_controller);
  auto* delegate = static_cast<FakeScannerProfileScopedDelegate*>(
      scanner_controller->delegate_for_testing()->GetProfileScopedDelegate());
  ON_CALL(*delegate, CheckFeatureAccess)
      .WillByDefault(Return(specialized_features::FeatureAccessFailureSet{
          specialized_features::FeatureAccessFailure::kDisabledInSettings}));
  ASSERT_FALSE(CanShowSunfishOrScannerUi());

  // The app list should be open by default when we enter tablet mode.
  SwitchToTabletMode();
  AppListView* app_list_view = GetAppListView();
  ASSERT_TRUE(app_list_view);
  views::ImageButton* sunfish_button =
      app_list_view->search_box_view()->sunfish_button();
  ASSERT_TRUE(sunfish_button);
  ASSERT_FALSE(sunfish_button->GetVisible());

  histogram_tester.ExpectBucketCount("Ash.ScannerFeature.UserState",
                                     kLauncherShownWithoutSunfishSessionButton,
                                     1);
}

TEST_F(ScannerMetricsTest, TabletLauncherShownWithSunfishSessionButton) {
  base::HistogramTester histogram_tester;
  ScannerController* scanner_controller = Shell::Get()->scanner_controller();
  ASSERT_TRUE(scanner_controller);
  auto* delegate = static_cast<FakeScannerProfileScopedDelegate*>(
      scanner_controller->delegate_for_testing()->GetProfileScopedDelegate());
  ON_CALL(*delegate, CheckFeatureAccess)
      .WillByDefault(Return(specialized_features::FeatureAccessFailureSet{}));
  ASSERT_TRUE(CanShowSunfishOrScannerUi());

  // The app list should be open by default when we enter tablet mode.
  SwitchToTabletMode();
  AppListView* app_list_view = GetAppListView();
  ASSERT_TRUE(app_list_view);
  views::ImageButton* sunfish_button =
      app_list_view->search_box_view()->sunfish_button();
  ASSERT_TRUE(sunfish_button);
  ASSERT_TRUE(sunfish_button->GetVisible());

  histogram_tester.ExpectBucketCount("Ash.ScannerFeature.UserState",
                                     kLauncherShownWithSunfishSessionButton, 1);
}

TEST_F(ScannerMetricsTest, TabletLauncherButtonClicked) {
  base::HistogramTester histogram_tester;
  ScannerController* scanner_controller = Shell::Get()->scanner_controller();
  ASSERT_TRUE(scanner_controller);
  auto* delegate = static_cast<FakeScannerProfileScopedDelegate*>(
      scanner_controller->delegate_for_testing()->GetProfileScopedDelegate());
  ON_CALL(*delegate, CheckFeatureAccess)
      .WillByDefault(Return(specialized_features::FeatureAccessFailureSet{}));
  ASSERT_TRUE(CanShowSunfishOrScannerUi());

  // The app list should be open by default when we enter tablet mode.
  SwitchToTabletMode();
  AppListView* app_list_view = GetAppListView();
  ASSERT_TRUE(app_list_view);
  views::ImageButton* sunfish_button =
      app_list_view->search_box_view()->sunfish_button();
  ASSERT_TRUE(sunfish_button);
  ASSERT_TRUE(sunfish_button->GetVisible());
  LeftClickOn(sunfish_button);

  histogram_tester.ExpectBucketCount("Ash.ScannerFeature.UserState",
                                     kSunfishSessionStartedFromLauncherButton,
                                     1);
}

TEST_F(ScannerMetricsTest, HomeButtonLongPress) {
  base::HistogramTester histogram_tester;
  ScannerController* scanner_controller = Shell::Get()->scanner_controller();
  ASSERT_TRUE(scanner_controller);
  auto* delegate = static_cast<FakeScannerProfileScopedDelegate*>(
      scanner_controller->delegate_for_testing()->GetProfileScopedDelegate());
  ON_CALL(*delegate, CheckFeatureAccess)
      .WillByDefault(Return(specialized_features::FeatureAccessFailureSet{}));
  ASSERT_TRUE(CanShowSunfishOrScannerUi());

  HomeButton* home_button =
      GetPrimaryShelf()->shelf_widget()->navigation_widget()->GetHomeButton();
  ui::GestureEvent long_press(
      0, 0, ui::EF_NONE, base::TimeTicks(),
      ui::GestureEventDetails(ui::EventType::kGestureLongPress));
  home_button->OnGestureEvent(&long_press);

  histogram_tester.ExpectBucketCount(
      "Ash.ScannerFeature.UserState",
      kSunfishSessionStartedFromHomeButtonLongPress, 1);
}

}  // namespace

}  // namespace ash