File: notification_channels_provider_android.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (283 lines) | stat: -rw-r--r-- 12,563 bytes parent folder | download | duplicates (3)
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_CHANNELS_PROVIDER_ANDROID_H_
#define CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_CHANNELS_PROVIDER_ANDROID_H_

#include <map>
#include <memory>
#include <optional>
#include <queue>
#include <string>
#include <tuple>
#include <vector>

#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/time/clock.h"
#include "base/time/time.h"
#include "components/content_settings/core/browser/content_settings_observer.h"
#include "components/content_settings/core/browser/content_settings_rule.h"
#include "components/content_settings/core/browser/user_modifiable_provider.h"
#include "components/content_settings/core/common/content_settings.h"
#include "components/content_settings/core/common/content_settings_types.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_service.h"
#include "url/origin.h"

class TemplateURLService;

// A Java counterpart will be generated for this enum.
// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.notifications
enum NotificationChannelStatus { ENABLED, BLOCKED, UNAVAILABLE };

struct NotificationChannel {
  NotificationChannel(const std::string& id,
                      const std::string& origin,
                      const base::Time& timestamp,
                      NotificationChannelStatus status);
  bool operator==(const NotificationChannel& other) const {
    return origin == other.origin && status == other.status;
  }

  std::string id;
  std::string origin;
  base::Time timestamp;
  NotificationChannelStatus status = NotificationChannelStatus::UNAVAILABLE;
};

// This class provides notification content settings from system notification
// channels on Android O+. This provider takes precedence over pref-provided
// content settings, but defers to supervised user and policy settings - see
// ordering of the ProviderType enum values in HostContentSettingsMap.
//
// PartitionKey is ignored by this provider because the content settings should
// apply across partitions.
class NotificationChannelsProviderAndroid
    : public content_settings::UserModifiableProvider {
 public:
  using GetChannelsCallback =
      base::OnceCallback<void(const std::vector<NotificationChannel>&)>;
  // Helper class to make the JNI calls.
  class NotificationChannelsBridge {
   public:
    virtual ~NotificationChannelsBridge() = default;
    virtual NotificationChannel CreateChannel(const std::string& origin,
                                              const base::Time& timestamp,
                                              bool enabled) = 0;
    virtual void DeleteChannel(const std::string& origin) = 0;
    virtual void GetChannels(GetChannelsCallback callback) = 0;
  };

  static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);

  // Whether this class listens to all notification channel changes.
  static bool IsListeningToNotificationChannelChanges();

  explicit NotificationChannelsProviderAndroid(PrefService* pref_service);
  NotificationChannelsProviderAndroid(
      const NotificationChannelsProviderAndroid&) = delete;
  NotificationChannelsProviderAndroid& operator=(
      const NotificationChannelsProviderAndroid&) = delete;
  ~NotificationChannelsProviderAndroid() override;

  // Initialize cached channels, do migration and clear blocked channels if
  // necessary.
  void Initialize(content_settings::ProviderInterface* pref_provider,
                  TemplateURLService* template_url_service);

  // Forces an update of cached channels and invokes callback upon completion.
  void EnsureUpdatedSettings(base::OnceClosure callback) override;

  // Called when a site channel is blocked/unblocked.
  void OnChannelStateChanged(const NotificationChannel& channel);

  // UserModifiableProvider methods.
  std::unique_ptr<content_settings::RuleIterator> GetRuleIterator(
      ContentSettingsType content_type,
      bool off_the_record,
      const content_settings::PartitionKey& partition_key) const override;
  bool SetWebsiteSetting(
      const ContentSettingsPattern& primary_pattern,
      const ContentSettingsPattern& secondary_pattern,
      ContentSettingsType content_type,
      base::Value&& value,
      const content_settings::ContentSettingConstraints& constraints,
      const content_settings::PartitionKey& partition_key) override;
  void ClearAllContentSettingsRules(
      ContentSettingsType content_type,
      const content_settings::PartitionKey& partition_key) override;
  void ShutdownOnUIThread() override;
  bool UpdateLastUsedTime(
      const GURL& primary_url,
      const GURL& secondary_url,
      ContentSettingsType content_type,
      const base::Time time,
      const content_settings::PartitionKey& partition_key) override;
  bool ResetLastVisitTime(
      const ContentSettingsPattern& primary_pattern,
      const ContentSettingsPattern& secondary_pattern,
      ContentSettingsType content_type,
      const content_settings::PartitionKey& partition_key) override;
  bool UpdateLastVisitTime(
      const ContentSettingsPattern& primary_pattern,
      const ContentSettingsPattern& secondary_pattern,
      ContentSettingsType content_type,
      const content_settings::PartitionKey& partition_key) override;
  std::optional<base::TimeDelta> RenewContentSetting(
      const GURL& primary_url,
      const GURL& secondary_url,
      ContentSettingsType content_type,
      std::optional<ContentSetting> setting_to_match,
      const content_settings::PartitionKey& partition_key) override;
  void SetClockForTesting(const base::Clock* clock) override;

 protected:
  // Migrates any notification settings from the passed-in provider to
  // channels, unless they were already migrated or channels should not be used.
  void MigrateToChannelsIfNecessary(
      content_settings::ProviderInterface* pref_provider);

  // Deletes any existing blocked site channels, unless this one-off deletion
  // already occurred. See https://crbug.com/835232.
  void ClearBlockedChannelsIfNecessary(
      TemplateURLService* template_url_service);

 private:
  NotificationChannelsProviderAndroid(
      PrefService* pref_service,
      std::unique_ptr<NotificationChannelsBridge> bridge);
  friend class NotificationChannelsProviderAndroidTest;

  // Don't call this directly.
  // Helper methods for implementing MigrateToChannelsIfNecessary(). Called
  // when `cached_channels_` are initialized.
  void MigrateToChannelsIfNecessaryImpl(
      content_settings::ProviderInterface* pref_provider);

  // Don't call this directly.
  // Helper methods for implementing ClearBlockedChannelsIfNecessary(). Called
  // when updated channels are retrieved.
  void ClearBlockedChannelsIfNecessaryImpl(
      const url::Origin& default_search_engine_origin,
      const std::vector<NotificationChannel>& channels);

  // Don't call this directly.
  // Helper methods for implementing ClearAllContentSettingsRules(). Called
  // when updated channels are retrieved. The `channel_timestamp_at_invocation`
  // is used to check whether a channel is modified after the
  // ClearAllContentSettingsRules() call and should not be cleared.
  void ClearAllChannelsImpl(ContentSettingsType content_type,
                            base::Time channel_timestamp_at_invocation,
                            const std::vector<NotificationChannel>& channels);

  // Check if a notification channel reflects the same rule as returned by
  // GetRuleIterator().
  bool IsSameAsCachedRule(const NotificationChannel& channel);

  // Don't call this directly.
  // Helper methods for implementing SetWebsiteSetting(). Called when
  // `cached_channels_` are initialized.
  void UpdateChannelForWebsiteImpl(
      const ContentSettingsPattern& primary_pattern,
      const ContentSettingsPattern& secondary_pattern,
      ContentSettingsType content_type,
      ContentSetting content_setting,
      const content_settings::ContentSettingConstraints& constraints,
      const NotificationChannel& pending_channel);

  // Don't call this directly. Pass this as a callback to ScheduleGetChannels().
  // Update cached channels. If `only_initialize_null_cached_channels`, cached
  // channel will get updated only if it is null. Otherwise, all the observers
  // will be notified if cached channel is updated. Once cached channels are
  // updated, `on_channel_updated_cb` will be invoked.  This method is posted by
  // ScheduleGetChannels() and runs when notification channels are retrieved
  // from Android.
  void UpdateCachedChannelsImpl(
      bool only_initialize_null_cached_channels,
      base::OnceClosure on_channel_updated_cb,
      const std::vector<NotificationChannel>& channels);

  // Create notification channel if required.
  void CreateChannelIfRequired(const ContentSettingsPattern& primary_pattern,
                               const ContentSettingsPattern& secondary_pattern,
                               NotificationChannelStatus new_channel_status);

  // Create notification channel for a given rule
  void CreateChannelForRule(const content_settings::Rule& rule);

  // Called to retrieve cached channels if it is null. Once complete,
  // `on_channels_initialized_cb` will be invoked.
  void GetCachedChannelsIfNecessary(
      base::OnceClosure on_channels_initialized_cb);

  // Schedule an pending operation to get Java notification channels. Once
  // the previous pending operation completes, GetChannelsImpl() will be
  // invoked.
  void ScheduleGetChannels(bool skip_get_if_cached_channels_are_available,
                           GetChannelsCallback callback);

  // Don't call this directly. Call ScheduleGetChannels() instead.
  // Gets channels from java side and invoke `get_channels_cb` and
  // `on_task_completed_cb` on completion. If
  // `skip_get_if_cached_channels_are_available` is true, callbacks will be
  // invoked immediately if cached channels are not empty.
  void GetChannelsImpl(bool skip_get_if_cached_channels_are_available,
                       GetChannelsCallback get_channels_cb,
                       base::OnceClosure on_task_completed_cb);

  // Called when GetChannels() completes.
  void OnGetChannelsDone(GetChannelsCallback get_channels_cb,
                         base::OnceClosure on_task_completed_cb,
                         const std::vector<NotificationChannel>& channels);

  // Called to process the next pending operation.
  void ProcessPendingOperations();

  // Called when a pending operation completes.
  void OnCurrentOperationFinished();

  void RecordCachedChannelStatus();

  std::unique_ptr<NotificationChannelsBridge> bridge_;

  raw_ptr<const base::Clock> clock_;

  // Map of origin - NotificationChannel. Channel status may be out of date.
  // This cache is completely refreshed every time GetRuleIterator is called;
  // entries are also added and deleted when channels are added and deleted.
  // This cache serves three purposes:
  //
  // 1. For looking up the channel ID for an origin.
  //
  // 2. For looking up the channel creation timestamp for an origin.
  //
  // 3. To check if any channels have changed status since the last time
  //    they were checked, in order to notify observers. This is necessary to
  //    detect channels getting blocked/enabled by the user, in the absence of a
  //    callback for this event.
  std::optional<std::map<std::string, NotificationChannel>> cached_channels_;

  // Notification channels that are pending creation or update after
  // SetWebsiteSetting() call. These channels don't have a channel Id yet. They
  // are used for providing a synchronous result to the GetRuleIterator() call.
  // They will be moved to `cached_channels_` once creation or update completes.
  std::map<std::string, NotificationChannel> pending_channels_;

  using PendingCallback = base::OnceCallback<void(base::OnceClosure)>;
  // This is a list of postponed calls to update cached_channels_.
  std::queue<PendingCallback> pending_operations_;

  // PrefService associated with this instance.
  raw_ptr<PrefService> pref_service_;

  bool is_processing_pending_operations_ = false;

  bool has_get_rule_iterator_called_ = false;

  base::WeakPtrFactory<NotificationChannelsProviderAndroid> weak_factory_{this};
};

#endif  // CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_CHANNELS_PROVIDER_ANDROID_H_