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") {
"accessibility/touch_exploration_controller_unittest.cc",
"accessibility/touch_exploration_manager_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_unittest.cc",
"app_list/home_launcher_gesture_handler_unittest.cc",
......
......@@ -27,7 +27,6 @@
#include "ash/shell.h"
#include "ash/voice_interaction/voice_interaction_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/splitview/split_view_controller.h"
#include "ash/wm/tablet_mode/tablet_mode_controller.h"
......@@ -86,18 +85,10 @@ AppListControllerImpl::AppListControllerImpl()
Shell::Get()->voice_interaction_controller()->AddLocalObserver(this);
Shell::Get()->window_tree_host_manager()->AddObserver(this);
Shell::Get()->mru_window_tracker()->AddObserver(this);
}
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);
}
AppListControllerImpl::~AppListControllerImpl() {}
void AppListControllerImpl::SetClient(mojom::AppListClientPtr client_ptr) {
client_ = std::move(client_ptr);
......@@ -451,6 +442,10 @@ void AppListControllerImpl::Show(int64_t display_id,
}
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(
......@@ -545,6 +540,20 @@ void AppListControllerImpl::OnOverviewModeEndingAnimationComplete(
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() {
if (presenter_.GetTargetVisibility()) {
DCHECK(IsVisible());
......@@ -614,6 +623,10 @@ void AppListControllerImpl::OnDisplayConfigurationChanged() {
ShowHomeLauncher();
}
void AppListControllerImpl::OnWindowUntracked(aura::Window* untracked_window) {
UpdateExpandArrowVisibility();
}
void AppListControllerImpl::Back() {
presenter_.GetView()->Back();
}
......@@ -677,6 +690,23 @@ bool AppListControllerImpl::IsShowingEmbeddedAssistantUI() const {
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_|:
......
......@@ -25,6 +25,7 @@
#include "ash/session/session_observer.h"
#include "ash/shell_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 "base/observer_list.h"
#include "components/sync/model/string_ordinal.h"
......@@ -54,7 +55,8 @@ class ASH_EXPORT AppListControllerImpl
public keyboard::KeyboardControllerObserver,
public WallpaperControllerObserver,
public DefaultVoiceInteractionObserver,
public WindowTreeHostManager::Observer {
public WindowTreeHostManager::Observer,
public ash::MruWindowTracker::Observer {
public:
using AppListItemMetadataPtr = mojom::AppListItemMetadataPtr;
using SearchResultMetadataPtr = mojom::SearchResultMetadataPtr;
......@@ -206,6 +208,7 @@ class ASH_EXPORT AppListControllerImpl
void OnOverviewModeStarting() override;
void OnOverviewModeEnding(OverviewSession* overview_session) override;
void OnOverviewModeEndingAnimationComplete(bool canceled) override;
void OnShellDestroying() override;
// TabletModeObserver:
void OnTabletModeStarted() override;
......@@ -227,6 +230,9 @@ class ASH_EXPORT AppListControllerImpl
// WindowTreeHostManager::Observer:
void OnDisplayConfigurationChanged() override;
// MruWindowTracker::Observer:
void OnWindowUntracked(aura::Window* untracked_window) override;
bool onscreen_keyboard_shown() const { return onscreen_keyboard_shown_; }
// Performs the 'back' action for the active page.
......@@ -245,6 +251,9 @@ class ASH_EXPORT AppListControllerImpl
// Returns current visibility of the Assistant page.
bool IsShowingEmbeddedAssistantUI() const;
// Update the visibility of expand arrow view.
void UpdateExpandArrowVisibility();
private:
syncer::StringOrdinal GetOemFolderPos();
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() {
window2_->ResetOpacityAndTransform();
if (is_final_state_show) {
// Show or hide the expand arrow view.
app_list_controller_->UpdateExpandArrowVisibility();
std::vector<aura::Window*> windows_to_hide_minimize;
windows_to_hide_minimize.push_back(GetWindow1());
......
......@@ -285,6 +285,13 @@ bool AppListPresenterImpl::IsShowingEmbeddedAssistantUI() const {
return false;
}
void AppListPresenterImpl::SetExpandArrowViewVisibility(bool show) {
if (view_) {
view_->app_list_main_view()->contents_view()->SetExpandArrowViewVisibility(
show);
}
}
////////////////////////////////////////////////////////////////////////////////
// AppListPresenterImpl, private:
......
......@@ -112,6 +112,9 @@ class APP_LIST_PRESENTER_EXPORT AppListPresenterImpl
// Returns current visibility of the Assistant page.
bool IsShowingEmbeddedAssistantUI() const;
// Show/hide the expand arrow view button.
void SetExpandArrowViewVisibility(bool show);
private:
// Sets the app list view and attempts to show it.
void SetView(AppListView* view);
......
......@@ -621,6 +621,13 @@ float ContentsView::GetAppListMainViewScale() const {
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,
ash::AppListState current_state,
ash::AppListState target_state) const {
......
......@@ -178,6 +178,10 @@ class APP_LIST_EXPORT ContentsView : public views::View,
// is also applied to search box window.
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:
// Sets the active launcher page, accounting for whether the change is for
// search results.
......
......@@ -711,6 +711,9 @@ Shell::Shell(std::unique_ptr<ShellDelegate> shell_delegate,
Shell::~Shell() {
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_server_controller_.reset();
......@@ -1099,9 +1102,6 @@ void Shell::Init(
voice_interaction_controller_ =
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>();
magnifier_key_scroll_handler_ = MagnifierKeyScroller::CreateHandler();
......@@ -1176,6 +1176,10 @@ void Shell::Init(
magnification_controller_ = std::make_unique<MagnificationController>();
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>();
high_contrast_controller_.reset(new HighContrastController);
......
......@@ -80,6 +80,9 @@ class ASH_EXPORT ShellObserver {
// Called at the end of Shell::Init.
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
// most of Shell's state has been deleted.
virtual void OnShellDestroyed() {}
......
......@@ -144,6 +144,14 @@ void MruWindowTracker::SetIgnoreActivations(bool ignore) {
SetActiveWindow(wm::GetActiveWindow());
}
void MruWindowTracker::AddObserver(Observer* observer) {
observers_.AddObserver(observer);
}
void MruWindowTracker::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
//////////////////////////////////////////////////////////////////////////////
// MruWindowTracker, private:
......@@ -174,6 +182,9 @@ void MruWindowTracker::OnWindowDestroyed(aura::Window* window) {
// else we may end up with a deleted window in |mru_windows_|.
base::Erase(mru_windows_, window);
window->RemoveObserver(this);
for (auto& observer : observers_)
observer.OnWindowUntracked(window);
}
} // namespace ash
......@@ -9,6 +9,7 @@
#include "ash/ash_export.h"
#include "base/macros.h"
#include "base/observer_list.h"
#include "ui/aura/window_observer.h"
#include "ui/wm/public/activation_change_observer.h"
......@@ -21,6 +22,12 @@ class ASH_EXPORT MruWindowTracker : public ::wm::ActivationChangeObserver,
public:
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() override;
......@@ -44,6 +51,10 @@ class ASH_EXPORT MruWindowTracker : public ::wm::ActivationChangeObserver,
// windows to the front of the MRU window list.
void SetIgnoreActivations(bool ignore);
// Add/Remove observers.
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
private:
// Updates the mru_windows_ list to insert/move |active_window| at/to the
// front.
......@@ -61,6 +72,8 @@ class ASH_EXPORT MruWindowTracker : public ::wm::ActivationChangeObserver,
// through, sorted such that the most recently used window comes last.
std::vector<aura::Window*> mru_windows_;
base::ObserverList<Observer, true> observers_;
bool ignore_window_activations_ = false;
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