Commit 26c049d1 authored by Andrew Xu's avatar Andrew Xu Committed by Commit Bot

Hiding the drag handle of app list depending on MRU windows

Implement a new UI feature: hiding the drag handle of app list
in tablet mode if there is no activatable window. The main strategy
is listed as following:

(1) OnWindowDestroyed event should be listened to. Considering
about the situation that closing the browser window through shelf
while home launcher is visible. Hence we need to observe all windows
from MRU list in app list code, which is pretty much what
MruWindowTracker does. So the app list controller should observe
MruWindowTracker and hide/show the drag handle when a window is closed.

(2) When the gesture makes the app list show, the home launcher
gesture handler should notify the app list controller when animation
ends. The latter checks MRU window list then hides/shows the handle.

Test: ash_unittests
Bug: 923089
Change-Id: I9d9d60e705326cfe2ff90c59da2cccb18db87942
Reviewed-on: https://chromium-review.googlesource.com/c/1445111
Commit-Queue: Andrew Xu <andrewxu@chromium.org>
Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#630039}
parent 8ca1a4de
...@@ -1535,6 +1535,7 @@ test("ash_unittests") { ...@@ -1535,6 +1535,7 @@ test("ash_unittests") {
"accessibility/touch_exploration_controller_unittest.cc", "accessibility/touch_exploration_controller_unittest.cc",
"accessibility/touch_exploration_manager_unittest.cc", "accessibility/touch_exploration_manager_unittest.cc",
"app_launch_unittest.cc", "app_launch_unittest.cc",
"app_list/app_list_controller_impl_unittest.cc",
"app_list/app_list_presenter_delegate_unittest.cc", "app_list/app_list_presenter_delegate_unittest.cc",
"app_list/app_list_unittest.cc", "app_list/app_list_unittest.cc",
"app_list/home_launcher_gesture_handler_unittest.cc", "app_list/home_launcher_gesture_handler_unittest.cc",
......
...@@ -27,7 +27,6 @@ ...@@ -27,7 +27,6 @@
#include "ash/shell.h" #include "ash/shell.h"
#include "ash/voice_interaction/voice_interaction_controller.h" #include "ash/voice_interaction/voice_interaction_controller.h"
#include "ash/wallpaper/wallpaper_controller.h" #include "ash/wallpaper/wallpaper_controller.h"
#include "ash/wm/mru_window_tracker.h"
#include "ash/wm/overview/overview_controller.h" #include "ash/wm/overview/overview_controller.h"
#include "ash/wm/splitview/split_view_controller.h" #include "ash/wm/splitview/split_view_controller.h"
#include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h"
...@@ -86,18 +85,10 @@ AppListControllerImpl::AppListControllerImpl() ...@@ -86,18 +85,10 @@ AppListControllerImpl::AppListControllerImpl()
Shell::Get()->voice_interaction_controller()->AddLocalObserver(this); Shell::Get()->voice_interaction_controller()->AddLocalObserver(this);
Shell::Get()->window_tree_host_manager()->AddObserver(this); Shell::Get()->window_tree_host_manager()->AddObserver(this);
Shell::Get()->mru_window_tracker()->AddObserver(this);
} }
AppListControllerImpl::~AppListControllerImpl() { AppListControllerImpl::~AppListControllerImpl() {}
Shell::Get()->window_tree_host_manager()->RemoveObserver(this);
keyboard::KeyboardController::Get()->RemoveObserver(this);
Shell::Get()->RemoveShellObserver(this);
Shell::Get()->wallpaper_controller()->RemoveObserver(this);
Shell::Get()->tablet_mode_controller()->RemoveObserver(this);
Shell::Get()->session_controller()->RemoveObserver(this);
Shell::Get()->voice_interaction_controller()->RemoveLocalObserver(this);
model_.RemoveObserver(this);
}
void AppListControllerImpl::SetClient(mojom::AppListClientPtr client_ptr) { void AppListControllerImpl::SetClient(mojom::AppListClientPtr client_ptr) {
client_ = std::move(client_ptr); client_ = std::move(client_ptr);
...@@ -451,6 +442,10 @@ void AppListControllerImpl::Show(int64_t display_id, ...@@ -451,6 +442,10 @@ void AppListControllerImpl::Show(int64_t display_id,
} }
presenter_.Show(display_id, event_time_stamp); presenter_.Show(display_id, event_time_stamp);
// AppListControllerImpl::Show is called in ash at the first time of showing
// app list view. So check whether the expand arrow view should be visible.
UpdateExpandArrowVisibility();
} }
void AppListControllerImpl::UpdateYPositionAndOpacity( void AppListControllerImpl::UpdateYPositionAndOpacity(
...@@ -545,6 +540,20 @@ void AppListControllerImpl::OnOverviewModeEndingAnimationComplete( ...@@ -545,6 +540,20 @@ void AppListControllerImpl::OnOverviewModeEndingAnimationComplete(
use_slide_to_exit_overview_); use_slide_to_exit_overview_);
} }
// Stop observing at the beginning of ~Shell to avoid unnecessary work during
// Shell shutdown.
void AppListControllerImpl::OnShellDestroying() {
Shell::Get()->window_tree_host_manager()->RemoveObserver(this);
keyboard::KeyboardController::Get()->RemoveObserver(this);
Shell::Get()->RemoveShellObserver(this);
Shell::Get()->wallpaper_controller()->RemoveObserver(this);
Shell::Get()->tablet_mode_controller()->RemoveObserver(this);
Shell::Get()->session_controller()->RemoveObserver(this);
Shell::Get()->voice_interaction_controller()->RemoveLocalObserver(this);
Shell::Get()->mru_window_tracker()->RemoveObserver(this);
model_.RemoveObserver(this);
}
void AppListControllerImpl::OnTabletModeStarted() { void AppListControllerImpl::OnTabletModeStarted() {
if (presenter_.GetTargetVisibility()) { if (presenter_.GetTargetVisibility()) {
DCHECK(IsVisible()); DCHECK(IsVisible());
...@@ -614,6 +623,10 @@ void AppListControllerImpl::OnDisplayConfigurationChanged() { ...@@ -614,6 +623,10 @@ void AppListControllerImpl::OnDisplayConfigurationChanged() {
ShowHomeLauncher(); ShowHomeLauncher();
} }
void AppListControllerImpl::OnWindowUntracked(aura::Window* untracked_window) {
UpdateExpandArrowVisibility();
}
void AppListControllerImpl::Back() { void AppListControllerImpl::Back() {
presenter_.GetView()->Back(); presenter_.GetView()->Back();
} }
...@@ -677,6 +690,23 @@ bool AppListControllerImpl::IsShowingEmbeddedAssistantUI() const { ...@@ -677,6 +690,23 @@ bool AppListControllerImpl::IsShowingEmbeddedAssistantUI() const {
return presenter_.IsShowingEmbeddedAssistantUI(); return presenter_.IsShowingEmbeddedAssistantUI();
} }
void AppListControllerImpl::UpdateExpandArrowVisibility() {
bool should_show = false;
// Hide the expand arrow view when tablet mode is enabled and there is no
// activatable window.
if (IsTabletMode()) {
should_show = !ash::Shell::Get()
->mru_window_tracker()
->BuildWindowForCycleList()
.empty();
} else {
should_show = true;
}
presenter_.SetExpandArrowViewVisibility(should_show);
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Methods of |client_|: // Methods of |client_|:
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "ash/session/session_observer.h" #include "ash/session/session_observer.h"
#include "ash/shell_observer.h" #include "ash/shell_observer.h"
#include "ash/wallpaper/wallpaper_controller_observer.h" #include "ash/wallpaper/wallpaper_controller_observer.h"
#include "ash/wm/mru_window_tracker.h"
#include "ash/wm/tablet_mode/tablet_mode_observer.h" #include "ash/wm/tablet_mode/tablet_mode_observer.h"
#include "base/observer_list.h" #include "base/observer_list.h"
#include "components/sync/model/string_ordinal.h" #include "components/sync/model/string_ordinal.h"
...@@ -54,7 +55,8 @@ class ASH_EXPORT AppListControllerImpl ...@@ -54,7 +55,8 @@ class ASH_EXPORT AppListControllerImpl
public keyboard::KeyboardControllerObserver, public keyboard::KeyboardControllerObserver,
public WallpaperControllerObserver, public WallpaperControllerObserver,
public DefaultVoiceInteractionObserver, public DefaultVoiceInteractionObserver,
public WindowTreeHostManager::Observer { public WindowTreeHostManager::Observer,
public ash::MruWindowTracker::Observer {
public: public:
using AppListItemMetadataPtr = mojom::AppListItemMetadataPtr; using AppListItemMetadataPtr = mojom::AppListItemMetadataPtr;
using SearchResultMetadataPtr = mojom::SearchResultMetadataPtr; using SearchResultMetadataPtr = mojom::SearchResultMetadataPtr;
...@@ -206,6 +208,7 @@ class ASH_EXPORT AppListControllerImpl ...@@ -206,6 +208,7 @@ class ASH_EXPORT AppListControllerImpl
void OnOverviewModeStarting() override; void OnOverviewModeStarting() override;
void OnOverviewModeEnding(OverviewSession* overview_session) override; void OnOverviewModeEnding(OverviewSession* overview_session) override;
void OnOverviewModeEndingAnimationComplete(bool canceled) override; void OnOverviewModeEndingAnimationComplete(bool canceled) override;
void OnShellDestroying() override;
// TabletModeObserver: // TabletModeObserver:
void OnTabletModeStarted() override; void OnTabletModeStarted() override;
...@@ -227,6 +230,9 @@ class ASH_EXPORT AppListControllerImpl ...@@ -227,6 +230,9 @@ class ASH_EXPORT AppListControllerImpl
// WindowTreeHostManager::Observer: // WindowTreeHostManager::Observer:
void OnDisplayConfigurationChanged() override; void OnDisplayConfigurationChanged() override;
// MruWindowTracker::Observer:
void OnWindowUntracked(aura::Window* untracked_window) override;
bool onscreen_keyboard_shown() const { return onscreen_keyboard_shown_; } bool onscreen_keyboard_shown() const { return onscreen_keyboard_shown_; }
// Performs the 'back' action for the active page. // Performs the 'back' action for the active page.
...@@ -245,6 +251,9 @@ class ASH_EXPORT AppListControllerImpl ...@@ -245,6 +251,9 @@ class ASH_EXPORT AppListControllerImpl
// Returns current visibility of the Assistant page. // Returns current visibility of the Assistant page.
bool IsShowingEmbeddedAssistantUI() const; bool IsShowingEmbeddedAssistantUI() const;
// Update the visibility of expand arrow view.
void UpdateExpandArrowVisibility();
private: private:
syncer::StringOrdinal GetOemFolderPos(); syncer::StringOrdinal GetOemFolderPos();
std::unique_ptr<app_list::AppListItem> CreateAppListItem( std::unique_ptr<app_list::AppListItem> CreateAppListItem(
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/app_list/app_list_controller_impl.h"
#include "ash/app_list/home_launcher_gesture_handler.h"
#include "ash/app_list/views/app_list_main_view.h"
#include "ash/app_list/views/app_list_view.h"
#include "ash/app_list/views/contents_view.h"
#include "ash/app_list/views/expand_arrow_view.h"
#include "ash/shell.h"
#include "ash/test/ash_test_base.h"
#include "ash/wm/tablet_mode/tablet_mode_controller.h"
#include "ash/wm/window_state.h"
#include "ash/wm/window_util.h"
namespace ash {
namespace {
bool IsTabletMode() {
return Shell::Get()
->tablet_mode_controller()
->IsTabletModeWindowManagerEnabled();
}
bool GetExpandArrowViewVisibility() {
return Shell::Get()
->app_list_controller()
->presenter()
->GetView()
->app_list_main_view()
->contents_view()
->expand_arrow_view()
->visible();
}
} // namespace
class AppListControllerImplTest : public AshTestBase {
public:
AppListControllerImplTest() = default;
~AppListControllerImplTest() override = default;
std::unique_ptr<aura::Window> CreateTestWindow() {
return AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400));
}
private:
DISALLOW_COPY_AND_ASSIGN(AppListControllerImplTest);
};
// Hide the expand arrow view in tablet mode when there is no activatable window
// (see https://crbug.com/923089).
TEST_F(AppListControllerImplTest, UpdateExpandArrowViewVisibility) {
// Turn on the tablet mode.
Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
EXPECT_TRUE(IsTabletMode());
// No activatable windows. So hide the expand arrow view.
EXPECT_FALSE(GetExpandArrowViewVisibility());
std::unique_ptr<aura::Window> w1(CreateTestWindow());
std::unique_ptr<aura::Window> w2(CreateTestWindow());
// Activate w1 then press home launcher button. Expand arrow view should show
// because w1 still exists.
wm::ActivateWindow(w1.get());
Shell::Get()
->app_list_controller()
->home_launcher_gesture_handler()
->ShowHomeLauncher(display::Screen::GetScreen()->GetPrimaryDisplay());
EXPECT_EQ(mojom::WindowStateType::MINIMIZED,
wm::GetWindowState(w1.get())->GetStateType());
EXPECT_TRUE(GetExpandArrowViewVisibility());
// Activate w2 then close w1. w2 still exists so expand arrow view shows.
wm::ActivateWindow(w2.get());
w1.reset();
EXPECT_TRUE(GetExpandArrowViewVisibility());
// No activatable windows. Hide the expand arrow view.
w2.reset();
EXPECT_FALSE(GetExpandArrowViewVisibility());
}
} // namespace ash
...@@ -475,6 +475,9 @@ void HomeLauncherGestureHandler::OnImplicitAnimationsCompleted() { ...@@ -475,6 +475,9 @@ void HomeLauncherGestureHandler::OnImplicitAnimationsCompleted() {
window2_->ResetOpacityAndTransform(); window2_->ResetOpacityAndTransform();
if (is_final_state_show) { if (is_final_state_show) {
// Show or hide the expand arrow view.
app_list_controller_->UpdateExpandArrowVisibility();
std::vector<aura::Window*> windows_to_hide_minimize; std::vector<aura::Window*> windows_to_hide_minimize;
windows_to_hide_minimize.push_back(GetWindow1()); windows_to_hide_minimize.push_back(GetWindow1());
......
...@@ -285,6 +285,13 @@ bool AppListPresenterImpl::IsShowingEmbeddedAssistantUI() const { ...@@ -285,6 +285,13 @@ bool AppListPresenterImpl::IsShowingEmbeddedAssistantUI() const {
return false; return false;
} }
void AppListPresenterImpl::SetExpandArrowViewVisibility(bool show) {
if (view_) {
view_->app_list_main_view()->contents_view()->SetExpandArrowViewVisibility(
show);
}
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// AppListPresenterImpl, private: // AppListPresenterImpl, private:
......
...@@ -112,6 +112,9 @@ class APP_LIST_PRESENTER_EXPORT AppListPresenterImpl ...@@ -112,6 +112,9 @@ class APP_LIST_PRESENTER_EXPORT AppListPresenterImpl
// Returns current visibility of the Assistant page. // Returns current visibility of the Assistant page.
bool IsShowingEmbeddedAssistantUI() const; bool IsShowingEmbeddedAssistantUI() const;
// Show/hide the expand arrow view button.
void SetExpandArrowViewVisibility(bool show);
private: private:
// Sets the app list view and attempts to show it. // Sets the app list view and attempts to show it.
void SetView(AppListView* view); void SetView(AppListView* view);
......
...@@ -621,6 +621,13 @@ float ContentsView::GetAppListMainViewScale() const { ...@@ -621,6 +621,13 @@ float ContentsView::GetAppListMainViewScale() const {
return app_list_view_->app_list_main_view()->GetTransform().Scale2d().x(); return app_list_view_->app_list_main_view()->GetTransform().Scale2d().x();
} }
void ContentsView::SetExpandArrowViewVisibility(bool show) {
if (expand_arrow_view_->visible() == show)
return;
expand_arrow_view_->SetVisible(show);
}
bool ContentsView::ShouldLayoutPage(AppListPage* page, bool ContentsView::ShouldLayoutPage(AppListPage* page,
ash::AppListState current_state, ash::AppListState current_state,
ash::AppListState target_state) const { ash::AppListState target_state) const {
......
...@@ -178,6 +178,10 @@ class APP_LIST_EXPORT ContentsView : public views::View, ...@@ -178,6 +178,10 @@ class APP_LIST_EXPORT ContentsView : public views::View,
// is also applied to search box window. // is also applied to search box window.
float GetAppListMainViewScale() const; float GetAppListMainViewScale() const;
// Show/hide the expand arrow view button when contents view is in fullscreen
// and tablet mode is enabled.
void SetExpandArrowViewVisibility(bool show);
private: private:
// Sets the active launcher page, accounting for whether the change is for // Sets the active launcher page, accounting for whether the change is for
// search results. // search results.
......
...@@ -711,6 +711,9 @@ Shell::Shell(std::unique_ptr<ShellDelegate> shell_delegate, ...@@ -711,6 +711,9 @@ Shell::Shell(std::unique_ptr<ShellDelegate> shell_delegate,
Shell::~Shell() { Shell::~Shell() {
TRACE_EVENT0("shutdown", "ash::Shell::Destructor"); TRACE_EVENT0("shutdown", "ash::Shell::Destructor");
for (auto& observer : shell_observers_)
observer.OnShellDestroying();
// Wayland depends upon some ash specific objects. Destroy it early on. // Wayland depends upon some ash specific objects. Destroy it early on.
wayland_server_controller_.reset(); wayland_server_controller_.reset();
...@@ -1099,9 +1102,6 @@ void Shell::Init( ...@@ -1099,9 +1102,6 @@ void Shell::Init(
voice_interaction_controller_ = voice_interaction_controller_ =
std::make_unique<VoiceInteractionController>(); std::make_unique<VoiceInteractionController>();
// |app_list_controller_| is put after |tablet_mode_controller_| as the former
// uses the latter in constructor.
app_list_controller_ = std::make_unique<AppListControllerImpl>();
shelf_controller_ = std::make_unique<ShelfController>(); shelf_controller_ = std::make_unique<ShelfController>();
magnifier_key_scroll_handler_ = MagnifierKeyScroller::CreateHandler(); magnifier_key_scroll_handler_ = MagnifierKeyScroller::CreateHandler();
...@@ -1176,6 +1176,10 @@ void Shell::Init( ...@@ -1176,6 +1176,10 @@ void Shell::Init(
magnification_controller_ = std::make_unique<MagnificationController>(); magnification_controller_ = std::make_unique<MagnificationController>();
mru_window_tracker_ = std::make_unique<MruWindowTracker>(); mru_window_tracker_ = std::make_unique<MruWindowTracker>();
// |tablet_mode_controller_| and |mru_window_tracker_| are put before
// |app_list_controller_| as they are used in constructor.
app_list_controller_ = std::make_unique<AppListControllerImpl>();
autoclick_controller_ = std::make_unique<AutoclickController>(); autoclick_controller_ = std::make_unique<AutoclickController>();
high_contrast_controller_.reset(new HighContrastController); high_contrast_controller_.reset(new HighContrastController);
......
...@@ -80,6 +80,9 @@ class ASH_EXPORT ShellObserver { ...@@ -80,6 +80,9 @@ class ASH_EXPORT ShellObserver {
// Called at the end of Shell::Init. // Called at the end of Shell::Init.
virtual void OnShellInitialized() {} virtual void OnShellInitialized() {}
// Called at the beginning of ~Shell.
virtual void OnShellDestroying() {}
// Called near the end of ~Shell. Shell::Get() still returns the Shell, but // Called near the end of ~Shell. Shell::Get() still returns the Shell, but
// most of Shell's state has been deleted. // most of Shell's state has been deleted.
virtual void OnShellDestroyed() {} virtual void OnShellDestroyed() {}
......
...@@ -144,6 +144,14 @@ void MruWindowTracker::SetIgnoreActivations(bool ignore) { ...@@ -144,6 +144,14 @@ void MruWindowTracker::SetIgnoreActivations(bool ignore) {
SetActiveWindow(wm::GetActiveWindow()); SetActiveWindow(wm::GetActiveWindow());
} }
void MruWindowTracker::AddObserver(Observer* observer) {
observers_.AddObserver(observer);
}
void MruWindowTracker::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// MruWindowTracker, private: // MruWindowTracker, private:
...@@ -174,6 +182,9 @@ void MruWindowTracker::OnWindowDestroyed(aura::Window* window) { ...@@ -174,6 +182,9 @@ void MruWindowTracker::OnWindowDestroyed(aura::Window* window) {
// else we may end up with a deleted window in |mru_windows_|. // else we may end up with a deleted window in |mru_windows_|.
base::Erase(mru_windows_, window); base::Erase(mru_windows_, window);
window->RemoveObserver(this); window->RemoveObserver(this);
for (auto& observer : observers_)
observer.OnWindowUntracked(window);
} }
} // namespace ash } // namespace ash
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "ash/ash_export.h" #include "ash/ash_export.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/observer_list.h"
#include "ui/aura/window_observer.h" #include "ui/aura/window_observer.h"
#include "ui/wm/public/activation_change_observer.h" #include "ui/wm/public/activation_change_observer.h"
...@@ -21,6 +22,12 @@ class ASH_EXPORT MruWindowTracker : public ::wm::ActivationChangeObserver, ...@@ -21,6 +22,12 @@ class ASH_EXPORT MruWindowTracker : public ::wm::ActivationChangeObserver,
public: public:
using WindowList = std::vector<aura::Window*>; using WindowList = std::vector<aura::Window*>;
class Observer : public base::CheckedObserver {
public:
// Invoked when a tracked window is destroyed,
virtual void OnWindowUntracked(aura::Window* untracked_window) {}
};
MruWindowTracker(); MruWindowTracker();
~MruWindowTracker() override; ~MruWindowTracker() override;
...@@ -44,6 +51,10 @@ class ASH_EXPORT MruWindowTracker : public ::wm::ActivationChangeObserver, ...@@ -44,6 +51,10 @@ class ASH_EXPORT MruWindowTracker : public ::wm::ActivationChangeObserver,
// windows to the front of the MRU window list. // windows to the front of the MRU window list.
void SetIgnoreActivations(bool ignore); void SetIgnoreActivations(bool ignore);
// Add/Remove observers.
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
private: private:
// Updates the mru_windows_ list to insert/move |active_window| at/to the // Updates the mru_windows_ list to insert/move |active_window| at/to the
// front. // front.
...@@ -61,6 +72,8 @@ class ASH_EXPORT MruWindowTracker : public ::wm::ActivationChangeObserver, ...@@ -61,6 +72,8 @@ class ASH_EXPORT MruWindowTracker : public ::wm::ActivationChangeObserver,
// through, sorted such that the most recently used window comes last. // through, sorted such that the most recently used window comes last.
std::vector<aura::Window*> mru_windows_; std::vector<aura::Window*> mru_windows_;
base::ObserverList<Observer, true> observers_;
bool ignore_window_activations_ = false; bool ignore_window_activations_ = false;
DISALLOW_COPY_AND_ASSIGN(MruWindowTracker); DISALLOW_COPY_AND_ASSIGN(MruWindowTracker);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment