Avi Drissman | 3a215d1e | 2022-09-07 19:43:09 | [diff] [blame] | 1 | // Copyright 2014 The Chromium Authors |
James Cook | b0bf8e8 | 2017-04-09 17:01:44 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Manu Cornet | f953d49 | 2019-06-27 05:56:51 | [diff] [blame] | 5 | #ifndef ASH_SHELF_HOME_BUTTON_H_ |
| 6 | #define ASH_SHELF_HOME_BUTTON_H_ |
James Cook | b0bf8e8 | 2017-04-09 17:01:44 | [diff] [blame] | 7 | |
| 8 | #include <memory> |
| 9 | |
Manu Cornet | 1ed1f6b | 2019-06-14 17:25:53 | [diff] [blame] | 10 | #include "ash/app_list/app_list_metrics.h" |
Matthew Mourgos | d477282 | 2023-04-05 18:35:03 | [diff] [blame] | 11 | #include "ash/app_list/app_list_model_provider.h" |
| 12 | #include "ash/app_list/quick_app_access_model.h" |
James Cook | b0bf8e8 | 2017-04-09 17:01:44 | [diff] [blame] | 13 | #include "ash/ash_export.h" |
Matthew Mourgos | d477282 | 2023-04-05 18:35:03 | [diff] [blame] | 14 | #include "ash/public/cpp/app_list/app_list_controller_observer.h" |
Toni Barzic | 705b8aa | 2023-05-24 01:50:10 | [diff] [blame] | 15 | #include "ash/public/cpp/shelf_config.h" |
Manu Cornet | f953d49 | 2019-06-27 05:56:51 | [diff] [blame] | 16 | #include "ash/shelf/home_button_controller.h" |
Manu Cornet | 86aef98 | 2019-07-18 21:31:10 | [diff] [blame] | 17 | #include "ash/shelf/shelf_button_delegate.h" |
Manu Cornet | 40f90812 | 2018-11-08 23:15:25 | [diff] [blame] | 18 | #include "ash/shelf/shelf_control_button.h" |
Matthew Mourgos | d477282 | 2023-04-05 18:35:03 | [diff] [blame] | 19 | #include "ash/shell_observer.h" |
Arthur Sonzogni | 834e018f | 2023-04-22 10:20:02 | [diff] [blame] | 20 | #include "base/memory/raw_ptr.h" |
Matthew Mourgos | d477282 | 2023-04-05 18:35:03 | [diff] [blame] | 21 | #include "base/scoped_observation.h" |
Yuki Awano | 2090b46 | 2021-06-08 01:33:07 | [diff] [blame] | 22 | #include "ui/gfx/geometry/rect.h" |
Matthew Mourgos | 1f28632 | 2023-04-20 18:16:50 | [diff] [blame] | 23 | #include "ui/gfx/geometry/transform.h" |
Ahmed Mehfooz | 6509620f | 2019-05-21 20:35:12 | [diff] [blame] | 24 | #include "ui/views/view_targeter_delegate.h" |
xiaohuic | fb5c54fc | 2017-06-28 17:32:02 | [diff] [blame] | 25 | |
Wen-Chien Wang | 3667df20 | 2021-09-30 20:08:23 | [diff] [blame] | 26 | namespace views { |
Wen-Chien Wang | 51a5d604d | 2022-05-10 18:18:01 | [diff] [blame] | 27 | class AnimationBuilder; |
Wen-Chien Wang | 3667df20 | 2021-09-30 20:08:23 | [diff] [blame] | 28 | class CircleLayerDelegate; |
Matthew Mourgos | d477282 | 2023-04-05 18:35:03 | [diff] [blame] | 29 | class ImageButton; |
Wen-Chien Wang | 51a5d604d | 2022-05-10 18:18:01 | [diff] [blame] | 30 | class Label; |
Wen-Chien Wang | 3667df20 | 2021-09-30 20:08:23 | [diff] [blame] | 31 | } // namespace views |
| 32 | |
Wen-Chien Wang | 617c38a | 2021-10-07 10:23:50 | [diff] [blame] | 33 | namespace ui { |
Wen-Chien Wang | 51a5d604d | 2022-05-10 18:18:01 | [diff] [blame] | 34 | class LayerOwner; |
Wen-Chien Wang | 617c38a | 2021-10-07 10:23:50 | [diff] [blame] | 35 | } |
| 36 | |
James Cook | b0bf8e8 | 2017-04-09 17:01:44 | [diff] [blame] | 37 | namespace ash { |
Sammie Quon | 9b911f2f | 2017-12-15 02:53:15 | [diff] [blame] | 38 | |
Wen-Chien Wang | 51a5d604d | 2022-05-10 18:18:01 | [diff] [blame] | 39 | class Shelf; |
Alex Newcomer | 030e706 | 2019-07-02 00:03:57 | [diff] [blame] | 40 | class ShelfButtonDelegate; |
Yuki Awano | 2090b46 | 2021-06-08 01:33:07 | [diff] [blame] | 41 | class ShelfNavigationWidget; |
Matthew Mourgos | d477282 | 2023-04-05 18:35:03 | [diff] [blame] | 42 | class Shell; |
James Cook | b0bf8e8 | 2017-04-09 17:01:44 | [diff] [blame] | 43 | |
Michael Giuffrida | 01adeb07 | 2019-03-21 22:05:30 | [diff] [blame] | 44 | // Button used for the AppList icon on the shelf. It opens the app list (in |
| 45 | // clamshell mode) or home screen (in tablet mode). Because the clamshell-mode |
| 46 | // app list appears like a dismissable overlay, the button is highlighted while |
| 47 | // the app list is open in clamshell mode. |
| 48 | // |
| 49 | // If Assistant is enabled, the button is filled in; long-pressing it will |
| 50 | // launch Assistant. |
Manu Cornet | f953d49 | 2019-06-27 05:56:51 | [diff] [blame] | 51 | class ASH_EXPORT HomeButton : public ShelfControlButton, |
Manu Cornet | 86aef98 | 2019-07-18 21:31:10 | [diff] [blame] | 52 | public ShelfButtonDelegate, |
Matthew Mourgos | d477282 | 2023-04-05 18:35:03 | [diff] [blame] | 53 | public views::ViewTargeterDelegate, |
| 54 | public ShellObserver, |
Toni Barzic | 705b8aa | 2023-05-24 01:50:10 | [diff] [blame] | 55 | public ShelfConfig::Observer, |
Matthew Mourgos | d477282 | 2023-04-05 18:35:03 | [diff] [blame] | 56 | public AppListModelProvider::Observer, |
| 57 | public QuickAppAccessModel::Observer { |
James Cook | b0bf8e8 | 2017-04-09 17:01:44 | [diff] [blame] | 58 | public: |
Yuki Awano | 2090b46 | 2021-06-08 01:33:07 | [diff] [blame] | 59 | class ScopedNoClipRect { |
| 60 | public: |
| 61 | explicit ScopedNoClipRect(ShelfNavigationWidget* shelf_navigation_widget); |
| 62 | ScopedNoClipRect(const ScopedNoClipRect&) = delete; |
| 63 | ScopedNoClipRect& operator=(const ScopedNoClipRect&) = delete; |
| 64 | ~ScopedNoClipRect(); |
| 65 | |
| 66 | private: |
Arthur Sonzogni | 834e018f | 2023-04-22 10:20:02 | [diff] [blame] | 67 | const raw_ptr<ShelfNavigationWidget, ExperimentalAsh> |
| 68 | shelf_navigation_widget_; |
Yuki Awano | 2090b46 | 2021-06-08 01:33:07 | [diff] [blame] | 69 | const gfx::Rect clip_rect_; |
| 70 | }; |
| 71 | |
Wen-Chien Wang | 617c38a | 2021-10-07 10:23:50 | [diff] [blame] | 72 | // An observer that can be used to track the nudge animation state. Currently |
| 73 | // used in testing. |
| 74 | class NudgeAnimationObserver : public base::CheckedObserver { |
| 75 | public: |
| 76 | NudgeAnimationObserver() = default; |
| 77 | NudgeAnimationObserver(const NudgeAnimationObserver&) = delete; |
| 78 | NudgeAnimationObserver& operator=(const NudgeAnimationObserver&) = delete; |
| 79 | ~NudgeAnimationObserver() override = default; |
| 80 | |
| 81 | // Called when the nudge animation is started/ended. |
| 82 | virtual void NudgeAnimationStarted(HomeButton* home_button) = 0; |
| 83 | virtual void NudgeAnimationEnded(HomeButton* home_button) = 0; |
Wen-Chien Wang | 51a5d604d | 2022-05-10 18:18:01 | [diff] [blame] | 84 | |
| 85 | // Called when the nudge label is animated to fully shown. |
| 86 | virtual void NudgeLabelShown(HomeButton* home_button) = 0; |
Wen-Chien Wang | 617c38a | 2021-10-07 10:23:50 | [diff] [blame] | 87 | }; |
| 88 | |
Manu Cornet | c006633 | 2019-02-20 19:26:03 | [diff] [blame] | 89 | static const char kViewClassName[]; |
| 90 | |
Manu Cornet | 86aef98 | 2019-07-18 21:31:10 | [diff] [blame] | 91 | explicit HomeButton(Shelf* shelf); |
Peter Boström | 5fc1d31 | 2021-09-24 02:32:15 | [diff] [blame] | 92 | |
| 93 | HomeButton(const HomeButton&) = delete; |
| 94 | HomeButton& operator=(const HomeButton&) = delete; |
| 95 | |
Manu Cornet | f953d49 | 2019-06-27 05:56:51 | [diff] [blame] | 96 | ~HomeButton() override; |
James Cook | b0bf8e8 | 2017-04-09 17:01:44 | [diff] [blame] | 97 | |
Wen-Chien Wang | 51a5d604d | 2022-05-10 18:18:01 | [diff] [blame] | 98 | // views::View: |
| 99 | gfx::Size CalculatePreferredSize() const override; |
| 100 | void Layout() override; |
| 101 | |
Manu Cornet | e363aec | 2019-01-13 13:07:07 | [diff] [blame] | 102 | // views::Button: |
James Cook | b0bf8e8 | 2017-04-09 17:01:44 | [diff] [blame] | 103 | void OnGestureEvent(ui::GestureEvent* event) override; |
Manu Cornet | c006633 | 2019-02-20 19:26:03 | [diff] [blame] | 104 | const char* GetClassName() const override; |
Jan Wilken Dörrie | 85285b0 | 2021-03-11 23:38:47 | [diff] [blame] | 105 | std::u16string GetTooltipText(const gfx::Point& p) const override; |
James Cook | b0bf8e8 | 2017-04-09 17:01:44 | [diff] [blame] | 106 | |
Manu Cornet | 86aef98 | 2019-07-18 21:31:10 | [diff] [blame] | 107 | // ShelfButtonDelegate: |
| 108 | void OnShelfButtonAboutToRequestFocusFromTabTraversal(ShelfButton* button, |
| 109 | bool reverse) override; |
| 110 | void ButtonPressed(views::Button* sender, |
| 111 | const ui::Event& event, |
| 112 | views::InkDrop* ink_drop) override; |
Manu Cornet | 86aef98 | 2019-07-18 21:31:10 | [diff] [blame] | 113 | |
Toni Barzic | 705b8aa | 2023-05-24 01:50:10 | [diff] [blame] | 114 | // ShelfConfig::Observer: |
| 115 | void OnShelfConfigUpdated() override; |
| 116 | |
Michael Giuffrida | 01adeb07 | 2019-03-21 22:05:30 | [diff] [blame] | 117 | // Called when the availability of a long-press gesture may have changed, e.g. |
| 118 | // when Assistant becomes enabled. |
Yue Li | bcdb6aa | 2019-10-02 17:50:57 | [diff] [blame] | 119 | void OnAssistantAvailabilityChanged(); |
Michael Giuffrida | 01adeb07 | 2019-03-21 22:05:30 | [diff] [blame] | 120 | |
| 121 | // True if the app list is shown for the display containing this button. |
| 122 | bool IsShowingAppList() const; |
| 123 | |
Toni Barzic | 71ebb6fd | 2020-05-29 17:16:53 | [diff] [blame] | 124 | // Called when a locale change is detected. Updates the button tooltip and |
| 125 | // accessible name. |
| 126 | void HandleLocaleChange(); |
Manu Cornet | 1ed1f6b | 2019-06-14 17:25:53 | [diff] [blame] | 127 | |
Alex Newcomer | 030e706 | 2019-07-02 00:03:57 | [diff] [blame] | 128 | // Returns the display which contains this view. |
| 129 | int64_t GetDisplayId() const; |
| 130 | |
Yuki Awano | 2090b46 | 2021-06-08 01:33:07 | [diff] [blame] | 131 | // Clip rect of this view's widget will be removed during the life time of the |
| 132 | // returned ScopedNoClipRect. |
Daniel Cheng | b28e2af6 | 2022-01-13 23:56:21 | [diff] [blame] | 133 | [[nodiscard]] std::unique_ptr<ScopedNoClipRect> CreateScopedNoClipRect(); |
Yuki Awano | 2090b46 | 2021-06-08 01:33:07 | [diff] [blame] | 134 | |
Wen-Chien Wang | 51a5d604d | 2022-05-10 18:18:01 | [diff] [blame] | 135 | // Checks if the `nudge_label_` can be shown for the launcher nudge. |
| 136 | // NOTE: This must be called after `CreateNudgeLabel()`, where the |
| 137 | // `nudge_label_` is created. This is because whether the nudge can be shown |
| 138 | // depends on nudge_label_'s preferred size. |
| 139 | bool CanShowNudgeLabel() const; |
| 140 | |
Wen-Chien Wang | 617c38a | 2021-10-07 10:23:50 | [diff] [blame] | 141 | // Starts the launcher nudge animation. |
| 142 | void StartNudgeAnimation(); |
| 143 | |
Toni Barzic | 2e554738 | 2023-05-26 21:53:24 | [diff] [blame^] | 144 | // Sets the button's "toggled" state - the button is toggled when the bubble |
| 145 | // launcher is shown. |
| 146 | void SetToggled(bool toggled); |
| 147 | |
Wen-Chien Wang | 617c38a | 2021-10-07 10:23:50 | [diff] [blame] | 148 | void AddNudgeAnimationObserverForTest(NudgeAnimationObserver* observer); |
| 149 | void RemoveNudgeAnimationObserverForTest(NudgeAnimationObserver* observer); |
| 150 | |
Matthew Mourgos | d477282 | 2023-04-05 18:35:03 | [diff] [blame] | 151 | views::View* expandable_container_for_test() const { |
| 152 | return expandable_container_; |
| 153 | } |
| 154 | |
| 155 | views::Label* nudge_label_for_test() const { return nudge_label_; } |
| 156 | |
| 157 | views::ImageButton* quick_app_button_for_test() const { |
| 158 | return quick_app_button_; |
| 159 | } |
Wen-Chien Wang | 51a5d604d | 2022-05-10 18:18:01 | [diff] [blame] | 160 | |
James Cook | b0bf8e8 | 2017-04-09 17:01:44 | [diff] [blame] | 161 | protected: |
Manu Cornet | e363aec | 2019-01-13 13:07:07 | [diff] [blame] | 162 | // views::Button: |
Yulun Wu | 8924cebb | 2021-01-12 20:23:28 | [diff] [blame] | 163 | void OnThemeChanged() override; |
James Cook | b0bf8e8 | 2017-04-09 17:01:44 | [diff] [blame] | 164 | |
| 165 | private: |
Toni Barzic | 705b8aa | 2023-05-24 01:50:10 | [diff] [blame] | 166 | class ButtonImageView; |
| 167 | |
Wen-Chien Wang | 51a5d604d | 2022-05-10 18:18:01 | [diff] [blame] | 168 | // Creates `nudge_label_` for launcher nudge. |
| 169 | void CreateNudgeLabel(); |
| 170 | |
Matthew Mourgos | d477282 | 2023-04-05 18:35:03 | [diff] [blame] | 171 | // Creates the `expandable_container_` which holds either the `nudge_label_` |
| 172 | // or the `quick_app_button_`. |
| 173 | void CreateExpandableContainer(); |
| 174 | |
| 175 | // Creates the `quick_app_button_` to be shown next to the home button. |
| 176 | void CreateQuickAppButton(); |
| 177 | |
| 178 | // Called when the quick app button is pressed. |
| 179 | void QuickAppButtonPressed(); |
| 180 | |
Wen-Chien Wang | 51a5d604d | 2022-05-10 18:18:01 | [diff] [blame] | 181 | // Animation functions for launcher nudge. |
| 182 | void AnimateNudgeRipple(views::AnimationBuilder& builder); |
| 183 | void AnimateNudgeBounce(views::AnimationBuilder& builder); |
| 184 | void AnimateNudgeLabelSlideIn(views::AnimationBuilder& builder); |
| 185 | void AnimateNudgeLabelSlideOut(); |
| 186 | void AnimateNudgeLabelFadeOut(); |
| 187 | |
| 188 | // Callbacks for the nudge animation. |
| 189 | void OnNudgeAnimationStarted(); |
| 190 | void OnNudgeAnimationEnded(); |
| 191 | void OnLabelSlideInAnimationEnded(); |
| 192 | void OnLabelFadeOutAnimationEnded(); |
| 193 | |
| 194 | // Removes the nudge label from the view hierarchy. |
| 195 | void RemoveNudgeLabel(); |
| 196 | |
Matthew Mourgos | be9f2827 | 2023-04-13 17:45:45 | [diff] [blame] | 197 | // Removes the quick app button from the view hierarchy. |
| 198 | void RemoveQuickAppButton(); |
| 199 | |
Ahmed Mehfooz | 6509620f | 2019-05-21 20:35:12 | [diff] [blame] | 200 | // views::ViewTargeterDelegate: |
| 201 | bool DoesIntersectRect(const views::View* target, |
| 202 | const gfx::Rect& rect) const override; |
| 203 | |
Matthew Mourgos | d477282 | 2023-04-05 18:35:03 | [diff] [blame] | 204 | // ShellObserver: |
| 205 | void OnShellDestroying() override; |
| 206 | |
| 207 | // AppListModelProvider::Observer: |
| 208 | void OnActiveAppListModelsChanged(AppListModel* model, |
| 209 | SearchModel* search_model) override; |
| 210 | |
| 211 | // QuickAppAccessModel::Observer: |
Matthew Mourgos | be9f2827 | 2023-04-13 17:45:45 | [diff] [blame] | 212 | void OnQuickAppShouldShowChanged(bool quick_app_shown) override; |
| 213 | void OnQuickAppIconChanged() override; |
Matthew Mourgos | d477282 | 2023-04-05 18:35:03 | [diff] [blame] | 214 | |
Matthew Mourgos | 1f28632 | 2023-04-20 18:16:50 | [diff] [blame] | 215 | // Create and animate in the quick app button from behind the home button. |
| 216 | void AnimateQuickAppButtonIn(); |
| 217 | |
| 218 | // Animate out the quick app button, deleting the quick app button when |
| 219 | // completed. |
| 220 | void AnimateQuickAppButtonOut(); |
| 221 | |
| 222 | // Callback for the quick app button slide out animation. |
| 223 | void OnQuickAppButtonSlideOutDone(); |
| 224 | |
| 225 | // Returns a transform which will translate the child of the |
| 226 | // `expandable_container` to be placed behind the home button. |
| 227 | gfx::Transform GetTransformForContainerChildBehindHomeButton(); |
| 228 | |
| 229 | // Returns a clip rect which will clip the `expandable_container` to the |
| 230 | // bounds of the home button. |
| 231 | gfx::Rect GetExpandableContainerClipRectToHomeButton(); |
| 232 | |
Toni Barzic | 2e554738 | 2023-05-26 21:53:24 | [diff] [blame^] | 233 | const bool jelly_enabled_; |
| 234 | |
Matthew Mourgos | d477282 | 2023-04-05 18:35:03 | [diff] [blame] | 235 | base::ScopedObservation<QuickAppAccessModel, QuickAppAccessModel::Observer> |
| 236 | quick_app_model_observation_{this}; |
| 237 | |
| 238 | base::ScopedObservation<Shell, ShellObserver> shell_observation_{this}; |
| 239 | |
| 240 | base::ScopedObservation<AppListModelProvider, AppListModelProvider::Observer> |
| 241 | app_list_model_observation_{this}; |
| 242 | |
Arthur Sonzogni | 834e018f | 2023-04-22 10:20:02 | [diff] [blame] | 243 | const raw_ptr<Shelf, ExperimentalAsh> shelf_; |
Wen-Chien Wang | 3667df20 | 2021-09-30 20:08:23 | [diff] [blame] | 244 | |
Toni Barzic | 705b8aa | 2023-05-24 01:50:10 | [diff] [blame] | 245 | // The view that paints the home button content. In its own view to ensure |
| 246 | // the background is stacked above `expandable_container_`. |
| 247 | raw_ptr<ButtonImageView, ExperimentalAsh> button_image_view_ = nullptr; |
| 248 | |
| 249 | // The container of `nudge_label_` or `quick_app_button_`. This is also |
| 250 | // responsible for painting the background of the contents. This container can |
| 251 | // expand visually by animation. |
| 252 | raw_ptr<views::View, ExperimentalAsh> expandable_container_ = nullptr; |
| 253 | |
| 254 | // The app button which is shown next to the home button. Only shown when |
| 255 | // set by SetQuickApp(). |
| 256 | raw_ptr<views::ImageButton, ExperimentalAsh> quick_app_button_ = nullptr; |
| 257 | |
Michael Giuffrida | 01adeb07 | 2019-03-21 22:05:30 | [diff] [blame] | 258 | // The controller used to determine the button's behavior. |
Manu Cornet | f953d49 | 2019-06-27 05:56:51 | [diff] [blame] | 259 | HomeButtonController controller_; |
Wen-Chien Wang | 3667df20 | 2021-09-30 20:08:23 | [diff] [blame] | 260 | |
| 261 | // The ripple layer in the launcher nudge animation. Only exists during the |
| 262 | // nudge animation. |
Wen-Chien Wang | 51a5d604d | 2022-05-10 18:18:01 | [diff] [blame] | 263 | ui::LayerOwner nudge_ripple_layer_; |
| 264 | |
| 265 | // The label view and for launcher nudge animation. |
Arthur Sonzogni | 834e018f | 2023-04-22 10:20:02 | [diff] [blame] | 266 | raw_ptr<views::Label, ExperimentalAsh> nudge_label_ = nullptr; |
Wen-Chien Wang | 51a5d604d | 2022-05-10 18:18:01 | [diff] [blame] | 267 | |
Wen-Chien Wang | 51a5d604d | 2022-05-10 18:18:01 | [diff] [blame] | 268 | // The timer that counts down to hide the nudge_label_ from showing state. |
| 269 | base::OneShotTimer label_nudge_timer_; |
Wen-Chien Wang | 3667df20 | 2021-09-30 20:08:23 | [diff] [blame] | 270 | |
| 271 | // The delegate used by |nudge_ripple_layer_|. Only exists during the |
| 272 | // nudge animation. |
| 273 | std::unique_ptr<views::CircleLayerDelegate> ripple_layer_delegate_; |
| 274 | |
| 275 | std::unique_ptr<ScopedNoClipRect> scoped_no_clip_rect_; |
| 276 | |
Wen-Chien Wang | 617c38a | 2021-10-07 10:23:50 | [diff] [blame] | 277 | base::ObserverList<NudgeAnimationObserver> observers_; |
| 278 | |
Wen-Chien Wang | 3667df20 | 2021-09-30 20:08:23 | [diff] [blame] | 279 | base::WeakPtrFactory<HomeButton> weak_ptr_factory_{this}; |
James Cook | b0bf8e8 | 2017-04-09 17:01:44 | [diff] [blame] | 280 | }; |
| 281 | |
| 282 | } // namespace ash |
| 283 | |
Manu Cornet | f953d49 | 2019-06-27 05:56:51 | [diff] [blame] | 284 | #endif // ASH_SHELF_HOME_BUTTON_H_ |