chromium/chrome/android/java/src/org/chromium/chrome/browser/autofill/save_card/AutofillSaveCardBottomSheetLifecycle.java

// Copyright 2024 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.autofill.save_card;

import org.chromium.chrome.browser.layouts.LayoutStateProvider;
import org.chromium.chrome.browser.layouts.LayoutType;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tabmodel.TabModel;
import org.chromium.chrome.browser.tabmodel.TabModelObserver;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.StateChangeReason;
import org.chromium.components.browser_ui.bottomsheet.EmptyBottomSheetObserver;

/**
 * The lifecycle for the save card bottom sheet. Notifies the caller when a tab or layout changes
 * (e.g., going into the "tab overview"), so the bottom sheet can be dismissed. Ignores page
 * navigation.
 */
/*package*/ class AutofillSaveCardBottomSheetLifecycle extends EmptyBottomSheetObserver
        implements TabModelObserver, LayoutStateProvider.LayoutStateObserver {
    /** Controller callbacks from the save card bottom sheet. */
    interface ControllerDelegate {
        void onCanceled();

        void onIgnored();
    }

    private final BottomSheetController mBottomSheetController;
    private final LayoutStateProvider mLayoutStateProvider;
    private final TabModel mTabModel;
    private ControllerDelegate mDelegate;
    private boolean mFinished;

    /**
     * Constructs the lifecycle for the save card bottom sheet.
     *
     * @param bottomSheetController The controller to use for showing or hiding the content.
     * @param layoutStateProvider The LayoutStateProvider used to detect when the bottom sheet needs
     *     to be hidden after a change of layout (e.g. to the tab switcher).
     * @param tabModel The TabModel used to detect when the bottom sheet needs to be hidden after a
     *     tab change.
     */
    AutofillSaveCardBottomSheetLifecycle(
            BottomSheetController bottomSheetController,
            LayoutStateProvider layoutStateProvider,
            TabModel tabModel) {
        mBottomSheetController = bottomSheetController;
        mLayoutStateProvider = layoutStateProvider;
        mTabModel = tabModel;
    }

    /**
     * Begins the lifecycle of the save card bottom sheet. Starts observing tab and layout changes.
     *
     * @param delegate The controller callbacks for user actions.
     */
    void begin(ControllerDelegate delegate) {
        mDelegate = delegate;

        mBottomSheetController.addObserver(this);
        mLayoutStateProvider.addObserver(this);
        mTabModel.addObserver(this);
    }

    /** Ends the lifecycle of the save card bottom sheet. Stops observing tab and layout changes. */
    void end() {
        mTabModel.removeObserver(this);
        mLayoutStateProvider.removeObserver(this);
        mBottomSheetController.removeObserver(this);
    }

    // Overrides EmptyBottomSheetObserver onSheetClosed method for BottomSheetController.
    @Override
    public void onSheetClosed(@StateChangeReason int reason) {
        switch (reason) {
            case StateChangeReason.BACK_PRESS:
            case StateChangeReason.SWIPE:
            case StateChangeReason.TAP_SCRIM:
                finish(mDelegate::onCanceled);
                break;
            case StateChangeReason.INTERACTION_COMPLETE:
                // Expecting AutofillSaveCardBottomSheetCoordinator to set up the appropriate
                // callbacks to native on button presses in this case.
                mFinished = true;
                break;
            default:
                finish(mDelegate::onIgnored);
                break;
        }
    }

    // Implements LayoutStateObserver for LayoutStateProvider.
    @Override
    public void onStartedShowing(int layoutType) {
        if (layoutType != LayoutType.BROWSING) {
            finish(mDelegate::onIgnored);
        }
    }

    // Implements TabModelObserver for TabModel.
    @Override
    public void didSelectTab(Tab tab, int type, int lastId) {
        if (lastId != tab.getId()) {
            finish(mDelegate::onIgnored);
        }
    }

    void finish(Runnable callback) {
        if (!mFinished) {
            mFinished = true;
            callback.run();
        }
    }
}