| // Copyright 2016 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ash/common/shelf/shelf_background_animator.h" |
| |
| #include <algorithm> |
| |
| #include "ash/common/material_design/material_design_controller.h" |
| #include "ash/common/shelf/shelf_background_animator_observer.h" |
| #include "ash/common/shelf/shelf_constants.h" |
| #include "ash/common/shelf/wm_shelf.h" |
| |
| namespace ash { |
| |
| namespace { |
| // The total number of animators that will call BackgroundAnimationEnded(). |
| const int kNumAnimators = 3; |
| |
| const int kMaxAlpha = 255; |
| } // namespace |
| |
| ShelfBackgroundAnimator::ShelfBackgroundAnimator( |
| ShelfBackgroundType background_type, |
| WmShelf* wm_shelf) |
| : wm_shelf_(wm_shelf) { |
| if (wm_shelf_) |
| wm_shelf_->AddObserver(this); |
| // Initialize animators so that adding observers get notified with consistent |
| // values. |
| AnimateBackground(background_type, BACKGROUND_CHANGE_IMMEDIATE); |
| } |
| |
| ShelfBackgroundAnimator::~ShelfBackgroundAnimator() { |
| if (wm_shelf_) |
| wm_shelf_->RemoveObserver(this); |
| } |
| |
| void ShelfBackgroundAnimator::AddObserver( |
| ShelfBackgroundAnimatorObserver* observer) { |
| observers_.AddObserver(observer); |
| Initialize(observer); |
| } |
| |
| void ShelfBackgroundAnimator::RemoveObserver( |
| ShelfBackgroundAnimatorObserver* observer) { |
| observers_.RemoveObserver(observer); |
| } |
| |
| void ShelfBackgroundAnimator::Initialize( |
| ShelfBackgroundAnimatorObserver* observer) const { |
| observer->UpdateShelfOpaqueBackground(opaque_background_animator_->alpha()); |
| observer->UpdateShelfAssetBackground(asset_background_animator_->alpha()); |
| observer->UpdateShelfItemBackground(item_background_animator_->alpha()); |
| } |
| |
| void ShelfBackgroundAnimator::PaintBackground( |
| ShelfBackgroundType background_type, |
| BackgroundAnimatorChangeType change_type) { |
| if (target_background_type_ == background_type && |
| change_type == BACKGROUND_CHANGE_ANIMATE) { |
| return; |
| } |
| |
| AnimateBackground(background_type, change_type); |
| } |
| |
| void ShelfBackgroundAnimator::OnBackgroundTypeChanged( |
| ShelfBackgroundType background_type, |
| BackgroundAnimatorChangeType change_type) { |
| PaintBackground(background_type, change_type); |
| } |
| |
| void ShelfBackgroundAnimator::UpdateBackground(BackgroundAnimator* animator, |
| int alpha) { |
| OnAlphaChanged(animator, alpha); |
| } |
| |
| void ShelfBackgroundAnimator::BackgroundAnimationEnded( |
| BackgroundAnimator* animator) { |
| ++successful_animator_count_; |
| DCHECK_LE(successful_animator_count_, kNumAnimators); |
| // UpdateBackground() is only called when alpha values change, this ensures |
| // observers are always notified for every background change. |
| OnAlphaChanged(animator, animator->alpha()); |
| } |
| |
| void ShelfBackgroundAnimator::OnAlphaChanged(BackgroundAnimator* animator, |
| int alpha) { |
| if (animator == opaque_background_animator_.get()) { |
| for (auto& observer : observers_) |
| observer.UpdateShelfOpaqueBackground(alpha); |
| } else if (animator == asset_background_animator_.get()) { |
| for (auto& observer : observers_) |
| observer.UpdateShelfAssetBackground(alpha); |
| } else if (animator == item_background_animator_.get()) { |
| for (auto& observer : observers_) |
| observer.UpdateShelfItemBackground(alpha); |
| } else { |
| NOTREACHED(); |
| } |
| } |
| |
| void ShelfBackgroundAnimator::AnimateBackground( |
| ShelfBackgroundType background_type, |
| BackgroundAnimatorChangeType change_type) { |
| // Ensure BackgroundAnimationEnded() has been called for all the |
| // BackgroundAnimators owned by this so that |successful_animator_count_| |
| // is stable and doesn't get updated as a side effect of destroying/animating |
| // the animators. |
| StopAnimators(); |
| |
| bool show_background = true; |
| if (can_reuse_animators_ && previous_background_type_ == background_type) { |
| DCHECK_EQ(opaque_background_animator_->paints_background(), |
| asset_background_animator_->paints_background()); |
| DCHECK_EQ(asset_background_animator_->paints_background(), |
| item_background_animator_->paints_background()); |
| |
| show_background = !opaque_background_animator_->paints_background(); |
| } else { |
| CreateAnimators(background_type, change_type); |
| |
| // If all the previous animators completed successfully and the animation |
| // was between 2 distinct states, then the last alpha values are valid |
| // end state values. |
| can_reuse_animators_ = target_background_type_ != background_type && |
| successful_animator_count_ == kNumAnimators; |
| } |
| |
| successful_animator_count_ = 0; |
| |
| opaque_background_animator_->SetPaintsBackground(show_background, |
| change_type); |
| asset_background_animator_->SetPaintsBackground(show_background, change_type); |
| item_background_animator_->SetPaintsBackground(show_background, change_type); |
| |
| if (target_background_type_ != background_type) { |
| previous_background_type_ = target_background_type_; |
| target_background_type_ = background_type; |
| } |
| } |
| |
| void ShelfBackgroundAnimator::CreateAnimators( |
| ShelfBackgroundType background_type, |
| BackgroundAnimatorChangeType change_type) { |
| const int opaque_background_alpha = |
| opaque_background_animator_ ? opaque_background_animator_->alpha() : 0; |
| const int asset_background_alpha = |
| asset_background_animator_ ? asset_background_animator_->alpha() : 0; |
| const int item_background_alpha = |
| item_background_animator_ ? item_background_animator_->alpha() : 0; |
| |
| const bool is_material = MaterialDesignController::IsShelfMaterial(); |
| int duration_ms = 0; |
| |
| switch (background_type) { |
| case SHELF_BACKGROUND_DEFAULT: |
| duration_ms = is_material ? 500 : 1000; |
| opaque_background_animator_.reset( |
| new BackgroundAnimator(this, opaque_background_alpha, 0)); |
| asset_background_animator_.reset( |
| new BackgroundAnimator(this, asset_background_alpha, 0)); |
| item_background_animator_.reset( |
| new BackgroundAnimator(this, item_background_alpha, |
| GetShelfConstant(SHELF_BACKGROUND_ALPHA))); |
| break; |
| case SHELF_BACKGROUND_OVERLAP: |
| duration_ms = is_material ? 500 : 1000; |
| opaque_background_animator_.reset(new BackgroundAnimator( |
| this, opaque_background_alpha, |
| is_material ? GetShelfConstant(SHELF_BACKGROUND_ALPHA) : 0)); |
| asset_background_animator_.reset(new BackgroundAnimator( |
| this, asset_background_alpha, |
| is_material ? 0 : GetShelfConstant(SHELF_BACKGROUND_ALPHA))); |
| item_background_animator_.reset(new BackgroundAnimator( |
| this, item_background_alpha, |
| is_material ? 0 : GetShelfConstant(SHELF_BACKGROUND_ALPHA))); |
| break; |
| case SHELF_BACKGROUND_MAXIMIZED: |
| duration_ms = is_material ? 250 : 1000; |
| opaque_background_animator_.reset( |
| new BackgroundAnimator(this, opaque_background_alpha, kMaxAlpha)); |
| asset_background_animator_.reset(new BackgroundAnimator( |
| this, asset_background_alpha, |
| is_material ? 0 : GetShelfConstant(SHELF_BACKGROUND_ALPHA))); |
| item_background_animator_.reset(new BackgroundAnimator( |
| this, item_background_alpha, is_material ? 0 : kMaxAlpha)); |
| break; |
| } |
| |
| opaque_background_animator_->SetDuration(duration_ms); |
| asset_background_animator_->SetDuration(duration_ms); |
| item_background_animator_->SetDuration(duration_ms); |
| } |
| |
| void ShelfBackgroundAnimator::StopAnimators() { |
| if (opaque_background_animator_) |
| opaque_background_animator_->Stop(); |
| if (asset_background_animator_) |
| asset_background_animator_->Stop(); |
| if (item_background_animator_) |
| item_background_animator_->Stop(); |
| } |
| |
| } // namespace ash |