chromium/chrome/android/java/src/org/chromium/chrome/browser/segmentation_platform/ReaderModeActionProvider.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.segmentation_platform;

import android.os.Handler;
import android.os.Looper;

import org.chromium.chrome.browser.dom_distiller.DomDistillerTabUtils;
import org.chromium.chrome.browser.dom_distiller.ReaderModeManager;
import org.chromium.chrome.browser.dom_distiller.TabDistillabilityProvider;
import org.chromium.chrome.browser.dom_distiller.TabDistillabilityProvider.DistillabilityObserver;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.toolbar.adaptive.AdaptiveToolbarButtonVariant;

/** Provides reader mode signal for showing contextual page action for a given tab. */
public class ReaderModeActionProvider implements ContextualPageActionController.ActionProvider {
    @Override
    public void getAction(Tab tab, SignalAccumulator signalAccumulator) {
        final TabDistillabilityProvider tabDistillabilityProvider =
                TabDistillabilityProvider.get(tab);
        if (tabDistillabilityProvider.isDistillabilityDetermined()) {
            notifyActionAvailable(
                    tabDistillabilityProvider.isDistillable(),
                    tabDistillabilityProvider.isMobileOptimized(),
                    tab,
                    signalAccumulator);
            return;
        }

        // Distillability score isn't available yet. Start observing the provider.
        final TabDistillabilityProvider.DistillabilityObserver distillabilityObserver =
                new DistillabilityObserver() {
                    @Override
                    public void onIsPageDistillableResult(
                            Tab tab,
                            boolean isDistillable,
                            boolean isLast,
                            boolean isMobileOptimized) {
                        notifyActionAvailable(
                                isDistillable, isMobileOptimized, tab, signalAccumulator);
                        tabDistillabilityProvider.removeObserver(this);
                    }
                };
        tabDistillabilityProvider.addObserver(distillabilityObserver);
    }

    @Override
    public void onActionShown(Tab tab, @AdaptiveToolbarButtonVariant int action) {
        if (tab == null) return;
        if (action != AdaptiveToolbarButtonVariant.READER_MODE) return;

        new Handler(Looper.getMainLooper())
                .postDelayed(
                        () -> {
                            if (tab.isDestroyed()) return;

                            ReaderModeManager readerModeManager =
                                    tab.getUserDataHost()
                                            .getUserData(ReaderModeManager.USER_DATA_KEY);
                            if (readerModeManager != null) {
                                readerModeManager.setReaderModeUiShown();
                            }
                        },
                        /* delayMillis= */ 500);
    }

    private void notifyActionAvailable(
            boolean isDistillable,
            boolean isMobileOptimized,
            Tab tab,
            SignalAccumulator signalAccumulator) {
        // TODO(shaktisahu): Can we merge these into a single method call?
        signalAccumulator.setHasReaderMode(isDistillable && !isFilteredOut(tab, isMobileOptimized));
        signalAccumulator.notifySignalAvailable();
    }

    private boolean isFilteredOut(Tab tab, boolean isMobileOptimized) {
        // Test if the user is requesting the desktop site. Ignore this if distiller is set to
        // ALWAYS_TRUE.
        boolean usingRequestDesktopSite =
                tab.getWebContents() != null
                        && tab.getWebContents().getNavigationController().getUseDesktopUserAgent()
                        && !DomDistillerTabUtils.isHeuristicAlwaysTrue();

        if (usingRequestDesktopSite) return true;

        if (isMobileOptimized && DomDistillerTabUtils.shouldExcludeMobileFriendly(tab)) {
            return true;
        }

        return false;
    }
}