chromium/content/browser/navigation_transitions/back_forward_transition_animation_manager_android.h

// 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.

#ifndef CONTENT_BROWSER_NAVIGATION_TRANSITIONS_BACK_FORWARD_TRANSITION_ANIMATION_MANAGER_ANDROID_H_
#define CONTENT_BROWSER_NAVIGATION_TRANSITIONS_BACK_FORWARD_TRANSITION_ANIMATION_MANAGER_ANDROID_H_

#include <memory>

#include "base/memory/raw_ptr.h"
#include "content/browser/navigation_transitions/back_forward_transition_animator.h"
#include "content/public/browser/back_forward_transition_animation_manager.h"
#include "ui/android/window_android.h"

namespace ui {
class BackGestureEvent;
}

namespace content {

class NavigationControllerImpl;
class NavigationRequest;
class WebContentsViewAndroid;
class RenderFrameHostImpl;

// A wrapper class that forwards the gesture event APIs to the `animator_`. It
// limits the APIs explosed to the embedder. Owned by `WebContentsViewAndroid`.
//
// If for some reason the history navigation couldn't be animated, this class
// won't create an `animator_`, and will start the history navigation via the
// `NavigationController`.
// TODO(crbug.com/40260440): We should always animate a gesture history
// navigation.
class CONTENT_EXPORT BackForwardTransitionAnimationManagerAndroid
    : public BackForwardTransitionAnimationManager,
      public ui::ViewAndroidObserver,
      public ui::WindowAndroidObserver,
      public RenderWidgetHostObserver,
      public RenderFrameMetadataProvider::Observer,
      public WebContentsObserver {
 public:
  BackForwardTransitionAnimationManagerAndroid(
      WebContentsViewAndroid* web_contents_view_android,
      NavigationControllerImpl* navigation_controller);
  BackForwardTransitionAnimationManagerAndroid(
      const BackForwardTransitionAnimationManagerAndroid&) = delete;
  BackForwardTransitionAnimationManagerAndroid& operator=(
      const BackForwardTransitionAnimationManagerAndroid&) = delete;
  ~BackForwardTransitionAnimationManagerAndroid() override;

  // `NavigationTransitionAnimationManager`:
  void OnGestureStarted(const ui::BackGestureEvent& gesture,
                        ui::BackGestureEventSwipeEdge edge,
                        NavigationDirection navigation_direction) override;
  void OnGestureProgressed(const ui::BackGestureEvent& gesture) override;
  void OnGestureCancelled() override;
  void OnGestureInvoked() override;
  void OnContentForNavigationEntryShown() override;
  AnimationStage GetCurrentAnimationStage() override;
  void SetFavicon(const SkBitmap& favicon) override;

  // `ui::ViewAndroidObserver`:
  void OnAttachedToWindow() override {}
  void OnDetachedFromWindow() override;

  // `ui::WindowAndroidObserver`:
  void OnRootWindowVisibilityChanged(bool visible) override;
  void OnAttachCompositor() override {}
  void OnDetachCompositor() override;
  void OnAnimate(base::TimeTicks frame_begin_time) override;
  void OnActivityStopped() override {}
  void OnActivityStarted() override {}

  // `RenderWidgetHostObserver`:
  void RenderWidgetHostDestroyed(RenderWidgetHost* widget_host) override;

  // `RenderFrameMetadataProvider::Observer`:
  void OnRenderFrameMetadataChangedBeforeActivation(
      const cc::RenderFrameMetadata& metadata) override {}
  void OnRenderFrameMetadataChangedAfterActivation(
      base::TimeTicks activation_time) override;
  void OnRenderFrameSubmission() override {}
  void OnLocalSurfaceIdChanged(
      const cc::RenderFrameMetadata& metadata) override {}

  // `WebContentsObserver`:
  void DidStartNavigation(NavigationHandle* navigation_handle) override;
  void ReadyToCommitNavigation(NavigationHandle* navigation_handle) override;
  void DidFinishNavigation(NavigationHandle* navigation_handle) override;

  // This is called before the `old_host` is swapped out and before the
  // `new_host` is swapped in.
  //
  // Note:
  // 1. This API won't get called if the navigation does not commit
  //    (204/205/Download), or the navigation is cancelled (aborted by the user)
  //    or replaced (by another browser-initiated navigation). We use
  //    `DidFinishNavigation()` for those cases.
  // 2. `old_host` might be the same as `new_host`. This can only happen for
  //    navigating away from a crashed frame (early-swap), or for same-RFH
  //    navigations.
  //
  // TODO(crbug.com/41487964): This also won't work for the initial
  // navigation away from "about:blank". We might be able to treat this
  // navigation as a same-doc one.
  //
  // TODO(crbug.com/40615943): Check the status of RD when it is close to
  // launch. Without RD we need to make sure no frames from the old document is
  // associated with the updated LocalSurfaceId (https://crbug.com/1445976).
  void OnDidNavigatePrimaryMainFramePreCommit(
      NavigationRequest* navigation_request,
      RenderFrameHostImpl* old_host,
      RenderFrameHostImpl* new_host);

  // Notified when a unstarted navigation request is destroyed.
  void OnNavigationCancelledBeforeStart(NavigationHandle* navigation_handle);

  // `animator_` invokes this callback to notify the state changes of the
  // current animation.
  void OnAnimationStageChanged();

  // Called upon ignoring an input event.
  void MaybeRecordIgnoredInput(const blink::WebInputEvent& event);

  // Called from the animator when a stable screenshot is not dismissed. This
  // can happen to a very busy renderer when it couldn't submit a new frame
  // after the navigation.
  void OnPostNavigationFirstFrameTimeout();

  WebContentsViewAndroid* web_contents_view_android() const {
    return web_contents_view_android_;
  }

  NavigationControllerImpl* navigation_controller() const {
    return navigation_controller_;
  }

  void set_animator_factory_for_testing(
      std::unique_ptr<BackForwardTransitionAnimator::Factory> factory) {
    animator_factory_ = std::move(factory);
  }

 private:
  // The browser test needs to access the test-only `animator_`.
  friend class BackForwardTransitionAnimationManagerBrowserTest;

  SkBitmap MaybeCopyContentAreaAsBitmapSync();

  // If the animator state is terminal, this will synchronously destroy the
  // animator. Terminal states are when all the animation has finished in the
  // browser UI or when an unexpected navigation occurs during the animation.
  void MaybeDestroyAnimator();

  // Destroys the animator. Must only be called when there is a valid animator.
  void DestroyAnimator();

  // The owning `WebContentsViewAndroid`. Guaranteed to outlive `this`.
  const raw_ptr<WebContentsViewAndroid> web_contents_view_android_;

  // The navigation controller of the primary `FrameTree` of this `WebContents`.
  // Its life time is bound to this `WebContents`, thus guaranteed to outlive
  // this manager.
  const raw_ptr<NavigationControllerImpl> navigation_controller_;

  // The index of the destination entry in the history list. Set when the
  // embedder notifies the animation manager upon a gesture's start. This is
  // used to ensure the navigation is initiated at gesture end, even if the
  // animation had to be terminated sooner.
  //
  // Use an index instead of an offset, in case during the animated transition
  // the session history is updated (e.g., history.pushState()) and we don't
  // want to lead the user to the wrong entry.
  int destination_entry_index_ = -1;

  // The actual implementation of the animation manager that manages the history
  // navigation animation. One instance per gesture.
  //
  // Only instantiated if the user gesture will trigger an animated session
  // history preview. Created when the eligible `OnGestureStarted()` arrives,
  // and destroyed when `DestroyAnimator()` is called (either when
  // the animations finished or animations have to aborted).
  //
  // `animator_` is only instantiated via `animator_factory_`. Tests can
  // override the `animator_factory_` via `set_animator_factory_for_testing()`.
  std::unique_ptr<BackForwardTransitionAnimator> animator_;
  std::unique_ptr<BackForwardTransitionAnimator::Factory> animator_factory_;
};

}  // namespace content

#endif  // CONTENT_BROWSER_NAVIGATION_TRANSITIONS_BACK_FORWARD_TRANSITION_ANIMATION_MANAGER_ANDROID_H_