C++ LayoutAnimations: solve crash when "animating" virtual views

Summary:
Index adjustment doesn't work if virtual views are inserted, because those don't actually result in the view hierarchy being mutated, as such.

Add an Android-specific check to solve the crash.

I don't love adding platform-specific checks here, so I'm considering wrapping this logic in a platform-specific class, so that logic lives outside of the core of LayoutAnimations and entirely in platform code.

Changelog: [Internal]

Reviewed By: mdvacca

Differential Revision: D21727805

fbshipit-source-id: 5af2cf479beaa4d0e9d94ea16ac989c4268920f8
This commit is contained in:
Joshua Gross 2020-05-26 16:09:28 -07:00 коммит произвёл Facebook GitHub Bot
Родитель 68c0eddb71
Коммит 8b2eb3766b
2 изменённых файлов: 24 добавлений и 1 удалений

Просмотреть файл

@ -311,6 +311,10 @@ void LayoutAnimationKeyFrameManager::adjustDelayedMutationIndicesForMutation(
bool isInsertMutation = mutation.type == ShadowViewMutation::Type::Insert; bool isInsertMutation = mutation.type == ShadowViewMutation::Type::Insert;
assert(isRemoveMutation || isInsertMutation); assert(isRemoveMutation || isInsertMutation);
if (mutatedViewIsVirtual(mutation)) {
return;
}
for (auto &inflightAnimation : inflightAnimations_) { for (auto &inflightAnimation : inflightAnimations_) {
if (inflightAnimation.surfaceId != surfaceId) { if (inflightAnimation.surfaceId != surfaceId) {
continue; continue;
@ -691,7 +695,8 @@ LayoutAnimationKeyFrameManager::pullTransaction(
for (const auto &otherMutation : mutations) { for (const auto &otherMutation : mutations) {
if (otherMutation.type == ShadowViewMutation::Type::Insert && if (otherMutation.type == ShadowViewMutation::Type::Insert &&
otherMutation.parentShadowView.tag == parentTag) { otherMutation.parentShadowView.tag == parentTag) {
if (otherMutation.index <= adjustedIndex) { if (otherMutation.index <= adjustedIndex &&
!mutatedViewIsVirtual(otherMutation)) {
adjustedIndex++; adjustedIndex++;
} }
} }
@ -861,6 +866,22 @@ LayoutAnimationKeyFrameManager::pullTransaction(
surfaceId, transactionNumber, std::move(mutations), {}}; surfaceId, transactionNumber, std::move(mutations), {}};
} }
bool LayoutAnimationKeyFrameManager::mutatedViewIsVirtual(
ShadowViewMutation const &mutation) const {
bool viewIsVirtual = false;
// TODO: extract this into an Android platform-specific class
// Explanation: for "Insert" mutations, oldChildShadowView is always empty.
// for "Remove" mutations, newChildShadowView is always empty.
#ifdef ANDROID
viewIsVirtual =
mutation.newChildShadowView.layoutMetrics == EmptyLayoutMetrics &&
mutation.oldChildShadowView.layoutMetrics == EmptyLayoutMetrics;
#endif
return viewIsVirtual;
}
ComponentDescriptor const & ComponentDescriptor const &
LayoutAnimationKeyFrameManager::getComponentDescriptorForShadowView( LayoutAnimationKeyFrameManager::getComponentDescriptorForShadowView(
ShadowView const &shadowView) const { ShadowView const &shadowView) const {

Просмотреть файл

@ -144,6 +144,8 @@ class LayoutAnimationKeyFrameManager : public UIManagerAnimationDelegate,
ShadowViewMutation const &mutation) const; ShadowViewMutation const &mutation) const;
protected: protected:
bool mutatedViewIsVirtual(ShadowViewMutation const &mutation) const;
ComponentDescriptor const &getComponentDescriptorForShadowView( ComponentDescriptor const &getComponentDescriptorForShadowView(
ShadowView const &shadowView) const; ShadowView const &shadowView) const;
std::pair<double, double> calculateAnimationProgress( std::pair<double, double> calculateAnimationProgress(