chromium/chrome/android/java/src/org/chromium/chrome/browser/browserservices/ui/trustedwebactivity/DisclosureUiPicker.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.browserservices.ui.trustedwebactivity;

import static android.app.NotificationManager.IMPORTANCE_NONE;

import static org.chromium.chrome.browser.notifications.channels.ChromeChannelDefinitions.ChannelId.WEBAPPS;
import static org.chromium.chrome.browser.notifications.channels.ChromeChannelDefinitions.ChannelId.WEBAPPS_QUIET;

import android.app.NotificationChannel;
import android.os.Build;

import androidx.annotation.RequiresApi;

import dagger.Lazy;

import org.chromium.base.BuildInfo;
import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider;
import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider.TwaDisclosureUi;
import org.chromium.chrome.browser.browserservices.ui.view.DisclosureInfobar;
import org.chromium.chrome.browser.browserservices.ui.view.DisclosureNotification;
import org.chromium.chrome.browser.browserservices.ui.view.DisclosureSnackbar;
import org.chromium.chrome.browser.dependency_injection.ActivityScope;
import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
import org.chromium.chrome.browser.lifecycle.NativeInitObserver;
import org.chromium.components.browser_ui.notifications.NotificationManagerProxy;

import javax.inject.Inject;

/**
 * Determines which of the versions of the "Running in Chrome" UI is displayed to the user.
 *
 * There are three:
 * * The old Infobar. (An Infobar doesn't go away until you accept it.)
 * * The new Notification. (When notifications are enabled.)
 * * The new Snackbar. (A Snackbar dismisses automatically, this one after 7 seconds.)
 */
@ActivityScope
public class DisclosureUiPicker implements NativeInitObserver {
    private final Lazy<DisclosureInfobar> mDisclosureInfobar;
    private final Lazy<DisclosureSnackbar> mDisclosureSnackbar;
    private final Lazy<DisclosureNotification> mDisclosureNotification;
    private final BrowserServicesIntentDataProvider mIntentDataProvider;
    private final NotificationManagerProxy mNotificationManager;

    @Inject
    public DisclosureUiPicker(
            Lazy<DisclosureInfobar> disclosureInfobar,
            Lazy<DisclosureSnackbar> disclosureSnackbar,
            Lazy<DisclosureNotification> disclosureNotification,
            BrowserServicesIntentDataProvider intentDataProvider,
            NotificationManagerProxy notificationManager,
            ActivityLifecycleDispatcher lifecycleDispatcher) {
        mDisclosureInfobar = disclosureInfobar;
        mDisclosureSnackbar = disclosureSnackbar;
        mDisclosureNotification = disclosureNotification;
        mIntentDataProvider = intentDataProvider;
        mNotificationManager = notificationManager;
        lifecycleDispatcher.register(this);
    }

    @Override
    public void onFinishNativeInitialization() {
        // Calling get on the appropriate Lazy instance will cause Dagger to create the class.
        // The classes wire themselves up to the rest of the code in their constructors.

        // TODO(peconn): Once this feature is enabled by default and we get rid of this check, move
        // this logic into the constructor and let the Views call showIfNeeded() themselves in
        // their onFinishNativeInitialization.

        if (mIntentDataProvider.getTwaDisclosureUi() == TwaDisclosureUi.V1_INFOBAR) {
            mDisclosureInfobar.get().showIfNeeded();
        } else if (areHeadsUpNotificationsEnabled()) {
            mDisclosureNotification.get().onStartWithNative();
        } else {
            mDisclosureSnackbar.get().showIfNeeded();
        }
    }

    private boolean areHeadsUpNotificationsEnabled() {
        if (!mNotificationManager.areNotificationsEnabled()) return false;
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return true;
        // Android Automotive doesn't currently allow heads-up notifications.
        if (BuildInfo.getInstance().isAutomotive) return false;

        return isChannelEnabled(WEBAPPS) && isChannelEnabled(WEBAPPS_QUIET);
    }

    @RequiresApi(Build.VERSION_CODES.O)
    private boolean isChannelEnabled(String channelId) {
        NotificationChannel channel = mNotificationManager.getNotificationChannel(channelId);

        // If the Channel is null we've not created it yet. Since we know that Chrome notifications
        // are not disabled in general, we know that once the channel is created it should be
        // enabled.
        if (channel == null) return true;

        return channel.getImportance() != IMPORTANCE_NONE;
    }
}