Commit bc24c94f authored by Jordy Greenblatt's avatar Jordy Greenblatt Committed by Commit Bot

[CrOS MultiDevice] Add instant tethering to settings subpage

The main thrust of this CL is to build the multidevice-tethering-item
element which is a wrapper for the network-summary-item and provides
relevant updates. It is intended to encapsulate the tether-relevant
functionality of the network-summary element.

This also involved some mild refactoring in the settings/internet_page
folder to allow the network-summary-item to be reused in the
multidevice subpage and a fix of a minor bug in the cr-network-icon
element that was causing problems for the multidevice-tethering-item.

Cq-Include-Trybots: luci.chromium.try:closure_compilation
Change-Id: Idb03c1f051cc03e825d0389508e1bd3e2e5d28e6
Reviewed-on: https://chromium-review.googlesource.com/1140733
Commit-Queue: Jordy Greenblatt <jordynass@chromium.org>
Reviewed-by: default avatarSteven Bennetts <stevenjb@chromium.org>
Reviewed-by: default avatarKyle Horimoto <khorimoto@chromium.org>
Cr-Commit-Position: refs/heads/master@{#583148}
parent 74754a85
...@@ -18,15 +18,21 @@ ...@@ -18,15 +18,21 @@
padding-inline-start: var(--settings-box-row-padding); padding-inline-start: var(--settings-box-row-padding);
} }
#outerBox {
padding: 0 var(--settings-box-row-padding);
@apply(--network-summary-item-outer-box);
}
#details { #details {
align-items: center; align-items: center;
display: flex; display: flex;
flex: auto; flex: auto;
} }
#networkName { #networkTitleText {
color: #333; color: #333;
font-weight: 500; font-weight: 500;
@apply(--network-summary-item-title);
} }
#networkState { #networkState {
...@@ -35,7 +41,7 @@ ...@@ -35,7 +41,7 @@
font-weight: 400; font-weight: 400;
} }
</style> </style>
<div class="settings-box two-line"> <div id="outerBox" class="settings-box two-line">
<div actionable class="flex layout horizontal center" <div actionable class="flex layout horizontal center"
on-click="onShowDetailsTap_"> on-click="onShowDetailsTap_">
<div id="details" no-flex$="[[showSimInfo_(deviceState)]]"> <div id="details" no-flex$="[[showSimInfo_(deviceState)]]">
...@@ -43,7 +49,9 @@ ...@@ -43,7 +49,9 @@
device-state="[[deviceState]]"> device-state="[[deviceState]]">
</cr-network-icon> </cr-network-icon>
<div class="flex"> <div class="flex">
<div id="networkName">[[getNetworkName_(activeNetworkState)]]</div> <div id="networkTitleText">
[[getTitleText_(activeNetworkState)]]
</div>
<div id="networkState"> <div id="networkState">
[[getNetworkStateText_(activeNetworkState, deviceState)]] [[getNetworkStateText_(activeNetworkState, deviceState)]]
</div> </div>
......
...@@ -51,14 +51,14 @@ Polymer({ ...@@ -51,14 +51,14 @@ Polymer({
* @type {!NetworkingPrivate} * @type {!NetworkingPrivate}
*/ */
networkingPrivate: Object, networkingPrivate: Object,
},
/** /**
* @return {string} * Title line describing the network type to appear in the row's top line.
* @private * If it is undefined, the title text is a default from CrOncStrings (see
*/ * this.getTitleText_() below).
getNetworkName_: function() { * @type {string|undefined}
return CrOncStrings['OncType' + this.activeNetworkState.Type]; */
networkTitleText: String,
}, },
/** /**
...@@ -334,6 +334,15 @@ Polymer({ ...@@ -334,6 +334,15 @@ Polymer({
'device-enabled-toggled', {enabled: !deviceIsEnabled, type: type}); 'device-enabled-toggled', {enabled: !deviceIsEnabled, type: type});
}, },
/**
* @return {string}
* @private
*/
getTitleText_: function() {
return this.networkTitleText ||
CrOncStrings['OncType' + this.activeNetworkState.Type];
},
/** /**
* Make sure events in embedded components do not propagate to onDetailsTap_. * Make sure events in embedded components do not propagate to onDetailsTap_.
* @param {!Event} event * @param {!Event} event
......
...@@ -12,6 +12,7 @@ js_type_check("closure_compile") { ...@@ -12,6 +12,7 @@ js_type_check("closure_compile") {
":multidevice_page", ":multidevice_page",
":multidevice_page_container", ":multidevice_page_container",
":multidevice_subpage", ":multidevice_subpage",
":multidevice_tether_item",
] ]
} }
...@@ -64,6 +65,17 @@ js_library("multidevice_subpage") { ...@@ -64,6 +65,17 @@ js_library("multidevice_subpage") {
":multidevice_constants", ":multidevice_constants",
"..:route", "..:route",
"../prefs:prefs_behavior", "../prefs:prefs_behavior",
"//ui/webui/resources/cr_elements/chromeos/network:cr_network_listener_behavior",
"//ui/webui/resources/js:i18n_behavior", "//ui/webui/resources/js:i18n_behavior",
] ]
externs_list = [ "$externs_path/networking_private.js" ]
extra_sources = [ "$interfaces_path/networking_private_interface.js" ]
}
js_library("multidevice_tether_item") {
deps = [
"//ui/webui/resources/cr_elements/chromeos/network:cr_onc_types",
]
externs_list = [ "$externs_path/networking_private.js" ]
extra_sources = [ "$interfaces_path/networking_private_interface.js" ]
} }
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
#card { #card {
border-top: var(--settings-separator-line); border-top: var(--settings-separator-line);
border-top-style: var(--feature-item-border-top-style, solid); border-top-style: var(--feature-item-border-top-style, solid);
padding: 0; padding: var(--feature-item-row-padding);
} }
iron-icon { iron-icon {
......
<link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_network_listener_behavior.html">
<link rel="import" href="chrome://resources/html/cr.html"> <link rel="import" href="chrome://resources/html/cr.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.html"> <link rel="import" href="chrome://resources/html/i18n_behavior.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
...@@ -12,10 +13,16 @@ ...@@ -12,10 +13,16 @@
<link rel="import" href="multidevice_constants.html"> <link rel="import" href="multidevice_constants.html">
<link rel="import" href="multidevice_feature_item.html"> <link rel="import" href="multidevice_feature_item.html">
<link rel="import" href="multidevice_feature_toggle.html"> <link rel="import" href="multidevice_feature_toggle.html">
<link rel="import" href="multidevice_tether_item.html">
<dom-module id="settings-multidevice-subpage"> <dom-module id="settings-multidevice-subpage">
<template> <template>
<style include="settings-shared iron-flex"> <style include="settings-shared iron-flex">
settings-multidevice-feature-item,
settings-multidevice-tether-item {
--feature-item-row-padding: 0;
}
settings-multidevice-feature-item:first-of-type { settings-multidevice-feature-item:first-of-type {
--feature-item-border-top-style: none; --feature-item-border-top-style: none;
} }
...@@ -64,6 +71,9 @@ ...@@ -64,6 +71,9 @@
</settings-multidevice-feature-toggle> </settings-multidevice-feature-toggle>
</div> </div>
</settings-multidevice-feature-item> </settings-multidevice-feature-item>
<settings-multidevice-tether-item
label="$i18n{multideviceInstantTetheringItemTitle}">
</settings-multidevice-tether-item>
<settings-multidevice-feature-item id="android-messages-item" <settings-multidevice-feature-item id="android-messages-item"
icon-name="settings:sms-connect" icon-name="settings:sms-connect"
feature-name="$i18n{multideviceAndroidMessagesItemTitle}" feature-name="$i18n{multideviceAndroidMessagesItemTitle}"
......
...@@ -12,7 +12,7 @@ cr.exportPath('settings'); ...@@ -12,7 +12,7 @@ cr.exportPath('settings');
Polymer({ Polymer({
is: 'settings-multidevice-subpage', is: 'settings-multidevice-subpage',
behaviors: [I18nBehavior, PrefsBehavior], behaviors: [I18nBehavior, PrefsBehavior, CrNetworkListenerBehavior],
properties: { properties: {
/** @type {?SettingsRoutes} */ /** @type {?SettingsRoutes} */
...@@ -21,6 +21,24 @@ Polymer({ ...@@ -21,6 +21,24 @@ Polymer({
value: settings.routes, value: settings.routes,
}, },
/** Overridden from NetworkListenerBehavior. */
networkingPrivate: {
type: Object,
value: chrome.networkingPrivate,
},
/** Overridden from NetworkListenerBehavior. */
networkListChangeSubscriberSelectors_: {
type: Array,
value: () => ['settings-multidevice-tether-item'],
},
/** Overridden from NetworkListenerBehavior. */
networksChangeSubscriberSelectors_: {
type: Array,
value: () => ['settings-multidevice-tether-item'],
},
/** @type {MultiDevicePageContentData} */ /** @type {MultiDevicePageContentData} */
pageContentData: Object, pageContentData: Object,
...@@ -44,6 +62,16 @@ Polymer({ ...@@ -44,6 +62,16 @@ Polymer({
this.setPrefValue('multidevice.sms_connect_enabled', true); this.setPrefValue('multidevice.sms_connect_enabled', true);
}, },
listeners: {
'show-networks': 'onShowNetworks_',
},
onShowNetworks_: function() {
settings.navigateTo(
settings.routes.INTERNET_NETWORKS,
new URLSearchParams('type=' + CrOnc.Type.TETHER));
},
/** /**
* @return {boolean} * @return {boolean}
* @private * @private
......
<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_onc_types.html">
<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_behavior.html">
<link rel="import" href="../i18n_setup.html">
<link rel="import" href="../internet_page/network_summary_item.html">
<link rel="import" href="../settings_shared_css.html">
<link rel="import" href="../settings_vars_css.html">
<dom-module id="settings-multidevice-tether-item">
<style include="settings-shared">
network-summary-item {
--network-summary-item-outer-box: {
padding: var(--feature-item-row-padding);
};
--network-summary-item-title: {
color: var(--cr-primary-text-color);
font-weight: 400;
};
}
</style>
<template>
<network-summary-item id="networkSummaryItem"
active-network-state="[[activeNetworkState_]]"
device-state="[[deviceState_]]"
network-state-list="[[getNetworkStateList_(activeNetworkState_)]]"
networking-private="[[networkingPrivate]]"
tether-device-state="[[deviceState_]]"
network-title-text="$i18n{multideviceInstantTetheringItemTitle}">
</network-summary-item>
</template>
<script src="multidevice_tether_item.js"></script>
</dom-module>
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview
* This element provides a layer between the settings-multidevice-subpage
* element and the internet_page folder's network-summary-item. It is
* responsible for loading initial tethering network data from the
* chrome.networkingPrivate API as well as updating the data in real time. It
* serves a role comparable to the internet_page's network-summary element.
*/
Polymer({
is: 'settings-multidevice-tether-item',
properties: {
/** @private {string} */
titleText_: String,
/**
* Interface for networkingPrivate calls.
* @private {!NetworkingPrivate}
*/
networkingPrivate_: {
type: Object,
value: chrome.networkingPrivate,
},
/**
* The device state for tethering.
* @private {?CrOnc.DeviceStateProperties|undefined}
*/
deviceState_: Object,
/**
* The network state for a potential tethering host phone. Note that there
* is at most one because only one MultiDevice host phone is allowed on an
* account at a given time.
* @private {?CrOnc.NetworkStateProperties|undefined}
*/
activeNetworkState_: Object,
},
listeners: {
'device-enabled-toggled': 'onDeviceEnabledToggled_',
'network-list-changed': 'updateTetherNetworkState_',
// network-changed is fired by the settings-multidevice-subpage element's
// CrNetworkListenerBehavior.
// TODO (jordynass): Refactor to allow this element to listen to network
// changes without requiring the settings-multidevice-subpage to communicate
// with the networkingPrivate API.
'networks-changed': 'onNetworksChanged_',
},
/**
* Listener function for chrome.networkingPrivate.onDeviceStateListChanged
* event.
* @private {?function(!Array<string>)}
*/
deviceStateListChangedListener_: null,
/** @override */
attached: function() {
this.updateTetherDeviceState_();
this.updateTetherNetworkState_();
this.deviceStateListChangedListener_ =
this.deviceStateListChangedListener_ ||
this.updateTetherDeviceState_.bind(this);
this.networkingPrivate_.onDeviceStateListChanged.addListener(
this.deviceStateListChangedListener_);
},
/** @override */
detached: function() {
this.networkingPrivate_.onDeviceStateListChanged.removeListener(
assert(this.deviceStateListChangedListener_));
},
/**
* Callback for the a network changing state. Note that any change to leading
* to a new active network would fire the 'network-list-changed' event,
* triggering updateTetherNetworkState_ and rendering this callback
* redundant. As a result, we return early if the active network is not
* changed.
* @param {{detail: Array<string>}} event stores an array of the GUIDs of all
* networks that changed in its detail property.
* @private
*/
onNetworksChanged_: function(event) {
const id = this.activeNetworkState_.GUID;
if (!event.detail.includes(id))
return;
this.networkingPrivate_.getState(id, newNetworkState => {
if (chrome.runtime.lastError) {
const message = chrome.runtime.lastError.message;
if (message != 'Error.NetworkUnavailable' &&
message != 'Error.InvalidNetworkGuid') {
console.error(
'Unexpected networkingPrivate.getState error: ' + message +
' For: ' + id);
return;
}
}
this.activeNetworkState_ = newNetworkState;
});
},
/**
* Event triggered by a device state enabled toggle.
* @param {!{detail: {enabled: boolean, type: CrOnc.Type}}} event
* @private
*/
onDeviceEnabledToggled_: function(event) {
if (event.detail.enabled)
this.networkingPrivate_.enableNetworkType(CrOnc.Type.TETHER);
else
this.networkingPrivate_.disableNetworkType(CrOnc.Type.TETHER);
},
/**
* Retrieves device states (CrOnc.DeviceStateProperties) and sets
* this.deviceState_ to the retrieved Instant Tethering state (or undefined if
* there is none) in its callback. Note that the function
* chrome.networkingPrivate.getDevicePolicy() retrieves at most one object per
* network type (CrOnc.Type) so, in particular there will be at most one state
* for Instant Tethering.
* @private
*/
updateTetherDeviceState_: function() {
this.networkingPrivate_.getDeviceStates(deviceStates => {
this.deviceState_ =
deviceStates.find(
deviceState => deviceState.Type == CrOnc.Type.TETHER) ||
null;
});
},
/**
* Retrieves all Instant Tethering network states
* (CrOnc.NetworkStateProperties). Note that there is at most one because
* only one host is allowed on an account at a given time. Then it sets
* this.activeNetworkState_ to that network if there is one or a dummy object
* with an empty string for a GUID otherwise.
* @private
*/
updateTetherNetworkState_: function() {
this.networkingPrivate_.getNetworks(
{networkType: CrOnc.Type.TETHER}, networkStates => {
this.activeNetworkState_ =
networkStates[0] || {GUID: '', Type: CrOnc.Type.TETHER};
});
},
/**
* Returns an array containing the active network state if there is one
* (note that if there is not GUID will be falsy). Returns an empty array
* otherwise.
* @return {!Array<CrOnc.NetworkStateProperties>}
* @private
*/
getNetworkStateList_: function() {
return this.activeNetworkState_.GUID ? [this.activeNetworkState_] : [];
},
});
...@@ -1354,6 +1354,12 @@ ...@@ -1354,6 +1354,12 @@
<structure name="IDR_SETTINGS_MULTIDEVICE_SUBPAGE_JS" <structure name="IDR_SETTINGS_MULTIDEVICE_SUBPAGE_JS"
file="multidevice_page/multidevice_subpage.js" file="multidevice_page/multidevice_subpage.js"
type="chrome_html" /> type="chrome_html" />
<structure name="IDR_SETTINGS_MULTIDEVICE_TETHER_ITEM_HTML"
file="multidevice_page/multidevice_tether_item.html"
type="chrome_html" />
<structure name="IDR_SETTINGS_MULTIDEVICE_TETHER_ITEM_JS"
file="multidevice_page/multidevice_tether_item.js"
type="chrome_html" />
<structure name="IDR_SETTINGS_NETWORK_PROXY_SECTION_HTML" <structure name="IDR_SETTINGS_NETWORK_PROXY_SECTION_HTML"
file="internet_page/network_proxy_section.html" file="internet_page/network_proxy_section.html"
type="chrome_html" /> type="chrome_html" />
......
...@@ -51,6 +51,9 @@ suite('Multidevice', function() { ...@@ -51,6 +51,9 @@ suite('Multidevice', function() {
assertEquals( assertEquals(
!!multideviceSubpage.$$('settings-multidevice-feature-item'), !!multideviceSubpage.$$('settings-multidevice-feature-item'),
mode == settings.MultiDeviceSettingsMode.HOST_SET_VERIFIED); mode == settings.MultiDeviceSettingsMode.HOST_SET_VERIFIED);
assertEquals(
!!multideviceSubpage.$$('settings-multidevice-tether-item'),
mode == settings.MultiDeviceSettingsMode.HOST_SET_VERIFIED);
} }
}); });
......
...@@ -138,7 +138,8 @@ ...@@ -138,7 +138,8 @@
100% { background: url(cellular_4.svg); } 100% { background: url(cellular_4.svg); }
} }
</style> </style>
<div id="icon" class$="[[getIconClass_(networkState, isListItem)]]"> <div id="icon"
class$="[[getIconClass_(networkState, deviceState, isListItem)]]">
</div> </div>
<iron-icon id="technology" hidden="[[!showTechnology_(networkState)]]" <iron-icon id="technology" hidden="[[!showTechnology_(networkState)]]"
icon="[[getTechnology_(networkState)]]"> icon="[[getTechnology_(networkState)]]">
......
...@@ -20,10 +20,14 @@ Polymer({ ...@@ -20,10 +20,14 @@ Polymer({
networkState: Object, networkState: Object,
/** /**
* If set, the device state for the network type. * If set, the device state for the network type. Otherwise it defaults to
* @type {!CrOnc.DeviceStateProperties|undefined} * null rather than undefined so that it does not block computed bindings.
* @type {?CrOnc.DeviceStateProperties}
*/ */
deviceState: Object, deviceState: {
type: Object,
value: null,
},
/** /**
* If true, the icon is part of a list of networks and may be displayed * If true, the icon is part of a list of networks and may be displayed
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment