| // Copyright 2020 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef ASH_CLIPBOARD_CLIPBOARD_NUDGE_CONTROLLER_H_ |
| #define ASH_CLIPBOARD_CLIPBOARD_NUDGE_CONTROLLER_H_ |
| |
| #include <memory> |
| |
| #include "ash/ash_export.h" |
| #include "ash/clipboard/clipboard_history.h" |
| #include "ash/clipboard/clipboard_nudge_constants.h" |
| #include "ash/public/cpp/clipboard_history_controller.h" |
| #include "ash/system/tray/system_nudge_controller.h" |
| #include "base/scoped_observation.h" |
| #include "base/time/time.h" |
| #include "ui/base/clipboard/clipboard_observer.h" |
| |
| class PrefRegistrySimple; |
| class ClipboardHistoryItem; |
| |
| namespace base { |
| class Clock; |
| } // namespace base |
| |
| namespace crosapi::mojom { |
| enum class ClipboardHistoryControllerShowSource; |
| } // namespace crosapi::mojom |
| |
| namespace ui { |
| class ClipboardMonitor; |
| } // namespace ui |
| |
| namespace ash { |
| |
| class ASH_EXPORT ClipboardNudgeController |
| : public SystemNudgeController, |
| public ClipboardHistory::Observer, |
| public ui::ClipboardObserver, |
| public ClipboardHistoryController::Observer { |
| public: |
| // Describes the clipboard history feature onboarding state. A user must |
| // perform copy, paste, copy and paste in sequence to activate onboarding |
| // nudges. |
| enum class OnboardingState { |
| kInit = 0, |
| kFirstCopy = 1, |
| kFirstPaste = 2, |
| kSecondCopy = 3, |
| }; |
| |
| explicit ClipboardNudgeController(ClipboardHistory* clipboard_history); |
| ClipboardNudgeController(const ClipboardNudgeController&) = delete; |
| ClipboardNudgeController& operator=(const ClipboardNudgeController&) = delete; |
| ~ClipboardNudgeController() override; |
| |
| // Registers profile prefs. |
| static void RegisterProfilePrefs(PrefRegistrySimple* registry); |
| |
| // ui::ClipboardHistory::Observer: |
| void OnClipboardHistoryItemAdded(const ClipboardHistoryItem& item, |
| bool is_duplicate = false) override; |
| |
| // ui::ClipboardObserver: |
| void OnClipboardDataRead() override; |
| |
| // ClipboardHistoryController::Observer: |
| void OnClipboardHistoryMenuShown( |
| crosapi::mojom::ClipboardHistoryControllerShowSource show_source) |
| override; |
| void OnClipboardHistoryPasted() override; |
| |
| // Returns the time in this session that any nudge was last shown, or |
| // `std::nullopt` if a nudge has not been shown. |
| std::optional<base::Time> GetNudgeLastTimeShown() const; |
| |
| // Increments the screenshot notification shown count. |
| void MarkScreenshotNotificationShown(); |
| |
| // Shows the nudge widget. |
| void ShowNudge(ClipboardNudgeType nudge_type); |
| |
| // Test methods for overriding and resetting the clock used by GetTime. |
| void OverrideClockForTesting(base::Clock* test_clock); |
| void ClearClockOverrideForTesting(); |
| |
| OnboardingState onboarding_state_for_testing() const { |
| return onboarding_state_; |
| } |
| |
| private: |
| // An internal class to track the nudge of the specified type then record the |
| // time deltas between showing a nudge and using clipboard history (e.g. |
| // showing the standalone clipboard history menu or pasting from the |
| // standalone menu). This allows us to understand the conversion rate of |
| // showing a nudge to the clipboard history feature usage. |
| class NudgeTimeDeltaRecorder { |
| public: |
| constexpr explicit NudgeTimeDeltaRecorder(ClipboardNudgeType nudge_type); |
| NudgeTimeDeltaRecorder(const NudgeTimeDeltaRecorder&) = delete; |
| NudgeTimeDeltaRecorder& operator=(const NudgeTimeDeltaRecorder&) = delete; |
| ~NudgeTimeDeltaRecorder(); |
| |
| // Called when the nudge of `nudge_type` shows. |
| void OnNudgeShown(); |
| |
| // Called when the clipboard history data is pasted. Maybe records the time |
| // delta since `nudge_shown_time_`. |
| void OnClipboardHistoryPasted(); |
| |
| // Called when the clipboard history menu shows. Maybe records the time |
| // delta since `nudge_shown_time_`. |
| void OnClipboardHistoryMenuShown(); |
| |
| // Returns the time in this session that the associated nudge was last |
| // shown, or a null value if the associated nudge was never shown. |
| const base::Time& nudge_shown_time() const { return nudge_shown_time_; } |
| |
| private: |
| // Resets the tracking on the most recent nudge shown, if any. If the |
| // previous nudge shown does not lead to a type of clipboard history usage |
| // (e.g. showing the standalone menu or pasting from the standalone menu), |
| // records the corresponding metric. |
| void Reset(); |
| |
| // Gets the time delta since `nudge_shown_time_`. |
| base::TimeDelta GetTimeSinceNudgeShown() const; |
| |
| // Returns true if the time delta between `nudge_shown_time_` and the |
| // clipboard history data paste time should be recorded. |
| bool ShouldRecordClipboardHistoryPasteTimeDelta() const; |
| |
| // Returns true if the time delta between `nudge_shown_time_` and the |
| // clipboard history menu shown time should be recorded. |
| bool ShouldRecordMenuOpenTimeDelta() const; |
| |
| // The type of the nudge that this class is tracking. |
| const ClipboardNudgeType nudge_type_; |
| |
| // Indicates the time stamp when the nudge specified by `nudge_type_` showed |
| // most recently. NOTE: It is different from the last shown time cached in |
| // the pref data which is the last nudge shown time across user sessions. In |
| // contrast, `nudge_shown_time_` is the last shown time of the nudge of |
| // `nudge_type_` in the current user session. |
| base::Time nudge_shown_time_; |
| |
| // True if pasting clipboard history data has ever been recorded since the |
| // last nudge shown. |
| bool has_recorded_paste_ = false; |
| |
| // True if showing the clipboard history menu has ever been recorded since |
| // the last nudge shown. |
| bool has_recorded_menu_shown_ = false; |
| }; |
| |
| // SystemNudgeController: |
| std::unique_ptr<SystemNudge> CreateSystemNudge() override; |
| |
| // Caches the onboarding state. |
| // TODO(http://b/284368255): move this data member to a separate class. |
| OnboardingState onboarding_state_ = OnboardingState::kInit; |
| |
| // The timestamp of the most recent paste. |
| // TODO(http://b/284368255): move this data member to a separate class. |
| base::Time last_paste_timestamp_; |
| |
| // The current nudge type being shown from ShowNudge(). |
| ClipboardNudgeType current_nudge_type_; |
| |
| // Nudge time delta recorders ------------------------------------------------ |
| |
| // Records time deltas for the onboarding nudge. |
| NudgeTimeDeltaRecorder onboarding_nudge_recorder_{ |
| ClipboardNudgeType::kOnboardingNudge}; |
| |
| // Records time deltas for the zero state nudge. |
| NudgeTimeDeltaRecorder zero_state_nudge_recorder_{ |
| ClipboardNudgeType::kZeroStateNudge}; |
| |
| // Records time deltas for the screenshot notification nudge. |
| NudgeTimeDeltaRecorder screenshot_nudge_recorder_{ |
| ClipboardNudgeType::kScreenshotNotificationNudge}; |
| |
| // Records time deltas for the duplicate copy nudge. Used only when the |
| // clipboard history refresh feature is enabled. |
| NudgeTimeDeltaRecorder duplicate_copy_nudge_recorder_{ |
| ClipboardNudgeType::kDuplicateCopyNudge}; |
| |
| // Observations -------------------------------------------------------------- |
| |
| // The observation on the clipboard history. |
| base::ScopedObservation<ClipboardHistory, ClipboardHistory::Observer> |
| clipboard_history_observation_{this}; |
| |
| // The observation on the clipboard history controller. |
| base::ScopedObservation<ClipboardHistoryController, |
| ClipboardHistoryController::Observer> |
| clipboard_history_controller_observation_{this}; |
| |
| // The observation on the clipboard monitor. |
| base::ScopedObservation<ui::ClipboardMonitor, ui::ClipboardObserver> |
| clipboard_monitor_observation_{this}; |
| }; |
| |
| } // namespace ash |
| |
| #endif // ASH_CLIPBOARD_CLIPBOARD_NUDGE_CONTROLLER_H_ |