Commit 54ccce3b authored by Hesen Zhang's avatar Hesen Zhang Committed by Commit Bot

[Update Notification Service]: Throttle flow.

- Throttle by extending the interval if user has
 two consecutive dismiss on notification.

Bug: 1013685
Change-Id: If476dc4aeda7bcd6eff7ecd47e2428605fcd6c42
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1988898
Commit-Queue: Hesen Zhang <hesen@chromium.org>
Reviewed-by: default avatarXing Liu <xingliu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#729533}
parent ab2437ed
...@@ -34,6 +34,8 @@ import org.chromium.chrome.browser.profiles.Profile; ...@@ -34,6 +34,8 @@ import org.chromium.chrome.browser.profiles.Profile;
public class UpdateNotificationServiceBridge implements UpdateNotificationController, Destroyable { public class UpdateNotificationServiceBridge implements UpdateNotificationController, Destroyable {
private static final String PREF_UPDATE_NOTIFICATION_THROTTLE_INTERVAL_KEY = private static final String PREF_UPDATE_NOTIFICATION_THROTTLE_INTERVAL_KEY =
"pref_update_notification_throttle_interval_key"; "pref_update_notification_throttle_interval_key";
private static final String PREF_UPDATE_NOTIFICATION_USER_DISMISS_COUNT_KEY =
"pref_update_notification_user_dismiss_count_key";
private final Callback<UpdateStatusProvider.UpdateStatus> mObserver = status -> { private final Callback<UpdateStatusProvider.UpdateStatus> mObserver = status -> {
mUpdateStatus = status; mUpdateStatus = status;
...@@ -122,4 +124,27 @@ public class UpdateNotificationServiceBridge implements UpdateNotificationContro ...@@ -122,4 +124,27 @@ public class UpdateNotificationServiceBridge implements UpdateNotificationContro
editor.putLong(PREF_UPDATE_NOTIFICATION_THROTTLE_INTERVAL_KEY, interval); editor.putLong(PREF_UPDATE_NOTIFICATION_THROTTLE_INTERVAL_KEY, interval);
editor.apply(); editor.apply();
} }
/**
* Gets the number of users consecutive dimiss action on update notification from {@link
* SharedPreferences}.
*/
@CalledByNative
public static int getUserDismissCount() {
SharedPreferences preferences = OmahaBase.getSharedPreferences();
return preferences.getInt(PREF_UPDATE_NOTIFICATION_USER_DISMISS_COUNT_KEY, 0);
}
/**
* Updates the number to record users consecutive dimiss action on update notification in {@link
* SharedPreferences}.
* @param count A number of users consecutive dimiss action.
*/
@CalledByNative
private static void updateUserDismissCount(int count) {
SharedPreferences preferences = OmahaBase.getSharedPreferences();
SharedPreferences.Editor editor = preferences.edit();
editor.putInt(PREF_UPDATE_NOTIFICATION_USER_DISMISS_COUNT_KEY, count);
editor.apply();
}
} }
...@@ -37,7 +37,25 @@ void UpdateNotificationClient::OnSchedulerInitialized( ...@@ -37,7 +37,25 @@ void UpdateNotificationClient::OnSchedulerInitialized(
} }
void UpdateNotificationClient::OnUserAction(const UserActionData& action_data) { void UpdateNotificationClient::OnUserAction(const UserActionData& action_data) {
NOTIMPLEMENTED(); DCHECK(action_data.client_type ==
notifications::SchedulerClientType::kChromeUpdate);
auto* update_notification_service = get_service_callback_.Run();
DCHECK(update_notification_service);
switch (action_data.action_type) {
case notifications::UserActionType::kClick:
NOTIMPLEMENTED();
break;
case notifications::UserActionType::kButtonClick:
NOTIMPLEMENTED();
break;
case notifications::UserActionType::kDismiss:
update_notification_service->OnUserDismiss();
break;
default:
NOTREACHED();
break;
}
} }
} // namespace updates } // namespace updates
...@@ -24,6 +24,9 @@ class UpdateNotificationService : public KeyedService { ...@@ -24,6 +24,9 @@ class UpdateNotificationService : public KeyedService {
// Validate the notification is ready to show. // Validate the notification is ready to show.
virtual bool IsReadyToDisplay() const = 0; virtual bool IsReadyToDisplay() const = 0;
// Called when the notification is dismissed by user.
virtual void OnUserDismiss() = 0;
~UpdateNotificationService() override = default; ~UpdateNotificationService() override = default;
protected: protected:
......
...@@ -70,4 +70,14 @@ base::Optional<base::TimeDelta> GetThrottleInterval() { ...@@ -70,4 +70,14 @@ base::Optional<base::TimeDelta> GetThrottleInterval() {
base::TimeDelta::FromMilliseconds(interval))); base::TimeDelta::FromMilliseconds(interval)));
} }
void UpdateUserDismissCount(int count) {
JNIEnv* env = base::android::AttachCurrentThread();
Java_UpdateNotificationServiceBridge_updateUserDismissCount(env, count);
}
int GetUserDismissCount() {
JNIEnv* env = base::android::AttachCurrentThread();
return Java_UpdateNotificationServiceBridge_getUserDismissCount(env);
}
} // namespace updates } // namespace updates
...@@ -12,20 +12,26 @@ namespace updates { ...@@ -12,20 +12,26 @@ namespace updates {
// Functions for calling into UpdateNotifiactionServiceBridge.java. // Functions for calling into UpdateNotifiactionServiceBridge.java.
// Updates and persists |timestamp| in Android shared preference. // Updates and persists |timestamp| in Android SharedPreferences.
void UpdateLastShownTimeStamp(base::Time timestamp); void UpdateLastShownTimeStamp(base::Time timestamp);
// Return persisted timestamp of last shown notification from Android shared // Returns persisted timestamp of last shown notification from Android
// preference. Return nullopt if there is no data. // SharedPreferences. Return nullopt if there is no data.
base::Optional<base::Time> GetLastShownTimeStamp(); base::Optional<base::Time> GetLastShownTimeStamp();
// Updates and persists |interval| in Android shared preference. // Updates and persists |interval| in Android SharedPreferences.
void UpdateThrottleInterval(base::TimeDelta interval); void UpdateThrottleInterval(base::TimeDelta interval);
// Return persisted interval that might be throttled from Android shared // Returns persisted interval that might be throttled from Android
// preference. Return nullopt if there is no data. // SharedPreferences. Return nullopt if there is no data.
base::Optional<base::TimeDelta> GetThrottleInterval(); base::Optional<base::TimeDelta> GetThrottleInterval();
// Updates and persists |count| in Android SharedPreferences.
void UpdateUserDismissCount(int count);
// Returns persisted count from Android SharedPreferences.
int GetUserDismissCount();
} // namespace updates } // namespace updates
#endif // CHROME_BROWSER_UPDATES_UPDATE_NOTIFICATION_SERVICE_BRIDGE_H_ #endif // CHROME_BROWSER_UPDATES_UPDATE_NOTIFICATION_SERVICE_BRIDGE_H_
...@@ -33,6 +33,10 @@ void BuildNotificationData(const updates::UpdateNotificationInfo& data, ...@@ -33,6 +33,10 @@ void BuildNotificationData(const updates::UpdateNotificationInfo& data,
// Maximum number of update notification should be cached in scheduler. // Maximum number of update notification should be cached in scheduler.
constexpr int kNumMaxNotificationsLimit = 1; constexpr int kNumMaxNotificationsLimit = 1;
// Maxmium number of consecutive dismiss actions from user that should be
// considered as negative feedback.
constexpr int kNumConsecutiveDismissCountCap = 2;
UpdateNotificationServiceImpl::UpdateNotificationServiceImpl( UpdateNotificationServiceImpl::UpdateNotificationServiceImpl(
notifications::NotificationScheduleService* schedule_service) notifications::NotificationScheduleService* schedule_service)
: schedule_service_(schedule_service), : schedule_service_(schedule_service),
...@@ -103,4 +107,21 @@ UpdateNotificationServiceImpl::BuildScheduleParams() { ...@@ -103,4 +107,21 @@ UpdateNotificationServiceImpl::BuildScheduleParams() {
return schedule_params; return schedule_params;
} }
void UpdateNotificationServiceImpl::OnUserDismiss() {
int count = updates::GetUserDismissCount() + 1;
if (count >= kNumConsecutiveDismissCountCap) {
ApplyLinearThrottle();
count = 0;
}
updates::UpdateUserDismissCount(count);
}
void UpdateNotificationServiceImpl::ApplyLinearThrottle() {
auto scale = config_->throttle_interval_linear_co_scale;
auto offset =
base::TimeDelta::FromDays(config_->throttle_interval_linear_co_offset);
auto interval = GetThrottleInterval();
updates::UpdateThrottleInterval(scale * interval + offset);
}
} // namespace updates } // namespace updates
...@@ -34,6 +34,8 @@ class UpdateNotificationServiceImpl : public UpdateNotificationService { ...@@ -34,6 +34,8 @@ class UpdateNotificationServiceImpl : public UpdateNotificationService {
bool IsReadyToDisplay() const override; bool IsReadyToDisplay() const override;
void OnUserDismiss() override;
// Called after querying the |ClientOverview| struct from scheduler system // Called after querying the |ClientOverview| struct from scheduler system
// completed. // completed.
void OnClientOverviewQueried(UpdateNotificationInfo data, void OnClientOverviewQueried(UpdateNotificationInfo data,
...@@ -46,6 +48,9 @@ class UpdateNotificationServiceImpl : public UpdateNotificationService { ...@@ -46,6 +48,9 @@ class UpdateNotificationServiceImpl : public UpdateNotificationService {
// otherwise return the default interval from config. // otherwise return the default interval from config.
base::TimeDelta GetThrottleInterval() const; base::TimeDelta GetThrottleInterval() const;
// Apply linear throttle logic.
void ApplyLinearThrottle();
// Used to schedule notification to show in the future. Must outlive this // Used to schedule notification to show in the future. Must outlive this
// class. // class.
notifications::NotificationScheduleService* schedule_service_; notifications::NotificationScheduleService* schedule_service_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment