Skip to content

Commit

Permalink
CrOS Settings: Add device menu item description
Browse files Browse the repository at this point in the history
When the OsSettingsRevampWayfinding feature is enabled, the device menu
item should show a description, which shows at most 3 of the following
words in order or priority and if the respective device is connected.
  - "keyboard"
  - "mouse" OR "touchpad" (prioritize mouse)
  - "print"
  - "display"

Examples:
- http://screen/6TC4sZMTYMUDmYx.png
- http://screen/9ApqtQNRCYtbgWz.png
- http://screen/7j6cbxPPJzQiTGh.png

Bug: b:295062054
Test: browser_tests --gtest_filter="OSSettingsOsSettingsMenu*"
Change-Id: If6419720a2e5ec7ff8044ecc457b63b158a1d3f6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4939429
Reviewed-by: Connie Xu <conniekxu@chromium.org>
Reviewed-by: Xiaohui Chen <xiaohuic@chromium.org>
Commit-Queue: Wes Okuhara <wesokuhara@google.com>
Cr-Commit-Position: refs/heads/main@{#1210556}
  • Loading branch information
Wes Okuhara authored and Chromium LUCI CQ committed Oct 17, 2023
1 parent 72f047c commit 9a2b460
Show file tree
Hide file tree
Showing 12 changed files with 420 additions and 4 deletions.
21 changes: 21 additions & 0 deletions chrome/app/os_settings_strings.grdp
Original file line number Diff line number Diff line change
Expand Up @@ -898,6 +898,27 @@
<message name="IDS_SETTINGS_DEVICE_TITLE" desc="Name of the settings page which displays device and peripheral settings.">
Device
</message>
<message name="IDS_OS_SETTINGS_DEVICE_MENU_ITEM_DESCRIPTION_2_WORDS" desc="Description for the Device menu item in the left menu which lists relevant settings in this page. This includes 2 words from a predefined set of words.">
<ph name="DESCRIPTION_ITEM_1">$1<ex>Keyboard</ex></ph>, <ph name="DESCRIPTION_ITEM_2">$2<ex>mouse</ex></ph>
</message>
<message name="IDS_OS_SETTINGS_DEVICE_MENU_ITEM_DESCRIPTION_3_WORDS" desc="Description for the Device menu item in the left menu which lists relevant settings in this page. This includes 3 words from a predefined set of words.">
<ph name="DESCRIPTION_ITEM_1">$1<ex>Keyboard</ex></ph>, <ph name="DESCRIPTION_ITEM_2">$2<ex>mouse</ex></ph>, <ph name="DESCRIPTION_ITEM_3">$3<ex>print</ex></ph>
</message>
<message name="IDS_OS_SETTINGS_DEVICE_MENU_ITEM_DESCRIPTION_KEYBOARD" desc="Label for keyboard settings in the Device menu item description in the left menu.">
keyboard
</message>
<message name="IDS_OS_SETTINGS_DEVICE_MENU_ITEM_DESCRIPTION_MOUSE" desc="Label for mouse settings in the Device menu item description in the left menu.">
mouse
</message>
<message name="IDS_OS_SETTINGS_DEVICE_MENU_ITEM_DESCRIPTION_TOUCHPAD" desc="Label for touchpad settings in the Device menu item description in the left menu.">
touchpad
</message>
<message name="IDS_OS_SETTINGS_DEVICE_MENU_ITEM_DESCRIPTION_PRINT" desc="Label for print settings in the Device menu item description in the left menu.">
print
</message>
<message name="IDS_OS_SETTINGS_DEVICE_MENU_ITEM_DESCRIPTION_DISPLAY" desc="Label for display settings in the Device menu item description in the left menu.">
display
</message>

<!-- Personalization Page (OS settings) -->
<message name="IDS_OS_SETTINGS_PERSONALIZATION" desc="Name of the OS settings page which displays personalization preferences.">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
41e5d9ea275c0a0ed0f2a4731da46e699c93ff99
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ae85d0374c55d3fcb235d837dc4ad7b4bd0f613b
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
41e5d9ea275c0a0ed0f2a4731da46e699c93ff99
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ae85d0374c55d3fcb235d837dc4ad7b4bd0f613b
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
6660864bf07bb5204acb0f5b5d1c5397b5d6347c
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ae85d0374c55d3fcb235d837dc4ad7b4bd0f613b
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ae85d0374c55d3fcb235d837dc4ad7b4bd0f613b
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,16 @@ import './menu_item.js';

import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js';
import {WebUiListenerMixin} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js';
import {assert} from 'chrome://resources/js/assert.js';
import {IronSelectorElement} from 'chrome://resources/polymer/v3_0/iron-selector/iron-selector.js';
import {DomRepeat, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';

import {assertExists} from '../assert_extras.js';
import {isRevampWayfindingEnabled} from '../common/load_time_booleans.js';
import {FakeInputDeviceSettingsProvider} from '../device_page/fake_input_device_settings_provider.js';
import {getInputDeviceSettingsProvider} from '../device_page/input_device_mojo_interface_provider.js';
import {InputDeviceSettingsProviderInterface, Keyboard, Mouse, PointingStick, Touchpad} from '../device_page/input_device_settings_types.js';
import {KeyboardSettingsObserverReceiver, MouseSettingsObserverReceiver, PointingStickSettingsObserverReceiver, TouchpadSettingsObserverReceiver} from '../mojom-webui/input_device_settings_provider.mojom-webui.js';
import * as routesMojom from '../mojom-webui/routes.mojom-webui.js';
import {OsPageAvailability} from '../os_page_availability.js';
import {AccountManagerBrowserProxyImpl} from '../os_people_page/account_manager_browser_proxy.js';
Expand Down Expand Up @@ -49,6 +54,16 @@ export interface OsSettingsMenuElement {
};
}

/**
* Returns a copy of the given `str` with the first letter capitalized according
* to the locale.
*/
function capitalize(str: string): string {
const firstChar = str.charAt(0).toLocaleUpperCase();
const remainingStr = str.slice(1);
return `${firstChar}${remainingStr}`;
}

const OsSettingsMenuElementBase =
WebUiListenerMixin(RouteObserverMixin(I18nMixin(PolymerElement)));

Expand Down Expand Up @@ -79,7 +94,8 @@ export class OsSettingsMenuElement extends OsSettingsMenuElementBase {
basicMenuItems_: {
type: Array,
computed: 'computeBasicMenuItems_(pageAvailability.*,' +
'accountsMenuItemDescription_)',
'accountsMenuItemDescription_,' +
'deviceMenuItemDescription_)',
readOnly: true,
},

Expand Down Expand Up @@ -116,6 +132,24 @@ export class OsSettingsMenuElement extends OsSettingsMenuElementBase {
return this.i18n('primaryUserEmail');
},
},

hasKeyboard_: Boolean,

hasMouse_: Boolean,

/**
* Whether a pointing stick (such as a TrackPoint) is connected.
*/
hasPointingStick_: Boolean,

hasTouchpad_: Boolean,

deviceMenuItemDescription_: {
type: String,
value: '',
computed: 'computeDeviceMenuItemDescription_(hasKeyboard_,' +
'hasMouse_, hasPointingStick_, hasTouchpad_, hasHapticTouchpad_)',
},
};
}

Expand All @@ -128,22 +162,61 @@ export class OsSettingsMenuElement extends OsSettingsMenuElementBase {
private aboutMenuItemPath_: string;
private accountsMenuItemDescription_: string;

// Device section members
private deviceMenuItemDescription_: string;
private hasKeyboard_: boolean|undefined;
private hasMouse_: boolean|undefined;
private hasPointingStick_: boolean|undefined;
private hasTouchpad_: boolean|undefined;
private inputDeviceSettingsProvider_: InputDeviceSettingsProviderInterface;
private keyboardSettingsObserverReceiver_: KeyboardSettingsObserverReceiver|
undefined;
private mouseSettingsObserverReceiver_: MouseSettingsObserverReceiver|
undefined;
private pointingStickSettingsObserverReceiver_:
PointingStickSettingsObserverReceiver|undefined;
private touchpadSettingsObserverReceiver_: TouchpadSettingsObserverReceiver|
undefined;

constructor() {
super();

this.inputDeviceSettingsProvider_ = getInputDeviceSettingsProvider();
}

override connectedCallback(): void {
super.connectedCallback();

if (this.isRevampWayfindingEnabled_) {
// Accounts menu item.
this.updateAccountsMenuItemDescription_();
this.addWebUiListener(
'accounts-changed',
this.updateAccountsMenuItemDescription_.bind(this));

// Device menu item.
this.observeKeyboardSettings_();
this.observeMouseSettings_();
this.observePointingStickSettings_();
this.observeTouchpadSettings_();
}
}

override disconnectedCallback(): void {
super.disconnectedCallback();

// The following receivers are undefined in tests.
this.keyboardSettingsObserverReceiver_?.$.close();
this.mouseSettingsObserverReceiver_?.$.close();
this.pointingStickSettingsObserverReceiver_?.$.close();
this.touchpadSettingsObserverReceiver_?.$.close();
}

override ready(): void {
super.ready();

// Force render menu items so the matching item can be selected when the
// page initially loads
// page initially loads.
this.$.topMenuRepeat.render();
}

Expand Down Expand Up @@ -218,6 +291,7 @@ export class OsSettingsMenuElement extends OsSettingsMenuElementBase {
path: `/${routesMojom.DEVICE_SECTION_PATH}`,
icon: 'os-settings:laptop-chromebook',
label: this.i18n('devicePageTitle'),
sublabel: this.deviceMenuItemDescription_,
},
{
section: Section.kPersonalization,
Expand Down Expand Up @@ -439,6 +513,125 @@ export class OsSettingsMenuElement extends OsSettingsMenuElementBase {
assertExists(deviceAccount, 'No device account found.');
this.accountsMenuItemDescription_ = deviceAccount.email;
}

private observeKeyboardSettings_(): void {
if (this.inputDeviceSettingsProvider_ instanceof
FakeInputDeviceSettingsProvider) {
this.inputDeviceSettingsProvider_.observeKeyboardSettings(this);
return;
}

this.keyboardSettingsObserverReceiver_ =
new KeyboardSettingsObserverReceiver(this);
this.inputDeviceSettingsProvider_.observeKeyboardSettings(
this.keyboardSettingsObserverReceiver_.$.bindNewPipeAndPassRemote());
}

/** Implements KeyboardSettingsObserverInterface */
onKeyboardListUpdated(keyboards: Keyboard[]): void {
this.hasKeyboard_ = keyboards.length > 0;
}

/** Implements KeyboardSettingsObserverInterface */
onKeyboardPoliciesUpdated(): void {
// Not handled.
}

private observeMouseSettings_(): void {
if (this.inputDeviceSettingsProvider_ instanceof
FakeInputDeviceSettingsProvider) {
this.inputDeviceSettingsProvider_.observeMouseSettings(this);
return;
}

this.mouseSettingsObserverReceiver_ =
new MouseSettingsObserverReceiver(this);
this.inputDeviceSettingsProvider_.observeMouseSettings(
this.mouseSettingsObserverReceiver_.$.bindNewPipeAndPassRemote());
}

/** Implements MouseSettingsObserverInterface */
onMouseListUpdated(mice: Mouse[]): void {
this.hasMouse_ = mice.length > 0;
}

/** Implements MouseSettingsObserverInterface */
onMousePoliciesUpdated(): void {
// Not handled.
}

private observePointingStickSettings_(): void {
if (this.inputDeviceSettingsProvider_ instanceof
FakeInputDeviceSettingsProvider) {
this.inputDeviceSettingsProvider_.observePointingStickSettings(this);
return;
}

this.pointingStickSettingsObserverReceiver_ =
new PointingStickSettingsObserverReceiver(this);
this.inputDeviceSettingsProvider_.observePointingStickSettings(
this.pointingStickSettingsObserverReceiver_.$
.bindNewPipeAndPassRemote());
}

/** Implements PointingStickSettingsObserverInterface */
onPointingStickListUpdated(pointingSticks: PointingStick[]): void {
this.hasPointingStick_ = pointingSticks.length > 0;
}

private observeTouchpadSettings_(): void {
if (this.inputDeviceSettingsProvider_ instanceof
FakeInputDeviceSettingsProvider) {
this.inputDeviceSettingsProvider_.observeTouchpadSettings(this);
return;
}

this.touchpadSettingsObserverReceiver_ =
new TouchpadSettingsObserverReceiver(this);
this.inputDeviceSettingsProvider_.observeTouchpadSettings(
this.touchpadSettingsObserverReceiver_.$.bindNewPipeAndPassRemote());
}

/** Implements TouchpadSettingsObserverInterface */
onTouchpadListUpdated(touchpads: Touchpad[]): void {
this.hasTouchpad_ = touchpads.length > 0;
}

/**
* Only show at most 3 strings in order of priority:
* - "keyboard" (if available)
* - "mouse" OR "touchpad" (if available, prioritize mouse)
* - "print"
* - "display"
*/
private computeDeviceMenuItemDescription_(): string {
if (!this.isRevampWayfindingEnabled_) {
return '';
}

const wordOptions: string[] = [];

if (this.hasKeyboard_) {
wordOptions.push(this.i18n('deviceMenuItemDescriptionKeyboard'));
}

if (this.hasMouse_ || this.hasPointingStick_) {
wordOptions.push(this.i18n('deviceMenuItemDescriptionMouse'));
} else if (this.hasTouchpad_) {
wordOptions.push(this.i18n('deviceMenuItemDescriptionTouchpad'));
}

wordOptions.push(
this.i18n('deviceMenuItemDescriptionPrint'),
this.i18n('deviceMenuItemDescriptionDisplay'));

const words = wordOptions.slice(0, 3);
assert(words.length === 2 || words.length === 3);
return capitalize(this.i18n(
words.length === 2 ? 'deviceMenuItemDescription2Words' :
'deviceMenuItemDescription3Words',
...words));
}
}

declare global {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1069,6 +1069,20 @@ void DeviceSection::AddLoadTimeData(content::WebUIDataSource* html_source) {
: IDS_OS_SETTINGS_TOUCHPAD_REVERSE_SCROLL_LABEL},
{"touchpadScrollDescription",
IDS_OS_SETTINGS_REVAMP_TOUCHPAD_REVERSE_SCROLL_DESCRIPTION},
{"deviceMenuItemDescription2Words",
IDS_OS_SETTINGS_DEVICE_MENU_ITEM_DESCRIPTION_2_WORDS},
{"deviceMenuItemDescription3Words",
IDS_OS_SETTINGS_DEVICE_MENU_ITEM_DESCRIPTION_3_WORDS},
{"deviceMenuItemDescriptionKeyboard",
IDS_OS_SETTINGS_DEVICE_MENU_ITEM_DESCRIPTION_KEYBOARD},
{"deviceMenuItemDescriptionMouse",
IDS_OS_SETTINGS_DEVICE_MENU_ITEM_DESCRIPTION_MOUSE},
{"deviceMenuItemDescriptionTouchpad",
IDS_OS_SETTINGS_DEVICE_MENU_ITEM_DESCRIPTION_TOUCHPAD},
{"deviceMenuItemDescriptionPrint",
IDS_OS_SETTINGS_DEVICE_MENU_ITEM_DESCRIPTION_PRINT},
{"deviceMenuItemDescriptionDisplay",
IDS_OS_SETTINGS_DEVICE_MENU_ITEM_DESCRIPTION_DISPLAY},
};
html_source->AddLocalizedStrings(kDeviceStrings);

Expand Down
4 changes: 4 additions & 0 deletions chrome/test/data/webui/chai_assert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@ export function assertStringContains(expected: string, contains: string) {
chai.expect(expected).to.have.string(contains);
}

export function assertStringExcludes(expected: string, excludes: string): void {
chai.expect(expected).not.to.have.string(excludes);
}

/**
* @param value The value to check if strictly equals null (value === null).
* @param message Optional error message.
Expand Down

0 comments on commit 9a2b460

Please sign in to comment.