summaryrefslogtreecommitdiff
path: root/chromium/components/feature_engagement/public/tracker.h
blob: 99039d3a665bed9970a4df80ea4bae0481f76a89 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// Copyright 2017 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_FEATURE_ENGAGEMENT_PUBLIC_TRACKER_H_
#define COMPONENTS_FEATURE_ENGAGEMENT_PUBLIC_TRACKER_H_

#include <memory>
#include <string>

#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/feature_list.h"
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/sequenced_task_runner.h"
#include "build/build_config.h"
#include "components/keyed_service/core/keyed_service.h"

#if defined(OS_ANDROID)
#include "base/android/jni_android.h"
#endif  // defined(OS_ANDROID)

namespace feature_engagement {

// A handle for the display lock. While this is unreleased, no in-product help
// can be displayed.
class DisplayLockHandle {
 public:
  typedef base::OnceClosure ReleaseCallback;
  explicit DisplayLockHandle(ReleaseCallback callback);
  ~DisplayLockHandle();

 private:
  ReleaseCallback release_callback_;
  DISALLOW_COPY_AND_ASSIGN(DisplayLockHandle);
};

// The Tracker provides a backend for displaying feature
// enlightenment or in-product help (IPH) with a clean and easy to use API to be
// consumed by the UI frontend. The backend behaves as a black box and takes
// input about user behavior. Whenever the frontend gives a trigger signal that
// IPH could be displayed, the backend will provide an answer to whether it is
// appropriate to show it or not.
class Tracker : public KeyedService {
 public:
  // Describes the state of whether in-product helps has already been displayed
  // enough times or not within the bounds of the configuration for a
  // base::Feature. NOT_READY is returned if the Tracker has not been
  // initialized yet before the call to GetTriggerState(...).
  // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.components.feature_engagement
  enum class TriggerState : int {
    HAS_BEEN_DISPLAYED = 0,
    HAS_NOT_BEEN_DISPLAYED = 1,
    NOT_READY = 2
  };

#if defined(OS_ANDROID)
  // Returns a Java object of the type Tracker for the given Tracker.
  static base::android::ScopedJavaLocalRef<jobject> GetJavaObject(
      Tracker* feature_engagement);
#endif  // defined(OS_ANDROID)

  // Invoked when the tracker has been initialized. The |success| parameter
  // indicates that the initialization was a success and the tracker is ready to
  // receive calls.
  using OnInitializedCallback = base::Callback<void(bool success)>;

  // The |storage_dir| is the path to where all local storage will be.
  // The |bakground_task_runner| will be used for all disk reads and writes.
  static Tracker* Create(
      const base::FilePath& storage_dir,
      const scoped_refptr<base::SequencedTaskRunner>& background_task_runner);

  // Must be called whenever an event happens.
  virtual void NotifyEvent(const std::string& event) = 0;

  // This function must be called whenever the triggering condition for a
  // specific feature happens. Returns true iff the display of the in-product
  // help must happen.
  // If |true| is returned, the caller *must* call Dismissed(...) when display
  // of feature enlightenment ends.
  virtual bool ShouldTriggerHelpUI(const base::Feature& feature)
      WARN_UNUSED_RESULT = 0;

  // Invoking this is basically the same as being allowed to invoke
  // ShouldTriggerHelpUI(...) without requiring to show the in-product help.
  // This function may be called to inspect if the current state would allow the
  // given |feature| to pass all its conditions and display the feature
  // enlightenment.
  //
  // NOTE: It is still required to invoke ShouldTriggerHelpUI(...) if feature
  // enlightenment should be shown.
  //
  // NOTE: It is not guaranteed that invoking ShouldTriggerHelpUI(...)
  // after this would yield the same result. The state might change
  // in-between the calls because time has passed, other events might have been
  // triggered, and other state might have changed.
  virtual bool WouldTriggerHelpUI(const base::Feature& feature) const = 0;

  // This function can be called to query if a particular |feature| meets its
  // particular precondition for triggering within the bounds of the current
  // feature configuration.
  // Calling this method requires the Tracker to already have been initialized.
  // See IsInitialized() and AddOnInitializedCallback(...) for how to ensure
  // the call to this is delayed.
  // This function can typically be used to ensure that expensive operations
  // for tracking other state related to in-product help do not happen if
  // in-product help has already been displayed for the given |feature|.
  virtual TriggerState GetTriggerState(const base::Feature& feature) const = 0;

  // Must be called after display of feature enlightenment finishes for a
  // particular |feature|.
  virtual void Dismissed(const base::Feature& feature) = 0;

  // Acquiring a display lock means that no in-product help can be displayed
  // while it is held. To release the lock, delete the handle.
  // If in-product help is already displayed while the display lock is
  // acquired, the lock is still handed out, but it will not dismiss the current
  // in-product help. However, no new in-product help will be shown until all
  // locks have been released. It is required to release the DisplayLockHandle
  // once the lock should no longer be held.
  // The DisplayLockHandle must be released on the main thread.
  // This method returns nullptr if no handle could be retrieved.
  virtual std::unique_ptr<DisplayLockHandle> AcquireDisplayLock() = 0;

  // Returns whether the tracker has been successfully initialized. During
  // startup, this will be false until the internal models have been loaded at
  // which point it is set to true if the initialization was successful. The
  // state will never change from initialized to uninitialized.
  // Callers can invoke AddOnInitializedCallback(...) to be notified when the
  // result of the initialization is ready.
  virtual bool IsInitialized() const = 0;

  // For features that trigger on startup, they can register a callback to
  // ensure that they are informed when the tracker has finished the
  // initialization. If the tracker has already been initialized, the callback
  // will still be invoked with the result. The callback is guaranteed to be
  // invoked exactly one time.
  virtual void AddOnInitializedCallback(OnInitializedCallback callback) = 0;

 protected:
  Tracker() = default;

 private:
  DISALLOW_COPY_AND_ASSIGN(Tracker);
};

}  // namespace feature_engagement

#endif  // COMPONENTS_FEATURE_ENGAGEMENT_PUBLIC_TRACKER_H_