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(
const gfx::Rect& new_bounds,
ui::PropertyChangeReason reason) {
if (split_view_type_ != SplitViewType::kClamshellType ||
reason == ui::PropertyChangeReason::FROM_ANIMATION) {
reason == ui::PropertyChangeReason::FROM_ANIMATION ||
!InSplitViewMode()) {
return;
}
DCHECK(InSplitViewMode());
wm::WindowState* window_state = wm::GetWindowState(window);
const bool is_window_moved = window_state->is_dragged() &&
......@@ -1109,14 +1109,37 @@ void SplitViewController::OnDisplayMetricsChanged(
UpdateSnappedWindowsAndDividerBounds();
}
void SplitViewController::OnTabletModeStarted() {
void SplitViewController::OnTabletModeStarting() {
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() {
if (IsClamshellSplitViewModeEnabled())
if (IsClamshellSplitViewModeEnabled()) {
split_view_type_ = SplitViewType::kClamshellType;
// 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() {
......
......@@ -59,18 +59,17 @@ class ASH_EXPORT SplitViewController : public SplitViewNotifier,
// top of the screen.
enum SnapPosition { NONE, LEFT, RIGHT };
// Why splitview was ended. For now, all reasons will be kNormal except when
// the home launcher button is pressed, an unsnappable window just got
// activated, the active user session changed, or the window dragging
// started.
// Why splitview was ended.
enum class EndReason {
kNormal = 0,
kHomeLauncherPressed,
kUnsnappableWindowActivated,
kActiveUserChanged,
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,
kExitTabletMode,
};
// The behaviors of split view are very different when in tablet mode and in
......@@ -192,7 +191,7 @@ class ASH_EXPORT SplitViewController : public SplitViewNotifier,
uint32_t metrics) override;
// TabletModeObserver:
void OnTabletModeStarted() override;
void OnTabletModeStarting() override;
void OnTabletModeEnding() override;
void OnTabletControllerDestroyed() override;
......
......@@ -251,8 +251,7 @@ SplitViewDivider::~SplitViewDivider() {
divider_widget_->Close();
split_view_window_targeter_.reset();
for (auto* iter : observed_windows_)
iter->RemoveObserver(this);
observed_windows_.clear();
RemoveObservedWindow(iter);
}
// static
......
......@@ -910,6 +910,8 @@ void TabletModeController::ResetPauser() {
}
void TabletModeController::FinishInitTabletMode() {
for (auto& observer : tablet_mode_observers_)
observer.OnTabletModeStarting();
tablet_mode_window_manager_ = std::make_unique<TabletModeWindowManager>();
tablet_mode_window_manager_->Init();
......
......@@ -13,6 +13,9 @@ namespace ash {
// NOTE: Code in chrome should use TabletModeClientObserver.
class ASH_EXPORT TabletModeObserver {
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
// though.
virtual void OnTabletModeStarted() {}
......
......@@ -124,9 +124,10 @@ class ASH_EXPORT TabletModeWindowManager : public aura::WindowObserver,
void ArrangeWindowsForTabletMode();
// Revert all windows to how they were arranged before tablet mode.
// |was_in_overview| indicates whether it was in overview before entering
// desktop mode.
void ArrangeWindowsForDesktopMode(bool was_in_overview = false);
// |windows_in_splitview| contains the windows that were in splitview before
// entering clamshell mode.
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
// the list of known windows (remembering the initial show state).
......@@ -137,13 +138,10 @@ class ASH_EXPORT TabletModeWindowManager : public aura::WindowObserver,
bool snap = false,
bool animate_bounds_on_attach = true);
// Remove a window from our tracking list. |was_in_overview| used when
// |destroyed| is false to help handle leaving tablet mode. If the window is
// going to be destroyed, do not restore its old previous window state object
// as it will send unnecessary window state change event.
void ForgetWindow(aura::Window* window,
bool destroyed,
bool was_in_overview = false);
// Remove a window from our tracking list. If the window is going to be
// destroyed, do not restore its old previous window state object as it will
// send unnecessary window state change event.
void ForgetWindow(aura::Window* window, bool destroyed);
// Returns true when the given window should be modified in any way by us.
bool ShouldHandleWindow(aura::Window* window);
......
......@@ -197,18 +197,19 @@ TabletModeWindowState::~TabletModeWindowState() {
creator_->WindowStateDestroyed(window_);
}
void TabletModeWindowState::LeaveTabletMode(wm::WindowState* window_state,
bool was_in_overview) {
// TODO(minch): Keep the current animation if leaving tablet mode from
// overview. Need more investigation for windows' transform animation and
// updates bounds animation when overview is active.
bool use_default = was_in_overview || window_state->IsSnapped() ||
IsTopWindow(window_state->window());
void TabletModeWindowState::LeaveTabletMode(wm::WindowState* window_state) {
// Only do bounds change animation if the window is the top window or a window
// showing in splitview, and the window has changed its state. Otherwise,
// restore its bounds immediately.
EnterAnimationType animation_type =
window_state->IsSnapped() || IsTopWindow(window_state->window())
? DEFAULT
: IMMEDIATE;
if (old_state_->GetType() == window_state->GetStateType() &&
!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|.
std::unique_ptr<wm::WindowState::State> our_reference =
window_state->SetStateObject(std::move(old_state_));
......
......@@ -41,7 +41,7 @@ class TabletModeWindowState : public wm::WindowState::State {
void set_ignore_wm_events(bool ignore) { ignore_wm_events_ = ignore; }
// 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:
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