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
ash / assistant / ui / main_stage / animated_container_view.h [blame]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_ASSISTANT_UI_MAIN_STAGE_ANIMATED_CONTAINER_VIEW_H_
#define ASH_ASSISTANT_UI_MAIN_STAGE_ANIMATED_CONTAINER_VIEW_H_
#include <memory>
#include <vector>
#include "ash/assistant/model/assistant_interaction_model_observer.h"
#include "ash/assistant/model/assistant_response_observer.h"
#include "ash/assistant/ui/base/assistant_scroll_view.h"
#include "ash/public/cpp/assistant/controller/assistant_controller.h"
#include "ash/public/cpp/assistant/controller/assistant_controller_observer.h"
#include "base/memory/raw_ptr.h"
#include "base/scoped_observation.h"
#include "chromeos/ash/services/libassistant/public/cpp/assistant_suggestion.h"
#include "ui/base/metadata/metadata_header_macros.h"
namespace ui {
class CallbackLayerAnimationObserver;
} // namespace ui
namespace ash {
class AssistantResponse;
class AssistantUiElement;
class AssistantViewDelegate;
class ElementAnimator;
// A view that will observe the AssistantResponse and which will use
// ElementAnimator to animate each child view.
//
// To use this you should implement HandleUiElement() and/or HandleSuggestion()
// to:
// - Add new child views as appropriate.
// - Return animators for any newly created views.
//
// More in detail, this is what will happen:
// 1) When AssistantInteractionModelObserver::OnCommittedQueryChanged() is
// observed, FadeOut() is called on all ElementAnimator instances.
// Furthermore all views will stop processing events (like click).
// 2) When AssistantInteractionModelObserver::OnResponseChanged() is
// observed, we wait until the FadeOut() animations are complete.
// 3) Next AnimateOut() is invoked on all ElementAnimator instances.
// 4) When these animations are complete, all child views are removed.
// 5) OnAllViewsRemoved() is invoked to inform the derived class all child
// views are removed.
// 6) Next HandleSuggestion() and HandleUiElement() is called for the new
// AssistantResponse. In those methods, the derived class should add the
// child views for the new response, as well as return ElementAnimator
// instances.
// 7) When all new child views have been added, AnimateIn() is invoked on
// all ElementAnimator instances.
// 8) Finally when this animation is complete the derived class is informed
// through OnAllViewsAnimatedIn().
class COMPONENT_EXPORT(ASSISTANT_UI) AnimatedContainerView
: public AssistantScrollView,
public AssistantScrollView::Observer,
public AssistantControllerObserver,
public AssistantInteractionModelObserver,
public AssistantResponseObserver {
METADATA_HEADER(AnimatedContainerView, AssistantScrollView)
public:
using AssistantSuggestion = assistant::AssistantSuggestion;
explicit AnimatedContainerView(AssistantViewDelegate* delegate);
AnimatedContainerView(const AnimatedContainerView&) = delete;
AnimatedContainerView& operator=(const AnimatedContainerView&) = delete;
~AnimatedContainerView() override;
// AssistantScrollView:
void PreferredSizeChanged() override;
void OnChildViewRemoved(View* observed_view, View* child) override;
// AssistantControllerObserver:
void OnAssistantControllerDestroying() override;
// AssistantInteractionModelObserver:
void OnCommittedQueryChanged(const AssistantQuery& query) override;
void OnResponseChanged(const scoped_refptr<AssistantResponse>&) override;
void OnResponseCleared() override;
// AssistantResponseObserver:
void OnUiElementAdded(const AssistantUiElement* ui_element) override;
void OnSuggestionsAdded(
const std::vector<AssistantSuggestion>& suggestions) override;
// Remove all current responses/views.
// This will abort all in progress animations, and remove all the child views
// and their animators.
void RemoveAllViews();
protected:
// Callback called when all (new) views have been added.
// This is called when the animate-in animations are done.
virtual void OnAllViewsAnimatedIn() {}
// Callback called when all (old) views have been removed.
// This is called when the exit animations are done.
virtual void OnAllViewsRemoved() {}
// Callback called to create a view for a UI element.
// The implementer should:
// - Create and add the appropriate views::View.
// - Return an ElementAnimator to animate the view. Note that it is
// permissible to return |nullptr| if no managed animation is desired.
virtual std::unique_ptr<ElementAnimator> HandleUiElement(
const AssistantUiElement* ui_element);
// Callback called to create a view for a suggestion.
// The implementer should:
// - Create and add the appropriate views::View.
// - Return an ElementAnimator to animate the view. Note that it is
// permissible to return |nullptr| if no managed animation is desired.
virtual std::unique_ptr<ElementAnimator> HandleSuggestion(
const AssistantSuggestion& suggestion);
AssistantViewDelegate* delegate() { return delegate_; }
private:
class ScopedDisablePreferredSizeChanged;
void SetPropagatePreferredSizeChanged(bool propagate);
void ChangeResponse(const scoped_refptr<const AssistantResponse>& response);
void AddResponse(scoped_refptr<const AssistantResponse> response);
bool IsAnimatingViews() const;
void AddElementAnimatorAndAnimateInView(std::unique_ptr<ElementAnimator>);
void FadeOutViews();
void EnableInteractions() { SetInteractionsEnabled(true); }
void DisableInteractions() { SetInteractionsEnabled(false); }
void SetInteractionsEnabled(bool enabled);
static bool AnimateInObserverCallback(
const base::WeakPtr<AnimatedContainerView>& weak_ptr,
const ui::CallbackLayerAnimationObserver& observer);
static bool AnimateOutObserverCallback(
const base::WeakPtr<AnimatedContainerView>& weak_ptr,
const ui::CallbackLayerAnimationObserver& observer);
static bool FadeOutObserverCallback(
const base::WeakPtr<AnimatedContainerView>& weak_ptr,
const ui::CallbackLayerAnimationObserver& observer);
const raw_ptr<AssistantViewDelegate>
delegate_; // Owned by AssistantController.
// The animators used to trigger the animations of the individual views.
std::vector<std::unique_ptr<ElementAnimator>> animators_;
// Whether we should allow propagation of PreferredSizeChanged events.
// Because we only animate views in/out in batches, we can prevent
// over-propagation of PreferredSizeChanged events by waiting until the
// entirety of a response has been added/removed before propagating. This
// reduces layout passes.
bool propagate_preferred_size_changed_ = true;
// Whether the animate-out animation is in progress.
bool animate_out_in_progress_ = false;
// Whether the fade-out animation is in progress.
bool fade_out_in_progress_ = false;
// Shared pointers to the response that is currently on stage as well as the
// queued response to be presented following the former's animated exit. We
// use shared pointers to ensure that underlying views are not destroyed
// before we have an opportunity to remove their associated views.
scoped_refptr<const AssistantResponse> response_;
scoped_refptr<const AssistantResponse> queued_response_;
base::ScopedObservation<AssistantController, AssistantControllerObserver>
assistant_controller_observation_{this};
base::WeakPtrFactory<AnimatedContainerView> weak_factory_{this};
};
} // namespace ash
#endif // ASH_ASSISTANT_UI_MAIN_STAGE_ANIMATED_CONTAINER_VIEW_H_