| Index: ios/chrome/browser/ui/ntp/notification_promo_whats_new.mm
|
| diff --git a/ios/chrome/browser/ui/ntp/notification_promo_whats_new.mm b/ios/chrome/browser/ui/ntp/notification_promo_whats_new.mm
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..2828c7980836750a96a8152376c65ca1a471eb29
|
| --- /dev/null
|
| +++ b/ios/chrome/browser/ui/ntp/notification_promo_whats_new.mm
|
| @@ -0,0 +1,287 @@
|
| +// Copyright (c) 2014 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.
|
| +
|
| +#import "ios/chrome/browser/ui/ntp/notification_promo_whats_new.h"
|
| +
|
| +#include <stdint.h>
|
| +#include <algorithm>
|
| +#include <memory>
|
| +#include <vector>
|
| +
|
| +#include "base/json/json_reader.h"
|
| +#include "base/metrics/field_trial.h"
|
| +#include "base/metrics/user_metrics.h"
|
| +#include "base/metrics/user_metrics_action.h"
|
| +#include "base/strings/string_util.h"
|
| +#include "base/time/time.h"
|
| +#include "base/values.h"
|
| +#include "components/metrics/metrics_pref_names.h"
|
| +#include "components/prefs/pref_service.h"
|
| +#include "ios/chrome/browser/experimental_flags.h"
|
| +#include "ios/chrome/browser/notification_promo.h"
|
| +#include "ios/chrome/browser/pref_names.h"
|
| +#include "ios/chrome/browser/ui/commands/ios_command_ids.h"
|
| +#include "ios/chrome/grit/ios_chromium_strings.h"
|
| +#include "ios/chrome/grit/ios_strings.h"
|
| +#include "ui/base/l10n/l10n_util.h"
|
| +
|
| +namespace {
|
| +
|
| +struct PromoStringToIdsMapEntry {
|
| + const char* promo_text_str;
|
| + int message_id;
|
| +};
|
| +
|
| +// A mapping from a string to a l10n message id.
|
| +const PromoStringToIdsMapEntry kPromoStringToIdsMap[] = {
|
| + {"IDS_IOS_APP_RATING_PROMO_STRING", IDS_IOS_APP_RATING_PROMO_STRING},
|
| + {"IDS_IOS_MOVE_TO_DOCK_FASTER_ACCESS", IDS_IOS_MOVE_TO_DOCK_FASTER_ACCESS},
|
| + {"IDS_IOS_MOVE_TO_DOCK_LOVE_CHROME", IDS_IOS_MOVE_TO_DOCK_LOVE_CHROME},
|
| + {"IDS_IOS_MOVE_TO_DOCK_TIP", IDS_IOS_MOVE_TO_DOCK_TIP},
|
| +};
|
| +
|
| +// Returns a localized version of |promo_text| if it has an entry in the
|
| +// |kPromoStringToIdsMap|. If there is no entry, |promo_text| is returned.
|
| +std::string GetLocalizedPromoText(const std::string& promo_text) {
|
| + for (size_t i = 0; i < arraysize(kPromoStringToIdsMap); ++i) {
|
| + if (kPromoStringToIdsMap[i].promo_text_str == promo_text)
|
| + return l10n_util::GetStringUTF8(kPromoStringToIdsMap[i].message_id);
|
| + }
|
| + return promo_text;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +NotificationPromoWhatsNew::NotificationPromoWhatsNew(PrefService* local_state)
|
| + : local_state_(local_state),
|
| + valid_(false),
|
| + notification_promo_(local_state_) {}
|
| +
|
| +NotificationPromoWhatsNew::~NotificationPromoWhatsNew() {}
|
| +
|
| +bool NotificationPromoWhatsNew::Init() {
|
| + notification_promo_.InitFromVariations();
|
| +
|
| + // Force enable a particular promo if experimental flag is set.
|
| + experimental_flags::WhatsNewPromoStatus forceEnabled =
|
| + experimental_flags::GetWhatsNewPromoStatus();
|
| + if (forceEnabled != experimental_flags::WHATS_NEW_DEFAULT) {
|
| + switch (forceEnabled) {
|
| + case experimental_flags::WHATS_NEW_APP_RATING:
|
| + InjectFakePromo("1", "IDS_IOS_APP_RATING_PROMO_STRING",
|
| + "chrome_command", "ratethisapp", "", "RateThisAppPromo",
|
| + "logo");
|
| + break;
|
| + case experimental_flags::WHATS_NEW_MOVE_TO_DOCK_FASTER:
|
| + InjectFakePromo("2", "IDS_IOS_MOVE_TO_DOCK_FASTER_ACCESS", "url", "",
|
| + "https://support.google.com/chrome/?p=iphone_dock",
|
| + "MoveToDockFasterAccessPromo",
|
| + "logoWithRoundedRectangle");
|
| + break;
|
| + case experimental_flags::WHATS_NEW_MOVE_TO_DOCK_LOVE:
|
| + InjectFakePromo("3", "IDS_IOS_MOVE_TO_DOCK_LOVE_CHROME", "url", "",
|
| + "https://support.google.com/chrome/?p=iphone_dock",
|
| + "MoveToDockLovePromo", "logoWithRoundedRectangle");
|
| + break;
|
| + case experimental_flags::WHATS_NEW_MOVE_TO_DOCK_TIP:
|
| + InjectFakePromo("4", "IDS_IOS_MOVE_TO_DOCK_TIP", "url", "",
|
| + "https://support.google.com/chrome/?p=iphone_dock",
|
| + "MoveToDockTipPromo", "logoWithRoundedRectangle");
|
| + break;
|
| + default:
|
| + NOTREACHED();
|
| + break;
|
| + }
|
| + }
|
| +
|
| + notification_promo_.InitFromPrefs(
|
| + ios::NotificationPromo::MOBILE_NTP_WHATS_NEW_PROMO);
|
| + return InitFromNotificationPromo();
|
| +}
|
| +
|
| +bool NotificationPromoWhatsNew::ClearAndInitFromJson(
|
| + const base::DictionaryValue& json) {
|
| + // This clears away old promos.
|
| + notification_promo_.MigrateUserPrefs(local_state_);
|
| +
|
| + notification_promo_.InitFromJson(
|
| + json, ios::NotificationPromo::MOBILE_NTP_WHATS_NEW_PROMO);
|
| + return InitFromNotificationPromo();
|
| +}
|
| +
|
| +bool NotificationPromoWhatsNew::CanShow() const {
|
| + if (!valid_ || !notification_promo_.CanShow()) {
|
| + return false;
|
| + }
|
| +
|
| + // Check optional restrictions.
|
| +
|
| + if (seconds_since_install_ > 0) {
|
| + // Do not show the promo if the app's installation did not occur more than
|
| + // |seconds_since_install_| seconds ago.
|
| + int64_t install_date = local_state_->GetInt64(metrics::prefs::kInstallDate);
|
| + const base::Time first_view_time =
|
| + base::Time::FromTimeT(install_date) +
|
| + base::TimeDelta::FromSeconds(seconds_since_install_);
|
| + if (first_view_time > base::Time::Now()) {
|
| + return false;
|
| + }
|
| + }
|
| +
|
| + if (max_seconds_since_install_ > 0) {
|
| + // Do not show the promo if the app's installation occurred more than
|
| + // |max_seconds_since_install_| seconds ago.
|
| + int64_t install_date = local_state_->GetInt64(metrics::prefs::kInstallDate);
|
| + const base::Time last_view_time =
|
| + base::Time::FromTimeT(install_date) +
|
| + base::TimeDelta::FromSeconds(max_seconds_since_install_);
|
| + if (last_view_time < base::Time::Now()) {
|
| + return false;
|
| + }
|
| + }
|
| +
|
| + if (promo_name_ == "WKWVGotFasterPromo") {
|
| + // Promo is not relevant anymore: It was shown during the migration to the
|
| + // WKWebview.
|
| + return false;
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +void NotificationPromoWhatsNew::HandleViewed() {
|
| + // TODO(justincohen): metrics actions names should be inlined. Since
|
| + // metric_name_ is retrieved from a server, it's not possible to know at build
|
| + // time the values. We should investigate to find a solution. In the meantime,
|
| + // metrics will be reported hashed.
|
| + // http://crbug.com/437500
|
| + std::string metric = std::string("WhatsNewPromoViewed_") + metric_name_;
|
| + base::RecordAction(base::UserMetricsAction(metric.c_str()));
|
| + base::RecordAction(base::UserMetricsAction("NTPPromoShown"));
|
| + notification_promo_.HandleViewed();
|
| +}
|
| +
|
| +void NotificationPromoWhatsNew::HandleClosed() {
|
| + // TODO(justincohen): metrics actions names should be inlined. Since
|
| + // metric_name_ is retrieved from a server, it's not possible to know at build
|
| + // time the values. We should investigate to find a solution. In the meantime,
|
| + // metrics will be reported hashed.
|
| + // http://crbug.com/437500
|
| + std::string metric = std::string("WhatsNewPromoClosed_") + metric_name_;
|
| + base::RecordAction(base::UserMetricsAction(metric.c_str()));
|
| + base::RecordAction(base::UserMetricsAction("NTPPromoClosed"));
|
| + notification_promo_.HandleClosed();
|
| +}
|
| +
|
| +bool NotificationPromoWhatsNew::IsURLPromo() const {
|
| + return promo_type_ == "url";
|
| +}
|
| +
|
| +bool NotificationPromoWhatsNew::IsChromeCommand() const {
|
| + return promo_type_ == "chrome_command";
|
| +}
|
| +
|
| +WhatsNewIcon NotificationPromoWhatsNew::ParseIconName(
|
| + const std::string& icon_name) {
|
| + if (icon_name == "logo") {
|
| + return WHATS_NEW_LOGO;
|
| + } else if (icon_name == "logoWithRoundedRectangle") {
|
| + return WHATS_NEW_LOGO_ROUNDED_RECTANGLE;
|
| + }
|
| + return WHATS_NEW_INFO;
|
| +}
|
| +
|
| +bool NotificationPromoWhatsNew::InitFromNotificationPromo() {
|
| + valid_ = false;
|
| +
|
| + notification_promo_.promo_payload()->GetString("promo_type", &promo_type_);
|
| + notification_promo_.promo_payload()->GetString("metric_name", &metric_name_);
|
| + promo_text_ = GetLocalizedPromoText(notification_promo_.promo_text());
|
| +
|
| + if (IsURLPromo()) {
|
| + std::string url_text;
|
| + notification_promo_.promo_payload()->GetString("url", &url_text);
|
| + url_ = GURL(url_text);
|
| + if (url_.is_empty() || !url_.is_valid()) {
|
| + valid_ = false;
|
| + return valid_;
|
| + }
|
| + }
|
| +
|
| + if (IsChromeCommand()) {
|
| + std::string command;
|
| + notification_promo_.promo_payload()->GetString("command", &command);
|
| + if (command == "bookmark") {
|
| + command_id_ = IDC_SHOW_BOOKMARK_MANAGER;
|
| + } else if (command == "ratethisapp") {
|
| + command_id_ = IDC_RATE_THIS_APP;
|
| + } else {
|
| + valid_ = false;
|
| + return valid_;
|
| + }
|
| + }
|
| +
|
| + valid_ =
|
| + !metric_name_.empty() && !promo_type_.empty() && !promo_text_.empty();
|
| +
|
| + notification_promo_.promo_payload()->GetString("promo_name", &promo_name_);
|
| + std::string icon_name;
|
| + notification_promo_.promo_payload()->GetString("icon", &icon_name);
|
| + icon_ = ParseIconName(icon_name);
|
| +
|
| + // Optional values don't need validation.
|
| + seconds_since_install_ = 0;
|
| + notification_promo_.promo_payload()->GetInteger("seconds_since_install",
|
| + &seconds_since_install_);
|
| + max_seconds_since_install_ = 0;
|
| + notification_promo_.promo_payload()->GetInteger("max_seconds_since_install",
|
| + &max_seconds_since_install_);
|
| + return valid_;
|
| +}
|
| +
|
| +void NotificationPromoWhatsNew::InjectFakePromo(const std::string& promo_id,
|
| + const std::string& promo_text,
|
| + const std::string& promo_type,
|
| + const std::string& command,
|
| + const std::string& url,
|
| + const std::string& metric_name,
|
| + const std::string& icon) {
|
| + // Build vector to fill in json string with given parameters.
|
| + std::vector<std::string> replacements;
|
| + replacements.push_back(promo_text);
|
| + replacements.push_back(promo_type);
|
| + replacements.push_back(metric_name);
|
| + replacements.push_back(command);
|
| + replacements.push_back(url);
|
| + replacements.push_back(icon);
|
| + replacements.push_back(promo_id);
|
| +
|
| + std::string promo_json =
|
| + "{"
|
| + " \"start\":\"1 Jan 1999 0:26:06 GMT\","
|
| + " \"end\":\"1 Jan 2199 0:26:06 GMT\","
|
| + " \"promo_text\":\"$1\","
|
| + " \"max_views\":20,"
|
| + " \"payload\":"
|
| + " {"
|
| + " \"promo_type\":\"$2\","
|
| + " \"metric_name\":\"$3\","
|
| + " \"command\":\"$4\","
|
| + " \"url\":\"$5\","
|
| + " \"icon\":\"$6\""
|
| + " },"
|
| + " \"max_seconds\":259200,"
|
| + " \"promo_id\":$7"
|
| + "}";
|
| + std::string promo_json_filled_in =
|
| + base::ReplaceStringPlaceholders(promo_json, replacements, NULL);
|
| +
|
| + std::unique_ptr<base::Value> value(
|
| + base::JSONReader::Read(promo_json_filled_in));
|
| + base::DictionaryValue* dict = NULL;
|
| + if (value->GetAsDictionary(&dict)) {
|
| + notification_promo_.InitFromJson(
|
| + *dict, ios::NotificationPromo::MOBILE_NTP_WHATS_NEW_PROMO);
|
| + }
|
| +}
|
|
|