0

[CrOS Cellular] Implement view only mode in <apn-detail-dialog>

Now the <apn-detail-dialog> has support for view only mode, which
 disables all the fields and changes the title and button of the dialog.

Screenshot: https://screenshot.googleplex.com/6joGLBQ4NGtgnLV

Test:
autoninja -C out/Default/ browser_tests && testing/xvfb.py ./out/Default/browser_tests --gtest_filter=*ApnDetailDialog*
autoninja -C out/Default/ browser_tests && testing/xvfb.py ./out/Default/browser_tests --gtest_filter=*ApnListItemTest*

Bug: b:162365553
Change-Id: Id2869a7de77d62c797b3db6f6b3345676715c70f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4080228
Reviewed-by: Chad Duffin <chadduffin@chromium.org>
Commit-Queue: Fahad Mansoor <fahadmansoor@google.com>
Reviewed-by: Gordon Seto <gordonseto@google.com>
Cr-Commit-Position: refs/heads/main@{#1080276}
This commit is contained in:
Fahad Mansoor
2022-12-07 11:13:45 +00:00
committed by Chromium LUCI CQ
parent e00792f9c3
commit cb62d52690
12 changed files with 277 additions and 53 deletions
ash/webui/common/resources/network
chrome
browser
resources
settings
test
data
webui
cr_components
chromeos
settings
chromeos
ui/chromeos/strings/network

@ -83,6 +83,7 @@ js_library("apn_list") {
js_library("apn_list_item") {
deps = [
"//ash/webui/common/resources:i18n_behavior",
"//ash/webui/common/resources/network:cellular_utils",
"//chromeos/services/network_config/public/mojom:mojom_webui_js",
"//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
"//ui/webui/resources/js:load_time_data.m",
@ -123,6 +124,7 @@ js_library("apn_detail_dialog") {
deps = [
":onc_mojo",
"//ash/webui/common/resources:i18n_behavior",
"//ash/webui/common/resources/network:cellular_utils",
"//chromeos/services/network_config/public/mojom:mojom_webui_js",
"//third_party/polymer/v3_0/components-chromium/iron-collapse:iron-collapse",
"//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",

@ -36,18 +36,20 @@
<cr-dialog id="apnDetailDialog"
close-text="[[i18n('close')]]" show-on-attach>
<div id="apnDetailDialogTitle" slot="title">
[[i18n('apnDetailAddApnDialogTitle')]]
[[getDialogTitle_(mode)]]
</div>
<div slot="body">
<!-- TODO(b/162365553): Add validation for the input box settings. -->
<cr-input id="apnInput" value="{{apn_}}" label="[[i18n('apn')]]"
type="text">
type="text" disabled="[[isUiElementDisabled_(mode)]]">
</cr-input>
<cr-input id="usernameInput" value="{{username_}}"
label="[[i18n('OncCellular-APN-Username')]]" type="text">
label="[[i18n('OncCellular-APN-Username')]]" type="text"
disabled="[[isUiElementDisabled_(mode)]]">
</cr-input>
<cr-input id="passwordInput" value="{{password_}}"
label="[[i18n('OncCellular-APN-Password')]]" type="password">
label="[[i18n('OncCellular-APN-Password')]]" type="password"
disabled="[[isUiElementDisabled_(mode)]]">
</cr-input>
<cr-expand-button id="advancedSettingsBtn"
class="advanced-settings cr-row"
@ -55,20 +57,21 @@
<div>[[i18n('apnDetailAdvancedSettings')]]</div>
</cr-expand-button>
<iron-collapse opened="[[advancedSettingsExpanded_]]">
<!-- TODO(b/162365553): Add validation. -->
<!-- TODO(b/162365553): Add validation. -->
<div id="authenticationTypeSelection" class="dropdown-section">
<div id="authenticationTypeLabel" class="cr-form-field-label">
[[i18n('apnDetailAuthType')]]
</div>
<select id="authTypeDropDown" class="select-field md-select"
value="{{selectedAuthType_::change}}"
disabled="[[isUiElementDisabled_(mode)]]"
aria-labelledby="authenticationTypeLabel">
<template is="dom-repeat"
items="[[AuthenticationTypes]]">
<option value="[[item]]"
selected="[[isSelectedAuthType_(item)]]">
[[getAuthTypeLocalizedLabel_(item)]]
</option>
<option value="[[item]]"
selected="[[isSelectedAuthType_(item)]]">
[[getAuthTypeLocalizedLabel_(item)]]
</option>
</template>
</select>
</div>
@ -77,13 +80,17 @@
</div>
<div id="checkboxContainer" class="checkbox-section">
<cr-checkbox id="apnDefaultTypeCheckbox"
aria-labelledby="apnDefaultTypelabel" checked>
aria-labelledby="apnDefaultTypelabel"
disabled="[[isUiElementDisabled_(mode)]]"
checked="{{isDefaultApnType_}}">
<div id="apnDefaultTypelabel" class="checkbox-text-area">
[[i18n('apnDetailApnTypeDefault')]]
</div>
</cr-checkbox>
<cr-checkbox id="apnAttachTypeCheckbox"
aria-labelledby="apnAttachTypeLabel">
disabled="[[isUiElementDisabled_(mode)]]"
aria-labelledby="apnAttachTypeLabel"
checked="{{isAttachApnType_}}">
<div id="apnAttachTypeLabel" class="checkbox-text-area">
[[i18n('apnDetailApnTypeAttach')]]
</div>
@ -93,30 +100,39 @@
<div id="ipTypeLabel" class="cr-form-field-label">
[[i18n('apnDetailIpType')]]
</div>
<select id="ipTypeDropDown" class="md-select select-field"
value="{{selectedIpType_::change}}"
aria-labelledby="ipTypeLabel">
<template is="dom-repeat"
items="[[IpTypes]]">
<option value="[[item]]"
selected="[[isSelectedIpType_(item)]]">
[[getIpTypeLocalizedLabel_(item)]]
</option>
</template>
<select id="ipTypeDropDown" class="md-select select-field"
value="{{selectedIpType_::change}}"
disabled="[[isUiElementDisabled_(mode)]]"
aria-labelledby="ipTypeLabel">
<template is="dom-repeat"
items="[[IpTypes]]">
<option value="[[item]]"
selected="[[isSelectedIpType_(item)]]">
[[getIpTypeLocalizedLabel_(item)]]
</option>
</template>
</select>
</div>
</iron-collapse>
<div class="cr-row-line cr-row"></div>
</div>
<div slot="button-container">
<cr-button id="apnDetailCancelBtn" class="cancel-button"
on-click="onCancelClicked_">
[[i18n('cancel')]]
</cr-button>
<!-- TODO(b/162365553): Disable Add button unless validated -->
<cr-button id="apnDetailAddBtn" class="action-button"
on-click="onAddClicked_">
[[i18n('add')]]
</cr-button>
<template is="dom-if" if="[[isUiElementVisible_(mode)]]" restamp>
<cr-button id="apnDetailCancelBtn" class="cancel-button"
on-click="onCancelClicked_">
[[i18n('cancel')]]
</cr-button>
<!-- TODO(b/162365553): Disable Add button unless validated -->
<cr-button id="apnDetailAddBtn" class="action-button"
on-click="onAddClicked_">
[[i18n('add')]]
</cr-button>
</template>
<template is="dom-if" if="[[isUiElementDisabled_(mode)]]" restamp>
<cr-button id="apnDoneBtn" class="action-button"
on-click="onCancelClicked_">
[[i18n('done')]]
</cr-button>
</template>
</div>
</cr-dialog>

@ -22,6 +22,7 @@ import {ApnAuthenticationType, ApnIpType, ApnProperties, ApnType, CrosNetworkCon
import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {getTemplate} from './apn_detail_dialog.html.js';
import {ApnDetailDialogMode} from './cellular_utils.js';
import {MojoInterfaceProviderImpl} from './mojo_interface_provider.js';
const AuthenticationTypes = [
@ -57,6 +58,18 @@ export class ApnDetailDialog extends ApnDetailDialogElementBase {
static get properties() {
return {
/** @type {ApnProperties|undefined} */
apnProperties: {
type: Object,
observer: 'onApnPropertiesUpdated_',
},
/** @type {ApnDetailDialogMode} */
mode: {
type: Object,
value: ApnDetailDialogMode.CREATE,
},
guid: {type: String},
/** @private */
@ -79,9 +92,7 @@ export class ApnDetailDialog extends ApnDetailDialogElementBase {
readOnly: true,
},
/**
* @private
*/
/** @private */
selectedAuthType_: {
type: String,
value: AuthenticationTypes[0].toString(),
@ -110,6 +121,18 @@ export class ApnDetailDialog extends ApnDetailDialogElementBase {
type: String,
value: '',
},
/** @private */
isDefaultApnType_: {
type: Boolean,
value: true,
},
/** @private */
isAttachApnType_: {
type: Boolean,
value: false,
},
};
}
@ -122,6 +145,28 @@ export class ApnDetailDialog extends ApnDetailDialogElementBase {
MojoInterfaceProviderImpl.getInstance().getMojoServiceRemote();
}
/**
* Observer method used to fill the apn detail dialog, with the provided apn.
* @private
*/
onApnPropertiesUpdated_() {
this.apn_ = /** @type {string}*/ (this.apnProperties.accessPointName);
this.username_ = /** @type {string}*/ (this.apnProperties.username);
this.password_ = /** @type {string}*/ (this.apnProperties.password);
this.selectedIpType_ = this.apnProperties.ipType.toString();
this.selectedAuthType_ = this.apnProperties.authenticationType.toString();
this.isDefaultApnType_ = false;
this.isAttachApnType_ = false;
for (const apnType of this.apnProperties.apnTypes) {
if (apnType === ApnType.kDefault) {
this.isDefaultApnType_ = true;
} else if (apnType === ApnType.kAttach) {
this.isAttachApnType_ = true;
}
}
}
/**
* @param {!Event} event
* @private
@ -154,6 +199,20 @@ export class ApnDetailDialog extends ApnDetailDialogElementBase {
this.$.apnDetailDialog.close();
}
/**
* @private
*/
getDialogTitle_() {
switch (this.mode) {
case ApnDetailDialogMode.CREATE:
return this.i18n('apnDetailAddApnDialogTitle');
case ApnDetailDialogMode.VIEW:
return this.i18n('apnDetailViewApnDialogTitle');
case ApnDetailDialogMode.EDIT:
// TODO(b/162365553): Add edit mode for the apn detail dialog.
return '';
}
}
/**
* Maps the checkboxes to an array of {@link ApnType}.
* @returns {Array<ApnType>}
@ -161,11 +220,11 @@ export class ApnDetailDialog extends ApnDetailDialogElementBase {
*/
getSelectedApnTypes_() {
const apnTypes = [];
if (this.$.apnDefaultTypeCheckbox.checked) {
if (this.isDefaultApnType_) {
apnTypes.push(ApnType.kDefault);
}
if (this.$.apnAttachTypeCheckbox.checked) {
if (this.isAttachApnType_) {
apnTypes.push(ApnType.kAttach);
}
return apnTypes;
@ -218,6 +277,20 @@ export class ApnDetailDialog extends ApnDetailDialogElementBase {
isSelectedAuthType_(item) {
return Number(this.selectedAuthType_) === item;
}
/**
* @returns {boolean}
*/
isUiElementDisabled_() {
return this.mode === ApnDetailDialogMode.VIEW;
}
/**
* @returns {boolean}
*/
isUiElementVisible_() {
return this.mode === ApnDetailDialogMode.CREATE;
}
}
customElements.define(ApnDetailDialog.is, ApnDetailDialog);

@ -11,6 +11,7 @@ import 'chrome://resources/cr_elements/cr_action_menu/cr_action_menu.js';
import {I18nBehavior, I18nBehaviorInterface} from '//resources/ash/common/i18n_behavior.js';
import {mixinBehaviors, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {ApnDetailDialogMode, ApnEventData} from 'chrome://resources/ash/common/network/cellular_utils.js';
import {MojoInterfaceProviderImpl} from 'chrome://resources/ash/common/network/mojo_interface_provider.js';
import {assert} from 'chrome://resources/js/assert.js';
import {ApnProperties, ApnState, CrosNetworkConfigRemote} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom-webui.js';
@ -81,7 +82,20 @@ class ApnListItem extends ApnListItemBase {
* TODO(b/162365553): Implement.
* @private
*/
onDetailsClicked_() {}
onDetailsClicked_() {
assert(!!this.guid);
assert(!!this.apn);
this.dispatchEvent(new CustomEvent('show-apn-detail-dialog', {
composed: true,
bubbles: true,
detail: /** @type {!ApnEventData} */ ({
apn: this.apn,
mode: ApnDetailDialogMode.VIEW,
guid: this.guid,
}),
}));
}
/**
* Disables the selected APN.

@ -6,9 +6,28 @@ import 'chrome://resources/ash/common/network/onc_mojo.js';
import {MojoInterfaceProviderImpl} from 'chrome://resources/ash/common/network/mojo_interface_provider.js';
import {OncMojo} from 'chrome://resources/ash/common/network/onc_mojo.js';
import {DeviceStateProperties, FilterType, NetworkStateProperties, NO_LIMIT} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom-webui.js';
import {ApnProperties, DeviceStateProperties, FilterType, NetworkStateProperties, NO_LIMIT} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom-webui.js';
import {ConnectionStateType, NetworkType} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/network_types.mojom-webui.js';
/**
* TODO(b/162365553): Implement Edit mode.
* @enum {string}
*/
export const ApnDetailDialogMode = {
CREATE: 'create',
EDIT: 'edit',
VIEW: 'view',
};
/**
* @typedef {{
* apn: !ApnProperties,
* mode: !ApnDetailDialogMode,
* guid: !string
* }}
*/
export let ApnEventData;
/**
* Checks if the device has a cellular network with connectionState not
* kNotConnected.

@ -130,7 +130,8 @@
$i18n{apnPageAddNewApn}
</cr-button>
</div>
<apn-subpage></apn-subpage>
<apn-subpage on-show-apn-detail-dialog="onShowApnDetailDialog_">
</apn-subpage>
</settings-subpage>
</template>

@ -36,7 +36,7 @@ import {getNumESimProfiles} from 'chrome://resources/ash/common/cellular_setup/e
import {getHotspotConfig} from 'chrome://resources/ash/common/hotspot/cros_hotspot_config.js';
import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/ash/common/i18n_behavior.js';
import {ApnDetailDialog} from 'chrome://resources/ash/common/network/apn_detail_dialog.js';
import {hasActiveCellularNetwork, isConnectedToNonCellularNetwork} from 'chrome://resources/ash/common/network/cellular_utils.js';
import {ApnDetailDialogMode, ApnEventData, hasActiveCellularNetwork, isConnectedToNonCellularNetwork} from 'chrome://resources/ash/common/network/cellular_utils.js';
import {MojoInterfaceProvider, MojoInterfaceProviderImpl} from 'chrome://resources/ash/common/network/mojo_interface_provider.js';
import {NetworkListenerBehavior, NetworkListenerBehaviorInterface} from 'chrome://resources/ash/common/network/network_listener_behavior.js';
import {OncMojo} from 'chrome://resources/ash/common/network/onc_mojo.js';
@ -44,7 +44,7 @@ import {WebUIListenerBehavior, WebUIListenerBehaviorInterface} from 'chrome://re
import {assert, assertNotReached} from 'chrome://resources/js/assert.js';
import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
import {CrosHotspotConfigInterface, CrosHotspotConfigObserverInterface, CrosHotspotConfigObserverReceiver, HotspotInfo, HotspotState} from 'chrome://resources/mojo/chromeos/ash/services/hotspot_config/public/mojom/cros_hotspot_config.mojom-webui.js';
import {CrosNetworkConfigRemote, GlobalPolicy, NetworkStateProperties, StartConnectResult, VpnProvider} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom-webui.js';
import {ApnProperties, CrosNetworkConfigRemote, GlobalPolicy, NetworkStateProperties, StartConnectResult, VpnProvider} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom-webui.js';
import {DeviceStateType, NetworkType} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/network_types.mojom-webui.js';
import {afterNextRender, html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
@ -720,13 +720,12 @@ class SettingsInternetPageElement extends SettingsInternetPageElementBase {
}
/**
* TODO(b/162365553): We should pass what mode the dialog should be in
* (create/edit/view)
*
* @param {!string} guid
* @param {!ApnDetailDialogMode} mode
* @param {ApnProperties|undefined} apn
* @private
*/
showApnDetailDialog_(guid) {
showApnDetailDialog_(guid, mode, apn) {
if (!this.isApnRevampEnabled_) {
return;
}
@ -738,6 +737,8 @@ class SettingsInternetPageElement extends SettingsInternetPageElementBase {
assert(!!apnDetailDialog);
apnDetailDialog.guid = guid;
apnDetailDialog.mode = mode;
apnDetailDialog.apnProperties = apn;
});
}
@ -1089,7 +1090,22 @@ class SettingsInternetPageElement extends SettingsInternetPageElementBase {
}
const guid = Router.getInstance().getQueryParameters().get('guid');
assert(!!guid);
this.showApnDetailDialog_(/** @type {!string} */ (guid));
this.showApnDetailDialog_(
guid, ApnDetailDialogMode.CREATE,
undefined /* apn */);
}
/**
*
* @param {!Event} event
*/
onShowApnDetailDialog_(event) {
event.stopPropagation();
if (this.shouldShowApnDetailDialog_) {
return;
}
const eventData = /** @type {!ApnEventData} */ (event.detail);
this.showApnDetailDialog_(eventData.guid, eventData.mode, eventData.apn);
}
/**

@ -6,6 +6,7 @@ import 'chrome://os-settings/strings.m.js';
import 'chrome://resources/ash/common/network/apn_list_item.js';
import 'chrome://resources/cr_elements/cr_action_menu/cr_action_menu.js';
import {ApnDetailDialogMode, ApnEventData} from 'chrome://resources/ash/common/network/cellular_utils.js';
import {MojoInterfaceProviderImpl} from 'chrome://resources/ash/common/network/mojo_interface_provider.js';
import {OncMojo} from 'chrome://resources/ash/common/network/onc_mojo.js';
import {ApnState, CrosNetworkConfigRemote} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom-webui.js';
@ -13,6 +14,16 @@ import {NetworkType} from 'chrome://resources/mojo/chromeos/services/network_con
import {assertEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
import {FakeNetworkConfig} from 'chrome://webui-test/chromeos/fake_network_config_mojom.js';
import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
import {eventToPromise} from 'chrome://webui-test/test_util.js';
/** @type {!ApnEventData} */
const TEST_APN_EVENT_DATA = {
apn: {
name: 'test_apn',
},
guid: 'test-guid',
mode: ApnDetailDialogMode.VIEW,
};
suite('ApnListItemTest', function() {
/** @type {ApnListItemElement} */
@ -195,4 +206,21 @@ suite('ApnListItemTest', function() {
ApnState.kDisabled,
managedProps.result.typeProperties.cellular.customApnList[0].state);
});
test(
'Clicking APN details button triggers a show-apn-detail-dialog event ',
async function() {
apnListItem.apn = TEST_APN_EVENT_DATA.apn;
apnListItem.guid = TEST_APN_EVENT_DATA.guid;
const apnDetailsClickedEvent =
eventToPromise('show-apn-detail-dialog', window);
assertTrue(!!apnListItem.$.detailsButton);
apnListItem.$.detailsButton.click();
const eventData = await apnDetailsClickedEvent;
assertEquals(TEST_APN_EVENT_DATA.apn.name, eventData.detail.apn.name);
assertEquals(TEST_APN_EVENT_DATA.guid, eventData.detail.guid);
assertEquals(TEST_APN_EVENT_DATA.mode, eventData.detail.mode);
});
});

@ -6,6 +6,7 @@ import 'chrome://os-settings/strings.m.js';
import 'chrome://resources/ash/common/network/apn_detail_dialog.js';
import {ApnDetailDialog} from 'chrome://resources/ash/common/network/apn_detail_dialog.js';
import {ApnDetailDialogMode} from 'chrome://resources/ash/common/network/cellular_utils.js';
import {MojoInterfaceProviderImpl} from 'chrome://resources/ash/common/network/mojo_interface_provider.js';
import {OncMojo} from 'chrome://resources/ash/common/network/onc_mojo.js';
import {ApnAuthenticationType, ApnIpType, ApnProperties, ApnType} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom-webui.js';
@ -28,6 +29,7 @@ const TEST_APN = {
suite('ApnDetailDialog', function() {
/** @type {ApnDetailDialog} */
let apnDetailDialog = null;
let mojoApi_ = null;
async function toggleAdvancedSettings() {
@ -69,14 +71,16 @@ suite('ApnDetailDialog', function() {
assertTrue(!!apnDetailDialog.shadowRoot.querySelector('#usernameInput'));
assertTrue(!!apnDetailDialog.shadowRoot.querySelector('#passwordInput'));
assertTrue(!!apnDetailDialog.shadowRoot.querySelector(
'#authenticationTypeSelection'));
assertTrue(!!apnDetailDialog.shadowRoot.querySelector('#authTypeDropDown'));
assertTrue(
!!apnDetailDialog.shadowRoot.querySelector('#apnDefaultTypeCheckbox'));
assertTrue(
!!apnDetailDialog.shadowRoot.querySelector('#apnAttachTypeCheckbox'));
assertTrue(!!apnDetailDialog.shadowRoot.querySelector('#ipTypeSelection'));
assertTrue(!!apnDetailDialog.shadowRoot.querySelector('#ipTypeDropDown'));
assertTrue(
!!apnDetailDialog.shadowRoot.querySelector('#apnDetailCancelBtn'));
assertTrue(!!apnDetailDialog.shadowRoot.querySelector('#apnDetailAddBtn'));
assertFalse(!!apnDetailDialog.shadowRoot.querySelector('#apnDoneBtn'));
});
test('Clicking the cancel button fires the close event', async function() {
@ -87,7 +91,7 @@ suite('ApnDetailDialog', function() {
cancelBtn.click();
await closeEventPromise;
assertFalse(!!apnDetailDialog.open);
assertFalse(!!apnDetailDialog.$.apnDetailDialog.open);
});
test(
@ -139,6 +143,22 @@ suite('ApnDetailDialog', function() {
});
test('Clicking on the add button calls createCustomApn', async () => {
const assertFieldEnabled = (selector) => {
const element = apnDetailDialog.shadowRoot.querySelector(selector);
assertTrue(!!element);
assertFalse(element.disabled);
};
assertFieldEnabled('#apnInput');
assertFieldEnabled('#usernameInput');
assertFieldEnabled('#passwordInput');
assertFieldEnabled('#authTypeDropDown');
assertFieldEnabled('#apnDefaultTypeCheckbox');
assertFieldEnabled('#apnAttachTypeCheckbox');
assertFieldEnabled('#ipTypeDropDown');
assertFieldEnabled('#apnDetailCancelBtn');
assertFieldEnabled('#apnDetailAddBtn');
// Add a network.
const network = OncMojo.getDefaultManagedProperties(
NetworkType.kCellular, apnDetailDialog.guid);
@ -155,10 +175,11 @@ suite('ApnDetailDialog', function() {
await mojoApi_.getManagedProperties(apnDetailDialog.guid);
assertTrue(!!managedProp);
assertFalse(!!managedProp.result.typeProperties.cellular.customApnList);
assertTrue(!!apnDetailDialog.$.apnDetailAddBtn);
apnDetailDialog.$.apnDetailAddBtn.click();
await flushTasks();
const addBtn = apnDetailDialog.shadowRoot.querySelector('#apnDetailAddBtn');
assertTrue(!!addBtn);
addBtn.click();
await flushTasks();
await mojoApi_.whenCalled('createCustomApn');
assertEquals(
@ -173,4 +194,33 @@ suite('ApnDetailDialog', function() {
assertEquals(TEST_APN.apnTypes.length, apn.apnTypes.length);
assertEquals(TEST_APN.apnTypes[0], apn.apnTypes[0]);
});
test('Setting mode to view changes buttons and fields', async () => {
const assertFieldDisabled = (selector) => {
const element = apnDetailDialog.shadowRoot.querySelector(selector);
assertTrue(!!element);
assertTrue(element.disabled);
};
apnDetailDialog.mode = ApnDetailDialogMode.VIEW;
apnDetailDialog.apn = TEST_APN;
await flushTasks();
assertEquals(
apnDetailDialog.i18n('apnDetailViewApnDialogTitle'),
apnDetailDialog.shadowRoot.querySelector('#apnDetailDialogTitle')
.innerText);
assertFalse(
!!apnDetailDialog.shadowRoot.querySelector('#apnDetailCancelBtn'));
assertFalse(!!apnDetailDialog.shadowRoot.querySelector('#apnDetailAddBtn'));
const doneBtn = apnDetailDialog.shadowRoot.querySelector('#apnDoneBtn');
assertTrue(!!doneBtn);
assertFalse(doneBtn.disabled);
assertFieldDisabled('#apnInput');
assertFieldDisabled('#usernameInput');
assertFieldDisabled('#passwordInput');
assertFieldDisabled('#authTypeDropDown');
assertFieldDisabled('#apnDefaultTypeCheckbox');
assertFieldDisabled('#apnAttachTypeCheckbox');
assertFieldDisabled('#ipTypeDropDown');
});
});

@ -3705,6 +3705,9 @@ Try tapping the mic to ask me anything.
<message name="IDS_SETTINGS_ADD_APN_DIALOG_TITLE" desc="Title for the dialog that creates a new custom APN">
Add a new APN
</message>
<message name="IDS_SETTINGS_VIEW_APN_DIALOG_TITLE" desc="Title for the dialog for viewing an APN">
APN details
</message>
<message name="IDS_SETTINGS_APN_INPUT_LABEL" desc="Label for the input field where the APN is specified">
APN
</message>

@ -0,0 +1 @@
23d6ede754c830c7e7af135124a8d8b9a5c36a36

@ -318,6 +318,7 @@ void AddDetailsLocalizedStrings(content::WebUIDataSource* html_source) {
{"apnMenuRemove", IDS_SETTINGS_APN_MENU_REMOVE},
{"apnMoreActionsTitle", IDS_SETTINGS_APN_MORE_ACTIONS_TITLE},
{"apnDetailAddApnDialogTitle", IDS_SETTINGS_ADD_APN_DIALOG_TITLE},
{"apnDetailViewApnDialogTitle", IDS_SETTINGS_VIEW_APN_DIALOG_TITLE},
{"apnDetailAdvancedSettings", IDS_SETTINGS_APN_DIALOG_ADVANCED_SETTING},
{"apnDetailApnTypes", IDS_SETTINGS_APN_DIALOG_APN_TYPES},
{"apnDetailApnTypeDefault",