chromium/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/CustomTabNavigationBarController.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.customtabs.features;

import android.content.Context;
import android.os.Build;
import android.view.Window;

import androidx.annotation.Nullable;

import org.chromium.chrome.R;
import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider;
import org.chromium.chrome.browser.customtabs.CustomTabsConnection;
import org.chromium.chrome.browser.ui.google_bottom_bar.GoogleBottomBarCoordinator;
import org.chromium.ui.UiUtils;
import org.chromium.ui.util.ColorUtils;

/**
 * Configures the system navigation bar while a Custom Tab activity is running.
 *
 * Lifecycle: currently is stateless, so it has only static methods.
 */
public class CustomTabNavigationBarController {

    private CustomTabNavigationBarController() {}

    /** Sets the navigation bar color and navigation divider color according to intent extras. */
    public static void update(
            Window window, BrowserServicesIntentDataProvider intentDataProvider, Context context) {
        Integer navigationBarColor = intentDataProvider.getColorProvider().getNavigationBarColor();
        Integer navigationBarDividerColor =
                intentDataProvider.getColorProvider().getNavigationBarDividerColor();
        // TODO(b/300419189): Pass the CCT Top Bar Color in AGSA intent after Page Insights Hub is
        // launched
        if (GoogleBottomBarCoordinator.isFeatureEnabled()
                && CustomTabsConnection.getInstance()
                        .shouldEnableGoogleBottomBarForIntent(intentDataProvider)) {
            navigationBarColor = context.getColor(R.color.google_bottom_bar_background_color);
            navigationBarDividerColor =
                    context.getColor(R.color.google_bottom_bar_background_color);
        }
        // PCCT is deemed incapable of system dark button support due to the way it implements
        // partial height (window coordinate translation). We do the darkening ourselves.
        boolean supportsDarkButtons =
                Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
                        && !intentDataProvider.isPartialCustomTab();
        boolean needsDarkButtons =
                navigationBarColor != null
                        && !ColorUtils.shouldUseLightForegroundOnBackground(navigationBarColor);

        updateBarColor(window, navigationBarColor, supportsDarkButtons, needsDarkButtons);

        // navigationBarDividerColor can only be set in Android P+
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) return;
        Integer dividerColor =
                getDividerColor(
                        context, navigationBarColor, navigationBarDividerColor, needsDarkButtons);

        if (dividerColor != null) window.setNavigationBarDividerColor(dividerColor);
    }

    /** Sets the navigation bar color according to intent extras. */
    private static void updateBarColor(
            Window window,
            Integer navigationBarColor,
            boolean supportsDarkButtons,
            boolean needsDarkButtons) {
        if (navigationBarColor == null) return;

        if (supportsDarkButtons) {
            UiUtils.setNavigationBarIconColor(
                    window.getDecorView().getRootView(), needsDarkButtons);
        } else if (needsDarkButtons) {
            // Can't make the buttons dark, darken the background instead with the same algorithm
            // as for the status bar.
            navigationBarColor = ColorUtils.getDarkenedColorForStatusBar(navigationBarColor);
        }

        window.setNavigationBarColor(navigationBarColor);
    }

    /**
     * Return the navigation bar divider color.
     * @param context {@link Context} to get color resource from.
     * @param navigationBarColor Color of the navigation bar.
     * @param navigationBarDividerColor Color of the divider.
     * @param needsDarkButtons Whether the buttons and the bar has a low contrast.
     */
    public static @Nullable Integer getDividerColor(
            Context context,
            Integer navigationBarColor,
            Integer navigationBarDividerColor,
            boolean needsDarkButtons) {
        if (navigationBarDividerColor == null && navigationBarColor != null && needsDarkButtons) {
            // Add grey divider color if the background is light (similar to
            // TabbedNavigationBarColorController#setNavigationBarColor).
            // bottom_system_nav_divider_color is overridden to black on Q+, so using it's pre-Q
            // value, black_alpha_12, directly.
            return context.getColor(R.color.black_alpha_12);
        }
        return navigationBarDividerColor;
    }
}