0

Deprecate and "unimplement" panel attach/detach API functionality

Update the Glic API to the panel becoming detached-only. This change
updates the API definition to comply with that and "unimplements" the
attachment related functions when the detached-only feature flag is
enabled.

The test client was updated to better represent unavailable functionality, and a breaking test parameterized to only be executed
if attachment is available.

BYPASS_GLIC_API_COMPATIBILITY_CHECK=PanelOpeningData is not yet being used by the web client

Bug: 406281026, 406528268
Change-Id: Ifff997a77c2022471cf246c72447f3372631f4c8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6406113
Reviewed-by: Nick Birnie <birnie@google.com>
Auto-Submit: Carlos Knippschild <carlosk@chromium.org>
Reviewed-by: Carlos Knippschild <carlosk@chromium.org>
Commit-Queue: Nick Birnie <birnie@google.com>
Cr-Commit-Position: refs/heads/main@{#1439847}
This commit is contained in:
Carlos Knippschild 2025-03-28 22:15:44 -07:00 committed by Chromium LUCI CQ
parent 1ef4f589a4
commit da4bba3901
7 changed files with 113 additions and 39 deletions
chrome
browser
test/data/webui/glic/test_client

@ -164,6 +164,8 @@ struct WebClientInitialState {
// Whether to enable the OpenOsPermissionSettingsMenu API for the client.
// Depends on platform. Currently only allowed for Mac.
bool open_os_settings_api_is_allowed;
// Reflects the enabling state of always-detached mode.
bool always_detached_mode;
};
// Options for getting tab context.

@ -324,6 +324,8 @@ class GlicWebClientHandler : public glic::mojom::WebClientHandler,
state->open_os_settings_api_is_allowed = false;
#endif
state->always_detached_mode = GlicWindowController::AlwaysDetached();
local_state_pref_change_registrar_.Init(g_browser_process->local_state());
local_state_pref_change_registrar_.Add(
prefs::kGlicLauncherHotkey,

@ -189,14 +189,28 @@ class GlicUiInteractiveUiTestBase : public test::InteractiveGlicTest {
};
// Tests the network being connected at startup (as normal).
class GlicUiConnectedUiTest : public GlicUiInteractiveUiTestBase {
class GlicUiConnectedUiTest : public GlicUiInteractiveUiTestBase,
public testing::WithParamInterface<bool> {
public:
GlicUiConnectedUiTest()
: GlicUiInteractiveUiTestBase(TestParams(/*connected=*/true)) {}
: GlicUiInteractiveUiTestBase(TestParams(/*connected=*/true)) {
if (IsDetachedOnlyModeEnabled()) {
feature_list_.InitAndEnableFeature(features::kGlicDetached);
} else {
feature_list_.InitAndDisableFeature(features::kGlicDetached);
}
}
~GlicUiConnectedUiTest() override = default;
bool IsDetachedOnlyModeEnabled() const { return GetParam(); }
private:
base::test::ScopedFeatureList feature_list_;
};
IN_PROC_BROWSER_TEST_F(GlicUiConnectedUiTest, DisconnectedPanelHidden) {
INSTANTIATE_TEST_SUITE_P(All, GlicUiConnectedUiTest, testing::Bool());
IN_PROC_BROWSER_TEST_P(GlicUiConnectedUiTest, DisconnectedPanelHidden) {
RunTestSequence(
ObserveState(kGlicUiStateHistory, &window_controller()),
OpenGlicWindow(GlicWindowMode::kAttached, GlicInstrumentMode::kHostOnly),
@ -204,7 +218,7 @@ IN_PROC_BROWSER_TEST_F(GlicUiConnectedUiTest, DisconnectedPanelHidden) {
CheckElementVisible(kOfflinePanel, false));
}
IN_PROC_BROWSER_TEST_F(GlicUiConnectedUiTest,
IN_PROC_BROWSER_TEST_P(GlicUiConnectedUiTest,
DoesNotHidePanelWhenReadyButOffline) {
RunTestSequence(
ObserveState(kGlicUiStateHistory, &window_controller()),
@ -214,14 +228,17 @@ IN_PROC_BROWSER_TEST_F(GlicUiConnectedUiTest,
CheckState(kGlicUiStateHistory, IsCurrently(WebUiState::kReady)));
}
IN_PROC_BROWSER_TEST_F(GlicUiConnectedUiTest, CanAttachWithBrowserWindow) {
IN_PROC_BROWSER_TEST_P(GlicUiConnectedUiTest, CanAttachWithBrowserWindow) {
if (IsDetachedOnlyModeEnabled()) {
GTEST_SKIP();
}
RunTestSequence(OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents),
CheckMockElementChecked({"#canAttachCheckbox"}, true));
}
// DISABLED: Not reliable yet.
IN_PROC_BROWSER_TEST_F(GlicUiConnectedUiTest,
IN_PROC_BROWSER_TEST_P(GlicUiConnectedUiTest,
DISABLED_CanNotAttachWithMinimizedBrowser) {
RunTestSequence(
OpenGlicWindow(GlicWindowMode::kDetached,
@ -235,7 +252,7 @@ IN_PROC_BROWSER_TEST_F(GlicUiConnectedUiTest,
CheckMockElementChecked({"#canAttachCheckbox"}, false));
}
IN_PROC_BROWSER_TEST_F(GlicUiConnectedUiTest,
IN_PROC_BROWSER_TEST_P(GlicUiConnectedUiTest,
DoesNotNavigateToUnsupportedOrigin) {
RunTestSequence(
ObserveState(kGlicUiStateHistory, &window_controller()),
@ -253,7 +270,7 @@ IN_PROC_BROWSER_TEST_F(GlicUiConnectedUiTest,
})js")));
}
IN_PROC_BROWSER_TEST_F(GlicUiConnectedUiTest, DoesNavigateToSupportedOrigin) {
IN_PROC_BROWSER_TEST_P(GlicUiConnectedUiTest, DoesNavigateToSupportedOrigin) {
RunTestSequence(
ObserveState(kGlicUiStateHistory, &window_controller()),
OpenGlicWindow(GlicWindowMode::kAttached,

@ -248,6 +248,8 @@ export declare interface GlicBrowserHost {
closePanel?(): Promise<void>;
/**
* @deprecated The panel will only maintain the detached state.
*
* Requests that the web client's panel be attached to a browser window.
* If attachment fails, the panel's state will not be updated. getPanelState
* can be used to monitor whether attachment is successful.
@ -255,6 +257,8 @@ export declare interface GlicBrowserHost {
attachPanel?(): void;
/**
* @deprecated The panel will only maintain the detached state.
*
* Requests that the web client's panel be detached from a browser window
* (floats free).
*/
@ -267,7 +271,11 @@ export declare interface GlicBrowserHost {
*/
showProfilePicker?(): void;
/** Returns the state of the panel. */
/**
* @deprecated The panel will only maintain the detached state.
*
* Returns the state of the panel.
*/
getPanelState?(): ObservableValue<PanelState>;
/**
@ -281,6 +289,8 @@ export declare interface GlicBrowserHost {
panelActive(): ObservableValue<boolean>;
/**
* @deprecated The panel will only maintain the detached state.
*
* Whether the panel can be attached. This is true if there is a browser
* window suitable for attachment. This state is only meaningful when the
* panel is in the detached state, and should be not be considered otherwise
@ -414,8 +424,8 @@ export declare interface GlicBrowserHost {
setSyntheticExperimentState?(trialName: string, groupName: string): void;
/**
* Opens the OS permission settings menu for the given permission type.
* Supports `media` for microphone ad `geolocation` for location. This
* Opens the OS permission settings page for the given permission type.
* Supports `media` for microphone and `geolocation` for location. This
* function is available when running on Mac.
*/
openOsPermissionSettingsMenu?(permission: string): void;
@ -537,7 +547,11 @@ export declare interface OpenPanelInfo {
canUserResize?: boolean;
}
/** A panel can be in one of these three states. */
/**
* @deprecated The panel will only maintain the detached state.
*
* A panel can be in one of these three states.
*/
export enum PanelStateKind {
/** Not shown. This is the initial state. */
HIDDEN = 0,
@ -551,9 +565,15 @@ export enum PanelStateKind {
ATTACHED = 2,
}
/** Information of how the panel is being presented/configured. */
/**
* @deprecated The panel will only maintain the detached state.
*
* Information of how the panel is being presented/configured.
*/
export declare interface PanelState {
/** The panel's presentation kind/state. */
/**
* The panel's presentation kind/state.
*/
kind: PanelStateKind;
/**
* Present only when attached to a window, indicating which window it is
@ -567,10 +587,14 @@ export declare interface PanelState {
* information.
*/
export declare interface PanelOpeningData {
/** The state of the panel as it's being opened. */
panelState: PanelState;
/**
* @deprecated The panel will only maintain the detached state.
*
* The state of the panel as it's being opened.
*/
panelState?: PanelState;
/** Indicates the entry point used to trigger the opening of the panel. */
invocationSource: InvocationSource;
invocationSource?: InvocationSource;
}
/** Entry points that can trigger the opening of the panel. */

@ -250,6 +250,13 @@ class GlicBrowserHostImpl implements GlicBrowserHost {
if (!state.openOsSettingsApiIsAllowed) {
(this as GlicBrowserHost).openOsPermissionSettingsMenu = undefined;
}
if (state.alwaysDetachedMode) {
(this as GlicBrowserHost).attachPanel = undefined;
(this as GlicBrowserHost).detachPanel = undefined;
(this as GlicBrowserHost).canAttachPanel = undefined;
(this as GlicBrowserHost).getPanelState = undefined;
}
}
webClientInitialized(

@ -126,6 +126,14 @@ found in the LICENSE file.
flex-grow: 1;
}
*:disabled {
pointer-events: none;
opacity: 0.6;
}
fieldset:disabled :is(h1, h2, h3, h4, h5, h6) {
text-decoration: line-through;
}
/* Dark Mode Styles */
@media (prefers-color-scheme: dark) {
body {
@ -192,17 +200,19 @@ found in the LICENSE file.
Update</button>
</div>
<div class="section">
<h1>MacOS Permissions</h2>
<button id="getOsMicrophonePermissionButton">Get OS Microphone permission state</button>
<span id="osMicrophonePermissionResult"></span>
<div>
<div class="permission-switch">
<label for="osGeolocationPermissionSwitch">OS Geolocation:</label>
<input type="checkbox" id="osGeolocationPermissionSwitch" disabled />
</div>
<button id="openOsLocationSettings">Open OS Location settings</button>
<button id="openOsMicrophoneSettings">Open OS Microphone settings</button>
</div>
<fieldset id="macOsPermissionsFieldset">
<h1>MacOS Permissions</h1>
<button id="getOsMicrophonePermissionButton">Get OS Microphone permission state</button>
<span id="osMicrophonePermissionResult"></span>
<div>
<div class="permission-switch">
<label for="osGeolocationPermissionSwitch">OS Geolocation:</label>
<input type="checkbox" id="osGeolocationPermissionSwitch" disabled />
</div>
<button id="openOsLocationSettings">Open OS Location settings</button>
<button id="openOsMicrophoneSettings">Open OS Microphone settings</button>
</div>
</fieldset>
</div>
<div class="section">
<h1>Glic Settings</h1>
@ -267,16 +277,17 @@ found in the LICENSE file.
<br />
</div>
<div class="section">
<h1>Test Panel Controls</h1>
<button id="attachpanelbn">Attach Panel</button>
<br />
<button id="detachpanelbn">Detach Panel</button>
<br />
<div>
<label>Can Attach:
<input id="canAttachCheckbox" type="checkbox" disabled>
</label>
</div>
<fieldset id="attachmentControlsFieldset">
<h1>Attachment Controls</h1>
<div>
<label>Can Attach:
<input id="canAttachCheckbox" type="checkbox" disabled>
</label>
</div>
<button id="attachpanelbn">Attach Panel</button>
&nbsp;
<button id="detachpanelbn">Detach Panel</button>
</fieldset>
</div>
<div class="section">
<h1>Test getContextFromFocusedTab()</h1>
@ -284,6 +295,7 @@ found in the LICENSE file.
<button id="getpagecontext">Get page Context</button>
<div>
<label> <input type="checkbox" id="innerTextCheckbox" /> Inner Text </label>
<br />
<label> innerTextBytesLimit: <input id="innerTextBytesLimit" value="100">
</label>
</div>

@ -112,6 +112,8 @@ interface PageElementTypes {
actionStatus: HTMLSpanElement;
actionUpdatedContextResult: HTMLSpanElement;
actionUpdatedScreenshotImg: HTMLImageElement;
macOsPermissionsFieldset: HTMLFieldSetElement;
attachmentControlsFieldset: HTMLFieldSetElement;
}
const $: PageElementTypes = new Proxy({}, {
@ -152,7 +154,15 @@ class WebClient implements GlicWebClient {
logMessage('initialize called');
$.pageHeader!.classList.add('connected');
// Disable sections with unavailable functionality.
if (this.browser.openOsPermissionSettingsMenu === undefined) {
logMessage('OS permissions are disabled');
$.macOsPermissionsFieldset.disabled = true;
}
if (this.browser.attachPanel === undefined) {
logMessage('Attachment controls are disabled (detached-only mode)');
$.attachmentControlsFieldset.disabled = true;
}
const ver = await browser.getChromeVersion();
logMessage(`Chrome version: ${JSON.stringify(ver)}`);