Commit 87d6424d authored by Xiaoqian Dai's avatar Xiaoqian Dai Committed by Commit Bot

Clamshell <-> tablet mode transition

There are 3 cases in clamshell to tablet mode transition:
1) overview is active but splitview is not: keep overview active during
   transition.
2) overview and splitview are both active: keep them both active during
   transition.
3) overview and splitview are both inactive: keep the current behavior.
   a) if the top window is a snapped window, put it in splitview
   b) if the second top window is also a snapped window that snaps to the
      opposite side of the screen, put it in splitview as well
   c) if the top window is not a snapped window, maximize or fullscreen
      all windows when entering tablet mode.

There are 4 cases in tablet to clamshell mode transition:
1) overview is active but splitview is not: keep overview active during
   transition.
2) overview and splitview are both active: keep them both active during
   transition.
3) overview is inactive but splitview is active (i.e., two snapped windows),
   splitview will be no longer active after transition. But the two snapped
   window will still keep snapped in clamshell mode.
4) overview and splitview are both inactive: keep the current behavior,
   i.e., restore all windows to its old window state before entering tablet
   mode.


Bug: 890029
Change-Id: I7769021f74c3e9d591b19258be2821992d780451
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1658955
Commit-Queue: Xiaoqian Dai <xdai@chromium.org>
Reviewed-by: default avatarMitsuru Oshima <oshima@chromium.org>
Cr-Commit-Position: refs/heads/master@{#670678}
parent 2f8031be
...@@ -768,10 +768,10 @@ void SplitViewController::OnWindowBoundsChanged( ...@@ -768,10 +768,10 @@ void SplitViewController::OnWindowBoundsChanged(
const gfx::Rect& new_bounds, const gfx::Rect& new_bounds,
ui::PropertyChangeReason reason) { ui::PropertyChangeReason reason) {
if (split_view_type_ != SplitViewType::kClamshellType || if (split_view_type_ != SplitViewType::kClamshellType ||
reason == ui::PropertyChangeReason::FROM_ANIMATION) { reason == ui::PropertyChangeReason::FROM_ANIMATION ||
!InSplitViewMode()) {
return; return;
} }
DCHECK(InSplitViewMode());
wm::WindowState* window_state = wm::GetWindowState(window); wm::WindowState* window_state = wm::GetWindowState(window);
const bool is_window_moved = window_state->is_dragged() && const bool is_window_moved = window_state->is_dragged() &&
...@@ -1109,14 +1109,37 @@ void SplitViewController::OnDisplayMetricsChanged( ...@@ -1109,14 +1109,37 @@ void SplitViewController::OnDisplayMetricsChanged(
UpdateSnappedWindowsAndDividerBounds(); UpdateSnappedWindowsAndDividerBounds();
} }
void SplitViewController::OnTabletModeStarted() { void SplitViewController::OnTabletModeStarting() {
split_view_type_ = SplitViewType::kTabletType; split_view_type_ = SplitViewType::kTabletType;
// If splitview is active when tablet mode is starting, do the clamshell mode
// splitview to tablet mode splitview transition by adding the split view
// divider bar.
if (InSplitViewMode()) {
divider_position_ = GetClosestFixedDividerPosition();
split_view_divider_ = std::make_unique<SplitViewDivider>(
this, GetDefaultSnappedWindow()->GetRootWindow());
UpdateSnappedWindowsAndDividerBounds();
NotifyDividerPositionChanged();
}
} }
void SplitViewController::OnTabletModeEnding() { void SplitViewController::OnTabletModeEnding() {
if (IsClamshellSplitViewModeEnabled()) if (IsClamshellSplitViewModeEnabled()) {
split_view_type_ = SplitViewType::kClamshellType; split_view_type_ = SplitViewType::kClamshellType;
EndSplitView();
// If splitview is active when tablet mode is ending, simply destroy the
// split view divider bar as we don't have the bar in clamshell split view
// mode.
if (InSplitViewMode())
split_view_divider_.reset();
} else if (InSplitViewMode()) {
// If clamshell splitview mode is not enabled, fall back to the old
// behavior: end splitview and overivew and all windows will return to its
// old window state before entering tablet mode.
EndSplitView();
EndOverview();
}
} }
void SplitViewController::OnTabletControllerDestroyed() { void SplitViewController::OnTabletControllerDestroyed() {
......
...@@ -59,18 +59,17 @@ class ASH_EXPORT SplitViewController : public SplitViewNotifier, ...@@ -59,18 +59,17 @@ class ASH_EXPORT SplitViewController : public SplitViewNotifier,
// top of the screen. // top of the screen.
enum SnapPosition { NONE, LEFT, RIGHT }; enum SnapPosition { NONE, LEFT, RIGHT };
// Why splitview was ended. For now, all reasons will be kNormal except when // Why splitview was ended.
// the home launcher button is pressed, an unsnappable window just got
// activated, the active user session changed, or the window dragging
// started.
enum class EndReason { enum class EndReason {
kNormal = 0, kNormal = 0,
kHomeLauncherPressed, kHomeLauncherPressed,
kUnsnappableWindowActivated, kUnsnappableWindowActivated,
kActiveUserChanged, kActiveUserChanged,
kWindowDragStarted, kWindowDragStarted,
// TODO(950827): Consider not ending Split-View on PIP expand. // TODO(edcourtney): Consider not ending Split-View on PIP expand.
// See crbug.com/950827.
kPipExpanded, kPipExpanded,
kExitTabletMode,
}; };
// The behaviors of split view are very different when in tablet mode and in // The behaviors of split view are very different when in tablet mode and in
...@@ -192,7 +191,7 @@ class ASH_EXPORT SplitViewController : public SplitViewNotifier, ...@@ -192,7 +191,7 @@ class ASH_EXPORT SplitViewController : public SplitViewNotifier,
uint32_t metrics) override; uint32_t metrics) override;
// TabletModeObserver: // TabletModeObserver:
void OnTabletModeStarted() override; void OnTabletModeStarting() override;
void OnTabletModeEnding() override; void OnTabletModeEnding() override;
void OnTabletControllerDestroyed() override; void OnTabletControllerDestroyed() override;
......
...@@ -251,8 +251,7 @@ SplitViewDivider::~SplitViewDivider() { ...@@ -251,8 +251,7 @@ SplitViewDivider::~SplitViewDivider() {
divider_widget_->Close(); divider_widget_->Close();
split_view_window_targeter_.reset(); split_view_window_targeter_.reset();
for (auto* iter : observed_windows_) for (auto* iter : observed_windows_)
iter->RemoveObserver(this); RemoveObservedWindow(iter);
observed_windows_.clear();
} }
// static // static
......
...@@ -910,6 +910,8 @@ void TabletModeController::ResetPauser() { ...@@ -910,6 +910,8 @@ void TabletModeController::ResetPauser() {
} }
void TabletModeController::FinishInitTabletMode() { void TabletModeController::FinishInitTabletMode() {
for (auto& observer : tablet_mode_observers_)
observer.OnTabletModeStarting();
tablet_mode_window_manager_ = std::make_unique<TabletModeWindowManager>(); tablet_mode_window_manager_ = std::make_unique<TabletModeWindowManager>();
tablet_mode_window_manager_->Init(); tablet_mode_window_manager_->Init();
......
...@@ -13,6 +13,9 @@ namespace ash { ...@@ -13,6 +13,9 @@ namespace ash {
// NOTE: Code in chrome should use TabletModeClientObserver. // NOTE: Code in chrome should use TabletModeClientObserver.
class ASH_EXPORT TabletModeObserver { class ASH_EXPORT TabletModeObserver {
public: public:
// Called when the tablet mode is about to start.
virtual void OnTabletModeStarting() {}
// Called when the tablet mode has started. Windows might still be animating // Called when the tablet mode has started. Windows might still be animating
// though. // though.
virtual void OnTabletModeStarted() {} virtual void OnTabletModeStarted() {}
......
...@@ -124,9 +124,10 @@ class ASH_EXPORT TabletModeWindowManager : public aura::WindowObserver, ...@@ -124,9 +124,10 @@ class ASH_EXPORT TabletModeWindowManager : public aura::WindowObserver,
void ArrangeWindowsForTabletMode(); void ArrangeWindowsForTabletMode();
// Revert all windows to how they were arranged before tablet mode. // Revert all windows to how they were arranged before tablet mode.
// |was_in_overview| indicates whether it was in overview before entering // |windows_in_splitview| contains the windows that were in splitview before
// desktop mode. // entering clamshell mode.
void ArrangeWindowsForDesktopMode(bool was_in_overview = false); void ArrangeWindowsForClamshellMode(
base::flat_map<aura::Window*, WindowStateType> windows_in_splitview);
// If the given window should be handled by us, this function will add it to // If the given window should be handled by us, this function will add it to
// the list of known windows (remembering the initial show state). // the list of known windows (remembering the initial show state).
...@@ -137,13 +138,10 @@ class ASH_EXPORT TabletModeWindowManager : public aura::WindowObserver, ...@@ -137,13 +138,10 @@ class ASH_EXPORT TabletModeWindowManager : public aura::WindowObserver,
bool snap = false, bool snap = false,
bool animate_bounds_on_attach = true); bool animate_bounds_on_attach = true);
// Remove a window from our tracking list. |was_in_overview| used when // Remove a window from our tracking list. If the window is going to be
// |destroyed| is false to help handle leaving tablet mode. If the window is // destroyed, do not restore its old previous window state object as it will
// going to be destroyed, do not restore its old previous window state object // send unnecessary window state change event.
// as it will send unnecessary window state change event. void ForgetWindow(aura::Window* window, bool destroyed);
void ForgetWindow(aura::Window* window,
bool destroyed,
bool was_in_overview = false);
// Returns true when the given window should be modified in any way by us. // Returns true when the given window should be modified in any way by us.
bool ShouldHandleWindow(aura::Window* window); bool ShouldHandleWindow(aura::Window* window);
......
...@@ -197,18 +197,19 @@ TabletModeWindowState::~TabletModeWindowState() { ...@@ -197,18 +197,19 @@ TabletModeWindowState::~TabletModeWindowState() {
creator_->WindowStateDestroyed(window_); creator_->WindowStateDestroyed(window_);
} }
void TabletModeWindowState::LeaveTabletMode(wm::WindowState* window_state, void TabletModeWindowState::LeaveTabletMode(wm::WindowState* window_state) {
bool was_in_overview) { // Only do bounds change animation if the window is the top window or a window
// TODO(minch): Keep the current animation if leaving tablet mode from // showing in splitview, and the window has changed its state. Otherwise,
// overview. Need more investigation for windows' transform animation and // restore its bounds immediately.
// updates bounds animation when overview is active. EnterAnimationType animation_type =
bool use_default = was_in_overview || window_state->IsSnapped() || window_state->IsSnapped() || IsTopWindow(window_state->window())
IsTopWindow(window_state->window()); ? DEFAULT
: IMMEDIATE;
if (old_state_->GetType() == window_state->GetStateType() && if (old_state_->GetType() == window_state->GetStateType() &&
!window_state->IsNormalStateType()) { !window_state->IsNormalStateType()) {
use_default = false; animation_type = IMMEDIATE;
} }
old_state_->set_enter_animation_type(use_default ? DEFAULT : IMMEDIATE); old_state_->set_enter_animation_type(animation_type);
// Note: When we return we will destroy ourselves with the |our_reference|. // Note: When we return we will destroy ourselves with the |our_reference|.
std::unique_ptr<wm::WindowState::State> our_reference = std::unique_ptr<wm::WindowState::State> our_reference =
window_state->SetStateObject(std::move(old_state_)); window_state->SetStateObject(std::move(old_state_));
......
...@@ -41,7 +41,7 @@ class TabletModeWindowState : public wm::WindowState::State { ...@@ -41,7 +41,7 @@ class TabletModeWindowState : public wm::WindowState::State {
void set_ignore_wm_events(bool ignore) { ignore_wm_events_ = ignore; } void set_ignore_wm_events(bool ignore) { ignore_wm_events_ = ignore; }
// Leaves the tablet mode by reverting to previous state object. // Leaves the tablet mode by reverting to previous state object.
void LeaveTabletMode(wm::WindowState* window_state, bool was_in_overview); void LeaveTabletMode(wm::WindowState* window_state);
// WindowState::State overrides: // WindowState::State overrides:
void OnWMEvent(wm::WindowState* window_state, void OnWMEvent(wm::WindowState* window_state,
......
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