photo_view.cc 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. // Copyright 2019 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ash/ambient/ui/photo_view.h"
  5. #include <algorithm>
  6. #include <iterator>
  7. #include <memory>
  8. #include "ash/ambient/ambient_constants.h"
  9. #include "ash/ambient/ambient_view_delegate_impl.h"
  10. #include "ash/ambient/model/ambient_backend_model.h"
  11. #include "ash/ambient/ui/ambient_background_image_view.h"
  12. #include "ash/ambient/ui/ambient_view_ids.h"
  13. #include "ash/public/cpp/ambient/ambient_ui_model.h"
  14. #include "ash/public/cpp/metrics_util.h"
  15. #include "base/bind.h"
  16. #include "base/metrics/histogram_functions.h"
  17. #include "base/strings/utf_string_conversions.h"
  18. #include "ui/aura/window.h"
  19. #include "ui/base/metadata/metadata_impl_macros.h"
  20. #include "ui/compositor/animation_throughput_reporter.h"
  21. #include "ui/compositor/layer.h"
  22. #include "ui/compositor/scoped_layer_animation_settings.h"
  23. #include "ui/views/controls/image_view.h"
  24. #include "ui/views/layout/fill_layout.h"
  25. namespace ash {
  26. namespace {
  27. constexpr char kPhotoTransitionSmoothness[] =
  28. "Ash.AmbientMode.AnimationSmoothness.PhotoTransition";
  29. void ReportSmoothness(int value) {
  30. base::UmaHistogramPercentage(kPhotoTransitionSmoothness, value);
  31. }
  32. constexpr JitterCalculator::Config kGlanceableInfoJitterConfig = {
  33. /*step_size=*/5,
  34. /*x_min_translation=*/0,
  35. /*x_max_translation=*/20,
  36. /*y_min_translation=*/-20,
  37. /*y_max_translation=*/0};
  38. } // namespace
  39. // PhotoView ------------------------------------------------------------------
  40. PhotoView::PhotoView(AmbientViewDelegateImpl* delegate)
  41. : delegate_(delegate),
  42. glanceable_info_jitter_calculator_(kGlanceableInfoJitterConfig) {
  43. DCHECK(delegate_);
  44. SetID(AmbientViewID::kAmbientPhotoView);
  45. Init();
  46. }
  47. PhotoView::~PhotoView() = default;
  48. void PhotoView::OnImageAdded() {
  49. // If NeedToAnimate() is true, will start transition animation and
  50. // UpdateImages() when animation completes. Otherwise, update images
  51. // immediately.
  52. if (NeedToAnimateTransition()) {
  53. StartTransitionAnimation();
  54. return;
  55. }
  56. PhotoWithDetails next_image;
  57. delegate_->GetAmbientBackendModel()->GetCurrentAndNextImages(
  58. /*current_image=*/nullptr, &next_image);
  59. UpdateImage(next_image);
  60. }
  61. void PhotoView::Init() {
  62. SetPaintToLayer();
  63. layer()->SetFillsBoundsOpaquely(false);
  64. SetLayoutManager(std::make_unique<views::FillLayout>());
  65. for (auto*& image_view : image_views_) {
  66. // Creates image views. The same |glanceable_info_jitter_calculator_|
  67. // instance is shared between the AmbientBackgroundImageViews so that the
  68. // glanceable info on screen does not shift too much at once when
  69. // transitioning between AmbientBackgroundImageViews in
  70. // StartTransitionAnimation().
  71. image_view = AddChildView(std::make_unique<AmbientBackgroundImageView>(
  72. delegate_, &glanceable_info_jitter_calculator_));
  73. // Each image view will be animated on its own layer.
  74. image_view->SetPaintToLayer();
  75. image_view->layer()->SetFillsBoundsOpaquely(false);
  76. }
  77. // Hides one image view initially for fade in animation.
  78. image_views_.back()->layer()->SetOpacity(0.0f);
  79. auto* model = delegate_->GetAmbientBackendModel();
  80. scoped_backend_model_observer_.Observe(model);
  81. // |PhotoView::Init| is called after
  82. // |AmbientBackendModelObserver::OnImagesReady| has been called.
  83. // |AmbientBackendModel| has two images ready and views should be constructed
  84. // for each one.
  85. PhotoWithDetails current_image, next_image;
  86. model->GetCurrentAndNextImages(&current_image, &next_image);
  87. UpdateImage(current_image);
  88. UpdateImage(next_image);
  89. delegate_->NotifyObserversMarkerHit(
  90. AmbientPhotoConfig::Marker::kUiStartRendering);
  91. }
  92. void PhotoView::UpdateImage(const PhotoWithDetails& next_image) {
  93. if (next_image.photo.isNull())
  94. return;
  95. image_views_.at(image_index_)
  96. ->UpdateImage(next_image.photo, next_image.related_photo,
  97. next_image.is_portrait, next_image.topic_type);
  98. image_views_.at(image_index_)
  99. ->UpdateImageDetails(base::UTF8ToUTF16(next_image.details),
  100. base::UTF8ToUTF16(next_image.related_details));
  101. image_index_ = 1 - image_index_;
  102. photo_refresh_timer_.Start(FROM_HERE,
  103. AmbientUiModel::Get()->photo_refresh_interval(),
  104. this, &PhotoView::OnImageCycleComplete);
  105. }
  106. void PhotoView::OnImageCycleComplete() {
  107. delegate_->NotifyObserversMarkerHit(
  108. AmbientPhotoConfig::Marker::kUiCycleEnded);
  109. }
  110. void PhotoView::StartTransitionAnimation() {
  111. ui::Layer* visible_layer = image_views_.at(image_index_)->layer();
  112. {
  113. ui::ScopedLayerAnimationSettings animation(visible_layer->GetAnimator());
  114. animation.SetTransitionDuration(kAnimationDuration);
  115. animation.SetTweenType(gfx::Tween::LINEAR);
  116. animation.SetPreemptionStrategy(
  117. ui::LayerAnimator::IMMEDIATELY_SET_NEW_TARGET);
  118. animation.CacheRenderSurface();
  119. ui::AnimationThroughputReporter reporter(
  120. animation.GetAnimator(),
  121. metrics_util::ForSmoothness(base::BindRepeating(ReportSmoothness)));
  122. visible_layer->SetOpacity(0.0f);
  123. }
  124. ui::Layer* invisible_layer = image_views_.at(1 - image_index_)->layer();
  125. {
  126. ui::ScopedLayerAnimationSettings animation(invisible_layer->GetAnimator());
  127. animation.SetTransitionDuration(kAnimationDuration);
  128. animation.SetTweenType(gfx::Tween::LINEAR);
  129. animation.SetPreemptionStrategy(
  130. ui::LayerAnimator::IMMEDIATELY_SET_NEW_TARGET);
  131. animation.CacheRenderSurface();
  132. // For simplicity, only observe one animation.
  133. animation.AddObserver(this);
  134. ui::AnimationThroughputReporter reporter(
  135. animation.GetAnimator(),
  136. metrics_util::ForSmoothness(base::BindRepeating(ReportSmoothness)));
  137. invisible_layer->SetOpacity(1.0f);
  138. }
  139. }
  140. void PhotoView::OnImplicitAnimationsCompleted() {
  141. PhotoWithDetails next_image;
  142. delegate_->GetAmbientBackendModel()->GetCurrentAndNextImages(
  143. /*current_image=*/nullptr, &next_image);
  144. UpdateImage(next_image);
  145. }
  146. bool PhotoView::NeedToAnimateTransition() const {
  147. // Can do transition animation if both two images in |images_unscaled_| are
  148. // not nullptr. Check the image index 1 is enough.
  149. return !image_views_.back()->GetCurrentImage().isNull();
  150. }
  151. gfx::ImageSkia PhotoView::GetVisibleImageForTesting() {
  152. return image_views_.at(image_index_)->GetCurrentImage();
  153. }
  154. BEGIN_METADATA(PhotoView, views::View)
  155. END_METADATA
  156. } // namespace ash