app_list_presenter_impl.cc 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750
  1. // Copyright 2016 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/app_list/app_list_presenter_impl.h"
  5. #include <utility>
  6. #include "ash/app_list/app_list_controller_impl.h"
  7. #include "ash/app_list/app_list_metrics.h"
  8. #include "ash/app_list/app_list_presenter_event_filter.h"
  9. #include "ash/app_list/app_list_util.h"
  10. #include "ash/app_list/app_list_view_delegate.h"
  11. #include "ash/app_list/views/app_list_main_view.h"
  12. #include "ash/app_list/views/apps_container_view.h"
  13. #include "ash/app_list/views/contents_view.h"
  14. #include "ash/app_list/views/search_box_view.h"
  15. #include "ash/keyboard/ui/keyboard_ui_controller.h"
  16. #include "ash/public/cpp/app_list/app_list_features.h"
  17. #include "ash/public/cpp/app_list/app_list_switches.h"
  18. #include "ash/public/cpp/app_list/app_list_types.h"
  19. #include "ash/public/cpp/assistant/controller/assistant_ui_controller.h"
  20. #include "ash/public/cpp/metrics_util.h"
  21. #include "ash/public/cpp/pagination/pagination_model.h"
  22. #include "ash/public/cpp/shell_window_ids.h"
  23. #include "ash/session/session_controller_impl.h"
  24. #include "ash/shell.h"
  25. #include "ash/wm/container_finder.h"
  26. #include "base/bind.h"
  27. #include "base/callback_helpers.h"
  28. #include "base/containers/contains.h"
  29. #include "base/metrics/histogram_macros.h"
  30. #include "base/metrics/user_metrics.h"
  31. #include "chromeos/ash/services/assistant/public/cpp/assistant_enums.h"
  32. #include "third_party/abseil-cpp/absl/types/optional.h"
  33. #include "ui/aura/client/focus_client.h"
  34. #include "ui/aura/window.h"
  35. #include "ui/compositor/animation_throughput_reporter.h"
  36. #include "ui/compositor/layer.h"
  37. #include "ui/compositor/scoped_layer_animation_settings.h"
  38. #include "ui/display/screen.h"
  39. #include "ui/display/types/display_constants.h"
  40. #include "ui/gfx/geometry/transform.h"
  41. #include "ui/gfx/geometry/transform_util.h"
  42. #include "ui/gfx/presentation_feedback.h"
  43. #include "ui/views/controls/textfield/textfield.h"
  44. #include "ui/views/widget/widget.h"
  45. #include "ui/wm/core/transient_window_manager.h"
  46. #include "ui/wm/public/activation_client.h"
  47. namespace ash {
  48. namespace {
  49. using assistant::AssistantExitPoint;
  50. inline ui::Layer* GetLayer(views::Widget* widget) {
  51. return widget->GetNativeView()->layer();
  52. }
  53. // Callback from the compositor when it presented a valid frame. Used to
  54. // record UMA of input latency.
  55. void DidPresentCompositorFrame(base::TimeTicks event_time_stamp,
  56. bool is_showing,
  57. const gfx::PresentationFeedback& feedback) {
  58. const base::TimeTicks present_time = feedback.timestamp;
  59. if (present_time.is_null() || event_time_stamp.is_null() ||
  60. present_time < event_time_stamp) {
  61. return;
  62. }
  63. const base::TimeDelta input_latency = present_time - event_time_stamp;
  64. if (is_showing) {
  65. UMA_HISTOGRAM_TIMES("Apps.AppListShow.InputLatency", input_latency);
  66. } else {
  67. UMA_HISTOGRAM_TIMES("Apps.AppListHide.InputLatency", input_latency);
  68. }
  69. }
  70. // Whether the shelf is oriented on the side, not on the bottom.
  71. bool IsSideShelf(Shelf* shelf) {
  72. switch (shelf->alignment()) {
  73. case ShelfAlignment::kBottom:
  74. case ShelfAlignment::kBottomLocked:
  75. return false;
  76. case ShelfAlignment::kLeft:
  77. case ShelfAlignment::kRight:
  78. return true;
  79. }
  80. return false;
  81. }
  82. // Whether the shelf background type indicates that shelf has rounded corners.
  83. bool IsShelfBackgroundTypeWithRoundedCorners(
  84. ShelfBackgroundType background_type) {
  85. switch (background_type) {
  86. case ShelfBackgroundType::kDefaultBg:
  87. case ShelfBackgroundType::kAppList:
  88. case ShelfBackgroundType::kOverview:
  89. return true;
  90. case ShelfBackgroundType::kMaximized:
  91. case ShelfBackgroundType::kMaximizedWithAppList:
  92. case ShelfBackgroundType::kOobe:
  93. case ShelfBackgroundType::kHomeLauncher:
  94. case ShelfBackgroundType::kLogin:
  95. case ShelfBackgroundType::kLoginNonBlurredWallpaper:
  96. case ShelfBackgroundType::kInApp:
  97. return false;
  98. }
  99. }
  100. // Implicit animation observer that runs a scoped closure runner, and deletes
  101. // itself when the observed implicit animations complete.
  102. class CallbackRunnerLayerAnimationObserver
  103. : public ui::ImplicitAnimationObserver {
  104. public:
  105. explicit CallbackRunnerLayerAnimationObserver(
  106. base::ScopedClosureRunner closure_runner)
  107. : closure_runner_(std::move(closure_runner)) {}
  108. ~CallbackRunnerLayerAnimationObserver() override = default;
  109. // ui::ImplicitAnimationObserver:
  110. void OnImplicitAnimationsCompleted() override {
  111. closure_runner_.RunAndReset();
  112. delete this;
  113. }
  114. private:
  115. base::ScopedClosureRunner closure_runner_;
  116. };
  117. } // namespace
  118. constexpr std::array<int, 7>
  119. AppListPresenterImpl::kIdsOfContainersThatWontHideAppList;
  120. AppListPresenterImpl::AppListPresenterImpl(AppListControllerImpl* controller)
  121. : controller_(controller) {
  122. DCHECK(controller_);
  123. }
  124. AppListPresenterImpl::~AppListPresenterImpl() {
  125. // Ensures app list view goes before the controller since pagination model
  126. // lives in the controller and app list view would access it on destruction.
  127. if (view_) {
  128. view_->GetAppsPaginationModel()->RemoveObserver(this);
  129. if (view_->GetWidget())
  130. view_->GetWidget()->CloseNow();
  131. }
  132. CHECK(!views::WidgetObserver::IsInObserverList());
  133. }
  134. aura::Window* AppListPresenterImpl::GetWindow() const {
  135. return is_target_visibility_show_ && view_
  136. ? view_->GetWidget()->GetNativeWindow()
  137. : nullptr;
  138. }
  139. void AppListPresenterImpl::Show(AppListViewState preferred_state,
  140. int64_t display_id,
  141. base::TimeTicks event_time_stamp,
  142. absl::optional<AppListShowSource> show_source) {
  143. if (is_target_visibility_show_) {
  144. // Launcher is always visible on the internal display when home launcher is
  145. // enabled in tablet mode.
  146. if (Shell::Get()->IsInTabletMode() || display_id == GetDisplayId())
  147. return;
  148. Dismiss(event_time_stamp);
  149. }
  150. if (!Shell::Get()->GetRootWindowForDisplayId(display_id)) {
  151. LOG(ERROR) << "Root window does not exist for display: " << display_id;
  152. return;
  153. }
  154. // TODO(https://crbug.com/1307871): Remove this when the linked crash gets
  155. // diagnosed - the crash is possible if app list gets dismissed while being
  156. // shown. `showing_app_list_` in intended to catch this case.
  157. showing_app_list_ = true;
  158. is_target_visibility_show_ = true;
  159. OnVisibilityWillChange(GetTargetVisibility(), display_id);
  160. RequestPresentationTime(display_id, event_time_stamp);
  161. if (!view_) {
  162. AppListView* view = new AppListView(controller_);
  163. view->InitView(controller_->GetContainerForDisplayId(display_id));
  164. SetView(view);
  165. view_->GetWidget()->GetNativeWindow()->TrackOcclusionState();
  166. }
  167. controller_->UpdateLauncherContainer(display_id);
  168. // App list needs to know the new shelf layout in order to calculate its
  169. // UI layout when AppListView visibility changes.
  170. Shelf* shelf =
  171. Shelf::ForWindow(view_->GetWidget()->GetNativeView()->GetRootWindow());
  172. shelf->shelf_layout_manager()->UpdateAutoHideState();
  173. // Observe the shelf for changes to rounded corners.
  174. // If presenter is observing a shelf instance different than `shelf`, it's
  175. // because the app list view on the associated display is closing. It's safe
  176. // to remove this observation (given that shelf background changes should not
  177. // affect appearance of a closing app list view).
  178. shelf_observer_.Reset();
  179. shelf_observer_.Observe(shelf);
  180. // By setting us as a drag-and-drop recipient, the app list knows that we can
  181. // handle items. Do this on every show because |view_| can be reused after a
  182. // monitor is disconnected but that monitor's ShelfView and
  183. // ScrollableShelfView are deleted. https://crbug.com/1163332
  184. view_->SetDragAndDropHostOfCurrentAppList(
  185. shelf->shelf_widget()->GetDragAndDropHostForAppList());
  186. view_->SetShelfHasRoundedCorners(
  187. IsShelfBackgroundTypeWithRoundedCorners(shelf->GetBackgroundType()));
  188. std::unique_ptr<AppListView::ScopedAccessibilityAnnouncementLock>
  189. scoped_accessibility_lock;
  190. // App list view state accessibility alerts should be suppressed when the app
  191. // list view is shown by the assistant. The assistant UI should handle its
  192. // own accessibility notifications.
  193. if (show_source && *show_source == kAssistantEntryPoint) {
  194. scoped_accessibility_lock =
  195. std::make_unique<AppListView::ScopedAccessibilityAnnouncementLock>(
  196. view_);
  197. }
  198. // Save data about how and when we opened the app list for metrics when we
  199. // close it.
  200. last_open_source_ = show_source;
  201. last_open_time_ = base::Time::Now();
  202. view_->Show(preferred_state, IsSideShelf(shelf));
  203. SnapAppListBoundsToDisplayEdge();
  204. event_filter_ =
  205. std::make_unique<AppListPresenterEventFilter>(controller_, this, view_);
  206. controller_->ViewShown(display_id);
  207. showing_app_list_ = false;
  208. OnVisibilityChanged(GetTargetVisibility(), display_id);
  209. }
  210. void AppListPresenterImpl::Dismiss(base::TimeTicks event_time_stamp) {
  211. if (!is_target_visibility_show_)
  212. return;
  213. // If the app list target visibility is shown, there should be an existing
  214. // view.
  215. DCHECK(view_);
  216. // TODO(https://crbug.com/1307871): Remove this when the linked crash gets
  217. // diagnosed.
  218. CHECK(!showing_app_list_);
  219. is_target_visibility_show_ = false;
  220. RequestPresentationTime(GetDisplayId(), event_time_stamp);
  221. // Hide the active window if it is a transient descendant of |view_|'s widget.
  222. aura::Window* window = view_->GetWidget()->GetNativeWindow();
  223. aura::Window* active_window =
  224. ::wm::GetActivationClient(window->GetRootWindow())->GetActiveWindow();
  225. if (active_window) {
  226. aura::Window* transient_parent =
  227. ::wm::TransientWindowManager::GetOrCreate(active_window)
  228. ->transient_parent();
  229. while (transient_parent) {
  230. if (window == transient_parent) {
  231. active_window->Hide();
  232. break;
  233. }
  234. transient_parent =
  235. ::wm::TransientWindowManager::GetOrCreate(transient_parent)
  236. ->transient_parent();
  237. }
  238. }
  239. // The dismissal may have occurred in response to the app list losing
  240. // activation. Otherwise, our widget is currently active. When the animation
  241. // completes we'll hide the widget, changing activation. If a menu is shown
  242. // before the animation completes then the activation change triggers the menu
  243. // to close. By deactivating now we ensure there is no activation change when
  244. // the animation completes and any menus stay open.
  245. if (view_->GetWidget()->IsActive())
  246. view_->GetWidget()->Deactivate();
  247. event_filter_.reset();
  248. if (view_->search_box_view()->is_search_box_active()) {
  249. // Close the virtual keyboard before the app list view is dismissed.
  250. // Otherwise if the browser is behind the app list view, after the latter is
  251. // closed, IME is updated because of the changed focus. Consequently,
  252. // the virtual keyboard is hidden for the wrong IME instance, which may
  253. // bring troubles when restoring the virtual keyboard (see
  254. // https://crbug.com/944233).
  255. keyboard::KeyboardUIController::Get()->HideKeyboardExplicitlyBySystem();
  256. }
  257. controller_->ViewClosing();
  258. OnVisibilityWillChange(GetTargetVisibility(), GetDisplayId());
  259. if (!Shell::Get()->IsInTabletMode() && last_open_source_.has_value() &&
  260. last_open_time_.has_value())
  261. RecordAppListUserJourneyTime(last_open_source_.value(),
  262. base::Time::Now() - last_open_time_.value());
  263. last_open_source_.reset();
  264. last_open_time_.reset();
  265. if (!view_->GetWidget()->GetNativeWindow()->is_destroying())
  266. view_->SetState(AppListViewState::kClosed);
  267. view_->SetDragAndDropHostOfCurrentAppList(nullptr);
  268. base::RecordAction(base::UserMetricsAction("Launcher_Dismiss"));
  269. }
  270. void AppListPresenterImpl::SetViewVisibility(bool visible) {
  271. if (!view_)
  272. return;
  273. view_->OnAppListVisibilityWillChange(visible);
  274. view_->SetVisible(visible);
  275. view_->search_box_view()->SetVisible(visible);
  276. }
  277. bool AppListPresenterImpl::HandleCloseOpenFolder() {
  278. return is_target_visibility_show_ && view_ && view_->HandleCloseOpenFolder();
  279. }
  280. ShelfAction AppListPresenterImpl::ToggleAppList(
  281. int64_t display_id,
  282. AppListShowSource show_source,
  283. base::TimeTicks event_time_stamp) {
  284. bool request_fullscreen = show_source == kSearchKeyFullscreen ||
  285. show_source == kShelfButtonFullscreen;
  286. // Dismiss or show based on the target visibility because the show/hide
  287. // animation can be reversed.
  288. if (is_target_visibility_show_ && GetDisplayId() == display_id) {
  289. if (request_fullscreen) {
  290. if (view_->app_list_state() == AppListViewState::kPeeking) {
  291. view_->SetState(AppListViewState::kFullscreenAllApps);
  292. return SHELF_ACTION_APP_LIST_SHOWN;
  293. } else if (view_->app_list_state() == AppListViewState::kHalf) {
  294. view_->SetState(AppListViewState::kFullscreenSearch);
  295. return SHELF_ACTION_APP_LIST_SHOWN;
  296. }
  297. }
  298. Dismiss(event_time_stamp);
  299. return SHELF_ACTION_APP_LIST_DISMISSED;
  300. }
  301. Show(request_fullscreen ? AppListViewState::kFullscreenAllApps
  302. : AppListViewState::kPeeking,
  303. display_id, event_time_stamp, show_source);
  304. return SHELF_ACTION_APP_LIST_SHOWN;
  305. }
  306. void AppListPresenterImpl::UpdateForNewSortingOrder(
  307. const absl::optional<AppListSortOrder>& new_order,
  308. bool animate,
  309. base::OnceClosure update_position_closure) {
  310. if (!view_)
  311. return;
  312. base::OnceClosure done_closure;
  313. if (animate) {
  314. // The search box should ignore a11y events during the reorder animation
  315. // so that the announcement of app list reorder is made before that of
  316. // focus change.
  317. SetViewIgnoredForAccessibility(view_->search_box_view(), true);
  318. // Focus on the search box before starting the reorder animation to prevent
  319. // focus moving through app list items as they're being hidden for order
  320. // update animation.
  321. view_->search_box_view()->search_box()->RequestFocus();
  322. done_closure =
  323. base::BindOnce(&AppListPresenterImpl::OnAppListReorderAnimationDone,
  324. weak_ptr_factory_.GetWeakPtr());
  325. }
  326. view_->app_list_main_view()
  327. ->contents_view()
  328. ->apps_container_view()
  329. ->UpdateForNewSortingOrder(new_order, animate,
  330. std::move(update_position_closure),
  331. std::move(done_closure));
  332. }
  333. void AppListPresenterImpl::UpdateContinueSectionVisibility() {
  334. if (!view_)
  335. return;
  336. view_->app_list_main_view()
  337. ->contents_view()
  338. ->apps_container_view()
  339. ->UpdateContinueSectionVisibility();
  340. }
  341. bool AppListPresenterImpl::IsVisibleDeprecated() const {
  342. return controller_->IsVisible(GetDisplayId());
  343. }
  344. bool AppListPresenterImpl::IsAtLeastPartiallyVisible() const {
  345. const auto* window = GetWindow();
  346. return window &&
  347. window->GetOcclusionState() == aura::Window::OcclusionState::VISIBLE;
  348. }
  349. bool AppListPresenterImpl::GetTargetVisibility() const {
  350. return is_target_visibility_show_;
  351. }
  352. void AppListPresenterImpl::UpdateYPositionAndOpacity(float y_position_in_screen,
  353. float background_opacity) {
  354. if (!is_target_visibility_show_)
  355. return;
  356. if (view_)
  357. view_->UpdateYPositionAndOpacity(y_position_in_screen, background_opacity);
  358. }
  359. void AppListPresenterImpl::EndDragFromShelf(AppListViewState app_list_state) {
  360. if (view_)
  361. view_->EndDragFromShelf(app_list_state);
  362. }
  363. void AppListPresenterImpl::ProcessScrollOffset(
  364. const gfx::Point& location,
  365. const gfx::Vector2d& scroll_offset_vector) {
  366. if (view_)
  367. view_->HandleScroll(location, scroll_offset_vector, ui::ET_SCROLL);
  368. }
  369. void AppListPresenterImpl::ProcessMouseWheelOffset(
  370. const gfx::Point& location,
  371. const gfx::Vector2d& scroll_offset_vector) {
  372. if (view_)
  373. view_->HandleScroll(location, scroll_offset_vector, ui::ET_MOUSEWHEEL);
  374. }
  375. void AppListPresenterImpl::UpdateScaleAndOpacityForHomeLauncher(
  376. float scale,
  377. float opacity,
  378. absl::optional<TabletModeAnimationTransition> transition,
  379. UpdateHomeLauncherAnimationSettingsCallback callback) {
  380. if (!view_)
  381. return;
  382. ui::Layer* layer = view_->GetWidget()->GetNativeWindow()->layer();
  383. if (!Shell::Get()->IsInTabletMode()) {
  384. // In clamshell mode, set the opacity of the AppList immediately to
  385. // instantly hide it. Opacity of the AppList is reset when it is shown
  386. // again.
  387. layer->SetOpacity(opacity);
  388. return;
  389. }
  390. if (layer->GetAnimator()->is_animating()) {
  391. layer->GetAnimator()->StopAnimating();
  392. // Reset the animation metrics reporter when the animation is interrupted.
  393. view_->ResetTransitionMetricsReporter();
  394. }
  395. absl::optional<ui::ScopedLayerAnimationSettings> settings;
  396. if (!callback.is_null()) {
  397. settings.emplace(layer->GetAnimator());
  398. callback.Run(&settings.value());
  399. // Disable suggestion chips blur during animations to improve performance.
  400. base::ScopedClosureRunner blur_disabler =
  401. view_->app_list_main_view()
  402. ->contents_view()
  403. ->apps_container_view()
  404. ->DisableSuggestionChipsBlur();
  405. // The observer will delete itself when the animations are completed.
  406. settings->AddObserver(
  407. new CallbackRunnerLayerAnimationObserver(std::move(blur_disabler)));
  408. }
  409. // The animation metrics reporter will run for opacity and transform
  410. // animations separately - to avoid reporting duplicated values, add the
  411. // reported for transform animation only.
  412. layer->SetOpacity(opacity);
  413. absl::optional<ui::AnimationThroughputReporter> reporter;
  414. if (settings.has_value() && transition.has_value()) {
  415. view_->OnTabletModeAnimationTransitionNotified(*transition);
  416. reporter.emplace(settings->GetAnimator(),
  417. metrics_util::ForSmoothness(
  418. view_->GetStateTransitionMetricsReportCallback()));
  419. }
  420. gfx::Transform transform =
  421. gfx::GetScaleTransform(gfx::Rect(layer->size()).CenterPoint(), scale);
  422. layer->SetTransform(transform);
  423. }
  424. void AppListPresenterImpl::ShowEmbeddedAssistantUI(bool show) {
  425. if (view_)
  426. view_->app_list_main_view()->contents_view()->ShowEmbeddedAssistantUI(show);
  427. }
  428. bool AppListPresenterImpl::IsShowingEmbeddedAssistantUI() const {
  429. if (view_) {
  430. return view_->app_list_main_view()
  431. ->contents_view()
  432. ->IsShowingEmbeddedAssistantUI();
  433. }
  434. return false;
  435. }
  436. void AppListPresenterImpl::OnTabletModeChanged(bool started) {
  437. if (started) {
  438. if (GetTargetVisibility())
  439. view_->OnTabletModeChanged(true);
  440. } else {
  441. if (IsVisibleDeprecated())
  442. view_->OnTabletModeChanged(false);
  443. }
  444. }
  445. ////////////////////////////////////////////////////////////////////////////////
  446. // AppListPresenterImpl, private:
  447. void AppListPresenterImpl::SetView(AppListView* view) {
  448. DCHECK(view_ == nullptr);
  449. DCHECK(is_target_visibility_show_);
  450. view_ = view;
  451. views::Widget* widget = view_->GetWidget();
  452. widget->AddObserver(this);
  453. aura::client::GetFocusClient(widget->GetNativeView())->AddObserver(this);
  454. view_->GetAppsPaginationModel()->AddObserver(this);
  455. // Sync the |onscreen_keyboard_shown_| in case |view_| is not initiated when
  456. // the on-screen is shown.
  457. view_->set_onscreen_keyboard_shown(controller_->onscreen_keyboard_shown());
  458. }
  459. void AppListPresenterImpl::ResetView() {
  460. if (!view_)
  461. return;
  462. views::Widget* widget = view_->GetWidget();
  463. widget->RemoveObserver(this);
  464. GetLayer(widget)->GetAnimator()->RemoveObserver(this);
  465. aura::client::GetFocusClient(widget->GetNativeView())->RemoveObserver(this);
  466. view_->GetAppsPaginationModel()->RemoveObserver(this);
  467. view_ = nullptr;
  468. }
  469. int64_t AppListPresenterImpl::GetDisplayId() const {
  470. views::Widget* widget = view_ ? view_->GetWidget() : nullptr;
  471. if (!widget)
  472. return display::kInvalidDisplayId;
  473. return display::Screen::GetScreen()
  474. ->GetDisplayNearestView(widget->GetNativeView())
  475. .id();
  476. }
  477. void AppListPresenterImpl::OnVisibilityChanged(bool visible,
  478. int64_t display_id) {
  479. controller_->OnVisibilityChanged(visible, display_id);
  480. }
  481. void AppListPresenterImpl::OnVisibilityWillChange(bool visible,
  482. int64_t display_id) {
  483. controller_->OnVisibilityWillChange(visible, display_id);
  484. }
  485. void AppListPresenterImpl::OnClosed() {
  486. if (!is_target_visibility_show_)
  487. shelf_observer_.Reset();
  488. }
  489. ////////////////////////////////////////////////////////////////////////////////
  490. // AppListPresenterImpl, aura::client::FocusChangeObserver implementation:
  491. void AppListPresenterImpl::OnWindowFocused(aura::Window* gained_focus,
  492. aura::Window* lost_focus) {
  493. // Do not focus app list window in the Kiosk mode.
  494. if (Shell::Get()->session_controller()->IsRunningInAppMode())
  495. return;
  496. if (!view_ || !is_target_visibility_show_)
  497. return;
  498. int gained_focus_container_id = kShellWindowId_Invalid;
  499. if (gained_focus) {
  500. gained_focus_container_id = gained_focus->GetId();
  501. const aura::Window* container = ash::GetContainerForWindow(gained_focus);
  502. if (container)
  503. gained_focus_container_id = container->GetId();
  504. }
  505. aura::Window* applist_window = view_->GetWidget()->GetNativeView();
  506. const aura::Window* applist_container = applist_window->parent();
  507. // An AppList dialog window, or a child window of the system tray, may
  508. // take focus from the AppList window. Don't consider this a visibility
  509. // change since the app list is still visible for the most part.
  510. const bool gained_focus_hides_app_list =
  511. gained_focus_container_id != kShellWindowId_Invalid &&
  512. !base::Contains(kIdsOfContainersThatWontHideAppList,
  513. gained_focus_container_id);
  514. const bool app_list_gained_focus = applist_window->Contains(gained_focus) ||
  515. applist_container->Contains(gained_focus);
  516. const bool app_list_lost_focus =
  517. gained_focus ? gained_focus_hides_app_list
  518. : (lost_focus && applist_container->Contains(lost_focus));
  519. // Either the app list has just gained focus, in which case it is already
  520. // visible or will very soon be, or it has neither gained nor lost focus
  521. // and it might still be partially visible just because the focused window
  522. // doesn't occlude it completely.
  523. const bool visible = app_list_gained_focus ||
  524. (IsAtLeastPartiallyVisible() && !app_list_lost_focus);
  525. if (Shell::Get()->IsInTabletMode()) {
  526. if (visible != controller_->IsVisible(GetDisplayId())) {
  527. if (app_list_gained_focus)
  528. view_->OnHomeLauncherGainingFocusWithoutAnimation();
  529. OnVisibilityChanged(visible, GetDisplayId());
  530. } else {
  531. // In tablet mode, when Assistant UI lost focus after other new App window
  532. // opened, we should reset the view.
  533. if (app_list_lost_focus && IsShowingEmbeddedAssistantUI())
  534. view_->Back();
  535. }
  536. }
  537. if (app_list_gained_focus)
  538. base::RecordAction(base::UserMetricsAction("AppList_WindowFocused"));
  539. if (app_list_lost_focus && !Shell::Get()->IsInTabletMode())
  540. Dismiss(base::TimeTicks());
  541. }
  542. ////////////////////////////////////////////////////////////////////////////////
  543. // AppListPresenterImpl, ui::ImplicitAnimationObserver implementation:
  544. void AppListPresenterImpl::OnImplicitAnimationsCompleted() {
  545. StopObservingImplicitAnimations();
  546. // This class observes the closing animation only.
  547. OnVisibilityChanged(GetTargetVisibility(), GetDisplayId());
  548. if (is_target_visibility_show_) {
  549. view_->GetWidget()->Activate();
  550. } else {
  551. // Hide the widget so it can be re-shown without re-creating it.
  552. view_->GetWidget()->Hide();
  553. OnClosed();
  554. }
  555. }
  556. ////////////////////////////////////////////////////////////////////////////////
  557. // AppListPresenterImpl, views::WidgetObserver implementation:
  558. void AppListPresenterImpl::OnWidgetDestroying(views::Widget* widget) {
  559. DCHECK_EQ(view_->GetWidget(), widget);
  560. if (is_target_visibility_show_)
  561. Dismiss(base::TimeTicks());
  562. ResetView();
  563. }
  564. void AppListPresenterImpl::OnWidgetDestroyed(views::Widget* widget) {
  565. OnClosed();
  566. }
  567. void AppListPresenterImpl::OnWidgetVisibilityChanged(views::Widget* widget,
  568. bool visible) {
  569. DCHECK_EQ(view_->GetWidget(), widget);
  570. OnVisibilityChanged(visible, GetDisplayId());
  571. }
  572. ////////////////////////////////////////////////////////////////////////////////
  573. // AppListPresenterImpl, PaginationModelObserver implementation:
  574. void AppListPresenterImpl::TotalPagesChanged(int previous_page_count,
  575. int new_page_count) {}
  576. void AppListPresenterImpl::SelectedPageChanged(int old_selected,
  577. int new_selected) {
  578. current_apps_page_ = new_selected;
  579. }
  580. void AppListPresenterImpl::RequestPresentationTime(
  581. int64_t display_id,
  582. base::TimeTicks event_time_stamp) {
  583. if (event_time_stamp.is_null())
  584. return;
  585. aura::Window* root_window =
  586. Shell::Get()->GetRootWindowForDisplayId(display_id);
  587. if (!root_window)
  588. return;
  589. ui::Compositor* compositor = root_window->layer()->GetCompositor();
  590. if (!compositor)
  591. return;
  592. compositor->RequestPresentationTimeForNextFrame(
  593. base::BindOnce(&DidPresentCompositorFrame, event_time_stamp,
  594. is_target_visibility_show_));
  595. }
  596. ////////////////////////////////////////////////////////////////////////////////
  597. // display::DisplayObserver implementation:
  598. void AppListPresenterImpl::OnDisplayMetricsChanged(
  599. const display::Display& display,
  600. uint32_t changed_metrics) {
  601. if (!GetWindow())
  602. return;
  603. view_->OnParentWindowBoundsChanged();
  604. SnapAppListBoundsToDisplayEdge();
  605. }
  606. void AppListPresenterImpl::OnShelfShuttingDown() {
  607. shelf_observer_.Reset();
  608. if (view_)
  609. view_->SetDragAndDropHostOfCurrentAppList(nullptr);
  610. }
  611. void AppListPresenterImpl::OnBackgroundTypeChanged(
  612. ShelfBackgroundType background_type,
  613. AnimationChangeType change_type) {
  614. view_->SetShelfHasRoundedCorners(
  615. IsShelfBackgroundTypeWithRoundedCorners(background_type));
  616. }
  617. void AppListPresenterImpl::SnapAppListBoundsToDisplayEdge() {
  618. CHECK(view_ && view_->GetWidget());
  619. aura::Window* window = view_->GetWidget()->GetNativeView();
  620. const gfx::Rect bounds =
  621. controller_->SnapBoundsToDisplayEdge(window->bounds());
  622. window->SetBounds(bounds);
  623. }
  624. void AppListPresenterImpl::OnAppListReorderAnimationDone() {
  625. if (!view_)
  626. return;
  627. // Re-enable the search box to handle a11y events.
  628. SetViewIgnoredForAccessibility(view_->search_box_view(), false);
  629. }
  630. } // namespace ash