chromium/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/TabObserver.java

// Copyright 2013 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.tab;

import android.graphics.Bitmap;

import androidx.annotation.Nullable;

import org.chromium.base.Token;
import org.chromium.cc.input.BrowserControlsOffsetTagsInfo;
import org.chromium.cc.input.BrowserControlsState;
import org.chromium.chrome.browser.tab.Tab.LoadUrlResult;
import org.chromium.components.find_in_page.FindMatchRectsDetails;
import org.chromium.components.find_in_page.FindNotificationDetails;
import org.chromium.content_public.browser.LoadUrlParams;
import org.chromium.content_public.browser.NavigationHandle;
import org.chromium.content_public.browser.WebContents;
import org.chromium.ui.base.WindowAndroid;
import org.chromium.ui.mojom.VirtualKeyboardMode;
import org.chromium.url.GURL;

/** An observer that is notified of changes to a {@link Tab} object. */
public interface TabObserver {
    /**
     * Called when a {@link Tab} finished initialization. The {@link TabState} contains,
     * if not {@code null}, various states that a Tab should restore itself from.
     * @param tab The notifying {@link Tab}.
     * @param appId ID of the external app that opened this tab.
     */
    void onInitialized(Tab tab, String appId);

    /**
     * Called when a {@link Tab} is shown.
     * @param tab The notifying {@link Tab}.
     * @param type Specifies how the tab was selected.
     */
    void onShown(Tab tab, @TabSelectionType int type);

    /**
     * Called when a {@link Tab} is hidden.
     * @param tab The notifying {@link Tab}.
     * @param type Specifies how the tab was hidden.
     */
    void onHidden(Tab tab, @TabHidingType int type);

    /**
     * Called when a {@link Tab}'s closing state has changed.
     *
     * @param tab The notifying {@link Tab}.
     * @param closing Whether the {@link Tab} is currently marked for closure.
     */
    void onClosingStateChanged(Tab tab, boolean closing);

    /**
     * Called when a {@link Tab} is being destroyed.
     * @param tab The notifying {@link Tab}.
     */
    void onDestroyed(Tab tab);

    /**
     * Called when the tab content changes (to/from native pages or swapping native WebContents).
     * @param tab The notifying {@link Tab}.
     */
    void onContentChanged(Tab tab);

    /**
     * Called when loadUrl is triggered on a a {@link Tab}.
     *
     * @param tab The notifying {@link Tab}.
     * @param params The params describe the page being loaded.
     * @param loadUrlResult The result of the loadUrl.
     */
    void onLoadUrl(Tab tab, LoadUrlParams params, LoadUrlResult loadUrlResult);

    /**
     * Called when a tab has started to load a page.
     * <p>
     * This will occur when the main frame starts the navigation, and will also occur in instances
     * where we need to simulate load progress (i.e. swapping in a not fully loaded pre-rendered
     * page).
     * <p>
     * For visual loading indicators/throbbers, {@link #onLoadStarted(Tab)} and
     * {@link #onLoadStopped(Tab)} should be used to drive updates.
     *  @param tab The notifying {@link Tab}.
     * @param url The committed URL being navigated to.
     */
    void onPageLoadStarted(Tab tab, GURL url);

    /**
     * Called when a tab has finished loading a page.
     *  @param tab The notifying {@link Tab}.
     * @param url The committed URL that was navigated to.
     */
    void onPageLoadFinished(Tab tab, GURL url);

    /**
     * Called when a tab has failed loading a page.
     *
     * @param tab The notifying {@link Tab}.
     * @param errorCode The error code that causes the page to fail loading.
     */
    void onPageLoadFailed(Tab tab, int errorCode);

    /**
     * Called when the favicon of a {@link Tab} has been updated.
     * @param tab The notifying {@link Tab}.
     * @param icon The favicon that was received.
     * @param iconUrl The URL that the icon was fetched from.
     */
    void onFaviconUpdated(Tab tab, Bitmap icon, GURL iconUrl);

    /**
     * Called when the title of a {@link Tab} changes.
     * @param tab The notifying {@link Tab}.
     */
    void onTitleUpdated(Tab tab);

    /**
     * Called when the URL of a {@link Tab} changes.
     * @param tab The notifying {@link Tab}.
     */
    void onUrlUpdated(Tab tab);

    /**
     * Called when the SSL state of a {@link Tab} changes.
     * @param tab The notifying {@link Tab}.
     */
    void onSSLStateUpdated(Tab tab);

    /**
     * Called when the ContentView of a {@link Tab} crashes.
     * @param tab The notifying {@link Tab}.
     */
    void onCrash(Tab tab);

    /**
     * Called when restore of the corresponding tab is triggered.
     * @param tab The notifying {@link Tab}.
     */
    void onRestoreStarted(Tab tab);

    /**
     * Called when restoration of the corresponding tab failed.
     * @param tab The notifying {@link Tab}.
     */
    void onRestoreFailed(Tab tab);

    /**
     * Called when the WebContents of a {@link Tab} is about to be swapped.
     * @param tab The notifying {@link Tab}
     */
    void webContentsWillSwap(Tab tab);

    /**
     * Called when the WebContents of a {@link Tab} have been swapped.
     * @param tab The notifying {@link Tab}.
     * @param didStartLoad Whether WebContentsObserver::DidStartProvisionalLoadForFrame() has
     *     already been called.
     * @param didFinishLoad Whether WebContentsObserver::DidFinishLoad() has already been called.
     */
    void onWebContentsSwapped(Tab tab, boolean didStartLoad, boolean didFinishLoad);

    /**
     * Called when a context menu is shown for a {@link WebContents} owned by a {@link Tab}.
     * @param tab  The notifying {@link Tab}.
     */
    void onContextMenuShown(Tab tab);

    // WebContentsDelegateAndroid methods ---------------------------------------------------------

    /**
     * Called when the WebContents is closed.
     * @param tab The notifying {@link Tab}.
     */
    void onCloseContents(Tab tab);

    /**
     * Called when the WebContents starts loading. Different from
     * {@link #onPageLoadStarted(Tab, GURL)}, if the user is navigated to a different url while
     * staying in the same html document, {@link #onLoadStarted(Tab)} will be called, while
     * {@link #onPageLoadStarted(Tab, GURL)} will not.
     * @param tab The notifying {@link Tab}.
     * @param toDifferentDocument Whether this navigation will transition between
     * documents (i.e., not a fragment navigation or JS History API call).
     */
    void onLoadStarted(Tab tab, boolean toDifferentDocument);

    /**
     * Called when the contents loading stops.
     * @param tab The notifying {@link Tab}.
     */
    void onLoadStopped(Tab tab, boolean toDifferentDocument);

    /**
     * Called when the load progress of a {@link Tab} changes.
     * @param tab      The notifying {@link Tab}.
     * @param progress The new progress from [0,1].
     */
    void onLoadProgressChanged(Tab tab, float progress);

    /**
     * Called when the URL of a {@link Tab} changes.
     * @param tab The notifying {@link Tab}.
     * @param url The new URL.
     */
    void onUpdateUrl(Tab tab, GURL url);

    // WebContentsObserver methods ---------------------------------------------------------

    /**
     * Called when a navigation in the primary main frame is started in the WebContents.
     * @param tab The notifying {@link Tab}.
     * @param navigationHandle Pointer to a NavigationHandle representing the navigation.
     *                         Its lifetime end at the end of onDidFinishNavigation().
     */
    void onDidStartNavigationInPrimaryMainFrame(Tab tab, NavigationHandle navigationHandle);

    /**
     * TODO(crbug.com/40264745) Temporary fix for LocationBarModel not properly caching same
     * document navigation state. Will be removed later, see bug for more details.
     */
    void onDidFinishNavigationEnd();

    /**
     * Called when a navigation is redirected in the WebContents.
     * @param tab The notifying {@link Tab}.
     * @param navigationHandle Pointer to a NavigationHandle representing the navigation.
     *                         Its lifetime end at the end of onDidFinishNavigation().
     */
    void onDidRedirectNavigation(Tab tab, NavigationHandle navigationHandle);

    /**
     * Called when a navigation is finished i.e. committed, aborted or replaced by a new one, in the
     * primary main frame.
     * @param tab The notifying {@link Tab}.
     * @param navigationHandle Pointer to a NavigationHandle representing the navigation.
     *                         Its lifetime end at the end of this function.
     */
    void onDidFinishNavigationInPrimaryMainFrame(Tab tab, NavigationHandle navigation);

    /**
     * Called when the page has painted something non-empty.
     * @param tab The notifying {@link Tab}.
     */
    void didFirstVisuallyNonEmptyPaint(Tab tab);

    /**
     * Called when the theme color is changed
     * @param tab   The notifying {@link Tab}.
     * @param color the new color in ARGB format.
     */
    void onDidChangeThemeColor(Tab tab, int color);

    /**
     * Called when the background color for the tab has changed.
     * @param tab The notifying {@link Tab}.
     * @param color The current background color.
     */
    void onBackgroundColorChanged(Tab tab, int color);

    /**
     * Called when the virtual keyboard mode in the tab's current page has been changed.
     * @param tab The notifying {@link Tab}.
     * @param mode The current virtual keyboard mode.
     */
    void onVirtualKeyboardModeChanged(Tab tab, @VirtualKeyboardMode.EnumType int mode);

    /**
     * Called when the Tab is attached or detached from an {@code Activity}. By default, this will
     * automatically unregister the tab observer if the Tab is detached from the window.
     *
     * TabObservers that are scoped to the Tab itself (either by direct ownership or through
     * UserData) will need to override this behavior. To do so, ensure there's a functional hook to
     * unregister the TabObserver to prevent leaking. When overriding this, keep in mind that tabs
     * can outlive the activity in some cases (change of theme, changing from phone/tablet,
     * multi-window, etc).
     *
     * @param tab The notifying {@link Tab}.
     * @param window {@link WindowAndroid} which the Tab is being associated with. {@code null} if
     *         the tab is being detached.
     */
    default void onActivityAttachmentChanged(Tab tab, @Nullable WindowAndroid window) {
        if (tab == null || window != null) return;
        tab.removeObserver(this);
    }

    /**
     * A notification when tab changes whether or not it is interactable and is accepting input.
     * @param tab The notifying {@link Tab}.
     * @param isInteractable Whether or not the tab is interactable.
     */
    void onInteractabilityChanged(Tab tab, boolean isInteractable);

    /**
     * Called when renderer changes its state about being responsive to requests.
     *
     * @param tab The notifying {@link Tab}.
     * @param {@code true} if the renderer becomes responsive, otherwise {@code false}.
     */
    void onRendererResponsiveStateChanged(Tab tab, boolean isResponsive);

    /**
     * Called when navigation entries of a tab have been appended while the tab is frozen.
     *
     * @param tab The notifying {@link Tab}.
     */
    void onNavigationEntriesAppended(Tab tab);

    /**
     * Called when navigation entries of a tab have been deleted.
     *
     * @param tab The notifying {@link Tab}.
     */
    void onNavigationEntriesDeleted(Tab tab);

    /**
     * Called when a find result is received.
     * @param result Detail information on the find result.
     */
    void onFindResultAvailable(FindNotificationDetails result);

    /**
     * Called when the rects corresponding to the find matches are received.
     * @param result Detail information on the matched rects.
     */
    void onFindMatchRectsAvailable(FindMatchRectsDetails result);

    /**
     * Called when offset values related with the browser controls have been changed by the
     * renderer.
     *
     * @param topControlsOffsetY The Y offset of the top controls in physical pixels.
     * @param bottomControlsOffsetY The Y offset of the bottom controls in physical pixels.
     * @param contentOffsetY The Y offset of the content in physical pixels.
     * @param topControlsMinHeightOffsetY The Y offset of the current top controls min-height.
     * @param bottomControlsMinHeightOffsetY The Y offset of the current bottom controls min-height.
     */
    void onBrowserControlsOffsetChanged(
            Tab tab,
            int topControlsOffsetY,
            int bottomControlsOffsetY,
            int contentOffsetY,
            int topControlsMinHeightOffsetY,
            int bottomControlsMinHeightOffsetY);

    /**
     * @see BrowserControlsStateProvider.onControlsConstraintsChanged
     */
    void onBrowserControlsConstraintsChanged(
            Tab tab,
            BrowserControlsOffsetTagsInfo oldOffsetTagsInfo,
            BrowserControlsOffsetTagsInfo offsetTagsInfo,
            @BrowserControlsState int constraints);

    /**
     * Called when the tab is about to notify its renderer to show the browser controls.
     *
     * @param tab The notifying {@link Tab}.
     * @param tab Whether the current page has opted in to same-origin view transitions.
     */
    void onWillShowBrowserControls(Tab tab, boolean viewTransitionOptIn);

    /**
     * Called when scrolling state of Tab's content view changes.
     *
     * @param scrolling {@code true} if scrolling started; {@code false} if stopped.
     */
    void onContentViewScrollingStateChanged(boolean scrolling);

    /** Called when the gesture begin event is received. */
    void onGestureBegin();

    /** Called when the gesture end event is received. */
    void onGestureEnd();

    /** Back press refactor related. Called when navigation state is invalidated. */
    void onNavigationStateChanged();

    /**
     * CloseWatcher web API support. If the currently focused frame has a CloseWatcher registered in
     * JavaScript, the CloseWatcher should receive the next "close" operation, based on what the OS
     * convention for closing is. This function is called when the focused frame changes or a
     * CloseWatcher registered/unregistered to update whether the CloseWatcher should intercept.
     */
    void onDidChangeCloseSignalInterceptStatus();

    /**
     * Broadcast that the timestamp on a {@link Tab} has changed
     *
     * @param tab {@link Tab} timestamp has changed on
     * @param timestampMillis new value of the timestamp
     */
    default void onTimestampChanged(Tab tab, long timestampMillis) {}

    // TODO(crbug.com/41497290): deprecate RootId once TabGroupId has finished replacing it.
    /**
     * Broadcast that root identifier on a {@link Tab} has changed. This method will be functionally
     * replaced by onTabGroupIdChanged as part of https://crbug.com/1523745.
     *
     * @param tab {@link Tab} root identifier has changed on
     * @param newRootId new value of new root id
     */
    default void onRootIdChanged(Tab tab, int newRootId) {}

    /**
     * Broadcast that tab group ID on a {@link Tab} has changed.
     *
     * @param tab The {@link Tab} root identifier has changed on
     * @param tabGroupId The new tab group ID, may be null.
     */
    default void onTabGroupIdChanged(Tab tab, @Nullable Token tabGroupId) {}

    /**
     * Called when the animation state for the back forward session history navigation has changed.
     * Retrieve the current animation state using the Tab's WebContents.
     */
    default void didBackForwardTransitionAnimationChange() {}
}