0

Add shortcut to toggle the Gemini app

Bug: b:375245704
Change-Id: Ieb732b597a06f6889a33f6a384292eb60b90337a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5967254
Reviewed-by: David Padlipsky <dpad@google.com>
Commit-Queue: Michael Checo <michaelcheco@google.com>
Reviewed-by: Matthew Denton <mpdenton@chromium.org>
Reviewed-by: Jimmy Gong <jimmyxgong@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Reviewed-by: James Cook <jamescook@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1392974}
This commit is contained in:
Michael Checo
2024-12-06 17:06:40 +00:00
committed by Chromium LUCI CQ
parent b74451d27c
commit 833ea8ffb6
20 changed files with 94 additions and 2 deletions

@@ -658,6 +658,10 @@ bool CanResizePipWindow() {
return Shell::Get()->pip_controller()->CanResizePip(); return Shell::Get()->pip_controller()->CanResizePip();
} }
bool CanToggleGeminiApp() {
return features::IsAppLaunchShortcutEnabled();
}
bool CanScreenshot(bool take_screenshot) { bool CanScreenshot(bool take_screenshot) {
// |AcceleratorAction::kTakeScreenshot| is allowed when user session is // |AcceleratorAction::kTakeScreenshot| is allowed when user session is
// blocked. // blocked.
@@ -1087,6 +1091,12 @@ void OpenHelp() {
NewWindowDelegate::GetInstance()->OpenGetHelp(); NewWindowDelegate::GetInstance()->OpenGetHelp();
} }
void ToggleGeminiApp() {
if (ash::features::IsAppLaunchShortcutEnabled()) {
NewWindowDelegate::GetInstance()->ToggleGeminiApp();
}
}
void PerformTilingWindowResize(AcceleratorAction action) { void PerformTilingWindowResize(AcceleratorAction action) {
if (!features::IsTilingWindowResizeEnabled()) { if (!features::IsTilingWindowResizeEnabled()) {
return; return;

@@ -111,6 +111,8 @@ ASH_EXPORT bool CanWindowSnap();
ASH_EXPORT bool CanResizePipWindow(); ASH_EXPORT bool CanResizePipWindow();
ASH_EXPORT bool CanToggleGeminiApp();
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// Accelerator commands. // Accelerator commands.
// Note: These functions should be independent and not depend on ui::Accelerator // Note: These functions should be independent and not depend on ui::Accelerator
@@ -327,6 +329,9 @@ ASH_EXPORT void ToggleClipboardHistory(bool is_plain_text_paste);
// triggered Quick Insert. // triggered Quick Insert.
ASH_EXPORT void ToggleQuickInsert(base::TimeTicks accelerator_timestamp); ASH_EXPORT void ToggleQuickInsert(base::TimeTicks accelerator_timestamp);
// Toggles Gemini.
ASH_EXPORT void ToggleGeminiApp();
// Enables Select to Speak if the feature is currently disabled. Does nothing if // Enables Select to Speak if the feature is currently disabled. Does nothing if
// the feature is currently enabled. // the feature is currently enabled.
ASH_EXPORT void EnableSelectToSpeak(); ASH_EXPORT void EnableSelectToSpeak();

@@ -1030,6 +1030,8 @@ bool AcceleratorControllerImpl::CanPerformAction(
return CanHandleLockButton(accelerator); return CanHandleLockButton(accelerator);
case AcceleratorAction::kResizePipWindow: case AcceleratorAction::kResizePipWindow:
return accelerators::CanResizePipWindow(); return accelerators::CanResizePipWindow();
case AcceleratorAction::kToggleGeminiApp:
return accelerators::CanToggleGeminiApp();
// The following are always enabled. // The following are always enabled.
case AcceleratorAction::kBrightnessDown: case AcceleratorAction::kBrightnessDown:
@@ -1678,6 +1680,9 @@ void AcceleratorControllerImpl::PerformAction(
case AcceleratorAction::kResizePipWindow: case AcceleratorAction::kResizePipWindow:
accelerators::ResizePipWindow(); accelerators::ResizePipWindow();
break; break;
case AcceleratorAction::kToggleGeminiApp:
accelerators::ToggleGeminiApp();
break;
} }
RecordActionUmaHistogram(action, accelerator); RecordActionUmaHistogram(action, accelerator);

@@ -160,6 +160,11 @@ std::vector<ash::AcceleratorData> GetDefaultAccelerators() {
if (ash::debug::DeveloperAcceleratorsEnabled()) { if (ash::debug::DeveloperAcceleratorsEnabled()) {
AppendAcceleratorData(accelerators, ash::kDeveloperAcceleratorData); AppendAcceleratorData(accelerators, ash::kDeveloperAcceleratorData);
} }
if (ash::features::IsAppLaunchShortcutEnabled()) {
AppendAcceleratorData(accelerators, ash::kGeminiAcceleratorData);
}
return accelerators; return accelerators;
} }

@@ -4306,6 +4306,9 @@ No devices connected.
<message name="IDS_ASH_ACCELERATOR_DESCRIPTION_OPEN_CROSH" desc="Label for accelerator action - Open Crosh window."> <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_OPEN_CROSH" desc="Label for accelerator action - Open Crosh window.">
Open Crosh window Open Crosh window
</message> </message>
<message name="IDS_ASH_ACCELERATOR_DESCRIPTION_TOGGLE_GEMINI_APP" desc="Label for accelerator action - Toggle Gemini App.">
Toggle Gemini
</message>
<message name="IDS_ASH_ACCELERATOR_DESCRIPTION_OPEN_DIAGNOSTICS" desc="Label for accelerator action - Open Diagnostics App."> <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_OPEN_DIAGNOSTICS" desc="Label for accelerator action - Open Diagnostics App.">
Open Diagnostics app Open Diagnostics app
</message> </message>

@@ -0,0 +1 @@
fa7328a6b95120ad9c571390f3fb50477babe017

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

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

@@ -451,6 +451,13 @@ ASH_PUBLIC_EXPORT inline constexpr size_t
kTilingWindowResizeAcceleratorDataLength = kTilingWindowResizeAcceleratorDataLength =
std::size(kTilingWindowResizeAcceleratorData); std::size(kTilingWindowResizeAcceleratorData);
ASH_PUBLIC_EXPORT inline constexpr AcceleratorData kGeminiAcceleratorData[] = {
{true, ui::VKEY_F23, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN,
AcceleratorAction::kToggleGeminiApp},
};
ASH_PUBLIC_EXPORT inline constexpr size_t kGeminiAcceleratorDataLength =
std::size(kGeminiAcceleratorData);
// The public-facing interface for accelerator handling, which is Ash's duty to // The public-facing interface for accelerator handling, which is Ash's duty to
// implement. // implement.
class ASH_PUBLIC_EXPORT AcceleratorController { class ASH_PUBLIC_EXPORT AcceleratorController {

@@ -135,6 +135,9 @@ class ASH_PUBLIC_EXPORT NewWindowDelegate {
// Opens a file on the local file system (which may be DriveFS). // Opens a file on the local file system (which may be DriveFS).
virtual void OpenFile(const base::FilePath& file_path) = 0; virtual void OpenFile(const base::FilePath& file_path) = 0;
// Toggles Gemini.
virtual void ToggleGeminiApp() = 0;
protected: protected:
NewWindowDelegate(); NewWindowDelegate();
NewWindowDelegate(const NewWindowDelegate&) = delete; NewWindowDelegate(const NewWindowDelegate&) = delete;

@@ -40,5 +40,6 @@ void TestNewWindowDelegate::OpenFeedbackPage(
void TestNewWindowDelegate::OpenPersonalizationHub() {} void TestNewWindowDelegate::OpenPersonalizationHub() {}
void TestNewWindowDelegate::OpenCaptivePortalSignin(const GURL& url) {} void TestNewWindowDelegate::OpenCaptivePortalSignin(const GURL& url) {}
void TestNewWindowDelegate::OpenFile(const base::FilePath& file_path) {} void TestNewWindowDelegate::OpenFile(const base::FilePath& file_path) {}
void TestNewWindowDelegate::ToggleGeminiApp() {}
} // namespace ash } // namespace ash

@@ -44,6 +44,7 @@ class ASH_PUBLIC_EXPORT TestNewWindowDelegate : public NewWindowDelegate {
void OpenPersonalizationHub() override; void OpenPersonalizationHub() override;
void OpenCaptivePortalSignin(const GURL& url) override; void OpenCaptivePortalSignin(const GURL& url) override;
void OpenFile(const base::FilePath& file_path) override; void OpenFile(const base::FilePath& file_path) override;
void ToggleGeminiApp() override;
}; };
} // namespace ash } // namespace ash

@@ -145,6 +145,7 @@ enum AcceleratorAction {
kTilingWindowResizeDown, kTilingWindowResizeDown,
kToggleMouseKeys, kToggleMouseKeys,
kResizePipWindow, kResizePipWindow,
kToggleGeminiApp,
// The following are DEBUG actions with an offset. This is to keep the enum // 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. // in sync with `AcceleratorActions` in ash/public/cpp/accelerator_actions.h.
kDebugClearUseKMeansPref = 9000, kDebugClearUseKMeansPref = 9000,

@@ -293,6 +293,8 @@ EnumTraits<mojom_accelerator_action, ash::AcceleratorAction>::ToMojom(
return mojom_accelerator_action::kMinimizeTopWindowOnBack; return mojom_accelerator_action::kMinimizeTopWindowOnBack;
case ash::AcceleratorAction::kResizePipWindow: case ash::AcceleratorAction::kResizePipWindow:
return mojom_accelerator_action::kResizePipWindow; return mojom_accelerator_action::kResizePipWindow;
case ash::AcceleratorAction::kToggleGeminiApp:
return mojom_accelerator_action::kToggleGeminiApp;
case ash::AcceleratorAction::kDebugClearUseKMeansPref: case ash::AcceleratorAction::kDebugClearUseKMeansPref:
return mojom_accelerator_action::kDebugClearUseKMeansPref; return mojom_accelerator_action::kDebugClearUseKMeansPref;
case ash::AcceleratorAction::kDebugKeyboardBacklightToggle: case ash::AcceleratorAction::kDebugKeyboardBacklightToggle:
@@ -775,6 +777,9 @@ bool EnumTraits<mojom_accelerator_action, ash::AcceleratorAction>::FromMojom(
case mojom_accelerator_action::kResizePipWindow: case mojom_accelerator_action::kResizePipWindow:
*out = ash::AcceleratorAction::kResizePipWindow; *out = ash::AcceleratorAction::kResizePipWindow;
return true; return true;
case mojom_accelerator_action::kToggleGeminiApp:
*out = ash::AcceleratorAction::kToggleGeminiApp;
return true;
case mojom_accelerator_action::kDebugClearUseKMeansPref: case mojom_accelerator_action::kDebugClearUseKMeansPref:
*out = ash::AcceleratorAction::kDebugClearUseKMeansPref; *out = ash::AcceleratorAction::kDebugClearUseKMeansPref;
return true; return true;

@@ -664,6 +664,14 @@ const AcceleratorLayoutMap& GetAcceleratorLayoutMap() {
/*locked=*/false, /*locked=*/false,
mojom::AcceleratorLayoutStyle::kDefault, mojom::AcceleratorLayoutStyle::kDefault,
mojom::AcceleratorSource::kAsh)}, mojom::AcceleratorSource::kAsh)},
{AcceleratorAction::kToggleGeminiApp,
AcceleratorLayoutDetails(
AcceleratorAction::kToggleGeminiApp,
IDS_ASH_ACCELERATOR_DESCRIPTION_TOGGLE_GEMINI_APP,
mojom::AcceleratorCategory::kGeneral,
mojom::AcceleratorSubcategory::kApps,
/*locked=*/false, mojom::AcceleratorLayoutStyle::kDefault,
mojom::AcceleratorSource::kAsh)},
// Device // Device
{AcceleratorAction::kVolumeUp, {AcceleratorAction::kVolumeUp,

@@ -310,6 +310,7 @@ inline constexpr uint32_t kAcceleratorLayouts[] = {
AcceleratorAction::kToggleResizeLockMenu, AcceleratorAction::kToggleResizeLockMenu,
AcceleratorAction::kShowTaskManager, AcceleratorAction::kShowTaskManager,
AcceleratorAction::kOpenCrosh, AcceleratorAction::kOpenCrosh,
AcceleratorAction::kToggleGeminiApp,
// Device // Device
// Device > Media // Device > Media

@@ -49,6 +49,7 @@
#include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_navigator.h" #include "chrome/browser/ui/browser_navigator.h"
#include "chrome/browser/ui/browser_navigator_params.h" #include "chrome/browser/ui/browser_navigator_params.h"
#include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/browser_window.h"
@@ -165,6 +166,11 @@ bool OpenFilesSwa(Profile* const profile,
return true; return true;
} }
bool IsGeminiApp(Browser* browser) {
return web_app::GetAppIdFromApplicationName(browser->app_name()) ==
ash::kGeminiAppId;
}
} // namespace } // namespace
ChromeNewWindowClient::ChromeNewWindowClient() { ChromeNewWindowClient::ChromeNewWindowClient() {
@@ -525,6 +531,32 @@ void ChromeNewWindowClient::OpenFile(const base::FilePath& file_path) {
platform_util::OpenOperationCallback()); platform_util::OpenOperationCallback());
} }
void ChromeNewWindowClient::ToggleGeminiApp() {
Profile* const profile = ProfileManager::GetActiveUserProfile();
const auto& browsers = BrowserList::GetInstance()->OrderedByActivation();
auto it = std::find_if(browsers.begin(), browsers.end(),
[profile](Browser* browser) {
return browser->profile() == profile &&
browser->type() == Browser::Type::TYPE_APP &&
IsGeminiApp(browser);
});
Browser* active_browser = (it != browsers.end()) ? *it : nullptr;
if (!active_browser) {
apps::AppServiceProxyFactory::GetForProfile(profile)->Launch(
ash::kGeminiAppId, ui::EF_NONE, apps::LaunchSource::kFromKeyboard);
return;
}
BrowserWindow* app_window = active_browser->window();
if (app_window->IsActive()) {
app_window->Minimize();
} else {
app_window->Activate();
}
}
void ChromeNewWindowClient::LaunchCameraApp(const std::string& queries, void ChromeNewWindowClient::LaunchCameraApp(const std::string& queries,
bool launch_in_dialog, bool launch_in_dialog,
int32_t task_id) { int32_t task_id) {

@@ -50,6 +50,7 @@ class ChromeNewWindowClient : public ash::NewWindowDelegate,
void OpenPersonalizationHub() override; void OpenPersonalizationHub() override;
void OpenCaptivePortalSignin(const GURL& url) override; void OpenCaptivePortalSignin(const GURL& url) override;
void OpenFile(const base::FilePath& file_path) override; void OpenFile(const base::FilePath& file_path) override;
void ToggleGeminiApp() override;
// arc::ControlCameraAppDelegate: // arc::ControlCameraAppDelegate:
void LaunchCameraApp(const std::string& queries, void LaunchCameraApp(const std::string& queries,

@@ -160,6 +160,7 @@ chromium-metrics-reviews@google.com.
<variant name="ToggleFullscreen"/> <variant name="ToggleFullscreen"/>
<variant name="ToggleFullscreenMagnifier"/> <variant name="ToggleFullscreenMagnifier"/>
<variant name="ToggleGameDashboard"/> <variant name="ToggleGameDashboard"/>
<variant name="ToggleGeminiApp"/>
<variant name="ToggleHighContrast"/> <variant name="ToggleHighContrast"/>
<variant name="ToggleImeMenuBubble"/> <variant name="ToggleImeMenuBubble"/>
<variant name="ToggleMaximized"/> <variant name="ToggleMaximized"/>

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