chromium/chrome/browser/commerce/android/java/src/org/chromium/chrome/browser/commerce/PriceNotificationSettingsFragment.java

// Copyright 2022 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.commerce;

import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;

import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;

import org.chromium.base.ContextUtils;
import org.chromium.base.supplier.ObservableSupplier;
import org.chromium.base.supplier.ObservableSupplierImpl;
import org.chromium.chrome.browser.notifications.channels.ChromeChannelDefinitions;
import org.chromium.chrome.browser.preferences.Pref;
import org.chromium.chrome.browser.preferences.PrefChangeRegistrar;
import org.chromium.chrome.browser.settings.ChromeBaseSettingsFragment;
import org.chromium.chrome.browser.signin.services.IdentityServicesProvider;
import org.chromium.components.browser_ui.notifications.NotificationManagerProxy;
import org.chromium.components.browser_ui.notifications.NotificationManagerProxyImpl;
import org.chromium.components.browser_ui.settings.ChromeSwitchPreference;
import org.chromium.components.browser_ui.settings.SettingsUtils;
import org.chromium.components.browser_ui.settings.TextMessagePreference;
import org.chromium.components.prefs.PrefService;
import org.chromium.components.signin.base.CoreAccountInfo;
import org.chromium.components.signin.identitymanager.ConsentLevel;
import org.chromium.components.user_prefs.UserPrefs;
import org.chromium.ui.text.NoUnderlineClickableSpan;
import org.chromium.ui.text.SpanApplier;

/** Preferences for features related to price tracking. */
public class PriceNotificationSettingsFragment extends ChromeBaseSettingsFragment {
    @VisibleForTesting static final String PREF_MOBILE_NOTIFICATIONS = "mobile_notifications_text";

    @VisibleForTesting static final String PREF_EMAIL_NOTIFICATIONS = "send_email_switch";

    private final PrefChangeRegistrar mPrefChangeRegistrar = new PrefChangeRegistrar();

    private PrefService mPrefService;
    private TextMessagePreference mMobileNotificationsText;
    private ChromeSwitchPreference mEmailNotificationsSwitch;
    private NotificationManagerProxy mNotificationManagerProxy;
    private final ObservableSupplierImpl<String> mPageTitle = new ObservableSupplierImpl<>();

    @Override
    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
        mPrefService = UserPrefs.get(getProfile());
        mNotificationManagerProxy =
                new NotificationManagerProxyImpl(ContextUtils.getApplicationContext());

        SettingsUtils.addPreferencesFromResource(this, R.xml.price_notification_preferences);
        mPageTitle.set(getString(R.string.price_notifications_settings_detailed_page_title));

        mMobileNotificationsText =
                (TextMessagePreference) findPreference(PREF_MOBILE_NOTIFICATIONS);
        updateMobileNotificationsText();

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
            // App settings are only available on O+.
            getPreferenceScreen().removePreference(mMobileNotificationsText);
            mMobileNotificationsText = null;
        }

        mEmailNotificationsSwitch =
                (ChromeSwitchPreference) findPreference(PREF_EMAIL_NOTIFICATIONS);
        mEmailNotificationsSwitch.setOnPreferenceChangeListener(this::onPreferenceChange);
        CoreAccountInfo info =
                IdentityServicesProvider.get()
                        .getIdentityManager(getProfile())
                        .getPrimaryAccountInfo(ConsentLevel.SIGNIN);
        if (info != null) {
            String email = info.getEmail();
            mEmailNotificationsSwitch.setSummary(
                    getString(R.string.price_notifications_settings_email_description, email));
            mPrefChangeRegistrar.addObserver(
                    Pref.PRICE_EMAIL_NOTIFICATIONS_ENABLED, this::updateEmailNotificationSwitch);
            updateEmailNotificationSwitch();
        } else {
            mEmailNotificationsSwitch.setVisible(false);
        }
    }

    @Override
    public ObservableSupplier<String> getPageTitle() {
        return mPageTitle;
    }

    @Override
    public void onStart() {
        super.onStart();
        updateMobileNotificationsText();

        ShoppingServiceFactory.getForProfile(getProfile()).fetchPriceEmailPref();
    }

    /** Handle preference changes from any of the toggles in this UI. */
    private boolean onPreferenceChange(Preference preference, Object newValue) {
        if (PREF_EMAIL_NOTIFICATIONS.equals(preference.getKey())) {
            mPrefService.setBoolean(Pref.PRICE_EMAIL_NOTIFICATIONS_ENABLED, (boolean) newValue);
            return true;
        }
        return false;
    }

    /** Update the appearance of the email notification switch to reflect its corresponding pref. */
    private void updateEmailNotificationSwitch() {
        boolean emailEnabled = mPrefService.getBoolean(Pref.PRICE_EMAIL_NOTIFICATIONS_ENABLED);
        if (mEmailNotificationsSwitch.isChecked() != emailEnabled) {
            mEmailNotificationsSwitch.setChecked(emailEnabled);
        }
    }

    /**
     * Update the text displayed in the mobile notifications section. The text changes based on the
     * state of notifications and the price tracking channel
     */
    private void updateMobileNotificationsText() {
        if (mMobileNotificationsText == null) return;

        String linkText = getString(R.string.chrome_notification_settings_for_price_tracking);

        String settingsFullText;
        if (arePriceTrackingNotificationsEnabled()) {
            settingsFullText =
                    getString(
                            R.string.price_notifications_settings_mobile_description_on, linkText);
        } else {
            settingsFullText =
                    getString(
                            R.string.price_notifications_settings_mobile_description_off, linkText);
        }

        SpanApplier.SpanInfo info =
                new SpanApplier.SpanInfo(
                        "<link>",
                        "</link>",
                        new NoUnderlineClickableSpan(getContext(), (view) -> launchAppSettings()));
        SpanApplier.applySpans(settingsFullText, info);

        mMobileNotificationsText.setSummary(SpanApplier.applySpans(settingsFullText, info));
    }

    /** @return True if both app-level and price tracking notifications are enabled. */
    private boolean arePriceTrackingNotificationsEnabled() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel =
                    mNotificationManagerProxy.getNotificationChannel(
                            ChromeChannelDefinitions.ChannelId.PRICE_DROP_DEFAULT);
            if (mNotificationManagerProxy.areNotificationsEnabled()
                    && channel != null
                    && channel.getImportance() != NotificationManager.IMPORTANCE_NONE) {
                return true;
            }
        }
        return false;
    }

    /** Launch app settings so the user can view or change notification settings. */
    private void launchAppSettings() {
        Intent notificationsPrefIntent = new Intent();
        notificationsPrefIntent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
        notificationsPrefIntent.putExtra(
                Settings.EXTRA_APP_PACKAGE, ContextUtils.getApplicationContext().getPackageName());
        PackageManager pm = getActivity().getPackageManager();
        if (notificationsPrefIntent.resolveActivity(pm) != null) {
            startActivity(notificationsPrefIntent);
        }
    }

    void setPrefServiceForTesting(PrefService prefs) {
        mPrefService = prefs;
    }
}