chromium/chrome/android/java/src/org/chromium/chrome/browser/reengagement/ReengagementNotificationController.java

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.chrome.browser.reengagement;

import android.app.Activity;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.text.TextUtils;

import androidx.annotation.StringRes;
import androidx.annotation.VisibleForTesting;

import org.chromium.base.Callback;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.DefaultBrowserInfo2;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.notifications.NotificationUmaTracker;
import org.chromium.chrome.browser.notifications.NotificationUmaTracker.SystemNotificationType;
import org.chromium.chrome.browser.notifications.NotificationWrapperBuilderFactory;
import org.chromium.chrome.browser.notifications.channels.ChromeChannelDefinitions.ChannelId;
import org.chromium.components.browser_ui.notifications.BaseNotificationManagerProxy;
import org.chromium.components.browser_ui.notifications.BaseNotificationManagerProxyFactory;
import org.chromium.components.browser_ui.notifications.NotificationMetadata;
import org.chromium.components.browser_ui.notifications.NotificationWrapper;
import org.chromium.components.browser_ui.notifications.NotificationWrapperBuilder;
import org.chromium.components.browser_ui.notifications.PendingIntentProvider;
import org.chromium.components.feature_engagement.FeatureConstants;
import org.chromium.components.feature_engagement.Tracker;

/**
 * Controller to manage when and how we show re-engagement notifications to users.
 * TODO(crbug.com/40140907): Modularize this file.
 */
public class ReengagementNotificationController {
    /** An {@link Intent} action to open Chrome to the NTP. */
    public static final String LAUNCH_NTP_ACTION = "launch_ntp";

    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
    protected static final String NOTIFICATION_TAG = "reengagement_notification";

    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
    protected static final int NOTIFICATION_ID = 200;

    private final Context mContext;
    private final Tracker mTracker;
    private final Class<? extends Activity> mActivityClazz;

    /** @return Whether or not the re-engagement notification is enabled. */
    public static boolean isEnabled() {
        return ChromeFeatureList.isEnabled(ChromeFeatureList.REENGAGEMENT_NOTIFICATION);
    }

    /** Creates an instance of ReengagementNotificationController. */
    public ReengagementNotificationController(
            Context context, Tracker tracker, Class<? extends Activity> activityClazz) {
        mContext = context;
        mTracker = tracker;
        mActivityClazz = activityClazz;
    }

    /** Attempt to re-engage the user by showing a notification (if criteria are met). */
    public void tryToReengageTheUser() {
        if (!isEnabled()) return;
        getDefaultBrowserInfo(
                info -> {
                    if (info == null || info.browserCount <= 1) return;

                    if (showNotification(
                            FeatureConstants.CHROME_REENGAGEMENT_NOTIFICATION_1_FEATURE)) {
                        return;
                    }
                    if (showNotification(
                            FeatureConstants.CHROME_REENGAGEMENT_NOTIFICATION_2_FEATURE)) {
                        return;
                    }
                    if (showNotification(
                            FeatureConstants.CHROME_REENGAGEMENT_NOTIFICATION_3_FEATURE)) {
                        return;
                    }
                });
    }

    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
    protected void getDefaultBrowserInfo(Callback<DefaultBrowserInfo2.DefaultInfo> callback) {
        DefaultBrowserInfo2.getDefaultBrowserInfo(callback);
    }

    private boolean showNotification(String feature) {
        @StringRes int titleId = 0;
        @StringRes int descriptionId = 0;
        @SystemNotificationType int notificationUmaType = SystemNotificationType.UNKNOWN;

        if (TextUtils.equals(
                feature, FeatureConstants.CHROME_REENGAGEMENT_NOTIFICATION_1_FEATURE)) {
            titleId = R.string.chrome_reengagement_notification_1_title;
            descriptionId = R.string.chrome_reengagement_notification_1_description;
            notificationUmaType = SystemNotificationType.CHROME_REENGAGEMENT_1;
        } else if (TextUtils.equals(
                feature, FeatureConstants.CHROME_REENGAGEMENT_NOTIFICATION_2_FEATURE)) {
            titleId = R.string.chrome_reengagement_notification_2_title;
            descriptionId = R.string.chrome_reengagement_notification_2_description;
            notificationUmaType = SystemNotificationType.CHROME_REENGAGEMENT_2;
        } else if (TextUtils.equals(
                feature, FeatureConstants.CHROME_REENGAGEMENT_NOTIFICATION_3_FEATURE)) {
            titleId = R.string.chrome_reengagement_notification_3_title;
            descriptionId = R.string.chrome_reengagement_notification_3_description;
            notificationUmaType = SystemNotificationType.CHROME_REENGAGEMENT_3;
        } else {
            return false;
        }

        if (!mTracker.shouldTriggerHelpUI(feature)) return false;
        mTracker.dismissed(feature);

        NotificationMetadata metadata =
                new NotificationMetadata(notificationUmaType, NOTIFICATION_TAG, NOTIFICATION_ID);
        NotificationWrapperBuilder builder =
                NotificationWrapperBuilderFactory.createNotificationWrapperBuilder(
                        ChannelId.UPDATES, metadata);

        Intent intent = new Intent(mContext, mActivityClazz);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setAction(LAUNCH_NTP_ACTION);

        PendingIntentProvider intentProvider =
                PendingIntentProvider.getActivity(
                        mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

        builder.setContentTitle(mContext.getString(titleId))
                .setContentText(mContext.getString(descriptionId))
                .setSmallIcon(R.drawable.ic_chrome)
                .setContentIntent(intentProvider)
                .setAutoCancel(true);

        BaseNotificationManagerProxy notificationManager =
                BaseNotificationManagerProxyFactory.create(mContext);
        NotificationWrapper notification = builder.buildNotificationWrapper();
        notificationManager.notify(notification);

        NotificationUmaTracker.getInstance()
                .onNotificationShown(notificationUmaType, notification.getNotification());
        return true;
    }
}