0

Refactor printing restriction policies: color, duplex, pin

Migrate Chrome OS printing restriction policies to be consistent with
other printing policies.

Mojo fields are moved from CapabilitiesResponse to Policies in
local_printer.mojom.
C++ logic is moved from LocalPrinterHandlerChromeos to
PrintPreviewHandler
JavaScript structures are moved from Destination.Policies to
NativeInitialSettings.Policies. All related logic and browser tests were
also updated.

Bug: b/172223138,crrev.com/1234467
Change-Id: I3665c7b4a2e68bd8d4a73d66d8bea4027939af34
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3054054
Reviewed-by: Rebekah Potter <rbpotter@chromium.org>
Reviewed-by: Roland Bock <rbock@google.com>
Reviewed-by: Erik Chen <erikchen@chromium.org>
Reviewed-by: Chris Palmer <palmer@chromium.org>
Commit-Queue: Jan Kopański <jkopanski@google.com>
Cr-Commit-Position: refs/heads/master@{#907882}
This commit is contained in:
Jan Kopanski
2021-08-03 08:27:01 +00:00
committed by Chromium LUCI CQ
parent 447e92cc1e
commit 43fbda13a3
24 changed files with 788 additions and 396 deletions

@ -82,17 +82,12 @@ mojom::CapabilitiesResponsePtr OnSetUpPrinter(
const absl::optional<printing::PrinterSemanticCapsAndDefaults>& caps) {
return mojom::CapabilitiesResponse::New(
LocalPrinterAsh::PrinterToMojom(printer), printer.HasSecureProtocol(),
caps, prefs->GetInteger(prefs::kPrintingAllowedColorModes),
prefs->GetInteger(prefs::kPrintingAllowedDuplexModes),
static_cast<printing::mojom::PinModeRestriction>(
prefs->GetInteger(prefs::kPrintingAllowedPinModes)),
static_cast<printing::mojom::ColorModeRestriction>(
prefs->GetInteger(prefs::kPrintingColorDefault)),
static_cast<printing::mojom::DuplexModeRestriction>(
prefs->GetInteger(prefs::kPrintingDuplexDefault)),
static_cast<printing::mojom::PinModeRestriction>(
prefs->GetInteger(prefs::kPrintingPinDefault)),
0); // deprecated
caps, // comment to prevent git cl format
0, 0, 0, // deprecated
printing::mojom::PinModeRestriction::kUnset, // deprecated
printing::mojom::ColorModeRestriction::kUnset, // deprecated
printing::mojom::DuplexModeRestriction::kUnset, // deprecated
printing::mojom::PinModeRestriction::kUnset); // deprecated
}
} // namespace
@ -385,6 +380,7 @@ void LocalPrinterAsh::GetPolicies(GetPoliciesCallback callback) {
Profile* profile = GetProfile();
PrefService* prefs = profile->GetPrefs();
mojom::PoliciesPtr policies = mojom::Policies::New();
if (prefs->HasPrefPath(prefs::kPrintHeaderFooter)) {
(prefs->IsManagedPreference(prefs::kPrintHeaderFooter)
? policies->print_header_footer_allowed
@ -393,6 +389,7 @@ void LocalPrinterAsh::GetPolicies(GetPoliciesCallback callback) {
? mojom::Policies::OptionalBool::kTrue
: mojom::Policies::OptionalBool::kFalse;
}
if (prefs->HasPrefPath(prefs::kPrintingAllowedBackgroundGraphicsModes)) {
policies->allowed_background_graphics_modes =
static_cast<mojom::Policies::BackgroundGraphicsModeRestriction>(
@ -403,6 +400,7 @@ void LocalPrinterAsh::GetPolicies(GetPoliciesCallback callback) {
static_cast<mojom::Policies::BackgroundGraphicsModeRestriction>(
prefs->GetInteger(prefs::kPrintingBackgroundGraphicsDefault));
}
policies->paper_size_default = printing::ParsePaperSizeDefault(*prefs);
if (prefs->HasPrefPath(prefs::kPrintingMaxSheetsAllowed)) {
int max_sheets = prefs->GetInteger(prefs::kPrintingMaxSheetsAllowed);
@ -411,6 +409,30 @@ void LocalPrinterAsh::GetPolicies(GetPoliciesCallback callback) {
policies->max_sheets_allowed_has_value = true;
}
}
if (prefs->HasPrefPath(prefs::kPrintingAllowedColorModes))
policies->allowed_color_modes =
prefs->GetInteger(prefs::kPrintingAllowedColorModes);
if (prefs->HasPrefPath(prefs::kPrintingAllowedDuplexModes))
policies->allowed_duplex_modes =
prefs->GetInteger(prefs::kPrintingAllowedDuplexModes);
if (prefs->HasPrefPath(prefs::kPrintingAllowedPinModes))
policies->allowed_pin_modes =
static_cast<printing::mojom::PinModeRestriction>(
prefs->GetInteger(prefs::kPrintingAllowedPinModes));
if (prefs->HasPrefPath(prefs::kPrintingColorDefault))
policies->default_color_mode =
static_cast<printing::mojom::ColorModeRestriction>(
prefs->GetInteger(prefs::kPrintingColorDefault));
if (prefs->HasPrefPath(prefs::kPrintingDuplexDefault))
policies->default_duplex_mode =
static_cast<printing::mojom::DuplexModeRestriction>(
prefs->GetInteger(prefs::kPrintingDuplexDefault));
if (prefs->HasPrefPath(prefs::kPrintingPinDefault))
policies->default_pin_mode =
static_cast<printing::mojom::PinModeRestriction>(
prefs->GetInteger(prefs::kPrintingPinDefault));
std::move(callback).Run(std::move(policies));
}

@ -458,22 +458,6 @@ TEST_F(LocalPrinterAshTest, GetPrinters) {
// Tests that fetching capabilities for an existing installed printer is
// successful.
TEST_P(LocalPrinterAshProcessScopeTest, GetCapabilityValidPrinter) {
auto* prefs = GetPrefs();
// printing::mojom::ColorModeRestriction::kMonochrome |
// printing::mojom::ColorModeRestriction::kColor
prefs->SetInteger(prefs::kPrintingAllowedColorModes, 3);
// printing::mojom::DuplexModeRestriction::kSimplex |
// printing::mojom::DuplexModeRestriction::kDuplex
prefs->SetInteger(prefs::kPrintingAllowedDuplexModes, 7);
// printing::mojom::PinModeRestriction::kPin
prefs->SetInteger(prefs::kPrintingAllowedPinModes, 1);
// printing::mojom::ColorModeRestriction::kColor
prefs->SetInteger(prefs::kPrintingColorDefault, 2);
// printing::mojom::DuplexModeRestriction::kSimplex
prefs->SetInteger(prefs::kPrintingDuplexDefault, 1);
// printing::mojom::PinModeRestriction::kNoPin
prefs->SetInteger(prefs::kPrintingPinDefault, 2);
Printer saved_printer =
CreateTestPrinter("printer1", "saved", "description1");
printers_manager().AddPrinter(saved_printer, PrinterClass::kSaved);
@ -499,21 +483,6 @@ TEST_P(LocalPrinterAshProcessScopeTest, GetCapabilityValidPrinter) {
ASSERT_TRUE(fetched_caps->basic_info->uri);
EXPECT_EQ(kPrinterUri, *fetched_caps->basic_info->uri);
// printing::mojom::ColorModeRestriction::kMonochrome |
// printing::mojom::ColorModeRestriction::kColor
EXPECT_EQ(3, fetched_caps->allowed_color_modes);
// printing::mojom::DuplexModeRestriction::kSimplex |
// printing::mojom::DuplexModeRestriction::kDuplex
EXPECT_EQ(7, fetched_caps->allowed_duplex_modes);
EXPECT_EQ(printing::mojom::PinModeRestriction::kPin,
fetched_caps->allowed_pin_modes);
EXPECT_EQ(printing::mojom::ColorModeRestriction::kColor,
fetched_caps->default_color_mode);
EXPECT_EQ(printing::mojom::DuplexModeRestriction::kSimplex,
fetched_caps->default_duplex_mode);
EXPECT_EQ(printing::mojom::PinModeRestriction::kNoPin,
fetched_caps->default_pin_mode);
ASSERT_TRUE(fetched_caps->capabilities);
EXPECT_EQ(kPapers, fetched_caps->capabilities->papers);
}
@ -859,6 +828,55 @@ TEST_F(LocalPrinterAshTest, GetPolicies_PrintHeaderFooter_ManagedEnabled) {
policies->print_header_footer_default);
}
TEST_F(LocalPrinterAshTest, GetPolicies_Color) {
const uint32_t expected_allowed_color_modes = static_cast<uint32_t>(
static_cast<int32_t>(printing::mojom::ColorModeRestriction::kMonochrome) |
static_cast<int32_t>(printing::mojom::ColorModeRestriction::kColor));
auto* prefs = GetPrefs();
prefs->SetInteger(prefs::kPrintingAllowedColorModes, 3);
prefs->SetInteger(prefs::kPrintingColorDefault, 2);
crosapi::mojom::PoliciesPtr policies;
local_printer_ash()->GetPolicies(base::BindOnce(base::BindLambdaForTesting(
[&](crosapi::mojom::PoliciesPtr data) { policies = std::move(data); })));
EXPECT_EQ(expected_allowed_color_modes, policies->allowed_color_modes);
EXPECT_EQ(printing::mojom::ColorModeRestriction::kColor,
policies->default_color_mode);
}
TEST_F(LocalPrinterAshTest, GetPolicies_Duplex) {
const uint32_t expected_allowed_duplex_modes = static_cast<uint32_t>(
static_cast<int32_t>(printing::mojom::DuplexModeRestriction::kSimplex) |
static_cast<int32_t>(printing::mojom::DuplexModeRestriction::kDuplex));
auto* prefs = GetPrefs();
prefs->SetInteger(prefs::kPrintingAllowedDuplexModes, 7);
prefs->SetInteger(prefs::kPrintingDuplexDefault, 1);
crosapi::mojom::PoliciesPtr policies;
local_printer_ash()->GetPolicies(base::BindOnce(base::BindLambdaForTesting(
[&](crosapi::mojom::PoliciesPtr data) { policies = std::move(data); })));
EXPECT_EQ(expected_allowed_duplex_modes, policies->allowed_duplex_modes);
EXPECT_EQ(printing::mojom::DuplexModeRestriction::kSimplex,
policies->default_duplex_mode);
}
TEST_F(LocalPrinterAshTest, GetPolicies_Pin) {
auto* prefs = GetPrefs();
prefs->SetInteger(prefs::kPrintingAllowedPinModes, 1);
prefs->SetInteger(prefs::kPrintingPinDefault, 2);
crosapi::mojom::PoliciesPtr policies;
local_printer_ash()->GetPolicies(base::BindOnce(base::BindLambdaForTesting(
[&](crosapi::mojom::PoliciesPtr data) { policies = std::move(data); })));
EXPECT_EQ(printing::mojom::PinModeRestriction::kPin,
policies->allowed_pin_modes);
EXPECT_EQ(printing::mojom::PinModeRestriction::kNoPin,
policies->default_pin_mode);
}
TEST_F(LocalPrinterAshTest, GetUsernamePerPolicy_Allowed) {
SetUsername("user@email.com");
GetPrefs()->SetBoolean(prefs::kPrintingSendUsernameAndFilenameEnabled, true);

@ -94,7 +94,6 @@ preprocess_if_expr("preprocess") {
"data/coordinate2d.js",
"data/destination.js",
"data/destination_match.js",
"data/destination_policies.js",
"data/destination_store.js",
"data/document_info.js",
"data/local_parsers.js",
@ -327,7 +326,6 @@ js_library("native_layer") {
js_library("native_layer_cros") {
deps = [
"data:destination_policies",
"data:printer_status_cros",
"//ui/webui/resources/js:assert.m",
"//ui/webui/resources/js:cr.m",

@ -14,7 +14,6 @@ js_type_check("closure_compile_module") {
":coordinate2d",
":destination",
":destination_match",
":destination_policies",
":destination_store",
":document_info",
":local_parsers",
@ -37,9 +36,6 @@ js_type_check("closure_compile_module") {
js_library("cdd") {
}
js_library("destination_policies") {
}
js_library("destination_store") {
deps = [
":cdd",
@ -72,7 +68,6 @@ js_library("local_parsers") {
deps = [
":destination",
":destination_match",
":destination_policies",
"..:native_layer",
"//ui/webui/resources/js:cr.m",
]
@ -100,10 +95,7 @@ js_library("destination") {
]
if (is_chromeos) {
deps += [
":destination_policies",
"..:native_layer_cros",
]
deps += [ "..:native_layer_cros" ]
}
}

@ -12,7 +12,6 @@ import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
import {NativeLayerCrosImpl} from '../native_layer_cros.js';
import {Cdd} from './cdd.js';
import {ColorModeRestriction, DestinationPolicies, DuplexModeRestriction, PinModeRestriction} from './destination_policies.js';
import {getStatusReasonFromPrinterStatus, PrinterStatus, PrinterStatusReason} from './printer_status_cros.js';
// </if>
@ -185,7 +184,6 @@ export class Destination {
* description: (string|undefined),
* certificateStatus:
* (DestinationCertificateStatus|undefined),
* policies: (DestinationPolicies|undefined),
* }=} opt_params Optional
* parameters for the destination.
*/
@ -226,12 +224,6 @@ export class Destination {
*/
this.capabilities_ = null;
/**
* Policies affecting the destination.
* @private {?DestinationPolicies}
*/
this.policies_ = (opt_params && opt_params.policies) || null;
/**
* Whether the destination is owned by the user.
* @private {boolean}
@ -499,21 +491,6 @@ export class Destination {
}
// <if expr="chromeos or lacros">
/**
* @return {?DestinationPolicies} Print policies affecting the destination.
*/
get policies() {
return this.policies_;
}
/**
* @param {?DestinationPolicies} policies Print policies affecting the
* destination.
*/
set policies(policies) {
this.policies_ = policies;
}
/** @return {string} The EULA URL for a the destination */
get eulaUrl() {
return this.eulaUrl_;
@ -808,37 +785,6 @@ export class Destination {
null;
}
// <if expr="chromeos or lacros">
/**
* @return {?ColorModeRestriction} Color mode set by policy.
*/
get colorPolicy() {
return this.policies && this.policies.allowedColorModes ?
this.policies.allowedColorModes :
null;
}
/**
* @return {?DuplexModeRestriction} Duplex modes allowed by
* policy.
*/
get duplexPolicy() {
return this.policies && this.policies.allowedDuplexModes ?
this.policies.allowedDuplexModes :
null;
}
/**
* @return {?PinModeRestriction} Pin mode allowed by policy.
*/
get pinPolicy() {
return this.policies && this.policies.allowedPinModes ?
this.policies.allowedPinModes :
null;
}
// </if>
/** @return {boolean} Whether the printer supports copies. */
get hasCopiesCapability() {
const capability = this.copiesCapability_();
@ -868,32 +814,6 @@ export class Destination {
return hasColor && hasMonochrome;
}
// <if expr="chromeos or lacros">
/**
* @return {?ColorModeRestriction} Value of default color
* setting given by policy.
*/
get defaultColorPolicy() {
return this.policies && this.policies.defaultColorMode;
}
/**
* @return {?DuplexModeRestriction} Value of default duplex
* setting given by policy.
*/
get defaultDuplexPolicy() {
return this.policies && this.policies.defaultDuplexMode;
}
/**
* @return {?PinModeRestriction} Value of default pin setting
* given by policy.
*/
get defaultPinPolicy() {
return this.policies && this.policies.defaultPinMode;
}
// </if>
/**
* @param {boolean} isColor Whether to use a color printing mode.
* @return {Object} Selected color option.

@ -1,54 +0,0 @@
// Copyright 2019 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.
/**
* Enumeration of color mode restrictions used by Chromium.
* This has to coincide with |printing::ColorModeRestriction| as defined in
* printing/backend/printing_restrictions.h
* @enum {number}
*/
export const ColorModeRestriction = {
UNSET: 0x0,
MONOCHROME: 0x1,
COLOR: 0x2,
};
/**
* Enumeration of duplex mode restrictions used by Chromium.
* This has to coincide with |printing::DuplexModeRestriction| as defined in
* printing/backend/printing_restrictions.h
* @enum {number}
*/
export const DuplexModeRestriction = {
UNSET: 0x0,
SIMPLEX: 0x1,
LONG_EDGE: 0x2,
SHORT_EDGE: 0x4,
DUPLEX: 0x6,
};
/**
* Enumeration of PIN printing mode restrictions used by Chromium.
* This has to coincide with |printing::PinModeRestriction| as defined in
* printing/backend/printing_restrictions.h
* @enum {number}
*/
export const PinModeRestriction = {
UNSET: 0,
PIN: 1,
NO_PIN: 2,
};
/**
* Policies affecting a destination.
* @typedef {{
* allowedColorModes: ?ColorModeRestriction,
* allowedDuplexModes: ?DuplexModeRestriction,
* allowedPinMode: ?PinModeRestriction,
* defaultColorMode: ?ColorModeRestriction,
* defaultDuplexMode: ?DuplexModeRestriction,
* defaultPinMode: ?PinModeRestriction,
* }}
*/
export let DestinationPolicies;

@ -1099,9 +1099,6 @@ export class DestinationStore extends EventTarget {
parseDestination(originToType(origin), assert(settingsInfo.printer)));
}
if (dest) {
if (settingsInfo.printer && settingsInfo.printer.policies) {
dest.policies = settingsInfo.printer.policies;
}
if ((origin === DestinationOrigin.LOCAL ||
origin === DestinationOrigin.CROS) &&
dest.capabilities) {

@ -7,9 +7,6 @@ import {isChromeOS, isLacros} from 'chrome://resources/js/cr.m.js';
import {Destination, DestinationConnectionStatus, DestinationOrigin, DestinationProvisionalType, DestinationType} from './destination.js';
import {PrinterType} from './destination_match.js';
// <if expr="chromeos or lacros">
import {DestinationPolicies} from './destination_policies.js';
// </if>
/**
* @typedef {{
@ -18,7 +15,6 @@ import {DestinationPolicies} from './destination_policies.js';
* printerDescription: (string | undefined),
* cupsEnterprisePrinter: (boolean | undefined),
* printerOptions: (Object | undefined),
* policies: (DestinationPolicies | undefined),
* }}
*/
export let LocalDestinationInfo;
@ -81,7 +77,6 @@ function parseLocalDestination(destinationInfo) {
const options = {
description: destinationInfo.printerDescription,
isEnterprisePrinter: destinationInfo.cupsEnterprisePrinter,
policies: destinationInfo.policies,
};
if (destinationInfo.printerOptions) {
// Convert options into cloud print tags format.

@ -8,13 +8,10 @@ import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
import {PromiseResolver} from 'chrome://resources/js/promise_resolver.m.js';
import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {BackgroundGraphicsModeRestriction, Policies} from '../native_layer.js';
import {BackgroundGraphicsModeRestriction, ColorModeRestriction, DuplexModeRestriction, PinModeRestriction, Policies} from '../native_layer.js';
import {Cdd, CddCapabilities, VendorCapability} from './cdd.js';
import {Destination, DestinationOrigin, DestinationType, RecentDestination} from './destination.js';
import {getPrinterTypeForDestination, PrinterType} from './destination_match.js';
// <if expr="chromeos or lacros">
import {ColorModeRestriction, DuplexModeRestriction, PinModeRestriction} from './destination_policies.js';
// </if>
import {DocumentSettings} from './document_info.js';
import {CustomMarginsOrientation, Margins, MarginsSetting, MarginsType} from './margins.js';
import {ScalingType} from './scaling.js';
@ -112,6 +109,9 @@ export let PolicyEntry;
* cssBackground: (PolicyEntry | undefined),
* mediaSize: (PolicyEntry | undefined),
* sheets: (number | undefined),
* color: (PolicyEntry | undefined),
* duplex: (PolicyEntry | undefined),
* pin: (PolicyEntry | undefined),
* }}
*/
export let PolicySettings;
@ -1108,6 +1108,33 @@ export class PrintPreviewModelElement extends PolymerElement {
}
break;
}
case 'color': {
const value = allowedMode ? allowedMode : defaultMode;
if (value !== undefined) {
this.setPolicySetting_(
settingName, value, !!allowedMode,
/*applyOnDestinationUpdate=*/ false);
}
break;
}
case 'duplex': {
const value = allowedMode ? allowedMode : defaultMode;
if (value !== undefined) {
this.setPolicySetting_(
settingName, value, !!allowedMode,
/*applyOnDestinationUpdate=*/ false);
}
break;
}
case 'pin': {
const value = allowedMode ? allowedMode : defaultMode;
if (value !== undefined) {
this.setPolicySetting_(
settingName, value, !!allowedMode,
/*applyOnDestinationUpdate=*/ false);
}
break;
}
default:
break;
}
@ -1140,6 +1167,14 @@ export class PrintPreviewModelElement extends PolymerElement {
applyOnDestinationUpdate: false
};
}
['color', 'duplex', 'pin'].forEach(settingName => {
if (!policies[settingName]) {
return;
}
const defaultMode = policies[settingName].defaultMode;
const allowedMode = policies[settingName].allowedMode;
this.configurePolicySetting_(settingName, allowedMode, defaultMode);
});
// </if>
}
@ -1202,6 +1237,42 @@ export class PrintPreviewModelElement extends PolymerElement {
this.maxSheets = this.policySettings_['sheets'].value;
continue;
}
if (settingName === 'color') {
this.set(
'settings.color.value',
policy.value === ColorModeRestriction.COLOR);
this.set('settings.color.setByPolicy', policy.managed);
continue;
}
if (settingName === 'duplex') {
let setDuplexTypeByPolicy = false;
this.set(
'settings.duplex.value',
policy.value !== DuplexModeRestriction.SIMPLEX);
if (policy.value === DuplexModeRestriction.SHORT_EDGE) {
this.set('settings.duplexShortEdge.value', true);
setDuplexTypeByPolicy = true;
} else if (policy.value === DuplexModeRestriction.LONG_EDGE) {
this.set('settings.duplexShortEdge.value', false);
setDuplexTypeByPolicy = true;
}
this.set('settings.duplex.setByPolicy', policy.managed);
this.set(
'settings.duplexShortEdge.setByPolicy',
policy.managed && setDuplexTypeByPolicy);
continue;
}
if (settingName === 'pin') {
if (policy.value === PinModeRestriction.NO_PIN && policy.managed) {
this.set('settings.pin.available', false);
this.set('settings.pinValue.available', false);
} else {
this.set(
'settings.pin.value', policy.value === PinModeRestriction.PIN);
}
this.set('settings.pin.setByPolicy', policy.managed);
continue;
}
// </if>
if (policy.value !== undefined && !policy.applyOnDestinationUpdate) {
this.setSetting(settingName, policy.value, true);
@ -1213,58 +1284,11 @@ export class PrintPreviewModelElement extends PolymerElement {
}
}
// TODO (crbug.com/1069802): Migrate these policies from Destination.policies
// to NativeInitialSettings.policies.
/**
* Restricts settings and applies defaults as defined by policy applicable to
* current destination.
*/
applyDestinationSpecificPolicies() {
// <if expr="chromeos or lacros">
const colorPolicy = this.destination.colorPolicy;
const colorValue =
colorPolicy ? colorPolicy : this.destination.defaultColorPolicy;
if (colorValue) {
// |this.setSetting| does nothing if policy is present.
// We want to set the value nevertheless so we call |this.set| directly.
this.set(
'settings.color.value', colorValue === ColorModeRestriction.COLOR);
}
this.set('settings.color.setByPolicy', !!colorPolicy);
const duplexPolicy = this.destination.duplexPolicy;
const duplexValue =
duplexPolicy ? duplexPolicy : this.destination.defaultDuplexPolicy;
let setDuplexTypeByPolicy = false;
if (duplexValue) {
this.set(
'settings.duplex.value',
duplexValue !== DuplexModeRestriction.SIMPLEX);
if (duplexValue === DuplexModeRestriction.SHORT_EDGE) {
this.set('settings.duplexShortEdge.value', true);
setDuplexTypeByPolicy = true;
} else if (duplexValue === DuplexModeRestriction.LONG_EDGE) {
this.set('settings.duplexShortEdge.value', false);
setDuplexTypeByPolicy = true;
}
}
this.set('settings.duplex.setByPolicy', !!duplexPolicy);
this.set(
'settings.duplexShortEdge.setByPolicy',
!!duplexPolicy && setDuplexTypeByPolicy);
const pinPolicy = this.destination.pinPolicy;
if (pinPolicy === PinModeRestriction.NO_PIN) {
this.set('settings.pin.available', false);
this.set('settings.pinValue.available', false);
}
const pinValue = pinPolicy ? pinPolicy : this.destination.defaultPinPolicy;
if (pinValue) {
this.set('settings.pin.value', pinValue === PinModeRestriction.PIN);
}
this.set('settings.pin.setByPolicy', !!pinPolicy);
// </if>
if (this.settings.mediaSize.available && this.policySettings_) {
const mediaSizePolicy = this.policySettings_['mediaSize'] &&
this.policySettings_['mediaSize'].value;

@ -6,7 +6,6 @@ import {assert} from 'chrome://resources/js/assert.m.js';
import {addSingletonGetter, sendWithPromise} from 'chrome://resources/js/cr.m.js';
import {Cdd} from './data/cdd.js';
import {Destination} from './data/destination.js';
import {PrinterType} from './data/destination_match.js';
import {LocalDestinationInfo, PrivetPrinterDescription} from './data/local_parsers.js';
import {MeasurementSystemUnitType} from './data/measurement_system.js';
@ -35,6 +34,44 @@ export const BackgroundGraphicsModeRestriction = {
DISABLED: 2,
};
/**
* Enumeration of color mode restrictions used by Chromium.
* This has to coincide with |printing::ColorModeRestriction| as defined in
* printing/backend/printing_restrictions.h
* @enum {number}
*/
export const ColorModeRestriction = {
UNSET: 0x0,
MONOCHROME: 0x1,
COLOR: 0x2,
};
/**
* Enumeration of duplex mode restrictions used by Chromium.
* This has to coincide with |printing::DuplexModeRestriction| as defined in
* printing/backend/printing_restrictions.h
* @enum {number}
*/
export const DuplexModeRestriction = {
UNSET: 0x0,
SIMPLEX: 0x1,
LONG_EDGE: 0x2,
SHORT_EDGE: 0x4,
DUPLEX: 0x6,
};
/**
* Enumeration of PIN printing mode restrictions used by Chromium.
* This has to coincide with |printing::PinModeRestriction| as defined in
* printing/backend/printing_restrictions.h
* @enum {number}
*/
export const PinModeRestriction = {
UNSET: 0,
PIN: 1,
NO_PIN: 2,
};
/**
* Policies affecting print settings values and availability.
* @typedef {{
@ -54,7 +91,19 @@ export const BackgroundGraphicsModeRestriction = {
* } | undefined),
* sheets: ({
* value: (number | undefined),
* } | undefined)
* } | undefined),
* color: ({
* allowedMode: (ColorModeRestriction | undefined),
* defaultMode: (ColorModeRestriction | undefined),
* } | undefined),
* duplex: ({
* allowedMode: (DuplexModeRestriction | undefined),
* defaultMode: (DuplexModeRestriction | undefined),
* } | undefined),
* pin: ({
* allowedMode: (PinModeRestriction | undefined),
* defaultMode: (PinModeRestriction | undefined),
* } | undefined),
* }}
*/
export let Policies;

@ -6,7 +6,6 @@ import {assert} from 'chrome://resources/js/assert.m.js';
import {addSingletonGetter, sendWithPromise} from 'chrome://resources/js/cr.m.js';
import {Cdd} from './data/cdd.js';
import {DestinationPolicies} from './data/destination_policies.js';
import {ProvisionalDestinationInfo} from './data/local_parsers.js';
import {PrinterStatus, PrinterStatusReason} from './data/printer_status_cros.js';
@ -14,7 +13,6 @@ import {PrinterStatus, PrinterStatusReason} from './data/printer_status_cros.js'
* @typedef {{
* printerId: string,
* capabilities: !Cdd,
* policies: (DestinationPolicies | undefined),
* }}
*/
export let PrinterSetupResponse;

@ -13,9 +13,6 @@ export {ColorMode, createDestinationKey, Destination, DestinationCertificateStat
export {SAVE_TO_DRIVE_CROS_DESTINATION_KEY} from './data/destination.js';
// </if>
export {PrinterType} from './data/destination_match.js';
// <if expr="chromeos or lacros">
export {ColorModeRestriction, DuplexModeRestriction, PinModeRestriction} from './data/destination_policies.js';
// </if>
export {DestinationErrorType, DestinationStore} from './data/destination_store.js';
export {PageLayoutInfo} from './data/document_info.js';
export {LocalDestinationInfo, ProvisionalDestinationInfo} from './data/local_parsers.js';
@ -31,7 +28,7 @@ export {PrinterState, PrinterStatus, PrinterStatusReason, PrinterStatusSeverity}
export {ScalingType} from './data/scaling.js';
export {Size} from './data/size.js';
export {Error, State} from './data/state.js';
export {BackgroundGraphicsModeRestriction, CapabilitiesResponse, NativeInitialSettings, NativeLayer, NativeLayerImpl} from './native_layer.js';
export {BackgroundGraphicsModeRestriction, CapabilitiesResponse, ColorModeRestriction, DuplexModeRestriction, NativeInitialSettings, NativeLayer, NativeLayerImpl, PinModeRestriction} from './native_layer.js';
// <if expr="chromeos or lacros">
export {NativeLayerCros, NativeLayerCrosImpl, PrinterSetupResponse, PrintServer, PrintServersConfig} from './native_layer_cros.js';
// </if>

@ -300,9 +300,6 @@ Polymer({
this.destinationInConfiguring_ = null;
listItem.onConfigureComplete(true);
destination.capabilities = response.capabilities;
if (response.policies) {
destination.policies = response.policies;
}
this.selectDestination_(destination);
// After destination is selected, start fetching for the EULA
// URL.

@ -118,17 +118,24 @@ base::Value LocalPrinterHandlerChromeos::CapabilityToValue(
: kValueFalse}}),
PrinterSemanticCapsAndDefaults::Papers(), caps->has_secure_protocol,
base::OptionalOrNullptr(caps->capabilities));
// TODO(b/195001379, jkopanski): This block of code should be removed once
// Ash Chrome M94 is on stable channel.
base::Value policies(base::Value::Type::DICTIONARY);
policies.SetIntKey(kAllowedColorModes, caps->allowed_color_modes);
policies.SetIntKey(kAllowedDuplexModes, caps->allowed_duplex_modes);
policies.SetIntKey(kAllowedPinModes,
static_cast<int>(caps->allowed_pin_modes));
policies.SetIntKey(kAllowedColorModes, caps->allowed_color_modes_deprecated);
policies.SetIntKey(kAllowedDuplexModes,
caps->allowed_duplex_modes_deprecated);
policies.SetIntKey(
kAllowedPinModes,
static_cast<int>(caps->allowed_pin_modes_deprecated_version_1));
policies.SetIntKey(kDefaultColorMode,
static_cast<int>(caps->default_color_mode));
static_cast<int>(caps->default_color_mode_deprecated));
policies.SetIntKey(kDefaultDuplexMode,
static_cast<int>(caps->default_duplex_mode));
policies.SetIntKey(kDefaultPinMode, static_cast<int>(caps->default_pin_mode));
static_cast<int>(caps->default_duplex_mode_deprecated));
policies.SetIntKey(kDefaultPinMode,
static_cast<int>(caps->default_pin_mode_deprecated));
dict.FindKey(kPrinter)->SetKey(kSettingPolicies, std::move(policies));
return dict;
}

@ -159,12 +159,21 @@ TEST(LocalPrinterHandlerChromeos, CapabilityToValue) {
auto caps = crosapi::mojom::CapabilitiesResponse::New();
caps->basic_info = crosapi::mojom::LocalDestinationInfo::New(
"device_name", "printer_name", "printer_description", false);
caps->allowed_color_modes = 1;
caps->allowed_duplex_modes = 2;
caps->allowed_pin_modes = printing::mojom::PinModeRestriction::kPin;
caps->default_color_mode = printing::mojom::ColorModeRestriction::kColor;
caps->default_duplex_mode = printing::mojom::DuplexModeRestriction::kSimplex;
caps->default_pin_mode = printing::mojom::PinModeRestriction::kNoPin;
// TODO(b/195001379, jkopanski): This block of code should be removed once
// Ash Chrome M94 is on stable channel. Also remove associated "policies"
// field in kExpectedValue below.
caps->allowed_color_modes_deprecated = 1;
caps->allowed_duplex_modes_deprecated = 2;
caps->allowed_pin_modes_deprecated_version_1 =
printing::mojom::PinModeRestriction::kPin;
caps->default_color_mode_deprecated =
printing::mojom::ColorModeRestriction::kColor;
caps->default_duplex_mode_deprecated =
printing::mojom::DuplexModeRestriction::kSimplex;
caps->default_pin_mode_deprecated =
printing::mojom::PinModeRestriction::kNoPin;
const base::Value kExpectedValue = *base::JSONReader::Read(R"({
"printer": {
"cupsEnterprisePrinter": false,
@ -190,12 +199,21 @@ TEST(LocalPrinterHandlerChromeos, CapabilityToValue_ConfiguredViaPolicy) {
auto caps = crosapi::mojom::CapabilitiesResponse::New();
caps->basic_info = crosapi::mojom::LocalDestinationInfo::New(
"device_name", "printer_name", "printer_description", true);
caps->allowed_color_modes = 1;
caps->allowed_duplex_modes = 2;
caps->allowed_pin_modes = printing::mojom::PinModeRestriction::kPin;
caps->default_color_mode = printing::mojom::ColorModeRestriction::kColor;
caps->default_duplex_mode = printing::mojom::DuplexModeRestriction::kSimplex;
caps->default_pin_mode = printing::mojom::PinModeRestriction::kNoPin;
// TODO(b/195001379, jkopanski): This block of code should be removed once
// Ash Chrome M94 is on stable channel. Also remove associated "policies"
// field in kExpectedValue below.
caps->allowed_color_modes_deprecated = 1;
caps->allowed_duplex_modes_deprecated = 2;
caps->allowed_pin_modes_deprecated_version_1 =
printing::mojom::PinModeRestriction::kPin;
caps->default_color_mode_deprecated =
printing::mojom::ColorModeRestriction::kColor;
caps->default_duplex_mode_deprecated =
printing::mojom::DuplexModeRestriction::kSimplex;
caps->default_pin_mode_deprecated =
printing::mojom::PinModeRestriction::kNoPin;
const base::Value kExpectedValue = *base::JSONReader::Read(R"({
"printer": {
"cupsEnterprisePrinter": true,

@ -181,6 +181,12 @@ const char kMediaSize[] = "mediaSize";
const char kValue[] = "value";
// Name of a dictionary pref holding the policy value for the sheets number.
const char kSheets[] = "sheets";
// Name of a dictionary pref holding the policy value for the color setting.
const char kColor[] = "color";
// Name of a dictionary pref holding the policy value for the duplex setting.
const char kDuplex[] = "duplex";
// Name of a dictionary pref holding the policy value for the pin setting.
const char kPin[] = "pin";
#endif // defined(OS_CHROMEOS)
// Name of a dictionary field indicating whether the 'Save to PDF' destination
// is disabled.
@ -300,6 +306,36 @@ base::Value PoliciesToValue(crosapi::mojom::PoliciesPtr ptr) {
policies.SetKey(kSheets, std::move(sheets_policy));
}
base::Value color_policy(base::Value::Type::DICTIONARY);
if (ptr->allowed_color_modes)
color_policy.SetIntKey(kAllowedMode,
static_cast<int>(ptr->allowed_color_modes));
if (ptr->default_color_mode != printing::mojom::ColorModeRestriction::kUnset)
color_policy.SetIntKey(kDefaultMode,
static_cast<int>(ptr->default_color_mode));
if (!color_policy.DictEmpty())
policies.SetKey(kColor, std::move(color_policy));
base::Value duplex_policy(base::Value::Type::DICTIONARY);
if (ptr->allowed_duplex_modes)
duplex_policy.SetIntKey(kAllowedMode,
static_cast<int>(ptr->allowed_duplex_modes));
if (ptr->default_duplex_mode !=
printing::mojom::DuplexModeRestriction::kUnset)
duplex_policy.SetIntKey(kDefaultMode,
static_cast<int>(ptr->default_duplex_mode));
if (!duplex_policy.DictEmpty())
policies.SetKey(kDuplex, std::move(duplex_policy));
base::Value pin_policy(base::Value::Type::DICTIONARY);
if (ptr->allowed_pin_modes != printing::mojom::PinModeRestriction::kUnset)
pin_policy.SetIntKey(kAllowedMode,
static_cast<int>(ptr->allowed_pin_modes));
if (ptr->default_pin_mode != printing::mojom::PinModeRestriction::kUnset)
pin_policy.SetIntKey(kDefaultMode, static_cast<int>(ptr->default_pin_mode));
if (!pin_policy.DictEmpty())
policies.SetKey(kPin, std::move(pin_policy));
return policies;
}

@ -986,6 +986,91 @@ TEST_F(PrintPreviewHandlerTest, InitialSettingsMaxSheetsAllowedPolicy) {
ValidateInitialSettingsValuePolicy(*web_ui()->call_data().back(), "sheets",
base::Value(2));
}
TEST_F(PrintPreviewHandlerTest, InitialSettingsEnableColorAndMonochrome) {
#if BUILDFLAG(IS_CHROMEOS_LACROS)
crosapi::mojom::Policies policies;
policies.allowed_color_modes = 3;
SetPolicies(policies);
#else
// Set a pref that should take priority over StickySettings.
prefs()->SetInteger(prefs::kPrintingAllowedColorModes, 3);
#endif
Initialize();
ValidateInitialSettingsAllowedDefaultModePolicy(
*web_ui()->call_data().back(), "color", base::Value(3), absl::nullopt);
}
TEST_F(PrintPreviewHandlerTest, InitialSettingsDefaultColor) {
#if BUILDFLAG(IS_CHROMEOS_LACROS)
crosapi::mojom::Policies policies;
policies.default_color_mode = printing::mojom::ColorModeRestriction::kColor;
SetPolicies(policies);
#else
// Set a pref that should take priority over StickySettings.
prefs()->SetInteger(prefs::kPrintingColorDefault, 2);
#endif
Initialize();
ValidateInitialSettingsAllowedDefaultModePolicy(
*web_ui()->call_data().back(), "color", absl::nullopt, base::Value(2));
}
TEST_F(PrintPreviewHandlerTest, InitialSettingsEnableSimplexAndDuplex) {
#if BUILDFLAG(IS_CHROMEOS_LACROS)
crosapi::mojom::Policies policies;
policies.allowed_duplex_modes = 7;
SetPolicies(policies);
#else
// Set a pref that should take priority over StickySettings.
prefs()->SetInteger(prefs::kPrintingAllowedDuplexModes, 7);
#endif
Initialize();
ValidateInitialSettingsAllowedDefaultModePolicy(
*web_ui()->call_data().back(), "duplex", base::Value(7), absl::nullopt);
}
TEST_F(PrintPreviewHandlerTest, InitialSettingsDefaultSimplex) {
#if BUILDFLAG(IS_CHROMEOS_LACROS)
crosapi::mojom::Policies policies;
policies.default_duplex_mode =
printing::mojom::DuplexModeRestriction::kSimplex;
SetPolicies(policies);
#else
// Set a pref that should take priority over StickySettings.
prefs()->SetInteger(prefs::kPrintingDuplexDefault, 1);
#endif
Initialize();
ValidateInitialSettingsAllowedDefaultModePolicy(
*web_ui()->call_data().back(), "duplex", absl::nullopt, base::Value(1));
}
TEST_F(PrintPreviewHandlerTest, InitialSettingsRestrictPin) {
#if BUILDFLAG(IS_CHROMEOS_LACROS)
crosapi::mojom::Policies policies;
policies.allowed_pin_modes = printing::mojom::PinModeRestriction::kPin;
SetPolicies(policies);
#else
// Set a pref that should take priority over StickySettings.
prefs()->SetInteger(prefs::kPrintingAllowedPinModes, 1);
#endif
Initialize();
ValidateInitialSettingsAllowedDefaultModePolicy(
*web_ui()->call_data().back(), "pin", base::Value(1), absl::nullopt);
}
TEST_F(PrintPreviewHandlerTest, InitialSettingsDefaultNoPin) {
#if BUILDFLAG(IS_CHROMEOS_LACROS)
crosapi::mojom::Policies policies;
policies.default_pin_mode = printing::mojom::PinModeRestriction::kNoPin;
SetPolicies(policies);
#else
// Set a pref that should take priority over StickySettings.
prefs()->SetInteger(prefs::kPrintingPinDefault, 2);
#endif
Initialize();
ValidateInitialSettingsAllowedDefaultModePolicy(
*web_ui()->call_data().back(), "pin", absl::nullopt, base::Value(2));
}
#endif // defined(OS_CHROMEOS)
TEST_F(PrintPreviewHandlerTest, GetPrinters) {

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {ColorModeRestriction, Destination, DestinationConnectionStatus, DestinationOrigin, DestinationStore, DestinationType, DuplexModeRestriction, NativeLayer, NativeLayerCrosImpl, NativeLayerImpl} from 'chrome://print/print_preview.js';
import {Destination, DestinationConnectionStatus, DestinationOrigin, DestinationStore, DestinationType, NativeLayerCrosImpl, NativeLayerImpl} from 'chrome://print/print_preview.js';
import {assert} from 'chrome://resources/js/assert.m.js';
import {NativeEventTarget as EventTarget} from 'chrome://resources/js/cr/event_target.m.js';
import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
@ -173,42 +173,4 @@ suite(destination_search_test_chromeos.suiteName, function() {
// Verify that the destination has been selected.
assertEquals(printerId, destinationStore.selectedDestination.id);
});
// Tests that if policies are set correctly if they are present
// for a destination.
test(
assert(destination_search_test_chromeos.TestNames
.ReceiveSuccessfulSetupWithPolicies),
function() {
const destId = '00112233DEADBEEF';
const response = {
printerId: destId,
capabilities: getCddTemplate(destId).capabilities,
policies: {
allowedColorModes: ColorModeRestriction.MONOCHROME,
allowedDuplexModes: DuplexModeRestriction.DUPLEX,
allowedPinMode: null,
defaultColorMode: null,
defaultDuplexMode: null,
defaultPinMode: null,
},
};
nativeLayerCros.setSetupPrinterResponse(response);
requestSetup(destId);
return nativeLayerCros.whenCalled('setupPrinter')
.then(function(actualId) {
assertEquals(destId, actualId);
const selectedDestination = destinationStore.selectedDestination;
assertNotEquals(null, selectedDestination);
assertEquals(destId, selectedDestination.id);
assertNotEquals(null, selectedDestination.capabilities);
assertNotEquals(null, selectedDestination.policies);
assertEquals(
ColorModeRestriction.MONOCHROME,
selectedDestination.policies.allowedColorModes);
assertEquals(
DuplexModeRestriction.DUPLEX,
selectedDestination.policies.allowedDuplexModes);
});
});
});

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {CloudPrintInterfaceEventType, Destination, DestinationConnectionStatus, DestinationErrorType, DestinationOrigin, DestinationStore, DestinationType, LocalDestinationInfo, makeRecentDestination, NativeInitialSettings, NativeLayer, NativeLayerImpl, PluginProxy, PrinterType} from 'chrome://print/print_preview.js';
import {CloudPrintInterfaceEventType, Destination, DestinationConnectionStatus, DestinationErrorType, DestinationOrigin, DestinationStore, DestinationType, LocalDestinationInfo, makeRecentDestination, NativeInitialSettings, NativeLayerImpl, PrinterType} from 'chrome://print/print_preview.js';
import {assert} from 'chrome://resources/js/assert.m.js';
import {isChromeOS, isLacros} from 'chrome://resources/js/cr.m.js';
import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
@ -578,21 +578,10 @@ suite(destination_store_test.suiteName, function() {
assertEquals(
Destination.GooglePromotedId.SAVE_AS_PDF,
destinationStore.selectedDestination.id);
// Update destination with ID 1 so that it has policies.
const localDestinationInfo = {
deviceName: id1,
printerName: name1
};
if (isChromeOS || isLacros) {
localDestinationInfo.policies = {
allowedColorModes: 0x1, // ColorModeRestriction.MONOCHROME
defaultColorMode: 0x1, // ColorModeRestriction.MONOCHROME
allowedPinMode: null,
defaultPinMode: null,
allowedDuplexModes: null,
defaultDuplexMode: null,
};
}
// Typecast localDestinationInfo to work around the fact that
// policy types are only defined on Chrome OS.
nativeLayer.setLocalDestinationCapabilities({
@ -608,9 +597,6 @@ suite(destination_store_test.suiteName, function() {
destinationStore.destinations().find(d => d.id === id1);
// No capabilities or policies yet.
assertFalse(!!destination.capabilities);
if (isChromeOS || isLacros) {
assertEquals(null, destination.policies);
}
destinationStore.selectDestination(destination);
return nativeLayer.whenCalled('getPrinterCapabilities');
})
@ -618,10 +604,6 @@ suite(destination_store_test.suiteName, function() {
assertEquals(destination, destinationStore.selectedDestination);
// Capabilities are updated.
assertTrue(!!destination.capabilities);
if (isChromeOS || isLacros) {
// Policies are updated.
assertTrue(!!destination.policies);
}
});
});

@ -14,8 +14,7 @@ suite('ModelSettingsPolicyTest', function() {
/** @type {!PrintPreviewModelElement} */
let model;
/** @override */
setup(function() {
function setupModel() {
document.body.innerHTML = '';
model = /** @type {!PrintPreviewModelElement} */ (
document.createElement('print-preview-model'));
@ -43,13 +42,9 @@ suite('ModelSettingsPolicyTest', function() {
model.set(
'destination.capabilities',
getCddTemplate(model.destination.id).capabilities);
});
}
test('color managed', function() {
// Remove color capability.
let capabilities = getCddTemplate(model.destination.id).capabilities;
delete capabilities.printer.color;
[{
// Policy has no effect, setting unavailable
colorCap: {option: [{type: 'STANDARD_COLOR', is_default: true}]},
@ -99,18 +94,37 @@ suite('ModelSettingsPolicyTest', function() {
expectedAvailable: true,
expectedManaged: false,
expectedEnforced: false,
},
{
// Default defined by policy but setting is modifiable (same as the case
// above but with swapped defaults).
colorCap: {
option: [
{type: 'STANDARD_MONOCHROME'},
{type: 'STANDARD_COLOR', is_default: true}
]
},
colorDefault: ColorModeRestriction.MONOCHROME,
expectedValue: false,
expectedAvailable: true,
expectedManaged: false,
expectedEnforced: false,
}].forEach(subtestParams => {
capabilities = getCddTemplate(model.destination.id).capabilities;
setupModel();
// Remove color capability.
const capabilities = getCddTemplate(model.destination.id).capabilities;
capabilities.printer.color = subtestParams.colorCap;
const policies = {
allowedColorModes: subtestParams.colorPolicy,
defaultColorMode: subtestParams.colorDefault,
color: {
allowedMode: subtestParams.colorPolicy,
defaultMode: subtestParams.colorDefault,
}
};
// In practice |capabilities| are always set after |policies| and
// observers only check for |capabilities|, so the order is important.
model.set('destination.policies', policies);
model.set('destination.capabilities', capabilities);
model.applyDestinationSpecificPolicies();
model.setPolicySettings(policies);
model.applyStickySettings();
assertEquals(subtestParams.expectedValue, model.getSettingValue('color'));
assertEquals(
subtestParams.expectedAvailable, model.settings.color.available);
@ -121,10 +135,6 @@ suite('ModelSettingsPolicyTest', function() {
});
test('duplex managed', function() {
// Remove duplex capability.
let capabilities = getCddTemplate(model.destination.id).capabilities;
delete capabilities.printer.duplex;
[{
// Policy has no effect.
duplexCap: {option: [{type: 'NO_DUPLEX', is_default: true}]},
@ -206,17 +216,21 @@ suite('ModelSettingsPolicyTest', function() {
expectedShortEdgeAvailable: true,
expectedShortEdgeEnforced: false,
}].forEach(subtestParams => {
capabilities = getCddTemplate('FooPrinter').capabilities;
setupModel();
// Remove duplex capability.
const capabilities = getCddTemplate(model.destination.id).capabilities;
capabilities.printer.duplex = subtestParams.duplexCap;
const policies = {
allowedDuplexModes: subtestParams.duplexPolicy,
defaultDuplexMode: subtestParams.duplexDefault,
duplex: {
allowedMode: subtestParams.duplexPolicy,
defaultMode: subtestParams.duplexDefault,
}
};
// In practice |capabilities| are always set after |policies| and
// observers only check for |capabilities|, so the order is important.
model.set('destination.policies', policies);
model.set('destination.capabilities', capabilities);
model.applyDestinationSpecificPolicies();
model.setPolicySettings(policies);
model.applyStickySettings();
assertEquals(
subtestParams.expectedValue, model.getSettingValue('duplex'));
assertEquals(
@ -237,14 +251,6 @@ suite('ModelSettingsPolicyTest', function() {
});
test('pin managed', function() {
// Remove pin capability.
let capabilities = getCddTemplate(model.destination.id).capabilities;
delete capabilities.printer.pin;
// Make device enterprise managed since pin setting is available only on
// managed devices.
loadTimeData.overrideValues({isEnterpriseManaged: true});
[{
// No policies, settings is modifiable.
pinCap: {supported: true},
@ -312,17 +318,24 @@ suite('ModelSettingsPolicyTest', function() {
expectedManaged: false,
expectedEnforced: false,
}].forEach(subtestParams => {
capabilities = getCddTemplate(model.destination.id).capabilities;
setupModel();
// Make device enterprise managed since pin setting is available only on
// managed devices.
loadTimeData.overrideValues({isEnterpriseManaged: true});
// Remove pin capability.
const capabilities = getCddTemplate(model.destination.id).capabilities;
capabilities.printer.pin = subtestParams.pinCap;
const policies = {
allowedPinModes: subtestParams.pinPolicy,
defaultPinMode: subtestParams.pinDefault,
pin: {
allowedMode: subtestParams.pinPolicy,
defaultMode: subtestParams.pinDefault,
}
};
// In practice |capabilities| are always set after |policies| and
// observers only check for |capabilities|, so the order is important.
model.set('destination.policies', policies);
model.set('destination.capabilities', capabilities);
model.applyDestinationSpecificPolicies();
model.setPolicySettings(policies);
model.applyStickySettings();
assertEquals(subtestParams.expectedValue, model.getSettingValue('pin'));
assertEquals(
subtestParams.expectedAvailable, model.settings.pin.available);

@ -2,11 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {BackgroundGraphicsModeRestriction, NativeLayer, NativeLayerImpl, PluginProxyImpl, PrintPreviewPluralStringProxyImpl} from 'chrome://print/print_preview.js';
import {BackgroundGraphicsModeRestriction, DuplexMode, NativeLayerImpl, PluginProxyImpl, PrintPreviewPluralStringProxyImpl} from 'chrome://print/print_preview.js';
// <if expr="chromeos or lacros">
import {ColorModeRestriction, DuplexModeRestriction, PinModeRestriction} from 'chrome://print/print_preview.js';
// </if>
import {assert} from 'chrome://resources/js/assert.m.js';
import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {NativeLayerStub} from 'chrome://test/print_preview/native_layer_stub.js';
import {getCddTemplate, getDefaultInitialSettings} from 'chrome://test/print_preview/print_preview_test_utils.js';
import {getDefaultInitialSettings} from 'chrome://test/print_preview/print_preview_test_utils.js';
import {TestPluginProxy} from 'chrome://test/print_preview/test_plugin_proxy.js';
import {TestPluralStringProxy} from 'chrome://test/test_plural_string_proxy.js';
@ -22,6 +25,9 @@ policy_tests.TestNames = {
CssBackgroundPolicy: 'css background policy',
MediaSizePolicy: 'media size policy',
SheetsPolicy: 'sheets policy',
ColorPolicy: 'color policy',
DuplexPolicy: 'duplex policy',
PinPolicy: 'pin policy',
};
class PolicyTestPluralStringProxy extends TestPluralStringProxy {
@ -137,7 +143,7 @@ suite(policy_tests.suiteName, function() {
.$$(`#${settingName}`);
}
/** Tests different scenarios of applying header/footer policy. */
// Tests different scenarios of applying header/footer policy.
test(assert(policy_tests.TestNames.HeaderFooterPolicy), async () => {
const tests = [
{
@ -187,7 +193,7 @@ suite(policy_tests.suiteName, function() {
}
});
/** Tests different scenarios of applying background graphics policy. */
// Tests different scenarios of applying background graphics policy.
test(assert(policy_tests.TestNames.CssBackgroundPolicy), async () => {
const tests = [
{
@ -239,7 +245,7 @@ suite(policy_tests.suiteName, function() {
}
});
/** Tests different scenarios of applying default paper policy. */
// Tests different scenarios of applying default paper policy.
test(assert(policy_tests.TestNames.MediaSizePolicy), async () => {
const tests = [
{
@ -341,4 +347,320 @@ suite(policy_tests.suiteName, function() {
!errorMessage.hidden && !!errorMessage.innerText);
}
});
// <if expr="chromeos or lacros">
// Tests different scenarios of color printing policy.
test(assert(policy_tests.TestNames.ColorPolicy), async () => {
const tests = [
{
// No policies.
allowedMode: undefined,
defaultMode: undefined,
expectedDisabled: false,
expectedValue: 'color',
},
{
// Print in color by default.
allowedMode: undefined,
defaultMode: ColorModeRestriction.COLOR,
expectedDisabled: false,
expectedValue: 'color',
},
{
// Print in black and white by default.
allowedMode: undefined,
defaultMode: ColorModeRestriction.MONOCHROME,
expectedDisabled: false,
expectedValue: 'bw',
},
{
// Allowed and default policies unset.
allowedMode: ColorModeRestriction.UNSET,
defaultMode: ColorModeRestriction.UNSET,
expectedDisabled: false,
expectedValue: 'bw',
},
{
// Allowed unset, default set to color printing.
allowedMode: ColorModeRestriction.UNSET,
defaultMode: ColorModeRestriction.COLOR,
expectedDisabled: false,
expectedValue: 'color',
},
{
// Enforce color printing.
allowedMode: ColorModeRestriction.COLOR,
defaultMode: ColorModeRestriction.UNSET,
expectedDisabled: true,
expectedValue: 'color',
},
{
// Enforce black and white printing.
allowedMode: ColorModeRestriction.MONOCHROME,
defaultMode: undefined,
expectedDisabled: true,
expectedValue: 'bw',
},
{
// Enforce color printing, default is ignored.
allowedMode: ColorModeRestriction.COLOR,
defaultMode: ColorModeRestriction.MONOCHROME,
expectedDisabled: true,
expectedValue: 'color',
},
];
for (const subtestParams of tests) {
await doAllowedDefaultModePolicySetup(
'color', 'isColorEnabled', subtestParams.allowedMode,
subtestParams.defaultMode);
const colorSettingsSelect = page.$$('print-preview-sidebar')
.$$('print-preview-color-settings')
.$$('select');
assertEquals(
subtestParams.expectedDisabled, colorSettingsSelect.disabled);
assertEquals(subtestParams.expectedValue, colorSettingsSelect.value);
}
});
// Tests different scenarios of duplex printing policy.
test(assert(policy_tests.TestNames.DuplexPolicy), async () => {
const tests = [
{
// No policies.
allowedMode: undefined,
defaultMode: undefined,
expectedChecked: false,
expectedOpened: false,
expectedDisabled: false,
expectedValue: DuplexMode.LONG_EDGE,
},
{
// No restriction, default set to SIMPLEX.
allowedMode: undefined,
defaultMode: DuplexModeRestriction.SIMPLEX,
expectedChecked: false,
expectedOpened: false,
expectedDisabled: false,
expectedValue: DuplexMode.LONG_EDGE,
},
{
// No restriction, default set to UNSET.
allowedMode: undefined,
defaultMode: DuplexModeRestriction.UNSET,
expectedChecked: true,
expectedOpened: true,
expectedDisabled: false,
expectedValue: DuplexMode.LONG_EDGE,
},
{
// Allowed mode set to UNSET.
allowedMode: DuplexModeRestriction.UNSET,
defaultMode: undefined,
expectedChecked: false,
expectedOpened: false,
expectedDisabled: false,
expectedValue: DuplexMode.LONG_EDGE,
},
{
// No restriction, default set to LONG_EDGE.
allowedMode: undefined,
defaultMode: DuplexModeRestriction.LONG_EDGE,
expectedChecked: true,
expectedOpened: true,
expectedDisabled: false,
expectedValue: DuplexMode.LONG_EDGE,
},
{
// No restriction, default set to SHORT_EDGE.
allowedMode: undefined,
defaultMode: DuplexModeRestriction.SHORT_EDGE,
expectedChecked: true,
expectedOpened: true,
expectedDisabled: false,
expectedValue: DuplexMode.SHORT_EDGE,
},
{
// No restriction, default set to DUPLEX.
allowedMode: undefined,
defaultMode: DuplexModeRestriction.DUPLEX,
expectedChecked: true,
expectedOpened: true,
expectedDisabled: false,
expectedValue: DuplexMode.LONG_EDGE,
},
{
// No restriction, default set to SHORT_EDGE.
allowedMode: DuplexModeRestriction.SIMPLEX,
defaultMode: undefined,
expectedChecked: false,
expectedOpened: false,
expectedDisabled: false,
expectedValue: DuplexMode.LONG_EDGE,
},
{
// Restricted to LONG_EDGE.
allowedMode: DuplexModeRestriction.LONG_EDGE,
defaultMode: undefined,
expectedChecked: true,
expectedOpened: true,
expectedDisabled: true,
expectedValue: DuplexMode.LONG_EDGE,
},
{
// Restricted to SHORT_EDGE.
allowedMode: DuplexModeRestriction.SHORT_EDGE,
defaultMode: undefined,
expectedChecked: true,
expectedOpened: true,
expectedDisabled: true,
expectedValue: DuplexMode.SHORT_EDGE,
},
{
// Restricted to DUPLEX.
allowedMode: DuplexModeRestriction.DUPLEX,
defaultMode: undefined,
expectedChecked: true,
expectedOpened: true,
expectedDisabled: false,
expectedValue: DuplexMode.LONG_EDGE,
},
{
// Restricted to SHORT_EDGE, default is ignored.
allowedMode: DuplexModeRestriction.SHORT_EDGE,
defaultMode: DuplexModeRestriction.LONG_EDGE,
expectedChecked: true,
expectedOpened: true,
expectedDisabled: true,
expectedValue: DuplexMode.SHORT_EDGE,
},
];
for (const subtestParams of tests) {
await doAllowedDefaultModePolicySetup(
'duplex', 'isDuplexEnabled', subtestParams.allowedMode,
subtestParams.defaultMode);
toggleMoreSettings();
const duplexSettingsSection =
page.$$('print-preview-sidebar').$$('print-preview-duplex-settings');
const checkbox = duplexSettingsSection.$$('cr-checkbox');
const collapse = duplexSettingsSection.$$('iron-collapse');
const select = duplexSettingsSection.$$('select');
const expectedValue = subtestParams.expectedValue.toString();
assertEquals(subtestParams.expectedChecked, checkbox.checked);
assertEquals(subtestParams.expectedOpened, collapse.opened);
assertEquals(subtestParams.expectedDisabled, select.disabled);
assertEquals(expectedValue, select.value);
}
});
// Tests different scenarios of pin printing policy.
test(assert(policy_tests.TestNames.PinPolicy), async () => {
const tests = [
{
// No policies.
allowedMode: undefined,
defaultMode: undefined,
expectedCheckboxDisabled: false,
expectedChecked: false,
expectedOpened: false,
expectedInputDisabled: true,
},
{
// No restriction, default set to UNSET.
allowedMode: undefined,
defaultMode: PinModeRestriction.UNSET,
expectedCheckboxDisabled: false,
expectedChecked: false,
expectedOpened: false,
expectedInputDisabled: true,
},
{
// No restriction, default set to PIN.
allowedMode: undefined,
defaultMode: PinModeRestriction.PIN,
expectedCheckboxDisabled: false,
expectedChecked: true,
expectedOpened: true,
expectedInputDisabled: false,
},
{
// No restriction, default set to NO_PIN.
allowedMode: undefined,
defaultMode: PinModeRestriction.NO_PIN,
expectedCheckboxDisabled: false,
expectedChecked: false,
expectedOpened: false,
expectedInputDisabled: true,
},
{
// Restriction se to UNSET.
allowedMode: PinModeRestriction.UNSET,
defaultMode: undefined,
expectedCheckboxDisabled: false,
expectedChecked: false,
expectedOpened: false,
expectedInputDisabled: true,
},
{
// Restriction set to PIN.
allowedMode: PinModeRestriction.PIN,
defaultMode: undefined,
expectedCheckboxDisabled: true,
expectedChecked: true,
expectedOpened: true,
expectedInputDisabled: false,
},
{
// Restriction set to NO_PIN.
allowedMode: PinModeRestriction.NO_PIN,
defaultMode: undefined,
expectedCheckboxDisabled: true,
expectedChecked: false,
expectedOpened: false,
expectedInputDisabled: true,
},
{
// Restriction set to PIN, default is ignored.
allowedMode: PinModeRestriction.NO_PIN,
defaultMode: PinModeRestriction.PIN,
expectedCheckboxDisabled: true,
expectedChecked: false,
expectedOpened: false,
expectedInputDisabled: true,
},
];
for (const subtestParams of tests) {
const initialSettings = getDefaultInitialSettings();
if (subtestParams.allowedMode !== undefined ||
subtestParams.defaultMode !== undefined) {
const policy = {};
if (subtestParams.allowedMode !== undefined) {
policy.allowedMode = subtestParams.allowedMode;
}
if (subtestParams.defaultMode !== undefined) {
policy.defaultMode = subtestParams.defaultMode;
}
initialSettings.policies = {"pin": policy};
}
const appState = {version: 2, "pinValue": "0000"};
if (subtestParams.defaultMode !== undefined) {
appState.isPinEnabled = !subtestParams.defaultMode;
}
initialSettings.serializedAppStateStr = JSON.stringify(appState);
await loadInitialSettings(initialSettings);
const pinSettingsSection =
page.$$('print-preview-sidebar').$$('print-preview-pin-settings');
const checkbox = pinSettingsSection.$$('cr-checkbox');
const collapse = pinSettingsSection.$$('iron-collapse');
const input = pinSettingsSection.$$('cr-input');
assertEquals(subtestParams.expectedCheckboxDisabled, checkbox.disabled);
assertEquals(subtestParams.expectedChecked, checkbox.checked);
assertEquals(subtestParams.expectedOpened, collapse.opened);
assertEquals(subtestParams.expectedInputDisabled, input.disabled);
}
});
// </if>
});

@ -235,6 +235,18 @@ GEN('#if defined(OS_CHROMEOS)');
TEST_F('PrintPreviewPolicyTest', 'SheetsPolicy', function() {
this.runMochaTest(policy_tests.TestNames.SheetsPolicy);
});
TEST_F('PrintPreviewPolicyTest', 'ColorPolicy', function() {
this.runMochaTest(policy_tests.TestNames.ColorPolicy);
});
TEST_F('PrintPreviewPolicyTest', 'DuplexPolicy', function() {
this.runMochaTest(policy_tests.TestNames.DuplexPolicy);
});
TEST_F('PrintPreviewPolicyTest', 'PinPolicy', function() {
this.runMochaTest(policy_tests.TestNames.PinPolicy);
});
GEN('#endif');
// eslint-disable-next-line no-var
@ -986,13 +998,6 @@ TEST_F(
destination_search_test_chromeos.TestNames.ResolutionFails);
});
TEST_F(
'PrintPreviewDestinationSearchTestChromeOS',
'ReceiveSuccessfultSetupWithPolicies', function() {
this.runMochaTest(
destination_search_test_chromeos.TestNames.ResolutionFails);
});
TEST_F(
'PrintPreviewDestinationSearchTestChromeOS', 'CloudKioskPrinter',
function() {

@ -173,17 +173,17 @@ struct CapabilitiesResponse {
// Printer capabilities and defaults corresponding to the
// PrinterSemanticCapsAndDefaults class in printing/backend/print_backend.h.
printing.mojom.PrinterSemanticCapsAndDefaults? capabilities@2;
// The fields below are no longer used.
// Bitmask of allowed color modes corresponding to the ColorModeRestriction
// enum in printing/backend/printing_restrictions.h.
uint32 allowed_color_modes@3;
uint32 allowed_color_modes_deprecated@3;
// Bitmask of allowed duplex modes.
uint32 allowed_duplex_modes@4;
[MinVersion=1] printing.mojom.PinModeRestriction allowed_pin_modes@9;
printing.mojom.ColorModeRestriction default_color_mode@6;
printing.mojom.DuplexModeRestriction default_duplex_mode@7;
printing.mojom.PinModeRestriction default_pin_mode@8;
// No longer used.
uint32 allowed_pin_modes_deprecated@5;
uint32 allowed_duplex_modes_deprecated@4;
uint32 allowed_pin_modes_deprecated_version_0@5;
[MinVersion=1] printing.mojom.PinModeRestriction allowed_pin_modes_deprecated_version_1@9;
printing.mojom.ColorModeRestriction default_color_mode_deprecated@6;
printing.mojom.DuplexModeRestriction default_duplex_mode_deprecated@7;
printing.mojom.PinModeRestriction default_pin_mode_deprecated@8;
};
// Global print policies that are not printer specific.
@ -202,6 +202,15 @@ struct Policies {
// Indicates how many sheets is allowed to use for a single print job.
uint32 max_sheets_allowed@5;
bool max_sheets_allowed_has_value@6;
// Bitmask of allowed color modes corresponding to the ColorModeRestriction
// enum in printing/backend/printing_restrictions.h.
[MinVersion=1] uint32 allowed_color_modes@7;
// Bitmask of allowed duplex modes.
[MinVersion=1] uint32 allowed_duplex_modes@8;
[MinVersion=1] printing.mojom.PinModeRestriction allowed_pin_modes@9;
[MinVersion=1] printing.mojom.ColorModeRestriction default_color_mode@10;
[MinVersion=1] printing.mojom.DuplexModeRestriction default_duplex_mode@11;
[MinVersion=1] printing.mojom.PinModeRestriction default_pin_mode@12;
// Allowed background graphics modes.
// This is used in pref file and should never change.
// Corresponds to enum class BackgroundGraphicsModeRestriction in

@ -16,11 +16,11 @@ namespace printing {
#if defined(OS_CHROMEOS)
// Allowed printing modes as a bitmask.
// This is used in pref file and should never change.
// This is used in pref file and crosapi. It should never change.
using ColorModeRestriction = mojom::ColorModeRestriction;
// Allowed duplex modes as a bitmask.
// This is used in pref file and should never change.
// This is used in pref file and crosapi. It should never change.
using DuplexModeRestriction = mojom::DuplexModeRestriction;
// Allowed PIN printing modes.