0

ash: Implement keyboard shortcut to resize the PiP Window

Use "Search + X" to resize the PiP Window.
This shortcut behaves the same as double-tapping the PiP window.

- Design doc: https://docs.google.com/document/d/1wTcLc9LEvDHQgi6K1FOiOxAYoUAf-yvwfLWCWiEq6pU/edit?usp=sharing&resourcekey=0-BZSEliNNgSFAnhKEJ69B5Q

- UXW review doc: https://docs.google.com/document/d/1E1tU2Tnv7urIcKeGjqjaHUTMz383l4YVSBfk5vq4L8U/edit?tab=t.0#heading=h.p6ytmfqg0fql
- Discussions we had we added a shortcut for PiP resizing: https://docs.google.com/document/d/1ZHLOd55rDCKDUSUeNbKEqOkwvskMQH1HepfreLL64KQ/edit?usp=sharing

    Push "Search + X" to resize the pip window properly.
    Show a description on the Key Shortcuts setting.

Bug: b:333656468
Test: ash_unittests --gtest_filter="*PipToggleResizeFeatureTest*"
Change-Id: I15f7919376abf327b9eab243c511ed277085906d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5874953
Commit-Queue: Kokoa Matsuda <komatsud@google.com>
Reviewed-by: Jimmy Gong <jimmyxgong@chromium.org>
Reviewed-by: Nergi Rahardi <nergi@google.com>
Cr-Commit-Position: refs/heads/main@{#1362270}
This commit is contained in:
Kokoa Matsuda
2024-10-01 09:29:07 +00:00
committed by Chromium LUCI CQ
parent 7820d8c457
commit 705fd7a97b
16 changed files with 102 additions and 17 deletions

@ -68,6 +68,7 @@
#include "ash/wm/overview/overview_controller.h"
#include "ash/wm/overview/overview_session.h"
#include "ash/wm/overview/overview_utils.h"
#include "ash/wm/pip/pip_controller.h"
#include "ash/wm/screen_pinning_controller.h"
#include "ash/wm/snap_group/snap_group.h"
#include "ash/wm/snap_group/snap_group_controller.h"
@ -652,6 +653,10 @@ bool CanPerformMagnifierZoom() {
Shell::Get()->docked_magnifier_controller()->GetEnabled();
}
bool CanResizePipWindow() {
return Shell::Get()->pip_controller()->CanResizePip();
}
bool CanScreenshot(bool take_screenshot) {
// |AcceleratorAction::kTakeScreenshot| is allowed when user session is
// blocked.
@ -1155,6 +1160,10 @@ void ResetDisplayZoom() {
display_manager->ResetDisplayZoom(display.id());
}
void ResizePipWindow() {
Shell::Get()->pip_controller()->HandleKeyboardShortcut();
}
void RestoreTab() {
NewWindowDelegate::GetPrimary()->RestoreTab();
}

@ -111,6 +111,8 @@ ASH_EXPORT bool CanUnpinWindow();
ASH_EXPORT bool CanWindowSnap();
ASH_EXPORT bool CanResizePipWindow();
//////////////////////////////////////////////////////////////////////////////
// Accelerator commands.
// Note: These functions should be independent and not depend on ui::Accelerator
@ -449,6 +451,9 @@ ASH_EXPORT void WindowSnap(AcceleratorAction action);
// Changes the display zooming up or down.
ASH_EXPORT bool ZoomDisplay(bool up);
// Resize the pip window.
ASH_EXPORT void ResizePipWindow();
} // namespace accelerators
} // namespace ash

@ -1030,6 +1030,8 @@ bool AcceleratorControllerImpl::CanPerformAction(
case AcceleratorAction::kLockPressed:
case AcceleratorAction::kLockReleased:
return CanHandleLockButton(accelerator);
case AcceleratorAction::kResizePipWindow:
return accelerators::CanResizePipWindow();
// The following are always enabled.
case AcceleratorAction::kBrightnessDown:
@ -1676,6 +1678,9 @@ void AcceleratorControllerImpl::PerformAction(
case kTouchFingerprintSensor3:
accelerators::TouchFingerprintSensor(3);
break;
case AcceleratorAction::kResizePipWindow:
accelerators::ResizePipWindow();
break;
}
RecordActionUmaHistogram(action, accelerator);

@ -4216,6 +4216,9 @@ No devices connected.
<message name="IDS_ASH_ACCELERATOR_DESCRIPTION_FOCUS_PIP" desc="Label for accelerator action - Focus on the picture-in-picture window.">
Focus on the picture-in-picture window
</message>
<message name="IDS_ASH_ACCELERATOR_DESCRIPTION_RESIZE_PIP_WINDOW" desc="Label for accelerator action - Resize the picture-in-picture window.">
Switch between the maximum or current size of the picture-in-picture window
</message>
<message name="IDS_ASH_ACCELERATOR_DESCRIPTION_FOCUS_PREVIOUS_PANE" desc="Label for accelerator action - Move focus to previous pane.">
Move focus to previous pane
</message>

@ -0,0 +1 @@
a286b6299d3a608deb52a7990aadafa537e06711

@ -170,6 +170,7 @@ namespace ash {
ACCELERATOR_ACTION_ENTRY(TilingWindowResizeUp) \
ACCELERATOR_ACTION_ENTRY(TilingWindowResizeDown) \
ACCELERATOR_ACTION_ENTRY(ToggleMouseKeys) \
ACCELERATOR_ACTION_ENTRY(ResizePipWindow) \
/* Debug actions are kept at an offset.*/ \
/* This offset should be kept consistent with the enum*/ \
/* `AcceleratorAction` in*/ \

@ -18,12 +18,12 @@ namespace ash {
namespace {
// The total number of accelerator actions.
constexpr int kAcceleratorActionsTotalNum = 166;
constexpr int kAcceleratorActionsTotalNum = 167;
// The toal number of debug accelerators, these will not be used for hashing.
constexpr int kDebugAcceleratorActionsNum = 28;
// The hash of accelerator actions. Please update this when adding a new
// accelerator action.
constexpr char kAcceleratorActionsHash[] = "af26f45ccfb2450d29171e3b3697a8dd";
constexpr char kAcceleratorActionsHash[] = "19f19f0e593d97ece036a1e5a9905135";
// Define the mapping between an AcceleratorAction and its string name.
// Example:

@ -313,6 +313,10 @@ const AcceleratorData kAcceleratorData[] = {
// TODO(yusukes): Handle VKEY_MEDIA_STOP, and VKEY_MEDIA_LAUNCH_MAIL.
// PIP-resize shortcut.
{true, ui::VKEY_X, ui::EF_COMMAND_DOWN,
AcceleratorAction::kResizePipWindow},
// ARC-specific shortcut.
{true, ui::VKEY_C, ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN,
AcceleratorAction::kToggleResizeLockMenu},

@ -144,6 +144,7 @@ enum AcceleratorAction {
kTilingWindowResizeUp,
kTilingWindowResizeDown,
kToggleMouseKeys,
kResizePipWindow,
// The following are DEBUG actions with an offset. This is to keep the enum
// in sync with `AcceleratorActions` in ash/public/cpp/accelerator_actions.h.
kDebugClearUseKMeansPref = 9000,

@ -291,6 +291,8 @@ EnumTraits<mojom_accelerator_action, ash::AcceleratorAction>::ToMojom(
return mojom_accelerator_action::kWindowMinimize;
case ash::AcceleratorAction::kMinimizeTopWindowOnBack:
return mojom_accelerator_action::kMinimizeTopWindowOnBack;
case ash::AcceleratorAction::kResizePipWindow:
return mojom_accelerator_action::kResizePipWindow;
case ash::AcceleratorAction::kDebugClearUseKMeansPref:
return mojom_accelerator_action::kDebugClearUseKMeansPref;
case ash::AcceleratorAction::kDebugKeyboardBacklightToggle:
@ -770,6 +772,9 @@ bool EnumTraits<mojom_accelerator_action, ash::AcceleratorAction>::FromMojom(
case mojom_accelerator_action::kMinimizeTopWindowOnBack:
*out = ash::AcceleratorAction::kMinimizeTopWindowOnBack;
return true;
case mojom_accelerator_action::kResizePipWindow:
*out = ash::AcceleratorAction::kResizePipWindow;
return true;
case mojom_accelerator_action::kDebugClearUseKMeansPref:
*out = ash::AcceleratorAction::kDebugClearUseKMeansPref;
return true;

@ -754,6 +754,14 @@ const AcceleratorLayoutMap& GetAcceleratorLayoutMap() {
/*locked=*/false,
mojom::AcceleratorLayoutStyle::kDefault,
mojom::AcceleratorSource::kAsh)},
{AcceleratorAction::kResizePipWindow,
AcceleratorLayoutDetails(
AcceleratorAction::kResizePipWindow,
IDS_ASH_ACCELERATOR_DESCRIPTION_RESIZE_PIP_WINDOW,
mojom::AcceleratorCategory::kDevice,
mojom::AcceleratorSubcategory::kMedia,
/*locked=*/false, mojom::AcceleratorLayoutStyle::kDefault,
mojom::AcceleratorSource::kAsh)},
{AcceleratorAction::kKeyboardBacklightToggle,
AcceleratorLayoutDetails(
AcceleratorAction::kKeyboardBacklightToggle,

@ -322,6 +322,7 @@ inline constexpr uint32_t kAcceleratorLayouts[] = {
AcceleratorAction::kMediaPrevTrack,
AcceleratorAction::kMediaFastForward,
AcceleratorAction::kFocusPip,
AcceleratorAction::kResizePipWindow,
// Device > Input
AcceleratorAction::kKeyboardBacklightToggle,

@ -27,9 +27,9 @@ namespace ash {
namespace {
// The total number of Ash accelerators.
constexpr int kAshAcceleratorsTotalNum = 156;
constexpr int kAshAcceleratorsTotalNum = 157;
// The hash of Ash accelerators.
constexpr char kAshAcceleratorsHash[] = "a51c3a9d4e052db8deba9a46a9ef48ce";
constexpr char kAshAcceleratorsHash[] = "00d64e050abba1b0354ad946f608d420";
std::string ToActionName(ash::AcceleratorAction action) {
return base::StrCat(

@ -220,17 +220,17 @@ TEST_F(PipControllerTest, TuckHandleIsShownAtCorrectPosition) {
EXPECT_FALSE(test_api.scoped_window_tucker());
}
class PipDoubleTapHandlerTest : public AshTestBase,
public testing::WithParamInterface<bool> {
class PipToggleResizeFeatureTest : public AshTestBase,
public testing::WithParamInterface<bool> {
public:
PipDoubleTapHandlerTest()
PipToggleResizeFeatureTest()
: scoped_feature_list_(features::kPipDoubleTapToResize) {}
PipDoubleTapHandlerTest(const PipDoubleTapHandlerTest&) = delete;
PipDoubleTapHandlerTest& operator=(const PipDoubleTapHandlerTest&) = delete;
PipToggleResizeFeatureTest(const PipToggleResizeFeatureTest&) = delete;
PipToggleResizeFeatureTest& operator=(const PipToggleResizeFeatureTest&) =
delete;
~PipDoubleTapHandlerTest() override = default;
~PipToggleResizeFeatureTest() override = default;
std::unique_ptr<aura::Window> CreateAppWindow(
const gfx::Rect& bounds,
@ -272,11 +272,18 @@ class PipDoubleTapHandlerTest : public AshTestBase,
}
}
void PressHotKey(aura::Window* window) {
auto* event_generator = GetEventGenerator();
event_generator->PressKeyAndModifierKeys(ui::VKEY_X, ui::EF_COMMAND_DOWN);
event_generator->ReleaseKeyAndModifierKeys(ui::VKEY_X, ui::EF_COMMAND_DOWN);
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
TEST_P(PipDoubleTapHandlerTest, TestSingleClick) {
TEST_P(PipToggleResizeFeatureTest, TestSingleClick) {
// Tests that single clicking a normal window or a PiP window does not change
// the bounds.
for (WindowStateType state_type :
@ -302,7 +309,7 @@ TEST_P(PipDoubleTapHandlerTest, TestSingleClick) {
}
}
TEST_P(PipDoubleTapHandlerTest, TestDoubleClickWithPip) {
TEST_P(PipToggleResizeFeatureTest, TestDoubleClickWithPip) {
auto window = CreateAppWindow(gfx::Rect(kExpectedPipDefaultSize),
WindowStateType::kPip);
@ -311,7 +318,7 @@ TEST_P(PipDoubleTapHandlerTest, TestDoubleClickWithPip) {
EXPECT_TRUE(WindowState::Get(window.get())->bounds_changed_by_user());
}
TEST_P(PipDoubleTapHandlerTest, TestDoubleClickAtMaxSize) {
TEST_P(PipToggleResizeFeatureTest, TestDoubleClickAtMaxSize) {
auto window =
CreateAppWindow(gfx::Rect(kExpectedPipMaxSize), WindowStateType::kPip);
@ -324,7 +331,7 @@ TEST_P(PipDoubleTapHandlerTest, TestDoubleClickAtMaxSize) {
gfx::Rect(kExpectedPipDefaultSize));
}
TEST_P(PipDoubleTapHandlerTest, TestDoubleClickAtNonMaxSize) {
TEST_P(PipToggleResizeFeatureTest, TestDoubleClickAtNonMaxSize) {
auto window = CreateAppWindow(gfx::Rect(300, 300), WindowStateType::kPip);
DoubleTapWindowCenter(window.get());
@ -332,7 +339,7 @@ TEST_P(PipDoubleTapHandlerTest, TestDoubleClickAtNonMaxSize) {
auto* window_state = WindowState::Get(window.get());
EXPECT_TRUE(window_state->bounds_changed_by_user());
// Expect it to go to max size on the first double-click/tap.
// Expect it to go to max size on the first hotkey press.
EXPECT_EQ(GetFakeWindowStateLastBounds(window_state),
gfx::Rect(kExpectedPipMaxSize));
@ -347,7 +354,40 @@ TEST_P(PipDoubleTapHandlerTest, TestDoubleClickAtNonMaxSize) {
EXPECT_EQ(GetFakeWindowStateLastBounds(window_state), gfx::Rect(300, 300));
}
TEST_P(PipToggleResizeFeatureTest, TestHotkeyWithPipWindow) {
auto window = CreateAppWindow(gfx::Rect(300, 300), WindowStateType::kPip);
PressHotKey(window.get());
auto* window_state = WindowState::Get(window.get());
EXPECT_TRUE(window_state->bounds_changed_by_user());
}
TEST_P(PipToggleResizeFeatureTest, TestHotKeyToggleTheSizeOfThePipWindow) {
auto window = CreateAppWindow(gfx::Rect(300, 300), WindowStateType::kPip);
PressHotKey(window.get());
auto* window_state = WindowState::Get(window.get());
EXPECT_TRUE(window_state->bounds_changed_by_user());
// Expect it to go to max size on the first double-click/tap.
EXPECT_EQ(GetFakeWindowStateLastBounds(window_state),
gfx::Rect(kExpectedPipMaxSize));
window =
CreateAppWindow(gfx::Rect(kExpectedPipMaxSize), WindowStateType::kPip);
window_state = WindowState::Get(window.get());
// Check when re-pressing the hotkey, if the window goes back to the last
// user-defined size.
PressHotKey(window.get());
EXPECT_TRUE(window_state->bounds_changed_by_user());
EXPECT_EQ(GetFakeWindowStateLastBounds(window_state), gfx::Rect(300, 300));
}
// Assume true is for mouse clicks and false is for gesture taps.
INSTANTIATE_TEST_SUITE_P(All, PipDoubleTapHandlerTest, testing::Bool());
INSTANTIATE_TEST_SUITE_P(All, PipToggleResizeFeatureTest, testing::Bool());
} // namespace ash

@ -123,6 +123,7 @@ chromium-metrics-reviews@google.com.
<variant name="PowerReleased"/>
<variant name="PrintUiHierarchies"/>
<variant name="PrivacyScreenToggle"/>
<variant name="ResizePipWindow"/>
<variant name="RestoreTab"/>
<variant name="RotateScreen"/>
<variant name="RotateWindow"/>

@ -188,6 +188,7 @@ chromium-metrics-reviews@google.com.
<int value="134" label="TilingWindowResizeUp"/>
<int value="135" label="TilingWindowResizeDown"/>
<int value="136" label="ToggleMouseKeys"/>
<int value="137" label="ResizePipWindow"/>
<int value="9000" label="DebugClearUseKMeansPref"/>
<int value="9001" label="DebugKeyboardBacklightToggle"/>
<int value="9002" label="DebugMicrophoneMuteToggle"/>