hotseat_widget.cc 49 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295
  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/shelf/hotseat_widget.h"
  5. #include <memory>
  6. #include <utility>
  7. #include "ash/constants/ash_features.h"
  8. #include "ash/focus_cycler.h"
  9. #include "ash/keyboard/ui/keyboard_ui_controller.h"
  10. #include "ash/public/cpp/shelf_config.h"
  11. #include "ash/public/cpp/shelf_model.h"
  12. #include "ash/public/cpp/shelf_types.h"
  13. #include "ash/public/cpp/wallpaper/wallpaper_controller_observer.h"
  14. #include "ash/shelf/hotseat_transition_animator.h"
  15. #include "ash/shelf/scrollable_shelf_view.h"
  16. #include "ash/shelf/shelf_app_button.h"
  17. #include "ash/shelf/shelf_layout_manager.h"
  18. #include "ash/shelf/shelf_navigation_widget.h"
  19. #include "ash/shelf/shelf_view.h"
  20. #include "ash/shell.h"
  21. #include "ash/style/system_shadow.h"
  22. #include "ash/system/status_area_widget.h"
  23. #include "ash/wallpaper/wallpaper_controller_impl.h"
  24. #include "ash/wm/overview/overview_controller.h"
  25. #include "ash/wm/overview/overview_observer.h"
  26. #include "ash/wm/tablet_mode/tablet_mode_controller.h"
  27. #include "base/i18n/rtl.h"
  28. #include "base/metrics/histogram_macros.h"
  29. #include "ui/aura/scoped_window_targeter.h"
  30. #include "ui/aura/window_targeter.h"
  31. #include "ui/compositor/animation_throughput_reporter.h"
  32. #include "ui/compositor/layer_animation_sequence.h"
  33. #include "ui/compositor/scoped_layer_animation_settings.h"
  34. #include "ui/gfx/color_analysis.h"
  35. #include "ui/gfx/color_palette.h"
  36. #include "ui/gfx/color_utils.h"
  37. #include "ui/gfx/geometry/rounded_corners_f.h"
  38. #include "ui/views/background.h"
  39. #include "ui/views/highlight_border.h"
  40. #include "ui/views/layout/fill_layout.h"
  41. #include "ui/views/view_targeter_delegate.h"
  42. #include "ui/views/widget/widget_delegate.h"
  43. namespace ash {
  44. namespace {
  45. void DoScopedAnimationSetting(
  46. ui::ScopedLayerAnimationSettings* animation_setter) {
  47. animation_setter->SetTransitionDuration(
  48. ShelfConfig::Get()->shelf_animation_duration());
  49. animation_setter->SetTweenType(gfx::Tween::EASE_OUT);
  50. animation_setter->SetPreemptionStrategy(
  51. ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
  52. }
  53. // Returns whether there is special hotseat animation for |transition|.
  54. bool HasSpecialAnimation(HotseatWidget::StateTransition transition) {
  55. switch (transition) {
  56. case HotseatWidget::StateTransition::kHomeLauncherAndExtended:
  57. case HotseatWidget::StateTransition::kHomeLauncherAndHidden:
  58. return true;
  59. case HotseatWidget::StateTransition::kHiddenAndExtended:
  60. case HotseatWidget::StateTransition::kOther:
  61. return false;
  62. }
  63. }
  64. // Calculates the state transition type for the given previous state and
  65. // the target state.
  66. HotseatWidget::StateTransition CalculateHotseatStateTransition(
  67. HotseatState previous_state,
  68. HotseatState target_state) {
  69. if (previous_state == HotseatState::kNone ||
  70. target_state == HotseatState::kNone) {
  71. return HotseatWidget::StateTransition::kOther;
  72. }
  73. if (previous_state == target_state)
  74. return HotseatWidget::StateTransition::kOther;
  75. const bool related_to_homelauncher =
  76. (previous_state == HotseatState::kShownHomeLauncher ||
  77. target_state == HotseatState::kShownHomeLauncher);
  78. const bool related_to_extended = (previous_state == HotseatState::kExtended ||
  79. target_state == HotseatState::kExtended);
  80. const bool related_to_hidden = (previous_state == HotseatState::kHidden ||
  81. target_state == HotseatState::kHidden);
  82. if (related_to_homelauncher && related_to_extended)
  83. return HotseatWidget::StateTransition::kHomeLauncherAndExtended;
  84. if (related_to_homelauncher && related_to_hidden)
  85. return HotseatWidget::StateTransition::kHomeLauncherAndHidden;
  86. if (related_to_extended && related_to_hidden)
  87. return HotseatWidget::StateTransition::kHiddenAndExtended;
  88. return HotseatWidget::StateTransition::kOther;
  89. }
  90. // Base class for hotseat animation transition.
  91. class HotseatStateTransitionAnimation : public ui::LayerAnimationElement {
  92. public:
  93. HotseatStateTransitionAnimation(const gfx::Rect& target_bounds_in_screen,
  94. double target_opacity,
  95. ui::Layer* hotseat_layer,
  96. HotseatWidget* hotseat_widget)
  97. : ui::LayerAnimationElement(
  98. LayerAnimationElement::BOUNDS | LayerAnimationElement::OPACITY,
  99. hotseat_layer->GetAnimator()->GetTransitionDuration()),
  100. target_widget_bounds_(target_bounds_in_screen),
  101. target_opacity_(target_opacity),
  102. tween_type_(hotseat_layer->GetAnimator()->tween_type()),
  103. hotseat_widget_(hotseat_widget) {}
  104. ~HotseatStateTransitionAnimation() override = default;
  105. HotseatStateTransitionAnimation(const HotseatStateTransitionAnimation& rhs) =
  106. delete;
  107. HotseatStateTransitionAnimation& operator=(
  108. const HotseatStateTransitionAnimation& rhs) = delete;
  109. protected:
  110. // ui::LayerAnimationElement:
  111. void OnGetTarget(TargetValue* target) const override {
  112. target->opacity = target_opacity_;
  113. target->bounds = target_widget_bounds_;
  114. }
  115. ScrollableShelfView* GetScrollableShelfView() {
  116. return hotseat_widget_->scrollable_shelf_view();
  117. }
  118. // Hotseat widget's target bounds in screen.
  119. gfx::Rect target_widget_bounds_;
  120. // Hotseat widget's initial opacity.
  121. double start_opacity_ = 0.f;
  122. // Hotseat widget's target opacity.
  123. double target_opacity_ = 0.f;
  124. gfx::Tween::Type tween_type_ = gfx::Tween::LINEAR;
  125. HotseatWidget* hotseat_widget_ = nullptr;
  126. };
  127. // Animation implemented specifically for the transition between the home
  128. // launcher state and the extended state.
  129. class HomeAndExtendedTransitionAnimation
  130. : public HotseatStateTransitionAnimation {
  131. public:
  132. HomeAndExtendedTransitionAnimation(const gfx::Rect& target_bounds_in_screen,
  133. double target_opacity,
  134. ui::Layer* hotseat_layer,
  135. HotseatWidget* hotseat_widget)
  136. : HotseatStateTransitionAnimation(target_bounds_in_screen,
  137. target_opacity,
  138. hotseat_layer,
  139. hotseat_widget) {}
  140. ~HomeAndExtendedTransitionAnimation() override = default;
  141. HomeAndExtendedTransitionAnimation(
  142. const HomeAndExtendedTransitionAnimation& rhs) = delete;
  143. HomeAndExtendedTransitionAnimation& operator=(
  144. const HomeAndExtendedTransitionAnimation& rhs) = delete;
  145. private:
  146. // HotseatStateTransitionAnimation:
  147. void OnStart(ui::LayerAnimationDelegate* delegate) override {
  148. DCHECK(hotseat_widget_->GetShelfView()->shelf()->IsHorizontalAlignment());
  149. ScrollableShelfView* scrollable_shelf_view = GetScrollableShelfView();
  150. scrollable_shelf_view->set_is_padding_configured_externally(
  151. /*is_padding_configured_externally=*/true);
  152. // Save initial and target padding insets.
  153. initial_padding_insets_ = scrollable_shelf_view->edge_padding_insets();
  154. target_padding_insets_ =
  155. scrollable_shelf_view->CalculateMirroredEdgePadding(
  156. /*use_target_bounds=*/true);
  157. // Save initial opacity.
  158. start_opacity_ = hotseat_widget_->GetNativeView()->layer()->opacity();
  159. // Save initial hotseat background bounds.
  160. initial_hotseat_background_in_screen_ =
  161. hotseat_widget_->GetWindowBoundsInScreen();
  162. initial_hotseat_background_in_screen_.Inset(initial_padding_insets_);
  163. // Save target hotseat background bounds.
  164. target_hotseat_background_in_screen_ = target_widget_bounds_;
  165. target_hotseat_background_in_screen_.Inset(target_padding_insets_);
  166. }
  167. // HotseatStateTransitionAnimation:
  168. bool OnProgress(double current,
  169. ui::LayerAnimationDelegate* delegate) override {
  170. const double tweened = gfx::Tween::CalculateValue(tween_type_, current);
  171. // Set scrollable shelf view's padding insets.
  172. gfx::Insets insets_in_animation_progress;
  173. insets_in_animation_progress.set_left(gfx::Tween::LinearIntValueBetween(
  174. tweened, initial_padding_insets_.left(),
  175. target_padding_insets_.left()));
  176. insets_in_animation_progress.set_right(gfx::Tween::LinearIntValueBetween(
  177. tweened, initial_padding_insets_.right(),
  178. target_padding_insets_.right()));
  179. ScrollableShelfView* scrollable_shelf_view = GetScrollableShelfView();
  180. scrollable_shelf_view->SetEdgePaddingInsets(insets_in_animation_progress);
  181. // Update hotseat widget opacity.
  182. delegate->SetOpacityFromAnimation(
  183. gfx::Tween::DoubleValueBetween(tweened, start_opacity_,
  184. target_opacity_),
  185. ui::PropertyChangeReason::FROM_ANIMATION);
  186. // Calculate the hotseat widget's bounds.
  187. const gfx::Rect hotseat_background_in_progress =
  188. gfx::Tween::RectValueBetween(tweened,
  189. initial_hotseat_background_in_screen_,
  190. target_hotseat_background_in_screen_);
  191. gfx::Rect widget_bounds_in_progress = hotseat_background_in_progress;
  192. widget_bounds_in_progress.Inset(
  193. -scrollable_shelf_view->edge_padding_insets());
  194. // Update hotseat widget bounds.
  195. delegate->SetBoundsFromAnimation(widget_bounds_in_progress,
  196. ui::PropertyChangeReason::FROM_ANIMATION);
  197. // Do recovering when the animation ends.
  198. if (current == 1.f) {
  199. scrollable_shelf_view->set_is_padding_configured_externally(
  200. /*is_padding_configured_externally=*/false);
  201. }
  202. return true;
  203. }
  204. // HotseatStateTransitionAnimation:
  205. void OnAbort(ui::LayerAnimationDelegate* delegate) override {
  206. GetScrollableShelfView()->set_is_padding_configured_externally(
  207. /*is_padding_configured_externally=*/false);
  208. }
  209. // Scrollable shelf's initial padding insets.
  210. gfx::Insets initial_padding_insets_;
  211. // Scrollable shelf's target padding insets.
  212. gfx::Insets target_padding_insets_;
  213. // Hotseat background's initial bounds in screen.
  214. gfx::Rect initial_hotseat_background_in_screen_;
  215. // Hotseat background's target bounds in screen.
  216. gfx::Rect target_hotseat_background_in_screen_;
  217. };
  218. // Animation implemented specifically for the transition between the home
  219. // launcher state and the hidden state.
  220. class HomeAndHiddenTransitionAnimation
  221. : public HotseatStateTransitionAnimation {
  222. public:
  223. HomeAndHiddenTransitionAnimation(const gfx::Rect& target_bounds_in_screen,
  224. double target_opacity,
  225. ui::Layer* hotseat_layer,
  226. HotseatWidget* hotseat_widget)
  227. : HotseatStateTransitionAnimation(target_bounds_in_screen,
  228. target_opacity,
  229. hotseat_layer,
  230. hotseat_widget) {}
  231. ~HomeAndHiddenTransitionAnimation() override = default;
  232. protected:
  233. // HotseatStateTransitionAnimation:
  234. void OnStart(ui::LayerAnimationDelegate* delegate) override {
  235. DCHECK(hotseat_widget_->GetShelfView()->shelf()->IsHorizontalAlignment());
  236. start_opacity_ = hotseat_widget_->GetNativeView()->layer()->opacity();
  237. if (hotseat_widget_->state() == HotseatState::kHidden)
  238. will_be_hidden_ = true;
  239. ScrollableShelfView* scrollable_shelf_view = GetScrollableShelfView();
  240. const gfx::Rect current_widget_bounds(
  241. hotseat_widget_->GetWindowBoundsInScreen());
  242. // Ensure that hotseat only has vertical movement during animation.
  243. if (will_be_hidden_) {
  244. animation_initial_bounds_ = current_widget_bounds;
  245. animation_target_bounds_ = current_widget_bounds;
  246. animation_target_bounds_.set_y(target_widget_bounds_.y());
  247. } else {
  248. animation_initial_bounds_ = target_widget_bounds_;
  249. animation_initial_bounds_.set_y(current_widget_bounds.y());
  250. // Ensure that hotseat is set with the target bounds at the end of
  251. // animation when hotseat is going to show in home launcher.
  252. animation_target_bounds_ = target_widget_bounds_;
  253. const gfx::Insets target_padding_insets =
  254. scrollable_shelf_view->CalculateMirroredEdgePadding(
  255. /*use_target_bounds=*/true);
  256. scrollable_shelf_view->SetEdgePaddingInsets(target_padding_insets);
  257. delegate->SetBoundsFromAnimation(
  258. animation_initial_bounds_, ui::PropertyChangeReason::FROM_ANIMATION);
  259. }
  260. }
  261. // HotseatStateTransitionAnimation:
  262. bool OnProgress(double current,
  263. ui::LayerAnimationDelegate* delegate) override {
  264. const double tweened = gfx::Tween::CalculateValue(tween_type_, current);
  265. delegate->SetOpacityFromAnimation(
  266. gfx::Tween::DoubleValueBetween(tweened, start_opacity_,
  267. target_opacity_),
  268. ui::PropertyChangeReason::FROM_ANIMATION);
  269. const gfx::Rect widget_bounds_in_progress = gfx::Tween::RectValueBetween(
  270. tweened, animation_initial_bounds_, animation_target_bounds_);
  271. const bool reach_end = current == 1.f;
  272. // When hotseat is going to be hidden, |animation_target_bounds_| is not
  273. // equal to |target_widget_bounds_|. So hotseat is set with the target
  274. // bounds at the end of animation. It does not bring animation regression
  275. // since hotseat is invisible to the user when setting bounds.
  276. delegate->SetBoundsFromAnimation(will_be_hidden_ && reach_end
  277. ? target_widget_bounds_
  278. : widget_bounds_in_progress,
  279. ui::PropertyChangeReason::FROM_ANIMATION);
  280. return true;
  281. }
  282. // HotseatStateTransitionAnimation:
  283. void OnAbort(ui::LayerAnimationDelegate* delegate) override {}
  284. private:
  285. // Whether hotseat widget is hidden after state transition animation.
  286. bool will_be_hidden_ = false;
  287. // Note that |animation_initial_bounds_| and |animation_target_bounds_| may
  288. // not be the hotseat's current bounds and |target_widget_bounds_|
  289. // respectively.
  290. gfx::Rect animation_initial_bounds_;
  291. gfx::Rect animation_target_bounds_;
  292. };
  293. // Custom window targeter for the hotseat. Used so the hotseat only processes
  294. // events that land on the visible portion of the hotseat, and only while the
  295. // hotseat is not animating.
  296. class HotseatWindowTargeter : public aura::WindowTargeter {
  297. public:
  298. explicit HotseatWindowTargeter(HotseatWidget* hotseat_widget)
  299. : hotseat_widget_(hotseat_widget) {}
  300. ~HotseatWindowTargeter() override = default;
  301. HotseatWindowTargeter(const HotseatWindowTargeter& other) = delete;
  302. HotseatWindowTargeter& operator=(const HotseatWindowTargeter& rhs) = delete;
  303. // aura::WindowTargeter:
  304. bool SubtreeShouldBeExploredForEvent(aura::Window* window,
  305. const ui::LocatedEvent& event) override {
  306. // Do not handle events if the hotseat window is animating as it may animate
  307. // over other items which want to process events.
  308. if (hotseat_widget_->GetLayer()->GetAnimator()->is_animating())
  309. return false;
  310. return aura::WindowTargeter::SubtreeShouldBeExploredForEvent(window, event);
  311. }
  312. bool GetHitTestRects(aura::Window* target,
  313. gfx::Rect* hit_test_rect_mouse,
  314. gfx::Rect* hit_test_rect_touch) const override {
  315. if (target == hotseat_widget_->GetNativeWindow()) {
  316. // Shrink the hit bounds from the size of the window to the size of the
  317. // hotseat translucent background.
  318. gfx::Rect hit_bounds = target->bounds();
  319. hit_bounds.ClampToCenteredSize(
  320. hotseat_widget_->GetTranslucentBackgroundSize());
  321. *hit_test_rect_mouse = *hit_test_rect_touch = hit_bounds;
  322. return true;
  323. }
  324. return aura::WindowTargeter::GetHitTestRects(target, hit_test_rect_mouse,
  325. hit_test_rect_touch);
  326. }
  327. private:
  328. // Unowned and guaranteed to be not null for the duration of |this|.
  329. HotseatWidget* const hotseat_widget_;
  330. };
  331. } // namespace
  332. class HotseatWidget::DelegateView : public HotseatTransitionAnimator::Observer,
  333. public views::WidgetDelegateView,
  334. public views::ViewTargeterDelegate,
  335. public OverviewObserver,
  336. public WallpaperControllerObserver {
  337. public:
  338. DelegateView() {
  339. SetEventTargeter(std::make_unique<views::ViewTargeter>(this));
  340. SetPaintToLayer(ui::LAYER_NOT_DRAWN);
  341. }
  342. DelegateView(const DelegateView&) = delete;
  343. DelegateView& operator=(const DelegateView&) = delete;
  344. ~DelegateView() override;
  345. // views::ViewTargetDelegate:
  346. View* TargetForRect(View* root, const gfx::Rect& rect) override {
  347. // If a context menu for a shelf app button is shown, redirect all events to
  348. // the shelf app button. Context menus generally capture all events, but
  349. // shelf app buttons' context menu redirect gesture events to the hotseat
  350. // widget so shelf app button can continue handling drag events.
  351. // See also HotseatWidget::OnGestureEvent().
  352. views::View* item_with_context_menu =
  353. scrollable_shelf_view_->shelf_view()->GetShelfItemViewWithContextMenu();
  354. if (item_with_context_menu)
  355. return item_with_context_menu;
  356. return views::ViewTargeterDelegate::TargetForRect(root, rect);
  357. }
  358. // Initializes the view.
  359. void Init(ScrollableShelfView* scrollable_shelf_view,
  360. HotseatWidget* hotseat_widget);
  361. // Updates the hotseat background.
  362. void UpdateTranslucentBackground();
  363. void SetTranslucentBackground(const gfx::Rect& translucent_background_bounds);
  364. // Sets whether the background should be blurred as requested by the argument,
  365. // unless the feature flag is disabled or |disable_blur_for_animations_| is
  366. // true, in which case this disables background blur.
  367. void SetBackgroundBlur(bool enable_blur);
  368. // HotseatTransitionAnimator::Observer:
  369. void OnHotseatTransitionAnimationWillStart(HotseatState from_state,
  370. HotseatState to_state) override;
  371. void OnHotseatTransitionAnimationEnded(HotseatState from_state,
  372. HotseatState to_state) override;
  373. void OnHotseatTransitionAnimationAborted() override;
  374. // views::View:
  375. void OnThemeChanged() override;
  376. // views::WidgetDelegateView:
  377. bool CanActivate() const override;
  378. // OverviewObserver:
  379. void OnOverviewModeWillStart() override;
  380. void OnOverviewModeEndingAnimationComplete(bool canceled) override;
  381. // WallpaperControllerObserver:
  382. void OnWallpaperColorsChanged() override;
  383. void set_focus_cycler(FocusCycler* focus_cycler) {
  384. focus_cycler_ = focus_cycler;
  385. }
  386. int background_blur() const {
  387. return translucent_background_->layer()->background_blur();
  388. }
  389. bool is_translucent_background_visible_for_test() {
  390. return translucent_background_->layer()->GetTargetVisibility();
  391. }
  392. private:
  393. FocusCycler* focus_cycler_ = nullptr;
  394. // A background layer that may be visible depending on HotseatState.
  395. views::View* translucent_background_ = nullptr;
  396. ScrollableShelfView* scrollable_shelf_view_ = nullptr; // unowned.
  397. HotseatWidget* hotseat_widget_ = nullptr; // unowned.
  398. // Blur is disabled during animations to improve performance.
  399. int blur_lock_ = 0;
  400. // The most recent color that the |translucent_background_| has been animated
  401. // to.
  402. SkColor target_color_ = SK_ColorTRANSPARENT;
  403. std::unique_ptr<SystemShadow> shadow_;
  404. };
  405. HotseatWidget::DelegateView::~DelegateView() {
  406. WallpaperControllerImpl* wallpaper_controller =
  407. Shell::Get()->wallpaper_controller();
  408. OverviewController* overview_controller = Shell::Get()->overview_controller();
  409. if (wallpaper_controller)
  410. wallpaper_controller->RemoveObserver(this);
  411. if (overview_controller)
  412. overview_controller->RemoveObserver(this);
  413. }
  414. void HotseatWidget::DelegateView::Init(
  415. ScrollableShelfView* scrollable_shelf_view,
  416. HotseatWidget* hotseat_widget) {
  417. hotseat_widget_ = hotseat_widget;
  418. SetLayoutManager(std::make_unique<views::FillLayout>());
  419. WallpaperControllerImpl* wallpaper_controller =
  420. Shell::Get()->wallpaper_controller();
  421. OverviewController* overview_controller = Shell::Get()->overview_controller();
  422. if (wallpaper_controller)
  423. wallpaper_controller->AddObserver(this);
  424. if (overview_controller) {
  425. overview_controller->AddObserver(this);
  426. if (overview_controller->InOverviewSession())
  427. ++blur_lock_;
  428. }
  429. DCHECK(scrollable_shelf_view);
  430. scrollable_shelf_view_ = scrollable_shelf_view;
  431. // A container view added here is to prevent the `translucent_background_`
  432. // being stretched by the fill layout.
  433. auto* background_container_view =
  434. AddChildViewAt(std::make_unique<views::View>(), 0);
  435. background_container_view->SetEnabled(false);
  436. translucent_background_ =
  437. background_container_view->AddChildView(std::make_unique<views::View>());
  438. if (features::IsDarkLightModeEnabled()) {
  439. translucent_background_->SetPaintToLayer();
  440. translucent_background_->layer()->SetFillsBoundsOpaquely(false);
  441. } else {
  442. translucent_background_->SetPaintToLayer(ui::LAYER_SOLID_COLOR);
  443. }
  444. translucent_background_->layer()->SetName("hotseat/Background");
  445. // Create a shadow and stack at the bottom.
  446. shadow_ = SystemShadow::CreateShadowOnTextureLayer(
  447. SystemShadow::Type::kElevation12);
  448. auto* parent_layer = translucent_background_->layer()->parent();
  449. auto* shadow_layer = shadow_->GetLayer();
  450. parent_layer->Add(shadow_layer);
  451. parent_layer->StackAtBottom(shadow_layer);
  452. }
  453. void HotseatWidget::DelegateView::UpdateTranslucentBackground() {
  454. if (!HotseatWidget::ShouldShowHotseatBackground()) {
  455. translucent_background_->SetVisible(false);
  456. SetBackgroundBlur(false);
  457. shadow_->GetLayer()->SetVisible(false);
  458. return;
  459. }
  460. DCHECK(scrollable_shelf_view_);
  461. SetTranslucentBackground(
  462. scrollable_shelf_view_->GetHotseatBackgroundBounds());
  463. // Hide the shadow when home launcher is showing in tablet mode.
  464. if (hotseat_widget_->state() == HotseatState::kShownHomeLauncher) {
  465. shadow_->GetLayer()->SetVisible(false);
  466. return;
  467. }
  468. // Update the shadow content bounds and corner radius.
  469. shadow_->GetLayer()->SetVisible(true);
  470. gfx::Rect background_bounds = translucent_background_->bounds();
  471. shadow_->SetRoundedCornerRadius(background_bounds.height() / 2);
  472. shadow_->SetContentBounds(background_bounds);
  473. }
  474. void HotseatWidget::DelegateView::SetTranslucentBackground(
  475. const gfx::Rect& background_bounds) {
  476. DCHECK(HotseatWidget::ShouldShowHotseatBackground());
  477. translucent_background_->SetVisible(true);
  478. SetBackgroundBlur(/*enable_blur=*/true);
  479. auto* animator = translucent_background_->layer()->GetAnimator();
  480. absl::optional<ui::AnimationThroughputReporter> reporter;
  481. if (hotseat_widget_ && hotseat_widget_->state() != HotseatState::kNone) {
  482. reporter.emplace(animator,
  483. hotseat_widget_->GetTranslucentBackgroundReportCallback());
  484. }
  485. if (ShelfConfig::Get()->GetDefaultShelfColor() != target_color_) {
  486. ui::ScopedLayerAnimationSettings color_animation_setter(animator);
  487. DoScopedAnimationSetting(&color_animation_setter);
  488. target_color_ = ShelfConfig::Get()->GetDefaultShelfColor();
  489. if (features::IsDarkLightModeEnabled()) {
  490. translucent_background_->SetBackground(
  491. views::CreateSolidBackground(target_color_));
  492. } else {
  493. translucent_background_->layer()->SetColor(target_color_);
  494. }
  495. }
  496. // Animate the bounds change if there's a change of width (for instance when
  497. // dragging an app into, or out of, the shelf) and meanwhile scrollable
  498. // shelf's bounds does not update at the same time.
  499. const bool animate_bounds =
  500. background_bounds.width() != translucent_background_->bounds().width() &&
  501. (scrollable_shelf_view_ &&
  502. !scrollable_shelf_view_->NeedUpdateToTargetBounds());
  503. absl::optional<ui::ScopedLayerAnimationSettings> bounds_animation_setter;
  504. if (animate_bounds) {
  505. bounds_animation_setter.emplace(animator);
  506. DoScopedAnimationSetting(&bounds_animation_setter.value());
  507. }
  508. const float radius = hotseat_widget_->GetHotseatSize() / 2.0f;
  509. gfx::RoundedCornersF rounded_corners = {radius, radius, radius, radius};
  510. if (translucent_background_->layer()->rounded_corner_radii() !=
  511. rounded_corners) {
  512. translucent_background_->layer()->SetRoundedCornerRadius(rounded_corners);
  513. if (features::IsDarkLightModeEnabled()) {
  514. translucent_background_->SetBorder(
  515. std::make_unique<views::HighlightBorder>(
  516. radius, views::HighlightBorder::Type::kHighlightBorder1,
  517. /*use_light_colors=*/!features::IsDarkLightModeEnabled()));
  518. }
  519. }
  520. const gfx::Rect mirrored_bounds = GetMirroredRect(background_bounds);
  521. if (translucent_background_->layer()->GetTargetBounds() != mirrored_bounds)
  522. translucent_background_->SetBoundsRect(mirrored_bounds);
  523. }
  524. void HotseatWidget::DelegateView::SetBackgroundBlur(bool enable_blur) {
  525. if (!features::IsBackgroundBlurEnabled() || blur_lock_ > 0)
  526. return;
  527. const int blur_radius =
  528. enable_blur ? ShelfConfig::Get()->shelf_blur_radius() : 0;
  529. if (translucent_background_->layer()->background_blur() != blur_radius)
  530. translucent_background_->layer()->SetBackgroundBlur(blur_radius);
  531. }
  532. void HotseatWidget::DelegateView::OnHotseatTransitionAnimationWillStart(
  533. HotseatState from_state,
  534. HotseatState to_state) {
  535. DCHECK_LE(blur_lock_, 2);
  536. SetBackgroundBlur(false);
  537. ++blur_lock_;
  538. }
  539. void HotseatWidget::DelegateView::OnHotseatTransitionAnimationEnded(
  540. HotseatState from_state,
  541. HotseatState to_state) {
  542. DCHECK_GT(blur_lock_, 0);
  543. --blur_lock_;
  544. SetBackgroundBlur(true);
  545. }
  546. void HotseatWidget::DelegateView::OnHotseatTransitionAnimationAborted() {
  547. DCHECK_GT(blur_lock_, 0);
  548. --blur_lock_;
  549. }
  550. void HotseatWidget::DelegateView::OnThemeChanged() {
  551. views::WidgetDelegateView::OnThemeChanged();
  552. // Only update the background when the `scrollable_shelf_view_` is
  553. // initialized.
  554. if (scrollable_shelf_view_)
  555. UpdateTranslucentBackground();
  556. }
  557. bool HotseatWidget::DelegateView::CanActivate() const {
  558. // We don't want mouse clicks to activate us, but we need to allow
  559. // activation when the user is using the keyboard (FocusCycler).
  560. return focus_cycler_ && focus_cycler_->widget_activating() == GetWidget();
  561. }
  562. void HotseatWidget::DelegateView::OnOverviewModeWillStart() {
  563. DCHECK_LE(blur_lock_, 2);
  564. SetBackgroundBlur(false);
  565. ++blur_lock_;
  566. }
  567. void HotseatWidget::DelegateView::OnOverviewModeEndingAnimationComplete(
  568. bool canceled) {
  569. DCHECK_GT(blur_lock_, 0);
  570. --blur_lock_;
  571. SetBackgroundBlur(true);
  572. }
  573. void HotseatWidget::DelegateView::OnWallpaperColorsChanged() {
  574. UpdateTranslucentBackground();
  575. }
  576. ////////////////////////////////////////////////////////////////////////////////
  577. // ScopedInStateTransition
  578. HotseatWidget::ScopedInStateTransition::ScopedInStateTransition(
  579. HotseatWidget* hotseat_widget,
  580. HotseatState old_state,
  581. HotseatState target_state)
  582. : hotseat_widget_(hotseat_widget) {
  583. hotseat_widget_->state_transition_in_progress_ =
  584. CalculateHotseatStateTransition(old_state, target_state);
  585. }
  586. HotseatWidget::ScopedInStateTransition::~ScopedInStateTransition() {
  587. hotseat_widget_->state_transition_in_progress_.reset();
  588. }
  589. ////////////////////////////////////////////////////////////////////////////////
  590. // HotseatWidget
  591. HotseatWidget::HotseatWidget() : delegate_view_(new DelegateView()) {
  592. ShelfConfig::Get()->AddObserver(this);
  593. }
  594. HotseatWidget::~HotseatWidget() {
  595. ui::LayerAnimator* hotseat_layer_animator =
  596. GetNativeView()->layer()->GetAnimator();
  597. if (hotseat_layer_animator->is_animating())
  598. hotseat_layer_animator->AbortAllAnimations();
  599. ShelfConfig::Get()->RemoveObserver(this);
  600. shelf_->shelf_widget()->hotseat_transition_animator()->RemoveObserver(
  601. delegate_view_);
  602. // Remove ScrollableShelfView to avoid any children accessing NativeWidget
  603. // after its destruction in ~Widget() before RootView clears.
  604. // TODO(pbos): This is defensive, consider having children observe
  605. // destruction and/or check the result of GetNativeWidget() and others.
  606. GetContentsView()->RemoveChildViewT(scrollable_shelf_view_);
  607. }
  608. bool HotseatWidget::ShouldShowHotseatBackground() {
  609. return Shell::Get()->tablet_mode_controller() &&
  610. Shell::Get()->tablet_mode_controller()->InTabletMode();
  611. }
  612. void HotseatWidget::Initialize(aura::Window* container, Shelf* shelf) {
  613. DCHECK(container);
  614. DCHECK(shelf);
  615. shelf_ = shelf;
  616. views::Widget::InitParams params(
  617. views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
  618. params.name = "HotseatWidget";
  619. params.delegate = delegate_view_;
  620. params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent;
  621. params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
  622. params.parent = container;
  623. params.layer_type = ui::LAYER_NOT_DRAWN;
  624. Init(std::move(params));
  625. set_focus_on_creation(false);
  626. scrollable_shelf_view_ = GetContentsView()->AddChildView(
  627. std::make_unique<ScrollableShelfView>(ShelfModel::Get(), shelf));
  628. delegate_view_->Init(scrollable_shelf_view(), this);
  629. delegate_view_->SetEnableArrowKeyTraversal(true);
  630. // The initialization of scrollable shelf should update the translucent
  631. // background which is stored in |delegate_view_|. So initializes
  632. // |scrollable_shelf_view_| after |delegate_view_|.
  633. scrollable_shelf_view_->Init();
  634. }
  635. void HotseatWidget::OnHotseatTransitionAnimatorCreated(
  636. HotseatTransitionAnimator* animator) {
  637. shelf_->shelf_widget()->hotseat_transition_animator()->AddObserver(
  638. delegate_view_);
  639. }
  640. void HotseatWidget::OnMouseEvent(ui::MouseEvent* event) {
  641. if (event->type() == ui::ET_MOUSE_PRESSED)
  642. keyboard::KeyboardUIController::Get()->HideKeyboardImplicitlyByUser();
  643. views::Widget::OnMouseEvent(event);
  644. }
  645. void HotseatWidget::OnGestureEvent(ui::GestureEvent* event) {
  646. if (event->type() == ui::ET_GESTURE_TAP_DOWN)
  647. keyboard::KeyboardUIController::Get()->HideKeyboardImplicitlyByUser();
  648. // Context menus for shelf app button forward gesture events to hotseat
  649. // widget, so the shelf app button can continue handling drag even after the
  650. // context menu starts capturing events. Ignore events not interesting to the
  651. // shelf app button in this state.
  652. ShelfAppButton* item_with_context_menu =
  653. GetShelfView()->GetShelfItemViewWithContextMenu();
  654. if (item_with_context_menu &&
  655. !ShelfAppButton::ShouldHandleEventFromContextMenu(event)) {
  656. event->SetHandled();
  657. return;
  658. }
  659. if (!event->handled())
  660. views::Widget::OnGestureEvent(event);
  661. // Ensure that the app button's drag state gets cleared on gesture end even if
  662. // the event doesn't get delivered to the app button.
  663. if (item_with_context_menu && event->type() == ui::ET_GESTURE_END)
  664. item_with_context_menu->ClearDragStateOnGestureEnd();
  665. }
  666. bool HotseatWidget::OnNativeWidgetActivationChanged(bool active) {
  667. if (!Widget::OnNativeWidgetActivationChanged(active))
  668. return false;
  669. scrollable_shelf_view_->OnFocusRingActivationChanged(active);
  670. return true;
  671. }
  672. void HotseatWidget::OnShelfConfigUpdated() {
  673. set_manually_extended(false);
  674. }
  675. bool HotseatWidget::IsExtended() const {
  676. DCHECK(GetShelfView()->shelf()->IsHorizontalAlignment());
  677. const int extended_bottom =
  678. display::Screen::GetScreen()
  679. ->GetDisplayNearestView(GetShelfView()->GetWidget()->GetNativeView())
  680. .bounds()
  681. .bottom() -
  682. (ShelfConfig::Get()->shelf_size() +
  683. ShelfConfig::Get()->hotseat_bottom_padding());
  684. return GetWindowBoundsInScreen().bottom() == extended_bottom;
  685. }
  686. void HotseatWidget::FocusFirstOrLastFocusableChild(bool last) {
  687. GetShelfView()->FindFirstOrLastFocusableChild(last)->RequestFocus();
  688. }
  689. void HotseatWidget::OnTabletModeChanged() {
  690. GetShelfView()->OnTabletModeChanged();
  691. }
  692. float HotseatWidget::CalculateShelfViewOpacity() const {
  693. const float target_opacity =
  694. GetShelfView()->shelf()->shelf_layout_manager()->GetOpacity();
  695. // Hotseat's shelf view should not be dimmed if hotseat is kExtended.
  696. return (state() == HotseatState::kExtended) ? 1.0f : target_opacity;
  697. }
  698. void HotseatWidget::UpdateTranslucentBackground() {
  699. delegate_view_->UpdateTranslucentBackground();
  700. }
  701. int HotseatWidget::CalculateHotseatYInScreen(
  702. HotseatState hotseat_target_state) const {
  703. DCHECK(shelf_->IsHorizontalAlignment());
  704. int hotseat_distance_from_bottom_of_display = 0;
  705. const int hotseat_size = GetHotseatSize();
  706. switch (hotseat_target_state) {
  707. case HotseatState::kShownClamshell:
  708. hotseat_distance_from_bottom_of_display = hotseat_size;
  709. break;
  710. case HotseatState::kShownHomeLauncher:
  711. // When the hotseat state is HotseatState::kShownHomeLauncher, the home
  712. // launcher is showing in tablet mode. Elevate the hotseat a few px to
  713. // match the navigation and status area.
  714. hotseat_distance_from_bottom_of_display =
  715. hotseat_size + ShelfConfig::Get()->hotseat_bottom_padding();
  716. break;
  717. case HotseatState::kHidden:
  718. // Show the hotseat offscreen.
  719. hotseat_distance_from_bottom_of_display = 0;
  720. break;
  721. case HotseatState::kExtended:
  722. // Show the hotseat at its extended position.
  723. hotseat_distance_from_bottom_of_display =
  724. ShelfConfig::Get()->in_app_shelf_size() +
  725. ShelfConfig::Get()->hotseat_bottom_padding() + hotseat_size;
  726. break;
  727. case HotseatState::kNone:
  728. NOTREACHED();
  729. }
  730. const int target_shelf_size =
  731. shelf_->shelf_widget()->GetTargetBounds().size().height();
  732. const int hotseat_y_in_shelf =
  733. -(hotseat_distance_from_bottom_of_display - target_shelf_size);
  734. const int shelf_y = shelf_->shelf_widget()->GetTargetBounds().y();
  735. return hotseat_y_in_shelf + shelf_y;
  736. }
  737. gfx::Size HotseatWidget::CalculateTargetBoundsSize(
  738. HotseatState hotseat_target_state) const {
  739. const gfx::Rect shelf_bounds = shelf_->shelf_widget()->GetTargetBounds();
  740. // |hotseat_size| is the height in horizontal alignment or the width in
  741. // vertical alignment.
  742. const int hotseat_size = GetHotseatSize();
  743. if (hotseat_target_state != HotseatState::kShownHomeLauncher &&
  744. hotseat_target_state != HotseatState::kShownClamshell) {
  745. DCHECK(shelf_->IsHorizontalAlignment());
  746. // Give the hotseat more space if it is shown outside of the shelf.
  747. return gfx::Size(shelf_bounds.width(), hotseat_size);
  748. }
  749. const gfx::Size status_size =
  750. shelf_->status_area_widget()->GetTargetBounds().size();
  751. const gfx::Rect nav_bounds = shelf_->navigation_widget()->GetVisibleBounds();
  752. // The navigation widget has extra padding on the hotseat side, to center the
  753. // buttons inside of it. Make sure to get the extra nav widget padding and
  754. // take it into account when calculating the hotseat size.
  755. const int nav_widget_padding =
  756. nav_bounds.size().IsEmpty()
  757. ? 0
  758. : ShelfConfig::Get()->control_button_edge_spacing(
  759. true /* is_primary_axis_edge */);
  760. // The minimum gap between hotseat widget and other shelf components including
  761. // the status area widget and shelf navigation widget (or the edge of display,
  762. // if the shelf navigation widget does not show).
  763. const int group_margin = ShelfConfig::Get()->GetAppIconGroupMargin();
  764. if (shelf_->IsHorizontalAlignment()) {
  765. const int width = shelf_bounds.width() - nav_bounds.size().width() +
  766. nav_widget_padding - 2 * group_margin -
  767. status_size.width();
  768. return gfx::Size(width, hotseat_size);
  769. }
  770. const int height = shelf_bounds.height() - nav_bounds.size().height() +
  771. nav_widget_padding - 2 * group_margin -
  772. status_size.height();
  773. return gfx::Size(hotseat_size, height);
  774. }
  775. void HotseatWidget::CalculateTargetBounds() {
  776. ShelfLayoutManager* layout_manager = shelf_->shelf_layout_manager();
  777. const HotseatState hotseat_target_state =
  778. layout_manager->CalculateHotseatState(layout_manager->visibility_state(),
  779. layout_manager->auto_hide_state());
  780. const gfx::Size hotseat_target_size =
  781. CalculateTargetBoundsSize(hotseat_target_state);
  782. if (hotseat_target_state == HotseatState::kShownHomeLauncher) {
  783. target_size_for_shown_state_ = hotseat_target_size;
  784. } else {
  785. target_size_for_shown_state_ =
  786. CalculateTargetBoundsSize(HotseatState::kShownHomeLauncher);
  787. }
  788. const gfx::Rect shelf_bounds = shelf_->shelf_widget()->GetTargetBounds();
  789. const gfx::Rect status_area_bounds =
  790. shelf_->status_area_widget()->GetTargetBounds();
  791. // The minimum gap between hotseat widget and other shelf components including
  792. // the status area widget and shelf navigation widget (or the edge of display,
  793. // if the shelf navigation widget does not show).
  794. const int group_margin = ShelfConfig::Get()->GetAppIconGroupMargin();
  795. gfx::Point hotseat_origin;
  796. if (shelf_->IsHorizontalAlignment()) {
  797. int hotseat_x;
  798. if (hotseat_target_state != HotseatState::kShownHomeLauncher &&
  799. hotseat_target_state != HotseatState::kShownClamshell) {
  800. hotseat_x = shelf_bounds.x();
  801. } else {
  802. hotseat_x = base::i18n::IsRTL()
  803. ? status_area_bounds.right() + group_margin
  804. : status_area_bounds.x() - group_margin -
  805. hotseat_target_size.width();
  806. }
  807. hotseat_origin =
  808. gfx::Point(hotseat_x, CalculateHotseatYInScreen(hotseat_target_state));
  809. } else {
  810. hotseat_origin =
  811. gfx::Point(shelf_bounds.x(), status_area_bounds.y() - group_margin -
  812. hotseat_target_size.height());
  813. }
  814. target_bounds_ = gfx::Rect(hotseat_origin, hotseat_target_size);
  815. // Check whether |target_bounds_| will change the state of app scaling. If
  816. // so, update |target_bounds_| here to avoid re-layout later.
  817. MaybeAdjustTargetBoundsForAppScaling(hotseat_target_state);
  818. }
  819. gfx::Rect HotseatWidget::GetTargetBounds() const {
  820. return target_bounds_;
  821. }
  822. void HotseatWidget::UpdateLayout(bool animate) {
  823. const LayoutInputs new_layout_inputs = GetLayoutInputs();
  824. if (layout_inputs_ == new_layout_inputs)
  825. return;
  826. // Never show this widget outside of an active session.
  827. if (!new_layout_inputs.is_active_session_state)
  828. Hide();
  829. ui::Layer* shelf_view_layer = GetShelfView()->layer();
  830. {
  831. ui::ScopedLayerAnimationSettings animation_setter(
  832. shelf_view_layer->GetAnimator());
  833. animation_setter.SetTransitionDuration(
  834. animate ? ShelfConfig::Get()->shelf_animation_duration()
  835. : base::Milliseconds(0));
  836. animation_setter.SetTweenType(gfx::Tween::EASE_OUT);
  837. animation_setter.SetPreemptionStrategy(
  838. ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
  839. absl::optional<ui::AnimationThroughputReporter> reporter;
  840. if (animate && state_ != HotseatState::kNone) {
  841. reporter.emplace(animation_setter.GetAnimator(),
  842. shelf_->GetHotseatTransitionReportCallback(state_));
  843. }
  844. shelf_view_layer->SetOpacity(new_layout_inputs.shelf_view_opacity);
  845. }
  846. // If shelf view is invisible, the hotseat should be as well. Otherwise the
  847. // hotseat opacity should be 1.0f to preserve background blur.
  848. const double target_opacity =
  849. (new_layout_inputs.shelf_view_opacity == 0.f ? 0.f : 1.f);
  850. const gfx::Rect& target_bounds = new_layout_inputs.bounds;
  851. if (animate) {
  852. LayoutHotseatByAnimation(target_opacity, target_bounds);
  853. } else {
  854. ui::Layer* hotseat_layer = GetNativeView()->layer();
  855. // If the running bounds animation is not aborted, it will be interrupted
  856. // and set hotseat widget with the old target bounds which may differ from
  857. // |target_bounds| greatly and bring DCHECK errors. For example,
  858. // if hotseat animation is interrupted by the bounds setting triggered by
  859. // shelf alignment update, hotseat will be caught in an intermediate state
  860. // where the shelf alignment is new and the hotseat bounds are old.
  861. hotseat_layer->GetAnimator()->AbortAllAnimations();
  862. hotseat_layer->SetOpacity(target_opacity);
  863. hotseat_layer->SetTransform(gfx::Transform());
  864. SetBounds(target_bounds);
  865. }
  866. layout_inputs_ = new_layout_inputs;
  867. delegate_view_->UpdateTranslucentBackground();
  868. // Setting visibility during an animation causes the visibility property to
  869. // animate. Set the visibility property without an animation.
  870. if (new_layout_inputs.shelf_view_opacity != 0.0f &&
  871. new_layout_inputs.is_active_session_state) {
  872. ShowInactive();
  873. }
  874. }
  875. void HotseatWidget::UpdateTargetBoundsForGesture(int shelf_position) {
  876. if (shelf_->IsHorizontalAlignment())
  877. target_bounds_.set_y(shelf_position);
  878. else
  879. target_bounds_.set_x(shelf_position);
  880. }
  881. gfx::Size HotseatWidget::GetTranslucentBackgroundSize() const {
  882. DCHECK(scrollable_shelf_view_);
  883. return scrollable_shelf_view_->GetHotseatBackgroundBounds().size();
  884. }
  885. void HotseatWidget::SetFocusCycler(FocusCycler* focus_cycler) {
  886. delegate_view_->set_focus_cycler(focus_cycler);
  887. if (focus_cycler)
  888. focus_cycler->AddWidget(this);
  889. }
  890. ShelfView* HotseatWidget::GetShelfView() {
  891. DCHECK(scrollable_shelf_view_);
  892. return scrollable_shelf_view_->shelf_view();
  893. }
  894. int HotseatWidget::GetHotseatSize() const {
  895. return ShelfConfig::Get()->GetShelfButtonSize(target_hotseat_density_);
  896. }
  897. int HotseatWidget::GetHotseatFullDragAmount() const {
  898. ShelfConfig* shelf_config = ShelfConfig::Get();
  899. return shelf_config->shelf_size() + shelf_config->hotseat_bottom_padding() +
  900. GetHotseatSize();
  901. }
  902. bool HotseatWidget::UpdateTargetHotseatDensityIfNeeded() {
  903. if (CalculateTargetHotseatDensity() == target_hotseat_density_) {
  904. return false;
  905. }
  906. shelf_->shelf_layout_manager()->LayoutShelf(/*animate=*/true);
  907. return true;
  908. }
  909. int HotseatWidget::GetHotseatBackgroundBlurForTest() const {
  910. return delegate_view_->background_blur();
  911. }
  912. bool HotseatWidget::GetIsTranslucentBackgroundVisibleForTest() const {
  913. return delegate_view_->is_translucent_background_visible_for_test();
  914. }
  915. bool HotseatWidget::IsShowingShelfMenu() const {
  916. return GetShelfView()->IsShowingMenu();
  917. }
  918. bool HotseatWidget::EventTargetsShelfView(const ui::LocatedEvent& event) const {
  919. DCHECK_EQ(event.target(), GetNativeWindow());
  920. gfx::Point location_in_shelf_view = event.location();
  921. views::View::ConvertPointFromWidget(scrollable_shelf_view_,
  922. &location_in_shelf_view);
  923. return scrollable_shelf_view_->GetHotseatBackgroundBounds().Contains(
  924. location_in_shelf_view);
  925. }
  926. const ShelfView* HotseatWidget::GetShelfView() const {
  927. return const_cast<const ShelfView*>(
  928. const_cast<HotseatWidget*>(this)->GetShelfView());
  929. }
  930. metrics_util::ReportCallback
  931. HotseatWidget::GetTranslucentBackgroundReportCallback() {
  932. return shelf_->GetTranslucentBackgroundReportCallback(state_);
  933. }
  934. void HotseatWidget::SetState(HotseatState state) {
  935. if (state_ == state)
  936. return;
  937. state_ = state;
  938. // If the hotseat is not extended we can use the normal targeting as the
  939. // hidden parts of the hotseat will not block non-shelf items from taking
  940. if (state == HotseatState::kExtended) {
  941. hotseat_window_targeter_ = std::make_unique<aura::ScopedWindowTargeter>(
  942. GetNativeWindow(), std::make_unique<HotseatWindowTargeter>(this));
  943. } else {
  944. hotseat_window_targeter_.reset();
  945. }
  946. }
  947. ui::Layer* HotseatWidget::GetLayerForNudgeAnimation() {
  948. return delegate_view_->layer();
  949. }
  950. HotseatWidget::LayoutInputs HotseatWidget::GetLayoutInputs() const {
  951. const ShelfLayoutManager* layout_manager = shelf_->shelf_layout_manager();
  952. return {target_bounds_, CalculateShelfViewOpacity(),
  953. layout_manager->is_active_session_state()};
  954. }
  955. void HotseatWidget::MaybeAdjustTargetBoundsForAppScaling(
  956. HotseatState hotseat_target_state) {
  957. // Return early if app scaling state does not change.
  958. HotseatDensity new_target_hotseat_density = CalculateTargetHotseatDensity();
  959. if (new_target_hotseat_density == target_hotseat_density_)
  960. return;
  961. target_hotseat_density_ = new_target_hotseat_density;
  962. // Update app icons of shelf view.
  963. scrollable_shelf_view_->shelf_view()->OnShelfConfigUpdated();
  964. const gfx::Point adjusted_hotseat_origin = gfx::Point(
  965. target_bounds_.x(), CalculateHotseatYInScreen(hotseat_target_state));
  966. target_bounds_ =
  967. gfx::Rect(adjusted_hotseat_origin,
  968. gfx::Size(target_bounds_.width(), GetHotseatSize()));
  969. }
  970. HotseatDensity HotseatWidget::CalculateTargetHotseatDensity() const {
  971. // App scaling is only applied to the standard shelf. So the hotseat density
  972. // should not update in dense shelf.
  973. if (ShelfConfig::Get()->is_dense())
  974. return target_hotseat_density_;
  975. // TODO(crbug.com/1081476): Currently the scaling animation of hotseat bounds
  976. // and that of shelf icons do not synchronize due to performance issue. As a
  977. // result, shelf scaling is not applied to the hotseat state transition, such
  978. // as the transition from the home launcher state to the extended state.
  979. // Hotseat density relies on the hotseat bounds in the home launcher state
  980. // instead of the current hotseat state.
  981. // Try candidate button sizes in decreasing order. If shelf buttons in one
  982. // size can show without scrolling, return the density type corresponding to
  983. // that particular size; if no candidate size can make it, return
  984. // HotseatDensity::kDense.
  985. const std::vector<HotseatDensity> kCandidates = {HotseatDensity::kNormal,
  986. HotseatDensity::kSemiDense};
  987. for (const auto& candidate : kCandidates) {
  988. if (!scrollable_shelf_view_->RequiresScrollingForItemSize(
  989. target_size_for_shown_state_,
  990. ShelfConfig::Get()->GetShelfButtonSize(candidate))) {
  991. return candidate;
  992. }
  993. }
  994. return HotseatDensity::kDense;
  995. }
  996. void HotseatWidget::LayoutHotseatByAnimation(double target_opacity,
  997. const gfx::Rect& target_bounds) {
  998. ui::Layer* hotseat_layer = GetNativeView()->layer();
  999. // Bounds animations do not take transforms into account, but animations
  1000. // between hidden and extended state use transform to animate. Clear any
  1001. // transform that may have been set by the previous animation, and update
  1002. // current bounds to match it.
  1003. gfx::RectF current_bounds_f(GetNativeView()->GetBoundsInScreen());
  1004. hotseat_layer->transform().TransformRect(&current_bounds_f);
  1005. gfx::Rect current_bounds = gfx::ToEnclosingRect(current_bounds_f);
  1006. // If the bounds size has not changed, set the target bounds immediately, and
  1007. // animate using transform.
  1008. // Avoid transforms if the transition has a horizontal component - logic for
  1009. // setting scrollable shelf padding depends on the horizontal in screen
  1010. // bounds, and setting horizontal translation would interfere with that. Note
  1011. // that generally, if horizontal widget position changes, so will its width.
  1012. const bool animate_transform =
  1013. target_bounds.size() == current_bounds.size() &&
  1014. target_bounds.x() == current_bounds.x();
  1015. if (animate_transform) {
  1016. SetBounds(target_bounds);
  1017. gfx::Transform initial_transform;
  1018. initial_transform.Translate(current_bounds.origin() -
  1019. target_bounds.origin());
  1020. hotseat_layer->SetTransform(initial_transform);
  1021. } else {
  1022. hotseat_layer->SetTransform(gfx::Transform());
  1023. SetBounds(current_bounds);
  1024. }
  1025. ui::ScopedLayerAnimationSettings animation_setter(
  1026. hotseat_layer->GetAnimator());
  1027. animation_setter.SetTransitionDuration(
  1028. ShelfConfig::Get()->shelf_animation_duration());
  1029. animation_setter.SetTweenType(gfx::Tween::EASE_OUT);
  1030. animation_setter.SetPreemptionStrategy(
  1031. ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
  1032. absl::optional<ui::AnimationThroughputReporter> reporter;
  1033. if (state_ != HotseatState::kNone) {
  1034. reporter.emplace(animation_setter.GetAnimator(),
  1035. shelf_->GetHotseatTransitionReportCallback(state_));
  1036. }
  1037. if (animate_transform) {
  1038. hotseat_layer->SetOpacity(target_opacity);
  1039. hotseat_layer->SetTransform(gfx::Transform());
  1040. return;
  1041. }
  1042. if (!state_transition_in_progress_.has_value()) {
  1043. // Hotseat animation is not triggered by the update in |state_|. So apply
  1044. // the normal bounds animation.
  1045. StartNormalBoundsAnimation(target_opacity, target_bounds);
  1046. return;
  1047. }
  1048. if (HasSpecialAnimation(*state_transition_in_progress_)) {
  1049. StartHotseatTransitionAnimation(*state_transition_in_progress_,
  1050. target_opacity, target_bounds);
  1051. } else {
  1052. StartNormalBoundsAnimation(target_opacity, target_bounds);
  1053. }
  1054. }
  1055. void HotseatWidget::StartHotseatTransitionAnimation(
  1056. StateTransition state_transition,
  1057. double target_opacity,
  1058. const gfx::Rect& target_bounds) {
  1059. ui::Layer* hotseat_layer = GetNativeView()->layer();
  1060. std::unique_ptr<ui::LayerAnimationElement> animation_elements;
  1061. switch (state_transition) {
  1062. case StateTransition::kHomeLauncherAndExtended:
  1063. animation_elements = std::make_unique<HomeAndExtendedTransitionAnimation>(
  1064. target_bounds, target_opacity, hotseat_layer,
  1065. /*hotseat_widget=*/this);
  1066. break;
  1067. case StateTransition::kHomeLauncherAndHidden:
  1068. animation_elements = std::make_unique<HomeAndHiddenTransitionAnimation>(
  1069. target_bounds, target_opacity, hotseat_layer,
  1070. /*hotseat_widget=*/this);
  1071. break;
  1072. case StateTransition::kHiddenAndExtended:
  1073. case StateTransition::kOther:
  1074. NOTREACHED();
  1075. }
  1076. auto* sequence =
  1077. new ui::LayerAnimationSequence(std::move(animation_elements));
  1078. hotseat_layer->GetAnimator()->StartAnimation(sequence);
  1079. }
  1080. void HotseatWidget::StartNormalBoundsAnimation(double target_opacity,
  1081. const gfx::Rect& target_bounds) {
  1082. GetNativeView()->layer()->SetOpacity(target_opacity);
  1083. SetBounds(target_bounds);
  1084. }
  1085. } // namespace ash