// Copyright 2021 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "ash/app_list/app_list_feature_usage_metrics.h" #include #include "ash/app_list/app_list_controller_impl.h" #include "ash/constants/ash_features.h" #include "ash/session/session_controller_impl.h" #include "ash/shell.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "chromeos/ash/components/feature_usage/feature_usage_metrics.h" namespace ash { namespace { // Feature name for clamshell mode launcher. constexpr char kClamshellLauncher[] = "ClamshellLauncher"; // Feature name for tablet mode launcher. constexpr char kTabletLauncher[] = "TabletLauncher"; // Supplies eligibility information for clamshell launcher. class ClamshellDelegate : public feature_usage::FeatureUsageMetrics::Delegate { public: ClamshellDelegate() = default; ClamshellDelegate(const ClamshellDelegate&) = delete; ClamshellDelegate& operator=(const ClamshellDelegate&) = delete; ~ClamshellDelegate() override = default; // feature_usage::FeatureUsageMetrics::Delegate: bool IsEligible() const override { // Kiosk app sessions cannot use the launcher. return !Shell::Get()->session_controller()->IsRunningInAppMode(); } bool IsEnabled() const override { // The launcher is always enabled for eligible sessions. return IsEligible(); } }; // Supplies eligibility information for tablet launcher. class TabletDelegate : public feature_usage::FeatureUsageMetrics::Delegate { public: TabletDelegate() = default; TabletDelegate(const TabletDelegate&) = delete; TabletDelegate& operator=(const TabletDelegate&) = delete; ~TabletDelegate() override = default; // feature_usage::FeatureUsageMetrics::Delegate: bool IsEligible() const override { // Kiosk app sessions cannot use the launcher. if (Shell::Get()->session_controller()->IsRunningInAppMode()) return false; // If the device cannot enter tablet mode, the tablet mode launcher is not // available. return Shell::Get()->tablet_mode_controller()->CanEnterTabletMode(); } bool IsEnabled() const override { // The launcher is always enabled for eligible sessions. return IsEligible(); } }; } // namespace AppListFeatureUsageMetrics::AppListFeatureUsageMetrics() : clamshell_delegate_(std::make_unique()), clamshell_metrics_(kClamshellLauncher, clamshell_delegate_.get()), tablet_delegate_(std::make_unique()), tablet_metrics_(kTabletLauncher, tablet_delegate_.get()) { Shell::Get()->app_list_controller()->AddObserver(this); Shell::Get()->tablet_mode_controller()->AddObserver(this); } AppListFeatureUsageMetrics::~AppListFeatureUsageMetrics() { Shell::Get()->tablet_mode_controller()->RemoveObserver(this); Shell::Get()->app_list_controller()->RemoveObserver(this); } void AppListFeatureUsageMetrics::OnTabletModeStarted() { // The legacy launcher can transition directly from clamshell to tablet mode // without triggering a visibility update. ProductivityLauncher explicitly // closes the clamshell launcher before showing the tablet launcher. if (is_using_clamshell_ && !features::IsProductivityLauncherEnabled()) { StopClamshellUsage(); if (Shell::Get()->app_list_controller()->IsVisible()) StartTabletUsage(); } } void AppListFeatureUsageMetrics::OnAppListVisibilityChanged( bool shown, int64_t display_id) { if (shown) { OnAppListShown(); } else { OnAppListHidden(); } } void AppListFeatureUsageMetrics::OnAppListShown() { if (Shell::Get()->IsInTabletMode()) { StartTabletUsage(); } else { StartClamshellUsage(); } } void AppListFeatureUsageMetrics::OnAppListHidden() { StopTabletUsage(); StopClamshellUsage(); } void AppListFeatureUsageMetrics::StartClamshellUsage() { if (is_using_clamshell_) return; DCHECK(clamshell_delegate_->IsEligible()); clamshell_metrics_.RecordUsage(true); clamshell_metrics_.StartSuccessfulUsage(); is_using_clamshell_ = true; } void AppListFeatureUsageMetrics::StopClamshellUsage() { if (!is_using_clamshell_) return; clamshell_metrics_.StopSuccessfulUsage(); is_using_clamshell_ = false; } void AppListFeatureUsageMetrics::StartTabletUsage() { if (is_using_tablet_) return; // Ignore users on ineligible devices who have forced tablet mode via flags // or debug shortcut keys. FeatureUsageMetrics requires that RecordUsage() // is never called when IsEligible() is false. if (!tablet_delegate_->IsEligible()) return; tablet_metrics_.RecordUsage(true); tablet_metrics_.StartSuccessfulUsage(); is_using_tablet_ = true; } void AppListFeatureUsageMetrics::StopTabletUsage() { if (!is_using_tablet_) return; tablet_metrics_.StopSuccessfulUsage(); is_using_tablet_ = false; } } // namespace ash