Commit 43ac8e14 authored by Jordy Greenblatt's avatar Jordy Greenblatt Committed by Commit Bot

[CrOS MultiDevice] Factor out behavior for interacting with features

In the course of preparing the Settings UI to interact with feature
prefs via the MultiDevice service, it became very cumbersome to pass
around data without some utilities common to the components. This CL
factors out some such utilities into their own behavior and passes
around feature data using the behavior

Note that this CL does not change the components' relationships with
feature prefs as that is in the next change, but the behavior is a
convenient intermediate point and should make the other significantly
easier to review/work with.

Note also that not all the components yet use the behavior but they
almost all will as it becomes more relevant over the next few CLs.

Change-Id: Iaeec623bd534287893f6c204a0fdf524ac0bfd77
Reviewed-on: https://chromium-review.googlesource.com/1179820Reviewed-by: default avatarHector Carmona <hcarmona@chromium.org>
Reviewed-by: default avatarKyle Horimoto <khorimoto@chromium.org>
Commit-Queue: Jordy Greenblatt <jordynass@chromium.org>
Cr-Commit-Position: refs/heads/master@{#584812}
parent 188c284e
......@@ -8,7 +8,9 @@ js_type_check("closure_compile") {
deps = [
":multidevice_browser_proxy",
":multidevice_constants",
":multidevice_feature_behavior",
":multidevice_feature_item",
":multidevice_feature_toggle",
":multidevice_page",
":multidevice_page_container",
":multidevice_subpage",
......@@ -18,6 +20,7 @@ js_type_check("closure_compile") {
js_library("multidevice_browser_proxy") {
deps = [
":multidevice_constants",
"//ui/webui/resources/js:cr",
]
}
......@@ -28,8 +31,17 @@ js_library("multidevice_constants") {
]
}
js_library("multidevice_feature_behavior") {
deps = [
":multidevice_constants",
"//ui/webui/resources/js:cr",
"//ui/webui/resources/js:i18n_behavior",
]
}
js_library("multidevice_feature_item") {
deps = [
":multidevice_feature_behavior",
"..:route",
"//ui/webui/resources/js:cr",
]
......@@ -45,16 +57,17 @@ js_library("multidevice_page") {
deps = [
":multidevice_browser_proxy",
":multidevice_constants",
":multidevice_feature_behavior",
"../prefs:prefs_behavior",
"//ui/webui/resources/js:cr",
"//ui/webui/resources/js:i18n_behavior",
]
}
js_library("multidevice_page_container") {
deps = [
":multidevice_browser_proxy",
":multidevice_constants",
":multidevice_page",
":multidevice_feature_behavior",
"//ui/webui/resources/js:cr",
"//ui/webui/resources/js:web_ui_listener_behavior",
]
......@@ -63,10 +76,10 @@ js_library("multidevice_page_container") {
js_library("multidevice_subpage") {
deps = [
":multidevice_constants",
":multidevice_feature_behavior",
"..:route",
"../prefs:prefs_behavior",
"//ui/webui/resources/cr_elements/chromeos/network:cr_network_listener_behavior",
"//ui/webui/resources/js:i18n_behavior",
]
externs_list = [ "$externs_path/networking_private.js" ]
extra_sources = [ "$interfaces_path/networking_private_interface.js" ]
......
<link rel="import" href="chrome://resources/html/cr.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.html">
<link rel="import" href="multidevice_constants.html">
<script src="multidevice_feature_behavior.js"></script>
// 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 Polymer behavior for dealing with MultiDevice features. It is
* intended to facilitate passing data between elements in the MultiDevice page
* cleanly and concisely. It includes some constants and utility methods.
*/
cr.exportPath('settings');
/** @polymerBehavior */
const MultiDeviceFeatureBehaviorImpl = {
properties: {
/** @type {MultiDevicePageContentData} */
pageContentData: Object,
/**
* Enum defined in multidevice_constants.js.
* @type {Object<string, number>}
*/
MultiDeviceFeature: {
type: Object,
value: settings.MultiDeviceFeature,
},
},
/**
* Whether the gatekeeper pref for the whole Better Together feature suite is
* on.
* @return {boolean}
*/
isSuiteOn: function() {
return this.pageContentData.betterTogetherState ===
settings.MultiDeviceFeatureState.ENABLED_BY_USER;
},
/**
* Whether the user is prevented from attempted to change a given feature. In
* the UI this corresponds to a disabled toggle.
* @param {!settings.MultiDeviceFeature} feature
* @return {boolean}
*/
isFeatureStateEditable: function(feature) {
// The suite is off and the toggle corresponds to an individual feature
// (as opposed to the full suite).
if (feature !== settings.MultiDeviceFeature.BETTER_TOGETHER_SUITE &&
!this.isSuiteOn()) {
return false;
}
if ([
settings.MultiDeviceFeatureState.DISABLED_BY_POLICY,
settings.MultiDeviceFeatureState.NOT_SUPPORTED_BY_CHROMEBOOK,
settings.MultiDeviceFeatureState.NOT_SUPPORTED_BY_PHONE,
settings.MultiDeviceFeatureState.UNAVAILABLE_INSUFFICIENT_SECURITY,
].includes(this.getFeatureState(feature))) {
return false;
}
return true;
},
/**
* The localized string representing the name of the feature.
* @param {!settings.MultiDeviceFeature} feature
* @return {string}
*/
getFeatureName: function(feature) {
switch (feature) {
case settings.MultiDeviceFeature.INSTANT_TETHERING:
return this.i18n('multideviceInstantTetheringItemTitle');
case settings.MultiDeviceFeature.MESSAGES:
return this.i18n('multideviceAndroidMessagesItemTitle');
case settings.MultiDeviceFeature.SMART_LOCK:
return this.i18n('multideviceSmartLockItemTitle');
default:
return '';
}
},
/**
* The full icon name used provided by the containing iron-iconset-svg
* (i.e. [iron-iconset-svg name]:[SVG <g> tag id]) for a given feature.
* @param {!settings.MultiDeviceFeature} feature
* @return {string}
*/
getIconName: function(feature) {
switch (feature) {
// TODO(jordynass): Insert Better Together Suite icon (i.e. phone SVG)
// when it is added.
case settings.MultiDeviceFeature.MESSAGES:
return 'settings:sms-connect';
case settings.MultiDeviceFeature.SMART_LOCK:
return 'settings:smart-lock';
default:
return '';
}
},
/**
* The localized string providing a description or useful status information
* concerning a given feature.
* @param {!settings.MultiDeviceFeature} feature
* @return {string}
*/
getFeatureSummaryHtml: function(feature) {
switch (feature) {
case settings.MultiDeviceFeature.SMART_LOCK:
return this.i18nAdvanced('multideviceSmartLockItemSummary');
case settings.MultiDeviceFeature.MESSAGES:
return this.i18nAdvanced('multideviceAndroidMessagesItemSummary');
default:
return '';
}
},
/**
* Extracts the MultiDeviceFeatureState enum value describing the given
* feature from this.pageContentData. Returns null if the feature is not
* an accepted value (e.g. testing fake).
* @param {!settings.MultiDeviceFeature} feature
* @return {?settings.MultiDeviceFeatureState}
*/
getFeatureState: function(feature) {
switch (feature) {
case settings.MultiDeviceFeature.BETTER_TOGETHER_SUITE:
return this.pageContentData.betterTogetherState;
case settings.MultiDeviceFeature.INSTANT_TETHERING:
return this.pageContentData.instantTetheringState;
case settings.MultiDeviceFeature.MESSAGES:
return this.pageContentData.messagesState;
case settings.MultiDeviceFeature.SMART_LOCK:
return this.pageContentData.smartLockState;
default:
return null;
}
},
};
/** @polymerBehavior */
const MultiDeviceFeatureBehavior = [
I18nBehavior,
MultiDeviceFeatureBehaviorImpl,
];
......@@ -8,6 +8,8 @@
<link rel="import" href="../route.html">
<link rel="import" href="../settings_shared_css.html">
<link rel="import" href="../settings_vars_css.html">
<link rel="import" href="multidevice_constants.html">
<link rel="import" href="multidevice_feature_behavior.html">
<dom-module id="settings-multidevice-feature-item">
<template>
......@@ -26,17 +28,17 @@
class="settings-box two-line"
on-click="handleItemClick_"
actionable$="[[hasSubpageClickHandler_(subpageRoute)]]">
<iron-icon icon="[[iconName]]"></iron-icon>
<iron-icon icon="[[getIconName(feature)]]"></iron-icon>
<div id="item-text-container" class="middle">
[[featureName]]
[[getFeatureName(feature)]]
<div class="secondary"
id="featureSecondary"
inner-h-t-m-l="[[featureSummaryHtml]]">
inner-h-t-m-l="[[getFeatureSummaryHtml(feature)]]">
</div>
</div>
<template is="dom-if" if="[[hasSubpageClickHandler_(subpageRoute)]]">
<paper-icon-button-light class="subpage-arrow">
<button aria-label="[[featureName]]"
<button aria-label="[[getFeatureName(feature)]]"
aria-describedby="featureSecondary"></button>
</paper-icon-button-light>
<div class="separator"></div>
......
......@@ -15,26 +15,11 @@ cr.exportPath('settings');
Polymer({
is: 'settings-multidevice-feature-item',
properties: {
/**
* The localized string representing the name of the feature.
* @type {string}
*/
featureName: String,
behaviors: [MultiDeviceFeatureBehavior],
/**
* The localized string providing a description or useful status information
* concertning the feature.
* @type {string}
*/
featureSummaryHtml: String,
/**
* The full icon name used provided by the containing iron-iconset-svg
* (i.e. [iron-iconset-svg name]:[SVG <g> tag id]).
* @type {string}
*/
iconName: String,
properties: {
/** @type {!settings.MultiDeviceFeature} */
feature: Number,
/**
* If it is non-null, the item should be actionable and clicking on it
......
......@@ -15,6 +15,7 @@
<link rel="import" href="../settings_shared_css.html">
<link rel="import" href="multidevice_browser_proxy.html">
<link rel="import" href="multidevice_constants.html">
<link rel="import" href="multidevice_feature_behavior.html">
<link rel="import" href="multidevice_feature_toggle.html">
<link rel="import" href="multidevice_subpage.html">
......
......@@ -11,12 +11,9 @@ cr.exportPath('settings');
Polymer({
is: 'settings-multidevice-page',
behaviors: [I18nBehavior, PrefsBehavior],
behaviors: [MultiDeviceFeatureBehavior, PrefsBehavior],
properties: {
/** @type {MultiDevicePageContentData} */
pageContentData: Object,
/**
* A Map specifying which element should be focused when exiting a subpage.
* The key of the map holds a settings.Route path, and the value holds a
......
......@@ -2,15 +2,16 @@
<link rel="import" href="chrome://resources/html/cr.html">
<link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html">
<link rel="import" href="multidevice_constants.html">
<link rel="import" href="multidevice_browser_proxy.html">
<link rel="import" href="multidevice_constants.html">
<link rel="import" href="multidevice_feature_behavior.html">
<link rel="import" href="multidevice_page.html">
<dom-module id="settings-multidevice-page-container">
<template>
<template is="dom-if" if="[[doesPotentialConnectedPhoneExist]]" restamp>
<settings-multidevice-page prefs="{{prefs}}"
page-content-data="[[pageContentData_]]">
page-content-data="[[pageContentData]]">
</settings-multidevice-page>
</template>
</template>
......
......@@ -18,7 +18,7 @@ cr.exportPath('settings');
Polymer({
is: 'settings-multidevice-page-container',
behaviors: [WebUIListenerBehavior],
behaviors: [MultiDeviceFeatureBehavior, WebUIListenerBehavior],
properties: {
/** SettingsPrefsElement 'prefs' Object reference. See prefs.js. */
......@@ -34,12 +34,9 @@ Polymer({
*/
doesPotentialConnectedPhoneExist: {
type: Boolean,
computed: 'computeDoesPotentialConnectedPhoneExist(pageContentData_)',
computed: 'computeDoesPotentialConnectedPhoneExist(pageContentData)',
notify: true,
},
/** @private {MultiDevicePageContentData} */
pageContentData_: Object,
},
/** @private {?settings.MultiDeviceBrowserProxy} */
......@@ -66,7 +63,7 @@ Polymer({
console.error('Invalid status change');
return;
}
this.pageContentData_ = newData;
this.pageContentData = newData;
},
/**
......@@ -89,8 +86,8 @@ Polymer({
* @private
*/
computeDoesPotentialConnectedPhoneExist: function() {
return !!this.pageContentData_ &&
this.pageContentData_.mode !=
return !!this.pageContentData &&
this.pageContentData.mode !=
settings.MultiDeviceSettingsMode.NO_ELIGIBLE_HOSTS;
},
});
......@@ -11,6 +11,7 @@
<link rel="import" href="../settings_shared_css.html">
<link rel="import" href="../settings_vars_css.html">
<link rel="import" href="multidevice_constants.html">
<link rel="import" href="multidevice_feature_behavior.html">
<link rel="import" href="multidevice_feature_item.html">
<link rel="import" href="multidevice_feature_toggle.html">
<link rel="import" href="multidevice_tether_item.html">
......@@ -58,10 +59,9 @@
restamp>
<div id="feature-items-container">
<settings-multidevice-feature-item id="smart-lock-item"
icon-name="settings:smart-lock"
subpage-route="[[routes.LOCK_SCREEN]]"
feature-name="$i18n{multideviceSmartLockItemTitle}"
feature-summary-html="$i18n{multideviceSmartLockItemSummary}">
feature="[[MultiDeviceFeature.SMART_LOCK]]"
page-content-data="[[pageContentData]]"
subpage-route="[[routes.LOCK_SCREEN]]">
<div slot="feature-controller">
<!-- TODO (jordynass): Change the pref property to the pref
controlling Easy Unlock and make sure it's effectively
......@@ -71,13 +71,11 @@
</settings-multidevice-feature-toggle>
</div>
</settings-multidevice-feature-item>
<settings-multidevice-tether-item
label="$i18n{multideviceInstantTetheringItemTitle}">
<settings-multidevice-tether-item>
</settings-multidevice-tether-item>
<settings-multidevice-feature-item id="android-messages-item"
icon-name="settings:sms-connect"
feature-name="$i18n{multideviceAndroidMessagesItemTitle}"
feature-summary-html="$i18n{multideviceAndroidMessagesItemSummary}">
feature="[[MultiDeviceFeature.MESSAGES]]"
page-content-data="[[pageContentData]]">
<div slot="feature-controller">
<template is="dom-if"
if="[[androidMessagesRequiresSetup_]]"
......
......@@ -12,7 +12,11 @@ cr.exportPath('settings');
Polymer({
is: 'settings-multidevice-subpage',
behaviors: [I18nBehavior, PrefsBehavior, CrNetworkListenerBehavior],
behaviors: [
MultiDeviceFeatureBehavior,
CrNetworkListenerBehavior,
PrefsBehavior,
],
properties: {
/** @type {?SettingsRoutes} */
......@@ -39,9 +43,6 @@ Polymer({
value: () => ['settings-multidevice-tether-item'],
},
/** @type {MultiDevicePageContentData} */
pageContentData: Object,
// TODO(jordynass): Set this variable once the information can be retrieved
// by whatever implementation we use (possibly an IPC or from prefs).
/**
......
......@@ -15,9 +15,6 @@ Polymer({
is: 'settings-multidevice-tether-item',
properties: {
/** @private {string} */
titleText_: String,
/**
* Interface for networkingPrivate calls.
* @private {!NetworkingPrivate}
......
......@@ -1330,6 +1330,12 @@
<structure name="IDR_SETTINGS_MULTIDEVICE_CONSTANTS_JS"
file="multidevice_page/multidevice_constants.js"
type="chrome_html" />
<structure name="IDR_SETTINGS_MULTIDEVICE_FEATURE_BEHAVIOR_HTML"
file="multidevice_page/multidevice_feature_behavior.html"
type="chrome_html" />
<structure name="IDR_SETTINGS_MULTIDEVICE_FEATURE_BEHAVIOR_JS"
file="multidevice_page/multidevice_feature_behavior.js"
type="chrome_html" />
<structure name="IDR_SETTINGS_MULTIDEVICE_FEATURE_ITEM_HTML"
file="multidevice_page/multidevice_feature_item.html"
type="chrome_html" />
......
......@@ -7,10 +7,9 @@ suite('Multidevice', function() {
/** @type {!settings.Route} */
let initialRoute;
const FAKE_NAME = 'TelePhone';
const FAKE_SUMMARY_HTML =
'Teleports your phone to your ChromeBook. <a href="link">Learn more.</a>';
const FAKE_ICON_NAME = 'settings:tele-phone';
// Fake MultiDeviceFeature enum value
const FAKE_MULTIDEVICE_FEATURE = -1;
const FAKE_SUMMARY_HTML = 'Gives you candy <a href="link">Learn more.</a>';
/**
* Verifies that the current route is not initialRoute and then navigates
......@@ -26,16 +25,14 @@ suite('Multidevice', function() {
setup(function() {
PolymerTest.clearBody();
featureItem = document.createElement('settings-multidevice-feature-item');
assertTrue(!!featureItem);
initialRoute = settings.routes.MULTIDEVICE_FEATURES;
settings.routes.TELE_PHONE =
settings.routes.BASIC.createSection('/telePhone');
featureItem.getFeatureSummaryHtml = () => FAKE_SUMMARY_HTML;
featureItem.feature = FAKE_MULTIDEVICE_FEATURE;
featureItem.featureName = FAKE_NAME;
featureItem.featureSummaryHtml = FAKE_SUMMARY_HTML;
featureItem.iconName = FAKE_ICON_NAME;
featureItem.subpageRoute = settings.routes.TELE_PHONE;
initialRoute = settings.routes.MULTIDEVICE_FEATURES;
settings.routes.FREE_CANDY =
settings.routes.BASIC.createSection('/freeCandy');
featureItem.subpageRoute = settings.routes.FREE_CANDY;
settings.navigateTo(initialRoute);
......
......@@ -129,7 +129,7 @@ suite('Multidevice', function() {
});
test(
'pageContentData_ property passes to multidevice page if present',
'pageContentData property passes to multidevice page if present',
function() {
return setInitialHostStatus(
settings.MultiDeviceSettingsMode.NO_ELIGIBLE_HOSTS)
......@@ -140,7 +140,7 @@ suite('Multidevice', function() {
assertEquals(getMultidevicePage(), null);
else
assertDeepEquals(
multidevicePageContainer.pageContentData_,
multidevicePageContainer.pageContentData,
getMultidevicePage().pageContentData);
}
});
......
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