Skip to content

Commit

Permalink
[cherry-pick][desktop ios promo] Triggering logic for desktop iOS
Browse files Browse the repository at this point in the history
password promo

This CL includes most of the triggering logic for showing the iOS promo
to an eligible user. A related follow-up CL contains the rest of the
triggering logic.

(cherry picked from commit 34f3615)

Bug: 1435035
Change-Id: I283ba69f239849b38af378b148a09baff02b202c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4628373
Commit-Queue: Nicolas MacBeth <nicolasmacbeth@google.com>
Reviewed-by: Roger McFarlane <rogerm@chromium.org>
Reviewed-by: Avi Drissman <avi@chromium.org>
Reviewed-by: Siddhartha S <ssid@chromium.org>
Reviewed-by: Vasilii Sukhanov <vasilii@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1163087}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4650105
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Reviewed-by: Sebastien Seguin-Gagnon <sebsg@chromium.org>
Cr-Commit-Position: refs/branch-heads/5845@{#225}
Cr-Branched-From: 5a5dff6-refs/heads/main@{#1160321}
  • Loading branch information
Nicolas-MacBeth authored and Chromium LUCI CQ committed Jun 29, 2023
1 parent 02c532a commit 58463f3
Show file tree
Hide file tree
Showing 10 changed files with 137 additions and 25 deletions.
4 changes: 4 additions & 0 deletions chrome/browser/promos/promos_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
#include "components/pref_registry/pref_registry_syncable.h"

namespace promos_utils {
// Amount of days of data to look back on for the segmentation platform model's
// input data.
constexpr int kiOSPasswordPromoLookbackWindow = 60;

// RegisterProfilePrefs is a helper to register the synced profile prefs.
void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);

Expand Down
3 changes: 3 additions & 0 deletions chrome/browser/ui/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -5676,6 +5676,7 @@ static_library("ui") {
"//components/power_bookmarks/core:core",
"//components/power_bookmarks/storage",
"//components/reading_list/features:flags",
"//components/segmentation_platform/embedder/default_model:default_model",
"//components/services/app_service/public/cpp:intents",
"//components/services/screen_ai/buildflags",
"//components/soda",
Expand All @@ -5702,6 +5703,8 @@ static_library("ui") {
"views/promos/ios_promo_password_bubble.cc",
"views/promos/ios_promo_password_bubble.h",
]

deps += [ "//components/prefs:prefs" ]
}

if (is_linux || is_chromeos_lacros) {
Expand Down
7 changes: 5 additions & 2 deletions chrome/browser/ui/browser_window.h
Original file line number Diff line number Diff line change
Expand Up @@ -413,8 +413,11 @@ class BrowserWindow : public ui::BaseWindow {
virtual void ShowBookmarkBubble(const GURL& url, bool already_bookmarked) = 0;

#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
// Maybe shows the IOS Password Promo Bubble.
virtual void MaybeShowIOSPasswordPromoBubble() = 0;
// Checks if the user is eligible for the iOS Password Promo Bubble. If they
// are, make a final eligibility check with a call to the segmentation
// platform with `MaybeShowIOSPasswordPromoBubble` passed as callback. That
// method may create/show a bubble to the user.
virtual void VerifyUserEligibilityIOSPasswordPromoBubble() = 0;
#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING)

// Shows the Screenshot bubble.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -827,7 +827,7 @@ void ManagePasswordsUIController::MaybeShowIOSPasswordPromo() {
if (!browser) {
return;
}
browser->window()->MaybeShowIOSPasswordPromoBubble();
browser->window()->VerifyUserEligibilityIOSPasswordPromoBubble();
#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING)
}

Expand Down
93 changes: 74 additions & 19 deletions chrome/browser/ui/views/frame/browser_view.cc
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,11 @@
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/profiles/profile_window.h"
#include "chrome/browser/profiles/profiles_state.h"
#include "chrome/browser/segmentation_platform/segmentation_platform_service_factory.h"
#include "chrome/browser/sessions/tab_restore_service_factory.h"
#include "chrome/browser/sharing_hub/sharing_hub_features.h"
#include "chrome/browser/signin/chrome_signin_helper.h"
#include "chrome/browser/sync/sync_service_factory.h"
#include "chrome/browser/themes/theme_properties.h"
#include "chrome/browser/themes/theme_service.h"
#include "chrome/browser/translate/chrome_translate_client.h"
Expand Down Expand Up @@ -189,6 +191,11 @@
#include "components/prefs/pref_service.h"
#include "components/reading_list/core/reading_list_pref_names.h"
#include "components/safe_browsing/core/browser/password_protection/metrics_util.h"
#include "components/segmentation_platform/embedder/default_model/device_switcher_model.h"
#include "components/segmentation_platform/public/constants.h"
#include "components/segmentation_platform/public/input_context.h"
#include "components/segmentation_platform/public/prediction_options.h"
#include "components/segmentation_platform/public/segmentation_platform_service.h"
#include "components/services/screen_ai/buildflags/buildflags.h"
#include "components/sessions/core/tab_restore_service.h"
#include "components/startup_metric_utils/browser/startup_metric_utils.h"
Expand Down Expand Up @@ -2491,33 +2498,81 @@ void BrowserView::ShowBookmarkBubble(const GURL& url, bool already_bookmarked) {
}

#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
void BrowserView::MaybeShowIOSPasswordPromoBubble() {
void BrowserView::VerifyUserEligibilityIOSPasswordPromoBubble() {
if (!browser_) {
return;
}

if (promos_utils::ShouldShowIOSPasswordPromo()) {
ToolbarButtonProvider* button_provider =
BrowserView::GetBrowserViewForBrowser(browser_.get())
->toolbar_button_provider();
const syncer::SyncService* sync_service =
SyncServiceFactory::GetForProfile(browser_->profile());

IOSPromoPasswordBubble::PromoVariant variant;
if (promos_utils::IsDirectVariantIOSPasswordPromo()) {
variant = IOSPromoPasswordBubble::PromoVariant::QR_CODE_VARIANT;
} else if (promos_utils::IsIndirectVariantIOSPasswordPromo()) {
variant =
IOSPromoPasswordBubble::PromoVariant::GET_STARTED_BUTTON_VARIANT;
} else {
NOTREACHED_NORETURN();
}
// Verify that the user is currently syncing their preferences, hasn't
// exceeded their impression limit, is not in the cooldown period or has not
// opted-out from seeing the promo.
if (sync_service && sync_service->IsSyncFeatureActive() &&
sync_service->GetActiveDataTypes().Has(syncer::PREFERENCES) &&
promos_utils::ShouldShowIOSPasswordPromo()) {
auto input_context =
base::MakeRefCounted<segmentation_platform::InputContext>();
input_context->metadata_args.emplace(
"active_days_limit", promos_utils::kiOSPasswordPromoLookbackWindow);
input_context->metadata_args.emplace(
"wait_for_device_info_in_seconds",
segmentation_platform::processing::ProcessedValue(0));

segmentation_platform::PredictionOptions options;
options.on_demand_execution = true;

// Get segmentation platform classification results and pass callback.
segmentation_platform::SegmentationPlatformServiceFactory::GetForProfile(
browser_->profile())
->GetClassificationResult(
segmentation_platform::kDeviceSwitcherKey, options, input_context,
base::BindOnce(&BrowserView::MaybeShowIOSPasswordPromoBubble,
GetAsWeakPtr()));
}
}

void BrowserView::MaybeShowIOSPasswordPromoBubble(
const segmentation_platform::ClassificationResult& result) {
if (!browser_) {
return;
}

feature_engagement::Tracker* tracker =
feature_engagement::TrackerFactory::GetForBrowserContext(
browser_->profile());

IOSPromoPasswordBubble::ShowBubble(
button_provider->GetAnchorView(PageActionIconType::kManagePasswords),
button_provider->GetPageActionIconView(
PageActionIconType::kManagePasswords),
variant, browser_.get());
if (tracker->ShouldTriggerHelpUI(
feature_engagement::kIPHiOSPasswordPromoDesktopFeature)) {
ShowIOSPasswordPromoBubble();
}
}

void BrowserView::ShowIOSPasswordPromoBubble() {
if (!browser_) {
return;
}

ToolbarButtonProvider* button_provider =
BrowserView::GetBrowserViewForBrowser(browser_.get())
->toolbar_button_provider();

IOSPromoPasswordBubble::PromoVariant variant;
if (promos_utils::IsDirectVariantIOSPasswordPromo()) {
variant = IOSPromoPasswordBubble::PromoVariant::QR_CODE_VARIANT;
} else if (promos_utils::IsIndirectVariantIOSPasswordPromo()) {
variant = IOSPromoPasswordBubble::PromoVariant::GET_STARTED_BUTTON_VARIANT;
} else {
NOTREACHED_NORETURN();
}

IOSPromoPasswordBubble::ShowBubble(
button_provider->GetAnchorView(PageActionIconType::kManagePasswords),
button_provider->GetPageActionIconView(
PageActionIconType::kManagePasswords),
variant, browser_.get());
}
#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING)

qrcode_generator::QRCodeGeneratorBubbleView*
Expand Down
13 changes: 12 additions & 1 deletion chrome/browser/ui/views/frame/browser_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include "chrome/browser/ui/views/user_education/browser_feature_promo_controller.h"
#include "chrome/common/buildflags.h"
#include "components/infobars/core/infobar_container.h"
#include "components/segmentation_platform/public/result.h"
#include "components/user_education/common/feature_promo_controller.h"
#include "components/user_education/common/feature_promo_handle.h"
#include "components/webapps/browser/banners/app_banner_manager.h"
Expand Down Expand Up @@ -535,7 +536,7 @@ class BrowserView : public BrowserWindow,
content::WebContents* contents,
const gfx::Image& image) override;
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
void MaybeShowIOSPasswordPromoBubble() override;
void VerifyUserEligibilityIOSPasswordPromoBubble() override;
#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING)
qrcode_generator::QRCodeGeneratorBubbleView* ShowQRCodeGeneratorBubble(
content::WebContents* contents,
Expand Down Expand Up @@ -827,6 +828,16 @@ class BrowserView : public BrowserWindow,
// |contents| can be null.
bool MaybeShowInfoBar(content::WebContents* contents);

#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
// Decides whether to show the iOS Password Promo Bubble based on segmentation
// platform classification results (is passed as a callback to the
// segmentation API).
void MaybeShowIOSPasswordPromoBubble(
const segmentation_platform::ClassificationResult& result);
// Shows the iOS Password Promo Bubble.
void ShowIOSPasswordPromoBubble();
#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING)

// Updates devtools window for given contents. This method will show docked
// devtools window for inspected |web_contents| that has docked devtools
// and hide it for null or not inspected |web_contents|. It will also make
Expand Down
2 changes: 1 addition & 1 deletion chrome/test/base/test_browser_window.cc
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ TestBrowserWindow::ShowScreenshotCapturedBubble(content::WebContents* contents,
#endif

#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
void TestBrowserWindow::MaybeShowIOSPasswordPromoBubble() {}
void TestBrowserWindow::VerifyUserEligibilityIOSPasswordPromoBubble() {}
#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING)

send_tab_to_self::SendTabToSelfBubbleView*
Expand Down
2 changes: 1 addition & 1 deletion chrome/test/base/test_browser_window.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ class TestBrowserWindow : public BrowserWindow {
IntentPickerResponse callback) override {}
#endif // !define(OS_ANDROID)
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
void MaybeShowIOSPasswordPromoBubble() override;
void VerifyUserEligibilityIOSPasswordPromoBubble() override;
#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING)
send_tab_to_self::SendTabToSelfBubbleView*
ShowSendTabToSelfDevicePickerBubble(content::WebContents* contents) override;
Expand Down
11 changes: 11 additions & 0 deletions tools/metrics/histograms/enums.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26829,6 +26829,17 @@ Called by update_debug_scenarios.py.-->
<int value="19" label="LegacyDesktopCaptureDeviceTypeWebContents"/>
</enum>

<enum name="DesktopIOSPasswordPromoAction">
<int value="0" label="Dismissed"/>
<int value="1" label="ExplicitlyClosed"/>
<int value="2" label="GetStartedClicked"/>
</enum>

<enum name="DesktopIOSPasswordPromoImpression">
<int value="0" label="FirstImpression"/>
<int value="1" label="SecondImpression"/>
</enum>

<enum name="DesktopIOSPromotionDismissalReason">
<obsolete>
Deprecated 11/2018 in issue 894963.
Expand Down
25 changes: 25 additions & 0 deletions tools/metrics/histograms/metadata/ios/histograms.xml
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,31 @@ chromium-metrics-reviews@google.com.
</summary>
</histogram>

<histogram name="IOS.DesktopPasswordPromo.Shown"
enum="DesktopIOSPasswordPromoImpression" expires_after="2024-01-31">
<owner>nicolasmacbeth@google.com</owner>
<owner>bling-get-set-up@google.com</owner>
<summary>
The impression of the iOS Password Promo shown to the user on Desktop.
Desktop only. This is only recorded for contextual promo appearances, not
when the eligibility criteria is override via feature flag.
</summary>
</histogram>

<histogram name="IOS.DesktopPasswordPromo.{Impression}.Action"
enum="DesktopIOSPasswordPromoAction" expires_after="2024-01-31">
<owner>nicolasmacbeth@google.com</owner>
<owner>bling-get-set-up@google.com</owner>
<summary>
The action taken by the user when shown the iOS Password Promo on Desktop
for the {Impression} impression. Desktop only.
</summary>
<token key="Impression">
<variant name="FirstImpression" summary="first"/>
<variant name="SecondImpression" summary="second"/>
</token>
</histogram>

<histogram name="IOS.DistantTab.TimeSinceLastUse" units="ms"
expires_after="2023-11-01">
<owner>ewannpv@chromium.org</owner>
Expand Down

0 comments on commit 58463f3

Please sign in to comment.