1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
|
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_VIEWS_ANIMATION_ANIMATION_BUILDER_H_
#define UI_VIEWS_ANIMATION_ANIMATION_BUILDER_H_
#include <map>
#include <memory>
#include <optional>
#include <vector>
#include "base/functional/callback.h"
#include "base/location.h"
#include "base/memory/raw_ptr.h"
#include "base/time/time.h"
#include "base/types/pass_key.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/compositor/layer_animation_sequence.h"
#include "ui/compositor/layer_animator.h"
#include "ui/views/animation/animation_key.h"
#include "ui/views/animation/animation_sequence_block.h"
#include "ui/views/views_export.h"
namespace ui {
class Layer;
}
namespace views {
class AnimationAbortHandle;
// Provides an unfinalized animation sequence block if any to build animations.
// Usage notes for callbacks set on AnimationBuilder:
// When setting callbacks for the animations note that the AnimationBuilder’s
// observer that calls these callbacks may outlive the callback's parameters.
// The OnEnded callback runs when all animations created on the AnimationBuilder
// have finished. The OnAborted callback runs when any one animation created on
// the AnimationBuilder has been aborted. Therefore, these callbacks and every
// object the callback accesses needs to outlive all the Layers/LayerOwners
// being animated on since the Layers ultimately own the objects that run the
// animation. Otherwise, developers may need to use weak pointers or force
// animations to be cancelled in the object’s destructor to prevent accessing
// destroyed objects. Note that aborted notifications can be sent during the
// destruction process. Therefore subclasses that own the Layers may actually be
// destroyed before the OnAborted callback is run.
class VIEWS_EXPORT AnimationBuilder {
public:
class Observer : public ui::LayerAnimationObserver {
public:
Observer();
Observer(const Observer&) = delete;
Observer& operator=(const Observer&) = delete;
~Observer() override;
void SetOnStarted(base::OnceClosure callback);
void SetOnEnded(base::OnceClosure callback, base::Location location);
void SetOnWillRepeat(base::RepeatingClosure callback);
void SetOnAborted(base::OnceClosure callback, base::Location location);
void SetOnScheduled(base::OnceClosure callback);
void SetAbortHandle(AnimationAbortHandle* abort_handle);
// ui::LayerAnimationObserver:
void OnLayerAnimationStarted(ui::LayerAnimationSequence* sequence) override;
void OnLayerAnimationEnded(ui::LayerAnimationSequence* sequence) override;
void OnLayerAnimationWillRepeat(
ui::LayerAnimationSequence* sequence) override;
void OnLayerAnimationAborted(ui::LayerAnimationSequence* sequence) override;
void OnLayerAnimationScheduled(
ui::LayerAnimationSequence* sequence) override;
bool GetAttachedToSequence() const { return attached_to_sequence_; }
protected:
void OnAttachedToSequence(ui::LayerAnimationSequence* sequence) override;
void OnDetachedFromSequence(ui::LayerAnimationSequence* sequence) override;
bool RequiresNotificationWhenAnimatorDestroyed() const override;
private:
using RepeatMap = base::flat_map<ui::LayerAnimationSequence*, int>;
RepeatMap repeat_map_;
base::OnceClosure on_started_;
base::OnceClosure on_ended_;
// Record where the on_ended_ callback was set from. Needed to debug a
// bad callback crash (https://g-issues.chromium.org/issues/335902543).
// TODO(b/335902543): Remove on_ended_location_.
base::Location on_ended_location_;
base::RepeatingClosure on_will_repeat_;
base::OnceClosure on_aborted_;
// Record where the on_aborted_ callback was set from. Needed to debug a
// bad callback crash (https://g-issues.chromium.org/issues/335902543).
// TODO(b/335902543): Remove on_aborted_location_.
base::Location on_aborted_location_;
base::OnceClosure on_scheduled_;
bool attached_to_sequence_ = false;
// Incremented when a sequence is attached and decremented when a sequence
// ends. Does not account for aborted sequences. This provides a more
// reliable way of tracking when all sequences have ended since IsFinished
// can return true before a sequence is started if the duration is zero.
int sequences_to_run_ = 0;
raw_ptr<AnimationAbortHandle, DanglingUntriaged> abort_handle_ = nullptr;
};
AnimationBuilder();
AnimationBuilder(AnimationBuilder&& rhs);
AnimationBuilder& operator=(AnimationBuilder&& rhs);
~AnimationBuilder();
// Options for the whole animation
AnimationBuilder& SetPreemptionStrategy(
ui::LayerAnimator::PreemptionStrategy preemption_strategy);
// Registers |callback| to be called when the animation starts.
// Must use before creating a sequence block.
AnimationBuilder& OnStarted(base::OnceClosure callback);
// Registers |callback| to be called when the animation ends. Not called if
// animation is aborted.
// Must use before creating a sequence block.
AnimationBuilder& OnEnded(base::OnceClosure callback,
base::Location location = FROM_HERE);
// Registers |callback| to be called when a sequence repetition ends and will
// repeat. Not called if sequence is aborted.
// Must use before creating a sequence block.
AnimationBuilder& OnWillRepeat(base::RepeatingClosure callback);
// Registers |callback| to be called if animation is aborted for any reason.
// Should never do anything that may cause another animation to be started.
// Must use before creating a sequence block.
AnimationBuilder& OnAborted(base::OnceClosure callback,
base::Location location = FROM_HERE);
// Registers |callback| to be called when the animation is scheduled.
// Must use before creating a sequence block.
AnimationBuilder& OnScheduled(base::OnceClosure callback);
// Returns a handle that can be destroyed later to abort all running
// animations. Must use before creating a sequence block.
// Caveat: ALL properties will be aborted, including those not initiated
// by the builder.
std::unique_ptr<AnimationAbortHandle> GetAbortHandle();
// Creates a new sequence (that optionally repeats).
AnimationSequenceBlock& Once();
AnimationSequenceBlock& Repeatedly();
// Adds an animation element `element` for `key` at `start` to `values`.
void AddLayerAnimationElement(
base::PassKey<AnimationSequenceBlock>,
AnimationKey key,
base::TimeDelta start,
base::TimeDelta original_duration,
std::unique_ptr<ui::LayerAnimationElement> element);
// Swaps `current_sequence_` with `new_sequence` and returns the old one.
[[nodiscard]] std::unique_ptr<AnimationSequenceBlock> SwapCurrentSequence(
base::PassKey<AnimationSequenceBlock>,
std::unique_ptr<AnimationSequenceBlock> new_sequence);
// Called when a block ends. Ensures all animations in the sequence will run
// until at least `end`.
void BlockEndedAt(base::PassKey<AnimationSequenceBlock>, base::TimeDelta end);
// Called when the sequence is ended. Converts `values_` to
// `layer_animation_sequences_`.
void TerminateSequence(base::PassKey<AnimationSequenceBlock>, bool repeating);
// Returns a left value reference to the object held by `current_sequence_`.
// Assumes that `current_sequence_` is set.
// NOTE: be wary when keeping this method's return value because the current
// sequence held by an `AnimationBuilder` instance could be destroyed during
// `AnimationBuilder` instance's life cycle.
AnimationSequenceBlock& GetCurrentSequence();
static void SetObserverDeletedCallbackForTesting(
base::RepeatingClosure deleted_closure);
private:
struct Value;
Observer* GetObserver();
// Resets data for the current sequence as necessary, creates a new sequence
// block and returns the new block's left value reference.
AnimationSequenceBlock& NewSequence(bool repeating);
// Returns a reference to the observer deleted callback used for testing.
static base::RepeatingClosure& GetObserverDeletedCallback();
// Data for all sequences.
std::multimap<ui::Layer*, std::unique_ptr<ui::LayerAnimationSequence>>
layer_animation_sequences_;
std::unique_ptr<Observer> animation_observer_;
// Sets up observer callbacks before .Once() or .Repeatedly() is called to
// start the sequence. next_animation_observer_ is moved to
// animation_observer_ once .Once() or Repeatedly() is called.
std::unique_ptr<Observer> next_animation_observer_;
std::optional<ui::LayerAnimator::PreemptionStrategy> preemption_strategy_;
// Data for the current sequence.
base::TimeDelta end_;
// Each vector is kept in sorted order.
std::map<AnimationKey, std::vector<Value>> values_;
raw_ptr<AnimationAbortHandle, DanglingUntriaged> abort_handle_ = nullptr;
// An unfinalized sequence block currently used to build animations. NOTE: the
// animation effects carried by `current_sequence_` attach to a layer only
// after `current_sequence_` is destroyed.
// The life cycle of `current_sequence_`:
// (1) The old sequence is replaced by a new one. When being replaced, the
// old sequence is destroyed.
// (2) Gets destroyed when the host `AnimationBuilder` is destroyed.
std::unique_ptr<AnimationSequenceBlock> current_sequence_;
};
} // namespace views
#endif // UI_VIEWS_ANIMATION_ANIMATION_BUILDER_H_
|