Commit f3e75ab6 authored by Xiaoqian Dai's avatar Xiaoqian Dai Committed by Commit Bot

split view: Allow dragging overview window to snap in clamshell mode.

This is an initial CL to allow dragging overview window to snap to
splitview in clamshell mode.

- Add a feature flag "DragToSnapInClamshellMode"
- In clamshell mode, split view mode behaviors are very different with that
in tablet mode. Split view mode is only active during an overview
session. Once the user has selected two windows to snap to both side of
the screen, split view mode is no longer active.

See https://drive.google.com/open?id=15A2CSJxxRfewbPzMvlhe5SmpST1TGJTC
for demo.

Bug: 890029
Change-Id: Iac9cc8f80b28df1d15b761fbb38e30b6a48c3214
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1559113
Commit-Queue: Xiaoqian Dai <xdai@chromium.org>
Reviewed-by: default avatarMitsuru Oshima <oshima@chromium.org>
Cr-Commit-Position: refs/heads/master@{#650538}
parent 9cd3ce44
......@@ -985,9 +985,14 @@ bool AppListControllerImpl::ProcessHomeLauncherGesture(
bool AppListControllerImpl::CanProcessEventsOnApplistViews() {
// Do not allow processing events during overview or while overview is
// finished but still animating out.
// finished but still animating out. Note in clamshell mode, if overview and
// splitview is both active, we still allow the user to open app list and
// select an app. The app will be opened in snapped window state and overview
// will be ended after the app is opened.
OverviewController* overview_controller = Shell::Get()->overview_controller();
if (overview_controller->IsSelecting() ||
auto* split_view_controller = Shell::Get()->split_view_controller();
if ((overview_controller->IsSelecting() &&
!split_view_controller->InClamshellSplitViewMode()) ||
overview_controller->IsCompletingShutdownAnimations()) {
return false;
}
......
......@@ -13,6 +13,9 @@ namespace features {
const base::Feature kDockedMagnifier{"DockedMagnifier",
base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kDragToSnapInClamshellMode{
"DragToSnapInClamshellMode", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kEnableOverviewRoundedCorners{
"EnableOverviewRoundedCorners", base::FEATURE_ENABLED_BY_DEFAULT};
......
......@@ -16,6 +16,10 @@ namespace features {
// https://crbug.com/709824.
ASH_PUBLIC_EXPORT extern const base::Feature kDockedMagnifier;
// Enables dragging and snapping an overview window in clamshell mode.
// TODO(crbug.com/890029): Remove this when the feature is fully launched.
ASH_PUBLIC_EXPORT extern const base::Feature kDragToSnapInClamshellMode;
// Enables rounded corners in overview mode for testing.
// TODO(crbug.com/903486): Remove this when new rounded corners implementation
// has landed.
......
......@@ -326,8 +326,9 @@ bool OverviewController::ToggleOverview(
if (IsSelecting()) {
// Do not allow ending overview if we're in single split mode unless swiping
// up from the shelf.
if (windows.empty() && Shell::Get()->IsSplitViewModeActive() &&
// up from the shelf in tablet mode.
if (windows.empty() &&
Shell::Get()->split_view_controller()->InTabletSplitViewMode() &&
type != OverviewSession::EnterExitOverviewType::kSwipeFromShelf) {
return true;
}
......
......@@ -9,6 +9,7 @@
#include <utility>
#include "ash/accessibility/accessibility_controller.h"
#include "ash/app_list/app_list_controller_impl.h"
#include "ash/metrics/user_metrics_recorder.h"
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/screen_util.h"
......@@ -350,7 +351,7 @@ void OverviewSession::OnGridEmpty(OverviewGrid* grid) {
// not active. Set |index| to -1 so that it does not attempt to select any
// items.
index = -1;
if (!Shell::Get()->IsSplitViewModeActive()) {
if (!Shell::Get()->split_view_controller()->InTabletSplitViewMode()) {
for (const auto& grid : grid_list_)
grid->Shutdown();
grid_list_.clear();
......@@ -760,6 +761,15 @@ void OverviewSession::OnWindowDestroying(aura::Window* window) {
}
void OverviewSession::OnKeyEvent(ui::KeyEvent* event) {
// If app list is open when overview is active (it can happen in clamshell
// mode, when we snap an overview window to one side of the screen and then
// open the app list to select an app to snap to the other side), in this case
// we let the app list to handle the key event.
// TODO(crbug.com/952315): Explore better ways to handle this splitview +
// overview + applist case.
if (Shell::Get()->app_list_controller()->IsVisible())
return;
if (event->type() != ui::ET_KEY_PRESSED)
return;
......@@ -831,6 +841,10 @@ void OverviewSession::OnShellDestroying() {
void OverviewSession::OnSplitViewStateChanged(
SplitViewController::State previous_state,
SplitViewController::State state) {
// Do nothing if overview is being shutdown.
if (!Shell::Get()->overview_controller()->IsSelecting())
return;
const bool unsnappable_window_activated =
state == SplitViewController::NO_SNAP &&
Shell::Get()->split_view_controller()->end_reason() ==
......@@ -842,9 +856,12 @@ void OverviewSession::OnSplitViewStateChanged(
ResetFocusRestoreWindow(false);
// If two windows were snapped to both sides of the screen or an unsnappable
// window was just activated, end overview mode and bail out.
// window was just activated, or we're in single split mode in clamshell mode
// and there is no window in overview, end overview mode and bail out.
if (state == SplitViewController::BOTH_SNAPPED ||
unsnappable_window_activated) {
unsnappable_window_activated ||
(Shell::Get()->split_view_controller()->InClamshellSplitViewMode() &&
IsEmpty())) {
CancelSelection();
return;
}
......
This diff is collapsed.
......@@ -13,6 +13,7 @@
#include "ash/public/interfaces/split_view.mojom.h"
#include "ash/shell_observer.h"
#include "ash/wm/overview/overview_observer.h"
#include "ash/wm/tablet_mode/tablet_mode_controller.h"
#include "ash/wm/tablet_mode/tablet_mode_observer.h"
#include "ash/wm/window_state_observer.h"
#include "base/containers/flat_map.h"
......@@ -76,6 +77,19 @@ class ASH_EXPORT SplitViewController : public mojom::SplitViewController,
kPipExpanded,
};
// The behaviors of split view are very different when in tablet mode and in
// clamshell mode. In tablet mode, split view mode will stay active until the
// user explicitly ends it (e.g., by pressing home launcher, or long pressing
// the overview button, or sliding the divider bar to the edge, etc). However,
// in clamshell mode, there is no divider bar, and split view mode only stays
// active during overview snapping, i.e., it's only possible that split view
// is active when overview is active. Once the user has selected two windows
// to snap to both side of the screen, split view mode is no longer active.
enum class SplitViewType {
kTabletType = 0,
kClamshellType,
};
class Observer {
public:
// Called when split view state changed from |previous_state| to |state|.
......@@ -93,8 +107,12 @@ class ASH_EXPORT SplitViewController : public mojom::SplitViewController,
// Binds the mojom::SplitViewController interface to this object.
void BindRequest(mojom::SplitViewControllerRequest request);
// Returns true if split view mode is active.
// Returns true if split view mode is active. Please see SplitViewType above
// to see the difference between tablet mode and clamshell mode splitview
// mode.
bool IsSplitViewModeActive() const;
bool InClamshellSplitViewMode() const;
bool InTabletSplitViewMode() const;
// Snaps window to left/right. It will try to remove |window| from the
// overview window grid first before snapping it if |window| is currently
......@@ -151,6 +169,12 @@ class ASH_EXPORT SplitViewController : public mojom::SplitViewController,
void OnWindowDragEnded(aura::Window* dragged_window,
SnapPosition desired_snap_position,
const gfx::Point& last_location_in_screen);
void OnWindowBoundsChanged(aura::Window* window,
const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds,
ui::PropertyChangeReason reason) override;
void OnResizeLoopStarted(aura::Window* window) override;
void OnResizeLoopEnded(aura::Window* window) override;
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
......@@ -188,7 +212,9 @@ class ASH_EXPORT SplitViewController : public mojom::SplitViewController,
uint32_t metrics) override;
// TabletModeObserver:
void OnTabletModeStarted() override;
void OnTabletModeEnding() override;
void OnTabletControllerDestroyed() override;
// AccessibilityObserver:
void OnAccessibilityStatusChanged() override;
......@@ -389,10 +415,10 @@ class ASH_EXPORT SplitViewController : public mojom::SplitViewController,
aura::Window* left_window_ = nullptr;
aura::Window* right_window_ = nullptr;
// Split view divider widget. It's a black bar stretching from one edge of the
// screen to the other, containing a small white drag bar in the middle. As
// the user presses on it and drag it to left or right, the left and right
// window will be resized accordingly.
// Split view divider widget. Only exist in tablet splitview mode. It's a
// black bar stretching from one edge of the screen to the other, containing a
// small white drag bar in the middle. As the user presses on it and drag it
// to left or right, the left and right window will be resized accordingly.
std::unique_ptr<SplitViewDivider> split_view_divider_;
// A black scrim layer that fades in over a window when it’s width drops under
......@@ -400,7 +426,7 @@ class ASH_EXPORT SplitViewController : public mojom::SplitViewController,
// closer to the edge of the screen.
std::unique_ptr<ui::Layer> black_scrim_layer_;
// The window observer that obseves the tab-dragged window.
// The window observer that obseves the tab-dragged window in tablet mode.
std::unique_ptr<TabDraggedWindowObserver> dragged_window_observer_;
// The distance between the origin of the divider and the origin of the
......@@ -443,6 +469,10 @@ class ASH_EXPORT SplitViewController : public mojom::SplitViewController,
// Stores the reason which cause splitview to end.
EndReason end_reason_ = EndReason::kNormal;
// The split view type. See SplitViewType for the differences between tablet
// split view and clamshell split view.
SplitViewType split_view_type_ = SplitViewType::kTabletType;
// The time when splitview starts. Used for metric collection purpose.
base::Time splitview_start_time_;
......@@ -453,6 +483,9 @@ class ASH_EXPORT SplitViewController : public mojom::SplitViewController,
base::ObserverList<Observer>::Unchecked observers_;
mojo::InterfacePtrSet<mojom::SplitViewObserver> mojo_observers_;
ScopedObserver<TabletModeController, TabletModeObserver>
tablet_mode_observer_{this};
// Records the presentation time of resize operation in split view mode.
std::unique_ptr<PresentationTimeRecorder> presentation_time_recorder_;
......
......@@ -5,6 +5,7 @@
#include "ash/wm/splitview/split_view_utils.h"
#include "ash/accessibility/accessibility_controller.h"
#include "ash/public/cpp/ash_features.h"
#include "ash/public/cpp/ash_switches.h"
#include "ash/screen_util.h"
#include "ash/shell.h"
......@@ -217,6 +218,11 @@ void DoSplitviewTransformAnimation(ui::Layer* layer,
layer->SetTransform(target_transform);
}
bool IsClamshellSplitViewModeEnabled() {
return base::FeatureList::IsEnabled(
ash::features::kDragToSnapInClamshellMode);
}
bool ShouldAllowSplitView() {
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kAshDisableTabletSplitView)) {
......@@ -225,7 +231,8 @@ bool ShouldAllowSplitView() {
if (!Shell::Get()
->tablet_mode_controller()
->IsTabletModeWindowManagerEnabled()) {
->IsTabletModeWindowManagerEnabled() &&
!IsClamshellSplitViewModeEnabled()) {
return false;
}
......
......@@ -79,8 +79,11 @@ void DoSplitviewTransformAnimation(ui::Layer* layer,
SplitviewAnimationType type,
const gfx::Transform& target_transform);
// Returns true if split view mode is supported. Currently the split view
// mode is only supported in tablet mode.
// Returns true if we allow dragging an overview window to snap to split view in
// clamshell mode.
ASH_EXPORT bool IsClamshellSplitViewModeEnabled();
// Returns true if split view mode is supported.
ASH_EXPORT bool ShouldAllowSplitView();
// Returns true if |window| can be activated and snapped in split screen in
......
......@@ -363,14 +363,15 @@ bool ShouldExcludeForCycleList(const aura::Window* window) {
}
bool ShouldExcludeForOverview(const aura::Window* window) {
// Remove the default snapped window from the window list. The default
// snapped window occupies one side of the screen, while the other windows
// occupy the other side of the screen in overview mode. The default snap
// position is the position where the window was first snapped. See
// |default_snap_position_| in SplitViewController for more detail.
if (Shell::Get()->IsSplitViewModeActive() &&
window ==
Shell::Get()->split_view_controller()->GetDefaultSnappedWindow()) {
// If we're currently in tablet splitview, remove the default snapped window
// from the window list. The default snapped window occupies one side of the
// screen, while the other windows occupy the other side of the screen in
// overview mode. The default snap position is the position where the window
// was first snapped. See |default_snap_position_| in SplitViewController for
// more detail.
auto* split_view_controller = Shell::Get()->split_view_controller();
if (split_view_controller->InTabletSplitViewMode() &&
window == split_view_controller->GetDefaultSnappedWindow()) {
return true;
}
......
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